/src/iotjs_string_ext.inl.h
/src/iotjs_module_inl.h
/test/tmp/*
+/test/dynamicmodule/build/*
eslint.log
# IDE related files
os: linux
dist: trusty
-sudo: required
+sudo: false
services:
- docker
before_install:
- - 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
+ - if [[ "$RUN_DOCKER" == "yes" ]]; then docker pull iotjs/ubuntu:0.9; fi
script:
tools/travis_script.py
-env:
- global:
- - secure: "lUGzoKK/Yn4/OmpqLQALrIgfY9mQWE51deUawPrCO87UQ2GknfQ4BvwY3UT5QY0XnztPBP1+vRQ2qxbiAU7VWicp280sXDnh0FeuZD14FcE9l0FczraL12reoLu+gY5HWFfbkZncmcBsZkxDEYxhkM14FJU8fxyqGQW2ypJNz+gUGP+8r40Re5J3WjcddCQNe5IG8U+M9B4YeDHhN2QspLdN5pkgn56XtdGa3+qbecO2NpjJG5ltM9j1tTuo/Dg22DxrIFVfeFSFKUj4nfMrgPo5LevRsC/lfaBSCsj751eqrxRcQRh2hkpiIJ7mEBs2LL1EH9O6Mbj+eRh8BvIYqTB85VPNFc43sLWk14apcSVBrxJE5j3kP9sAsOD9Y5JynnkeuxYyISrkywwoX2uxsmCzIfGbwsv5VLToQzrqWlGYrHOAmVXNi8561dLfsWwxxFUjdqkZr1Kgc8UfnBEcBUtSiKCHS86/YUUbBJGkEkjDUS0GiqhFY4bXLQCR7EX4qDX3m6p7Mnh4NVUolpnSmyeYE/MjmqQ+7PJsPLL3EcIYmJ7dtW3mZ3yE2NyaFD0Pym9+TiuCCXRtrNVK1M3Kya64KNv+HbhjT/fTCgXLSeyDmJOKVAqugRlDo3b1KGR1LI0AfegzSA6mEC4e9JLjYiSnHPMUahzgLt8oU0hNFRY="
- matrix:
- - OPTS="host-linux" RUN_DOCKER=yes
- - 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" 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:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - gcc-4.9
- - gcc-4.9-multilib
- env: OPTS="asan" ASAN_OPTIONS=detect_stack_use_after_return=1:check_initialization_order=true:strict_init_order=true
- - compiler: gcc-4.9
- before_install: tools/apt-get-install-travis-i686.sh
+ - env:
+ - JOBNAME="Linux/x86-64 Build & Correctness Tests"
+ - OPTS="host-linux"
+ - RUN_DOCKER=yes
+ - env:
+ - JOBNAME="Mock Linux Build & Correctness Tests"
+ - OPTS="mock-linux"
+ - RUN_DOCKER=yes
+ - env:
+ - JOBNAME="Raspberry Pi 2 Build Test"
+ - OPTS="rpi2"
+ - RUN_DOCKER=yes
+ - env:
+ - JOBNAME="STM32f4 Discovery with Nuttx Build Test"
+ - OPTS="stm32f4dis"
+ - RUN_DOCKER=yes
+ - env:
+ - JOBNAME="Artik053 with TizenRT Build Test"
+ - OPTS="artik053"
+ - RUN_DOCKER=yes
+ - env:
+ - JOBNAME="Tizen Build Test"
+ - OPTS="tizen"
+ - RUN_DOCKER=yes
+ - env:
+ - JOBNAME="ECMAScript 2015 features Build & Correctness Tests"
+ - OPTS="es2015"
+ - RUN_DOCKER=yes
+ - env:
+ - JOBNAME="External modules Build & Correctness Tests"
+ - OPTS="external-modules"
+ - RUN_DOCKER=yes
+ - env:
+ - JOBNAME="Linux/x86-64 without snapshot Build & Correctness Tests"
+ - OPTS="no-snapshot"
+ - RUN_DOCKER=yes
+ - env:
+ - JOBNAME="Misc checks (e.g. style checker)"
+ - OPTS="misc"
addons:
apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - gcc-4.9
- - gcc-4.9-multilib
- env: OPTS="ubsan" UBSAN_OPTIONS=print_stacktrace=1
- - os: linux
+ packages: [valgrind, clang-format-3.9]
+ - env:
+ - JOBNAME="OSX/x86-64 Build & Correctness Tests"
+ - OPTS="host-darwin"
+ os: osx
+ install: tools/brew-install-deps.sh
+ - env:
+ - JOBNAME="ASAN Tests"
+ - OPTS="asan"
+ - RUN_DOCKER=yes
+ - env:
+ - JOBNAME="UBSAN Tests"
+ - OPTS="ubsan"
+ - RUN_DOCKER=yes
+ - env:
+ - JOBNAME="Coverity Scan"
+ - OPTS="coverity"
+ # Declaration of the encrypted COVERITY_SCAN_TOKEN, created via the
+ # "travis encrypt" command using the project repo's public key.
+ - secure: "lUGzoKK/Yn4/OmpqLQALrIgfY9mQWE51deUawPrCO87UQ2GknfQ4BvwY3UT5QY0XnztPBP1+vRQ2qxbiAU7VWicp280sXDnh0FeuZD14FcE9l0FczraL12reoLu+gY5HWFfbkZncmcBsZkxDEYxhkM14FJU8fxyqGQW2ypJNz+gUGP+8r40Re5J3WjcddCQNe5IG8U+M9B4YeDHhN2QspLdN5pkgn56XtdGa3+qbecO2NpjJG5ltM9j1tTuo/Dg22DxrIFVfeFSFKUj4nfMrgPo5LevRsC/lfaBSCsj751eqrxRcQRh2hkpiIJ7mEBs2LL1EH9O6Mbj+eRh8BvIYqTB85VPNFc43sLWk14apcSVBrxJE5j3kP9sAsOD9Y5JynnkeuxYyISrkywwoX2uxsmCzIfGbwsv5VLToQzrqWlGYrHOAmVXNi8561dLfsWwxxFUjdqkZr1Kgc8UfnBEcBUtSiKCHS86/YUUbBJGkEkjDUS0GiqhFY4bXLQCR7EX4qDX3m6p7Mnh4NVUolpnSmyeYE/MjmqQ+7PJsPLL3EcIYmJ7dtW3mZ3yE2NyaFD0Pym9+TiuCCXRtrNVK1M3Kya64KNv+HbhjT/fTCgXLSeyDmJOKVAqugRlDo3b1KGR1LI0AfegzSA6mEC4e9JLjYiSnHPMUahzgLt8oU0hNFRY="
before_install:
- - tools/apt-get-install-deps.sh
- echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
addons:
coverity_scan:
notification_email: duddlf.choi@samsung.com
build_command: "tools/travis_script.py"
branch_pattern: master
- env: OPTS="coverity"
- - os: linux
+ - env:
+ - JOBNAME="SonarQube"
addons:
sonarcloud:
organization: "samsung-iotjs"
cache:
directories:
- '$HOME/.sonar/cache'
- env: OPTS="sonarqube"
fast_finish: true
set(IOTJS_VERSION_MAJOR 1)
set(IOTJS_VERSION_MINOR 0)
-# Do a few default checks
-if(NOT DEFINED PLATFORM_DESCRIPTOR)
- message(FATAL_ERROR "No PLATFORM_DESCRIPTOR specified (format: <arch>-<os>)")
-endif()
-
-string(REPLACE "-" ";" PLATFORM_ARGS ${PLATFORM_DESCRIPTOR})
if(NOT DEFINED TARGET_OS)
- list(GET PLATFORM_ARGS 1 TARGET_OS)
+ string(TOLOWER ${CMAKE_SYSTEM_NAME} TARGET_OS)
message(
- "TARGET_OS not specified, using '${TARGET_OS}' from PLATFORM_DESCRIPTOR")
+ "TARGET_OS not specified, using '${TARGET_OS}' from CMAKE_SYSTEM_NAME")
endif()
if(NOT CMAKE_BUILD_TYPE)
iotjs_add_flags(IOTJS_LINKER_FLAGS ${ARGV})
endmacro()
+macro(build_lib_name LIB_VAR NAME)
+ set(${LIB_VAR}
+ ${CMAKE_STATIC_LIBRARY_PREFIX}${NAME}${CMAKE_STATIC_LIBRARY_SUFFIX})
+endmacro()
+
+if(CMAKE_C_COMPILER_ID MATCHES "MSVC")
+ set(USING_MSVC 1)
+ set(CONFIG_TYPE $<$<CONFIG:Debug>:Debug>$<$<CONFIG:Release>:Release>)
+ # disable warning C4820: 'x' bytes padding added after construct 'membername'
+ iotjs_add_compile_flags(-wd4820)
+endif()
+
CHECK_C_COMPILER_FLAG(-no-pie HAS_NO_PIE)
# Add buildtype-related flags
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
iotjs_add_compile_flags(-DDEBUG -DENABLE_DEBUG_LOG)
- if(HAS_NO_PIE)
+ if(HAS_NO_PIE AND NOT "${TARGET_OS}" STREQUAL "darwin")
iotjs_add_link_flags(-no-pie)
endif()
endif()
if("${TARGET_ARCH}" STREQUAL "arm")
iotjs_add_compile_flags(-D__arm__ -mthumb -fno-short-enums -mlittle-endian)
elseif("${TARGET_ARCH}" STREQUAL "i686")
- iotjs_add_compile_flags(-D__i686__ -D__x86__ -march=i686 -m32)
+ iotjs_add_compile_flags(-D__i686__ -D__x86__)
+ if(NOT USING_MSVC)
+ iotjs_add_compile_flags(-march=i686 -m32)
+ endif()
elseif("${TARGET_ARCH}" STREQUAL "x86_64")
iotjs_add_compile_flags(-D__x86_64__)
elseif("${TARGET_ARCH}" STREQUAL "mips")
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 -rdynamic)
- iotjs_add_link_flags(-pthread)
+ iotjs_add_compile_flags(-D__LINUX__ -fno-builtin)
+ iotjs_add_link_flags(-pthread -rdynamic)
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__TIZEN__ -fno-builtin -rdynamic)
- iotjs_add_link_flags(-pthread)
+ iotjs_add_compile_flags(-D__TIZEN__ -fno-builtin)
+ iotjs_add_link_flags(-pthread -rdynamic)
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 "windows")
+ message("Windows support is experimental!")
+ if(NOT EXPERIMENTAL)
+ message(FATAL_ERROR "Missing --experimental build option for Windows!")
+ endif()
elseif("${TARGET_OS}" STREQUAL "openwrt")
message("OpenWrt support is experimental!")
if(NOT EXPERIMENTAL)
include(ExternalProject)
+if(NOT ${EXTERNAL_LIBC_INTERFACE} STREQUAL "")
+ iotjs_add_compile_flags(-isystem ${EXTERNAL_LIBC_INTERFACE})
+endif()
+
# Include external projects
include(cmake/jerry.cmake)
include(cmake/http-parser.cmake)
# IoT.js: Platform for Internet of Things with JavaScript
[](LICENSE)
[](https://travis-ci.org/Samsung/iotjs)
-[](https://scan.coverity.com/projects/samsung-iotjs)
+[](https://scan.coverity.com/projects/samsung-iotjs)
+[](https://sonarcloud.io/dashboard?id=samsung.iot.js)
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FSamsung%2Fiotjs?ref=badge_shield)
[](https://kiwiirc.com/client/irc.freenode.net/#iotjs)
The following table shows the latest results on the devices:
-| Artik053 | [](https://samsung.github.io/iotjs-test-results/?view=artik053) |
+| Artik053 | [](https://samsung.github.io/iotjs-test-results/?view=artik053) |
| :---: | :---: |
-| **Artik530** | [](https://samsung.github.io/iotjs-test-results/?view=artik530) |
-| **Raspberry Pi 2** | [](https://samsung.github.io/iotjs-test-results/?view=rpi2) |
-| **STM32F4-Discovery** | [](https://samsung.github.io/iotjs-test-results/?view=stm32f4dis) |
+| **Artik530** | [](https://samsung.github.io/iotjs-test-results/?view=artik530) |
+| **Raspberry Pi 2** | [](https://samsung.github.io/iotjs-test-results/?view=rpi2) |
+| **STM32F4-Discovery** | [](https://samsung.github.io/iotjs-test-results/?view=stm32f4dis) |
IRC channel: #iotjs on [freenode](https://freenode.net)
--- /dev/null
+version: 1.0.{build}
+pull_requests:
+ do_not_increment_build_number: true
+branches:
+ except:
+ - coverity_scan
+ - gh_pages
+skip_tags: true
+image:
+ - Visual Studio 2017
+configuration:
+ - Debug
+ - Release
+platform:
+ - Win32
+init:
+ - cmd: |
+ cmake -version
+before_build:
+ - cmd: |
+ tools\build.py --experimental --buildtype=debug
+
+artifacts:
+ - path: build\i686-windows\debug\bin\$(configuration)\
+ name: IoTjsbinary
+
+build:
+ project: build\i686-windows\debug\IOTJS.sln
+ parallel: true
+ verbosity: minimal
--- /dev/null
+# 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.
+
+set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSTEM_PROCESSOR i686)
+
+set(CMAKE_C_COMPILER CL.exe)
+set(CMAKE_C_COMPILER_WORKS TRUE)
--- /dev/null
+# 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 Linux)
--- /dev/null
+# 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 MockLinux)
+set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(HTTPPARSER_NUTTX_ARG -DNUTTX_HOME=${TARGET_SYSTEMROOT})
endif()
+build_lib_name(HTTPPARSER_NAME httpparser)
+
set(DEPS_HTTPPARSER deps/http-parser)
set(DEPS_HTTPPARSER_SRC ${ROOT_DIR}/${DEPS_HTTPPARSER}/)
ExternalProject_Add(http-parser
BUILD_IN_SOURCE 0
BINARY_DIR ${DEPS_HTTPPARSER}
INSTALL_COMMAND
- ${CMAKE_COMMAND} -E copy
- ${CMAKE_BINARY_DIR}/${DEPS_HTTPPARSER}/libhttpparser.a
+ ${CMAKE_COMMAND} -E copy_directory
+ ${CMAKE_BINARY_DIR}/${DEPS_HTTPPARSER}/${CONFIG_TYPE}/
${CMAKE_BINARY_DIR}/lib/
CMAKE_ARGS
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
add_library(libhttp-parser STATIC IMPORTED)
add_dependencies(libhttp-parser http-parser)
set_property(TARGET libhttp-parser PROPERTY
- IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libhttpparser.a)
+ IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${HTTPPARSER_NAME})
set_property(DIRECTORY APPEND PROPERTY
- ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/lib/libhttpparser.a)
+ ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/lib/${HTTPPARSER_NAME})
set(HTTPPARSER_INCLUDE_DIR ${DEPS_HTTPPARSER_SRC})
endforeach()
# Common compile flags
-iotjs_add_compile_flags(-Wall -Wextra -Werror -Wno-unused-parameter)
-iotjs_add_compile_flags(-Wsign-conversion -std=gnu99)
+iotjs_add_compile_flags(-Wall)
+if(NOT USING_MSVC)
+ iotjs_add_compile_flags(-Wextra -Werror -Wno-unused-parameter)
+ iotjs_add_compile_flags(-Wsign-conversion -std=gnu99)
+endif()
if(ENABLE_SNAPSHOT)
set(JS2C_SNAPSHOT_ARG --snapshot-tool=${JERRY_HOST_SNAPSHOT})
set(JS2C_RUN_MODE "debug")
endif()
+if(USING_MSVC)
+ set(JS2C_PREPROCESS_ARGS /EP /d1PP)
+else()
+ set(JS2C_PREPROCESS_ARGS -E -dD)
+endif()
+
+string (REPLACE ";" "," IOTJS_JS_MODULES_STR "${IOTJS_JS_MODULES}")
add_custom_command(
OUTPUT ${IOTJS_SOURCE_DIR}/iotjs_js.c ${IOTJS_SOURCE_DIR}/iotjs_js.h
- COMMAND ${CMAKE_C_COMPILER} -E -dD ${IOTJS_MODULE_DEFINES}
+ COMMAND ${CMAKE_C_COMPILER} ${JS2C_PREPROCESS_ARGS} ${IOTJS_MODULE_DEFINES}
${IOTJS_SOURCE_DIR}/iotjs_magic_strings.h
- | grep IOTJS_MAGIC_STRING
> ${IOTJS_SOURCE_DIR}/iotjs_magic_strings.in
COMMAND python ${ROOT_DIR}/tools/js2c.py
ARGS --buildtype=${JS2C_RUN_MODE}
- --modules '${IOTJS_JS_MODULES}'
+ --modules "${IOTJS_JS_MODULES_STR}"
${JS2C_SNAPSHOT_ARG}
COMMAND ${CMAKE_COMMAND} -E remove
-f ${IOTJS_SOURCE_DIR}/iotjs_magic_strings.in
${MODULES_INCLUDE_DIR}
${PLATFORM_OS_DIR}
${JERRY_PORT_DIR}/include
+ ${JERRY_EXT_DIR}/include
${JERRY_INCLUDE_DIR}
${HTTPPARSER_INCLUDE_DIR}
${MBEDTLS_INCLUDE_DIR}
if(NOT BUILD_LIB_ONLY)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
iotjs_add_link_flags("-Xlinker -map -Xlinker iotjs.map")
+ elseif(USING_MSVC)
+ iotjs_add_link_flags("/MAP:iotjs.map")
else()
iotjs_add_link_flags("-Xlinker -Map -Xlinker iotjs.map")
endif()
message(STATUS "JERRY_HEAP_SIZE_KB ${MEM_HEAP_SIZE_KB}")
message(STATUS "JERRY_MEM_STATS ${FEATURE_MEM_STATS}")
message(STATUS "JERRY_PROFILE ${FEATURE_PROFILE}")
-message(STATUS "PLATFORM_DESCRIPTOR ${PLATFORM_DESCRIPTOR}")
message(STATUS "TARGET_ARCH ${TARGET_ARCH}")
message(STATUS "TARGET_BOARD ${TARGET_BOARD}")
message(STATUS "TARGET_OS ${TARGET_OS}")
message(STATUS "TARGET_SYSTEMROOT ${TARGET_SYSTEMROOT}")
iotjs_add_compile_flags(${IOTJS_MODULE_DEFINES})
+if(FEATURE_DEBUGGER)
+ iotjs_add_compile_flags("-DJERRY_DEBUGGER")
+endif()
# Configure the libiotjs.a
set(TARGET_STATIC_IOTJS libiotjs)
install(TARGETS ${TARGET_STATIC_IOTJS} DESTINATION ${LIB_INSTALL_DIR})
+# Install headers
+if("${INCLUDE_INSTALL_DIR}" STREQUAL "")
+ set(INCLUDE_INSTALL_DIR "include/iotjs")
+endif()
+file(GLOB IOTJS_HEADERS include/*.h)
+install(FILES ${IOTJS_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR})
+
# Configure the libiotjs.so
if (NOT BUILD_LIB_ONLY AND CREATE_SHARED_LIB)
set(TARGET_SHARED_IOTJS shared_iotjs)
${MBEDTLS_LIBS}
-Wl,--no-whole-archive
${EXTERNAL_LIBS})
+ install(TARGETS ${TARGET_SHARED_IOTJS} DESTINATION ${LIB_INSTALL_DIR})
endif()
# Configure the iotjs executable
SOURCE_DIR ${ROOT_DIR}/deps/jerry/
BUILD_IN_SOURCE 0
BINARY_DIR ${DEPS_HOST_JERRY}
- INSTALL_COMMAND ""
CMAKE_ARGS
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/${DEPS_HOST_JERRY}
-DENABLE_ALL_IN_ONE=ON
-DENABLE_LTO=${ENABLE_LTO}
- -DJERRY_LIBC=OFF
-DJERRY_CMDLINE=OFF
-DJERRY_CMDLINE_SNAPSHOT=ON
- -DJERRY_EXT=OFF
+ -DJERRY_EXT=ON
+ -DFEATURE_LOGGING=ON
-DFEATURE_SNAPSHOT_SAVE=${ENABLE_SNAPSHOT}
-DFEATURE_PROFILE=${FEATURE_PROFILE}
${EXTRA_JERRY_CMAKE_PARAMS}
+
+ # The snapshot tool does not require the system allocator
+ # turn it off by default.
+ #
+ # Additionally this is required if one compiles on a
+ # 64bit system to a 32bit system with system allocator
+ # enabled. This is beacuse on 64bit the system allocator
+ # should not be used as it returns 64bit pointers which
+ # can not be represented correctly in the JerryScript engine
+ # currently.
+ -DFEATURE_SYSTEM_ALLOCATOR=OFF
)
set(JERRY_HOST_SNAPSHOT
${CMAKE_BINARY_DIR}/${DEPS_HOST_JERRY}/bin/jerry-snapshot)
endmacro(add_cmake_arg)
# Target libjerry
-set(JERRY_LIBS jerry-core jerry-port-default)
+set(JERRY_LIBS jerry-core jerry-port-default jerry-ext)
set(DEPS_LIB_JERRY_ARGS)
# Configure the MinSizeRel as the default build type
endif()
-# use system libc/libm on Unix like targets
+# use system libm on Unix like targets
if("${TARGET_OS}" MATCHES "TIZENRT|NUTTX")
list(APPEND JERRY_LIBS jerry-libm)
list(APPEND DEPS_LIB_JERRY_ARGS
- -DJERRY_LIBC=OFF
-DJERRY_LIBM=ON
- -DEXTERNAL_LIBC_INTERFACE=${EXTERNAL_LIBC_INTERFACE}
-DEXTERNAL_CMAKE_SYSTEM_PROCESSOR=${EXTERNAL_CMAKE_SYSTEM_PROCESSOR}
)
elseif("${TARGET_OS}" MATCHES "LINUX|TIZEN|DARWIN|OPENWRT")
list(APPEND JERRY_LIBS m)
list(APPEND DEPS_LIB_JERRY_ARGS
- -DJERRY_LIBC=OFF
+ -DJERRY_LIBM=OFF)
+elseif("${TARGET_OS}" MATCHES "WINDOWS")
+ list(APPEND DEPS_LIB_JERRY_ARGS
-DJERRY_LIBM=OFF)
else()
- list(APPEND JERRY_LIBS jerry-libm jerry-libc)
+ list(APPEND JERRY_LIBS jerry-libm)
list(APPEND DEPS_LIB_JERRY_ARGS
- -DEXTERNAL_LIBC_INTERFACE=${EXTERNAL_LIBC_INTERFACE}
-DEXTERNAL_CMAKE_SYSTEM_PROCESSOR=${EXTERNAL_CMAKE_SYSTEM_PROCESSOR}
)
endif()
endif()
# NuttX is not using the default port implementation of JerryScript
-if("${TARGET_OS}" MATCHES "NUTTX")
+if("${TARGET_OS}" MATCHES "NUTTX|TIZENRT")
list(APPEND DEPS_LIB_JERRY_ARGS -DJERRY_PORT_DEFAULT=OFF)
else()
list(APPEND DEPS_LIB_JERRY_ARGS -DJERRY_PORT_DEFAULT=ON)
add_cmake_arg(DEPS_LIB_JERRY_ARGS JERRY_HEAP_SECTION_ATTR)
separate_arguments(EXTRA_JERRY_CMAKE_PARAMS)
+
+build_lib_name(JERRY_CORE_NAME jerry-core)
+build_lib_name(JERRY_LIBM_NAME jerry-libm)
+build_lib_name(JERRY_EXT_NAME jerry-ext)
+
set(DEPS_LIB_JERRY deps/jerry)
set(DEPS_LIB_JERRY_SRC ${ROOT_DIR}/${DEPS_LIB_JERRY})
ExternalProject_Add(libjerry
BINARY_DIR ${DEPS_LIB_JERRY}
INSTALL_COMMAND
${CMAKE_COMMAND} -E copy_directory
- ${CMAKE_BINARY_DIR}/${DEPS_LIB_JERRY}/lib/
+ ${CMAKE_BINARY_DIR}/${DEPS_LIB_JERRY}/lib/${CONFIG_TYPE}
${CMAKE_BINARY_DIR}/lib/
CMAKE_ARGS
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
-DFEATURE_SNAPSHOT_EXEC=${ENABLE_SNAPSHOT}
-DFEATURE_SNAPSHOT_SAVE=OFF
-DFEATURE_PROFILE=${FEATURE_PROFILE}
+ -DFEATURE_LOGGING=ON
-DFEATURE_LINE_INFO=${FEATURE_JS_BACKTRACE}
-DFEATURE_VM_EXEC_STOP=ON
-DENABLE_LTO=${ENABLE_LTO}
set_property(DIRECTORY APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
- ${CMAKE_BINARY_DIR}/lib/libjerry-core.a
- ${CMAKE_BINARY_DIR}/lib/libjerry-libm.a
- ${CMAKE_BINARY_DIR}/lib/libjerry-libc.a
+ ${CMAKE_BINARY_DIR}/lib/${JERRY_CORE_NAME}
+ ${CMAKE_BINARY_DIR}/lib/${JERRY_LIBM_NAME}
+ ${CMAKE_BINARY_DIR}/lib/${JERRY_EXT_NAME}
)
# define external jerry-core target
add_library(jerry-core STATIC IMPORTED)
add_dependencies(jerry-core libjerry)
set_property(TARGET jerry-core PROPERTY
- IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libjerry-core.a)
-
-# define external jerry-libc target
-add_library(jerry-libc STATIC IMPORTED)
-add_dependencies(jerry-libc libjerry)
-set_property(TARGET jerry-libc PROPERTY
- IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libjerry-libc.a)
+ IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${JERRY_CORE_NAME})
# define external jerry-libm target
add_library(jerry-libm STATIC IMPORTED)
add_dependencies(jerry-libm libjerry)
set_property(TARGET jerry-libm PROPERTY
- IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libjerry-libm.a)
+ IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${JERRY_LIBM_NAME})
+
+# define external jerry-ext target
+add_library(jerry-ext STATIC IMPORTED)
+add_dependencies(jerry-ext libjerry)
+set_property(TARGET jerry-ext PROPERTY
+ IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${JERRY_EXT_NAME})
-if(NOT "${TARGET_OS}" MATCHES "NUTTX")
+if(NOT "${TARGET_OS}" MATCHES "NUTTX|TIZENRT")
+ build_lib_name(JERRY_PORT_NAME jerry-port)
+ build_lib_name(JERRY_PORT_DEFAULT_NAME jerry-port-default)
set_property(DIRECTORY APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
- ${CMAKE_BINARY_DIR}/lib/libjerry-port.a
+ ${CMAKE_BINARY_DIR}/lib/${JERRY_PORT_NAME}
)
# define external jerry-port-default target
add_library(jerry-port-default STATIC IMPORTED)
add_dependencies(jerry-port-default libjerry)
set_property(TARGET jerry-port-default PROPERTY
- IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libjerry-port-default.a)
+ IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${JERRY_PORT_DEFAULT_NAME})
set(JERRY_PORT_DIR ${DEPS_LIB_JERRY_SRC}/jerry-port/default)
endif()
set(JERRY_INCLUDE_DIR ${DEPS_LIB_JERRY_SRC}/jerry-core/include)
+set(JERRY_EXT_DIR ${DEPS_LIB_JERRY_SRC}/jerry-ext)
set(DEPS_TUV deps/libtuv)
set(DEPS_TUV_SRC ${ROOT_DIR}/${DEPS_TUV})
+build_lib_name(LIBTUV_NAME tuv)
+if("${TARGET_OS}" STREQUAL "MOCK")
+ string(TOLOWER ${TARGET_ARCH}-linux PLATFORM_DESCRIPTOR)
+else()
+ string(TOLOWER ${TARGET_ARCH}-${TARGET_OS} PLATFORM_DESCRIPTOR)
+endif()
set(DEPS_TUV_TOOLCHAIN
${DEPS_TUV_SRC}/cmake/config/config_${PLATFORM_DESCRIPTOR}.cmake)
message(STATUS "libtuv toolchain file: ${DEPS_TUV_TOOLCHAIN}")
BUILD_IN_SOURCE 0
BINARY_DIR ${DEPS_TUV}
INSTALL_COMMAND
- ${CMAKE_COMMAND} -E copy
- ${CMAKE_BINARY_DIR}/${DEPS_TUV}/lib/libtuv.a
+ ${CMAKE_COMMAND} -E copy_directory
+ ${CMAKE_BINARY_DIR}/${DEPS_TUV}/lib/${CONFIG_TYPE}/
${CMAKE_BINARY_DIR}/lib/
CMAKE_ARGS
-DCMAKE_TOOLCHAIN_FILE=${DEPS_TUV_TOOLCHAIN}
add_library(tuv STATIC IMPORTED)
add_dependencies(tuv libtuv)
set_property(TARGET tuv PROPERTY
- IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libtuv.a)
+ IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${LIBTUV_NAME})
set_property(DIRECTORY APPEND PROPERTY
- ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/lib/libtuv.a)
+ ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/lib/${LIBTUV_NAME})
set(TUV_INCLUDE_DIR ${DEPS_TUV_SRC}/include)
set(TUV_LIBS tuv)
-if("${TARGET_OS}" STREQUAL "LINUX")
+if("${TARGET_OS}" STREQUAL "MOCK" OR
+ "${TARGET_OS}" STREQUAL "LINUX")
list(APPEND TUV_LIBS pthread)
+elseif("${TARGET_OS}" STREQUAL "WINDOWS")
+ list(APPEND TUV_LIBS
+ ws2_32.lib
+ UserEnv.lib
+ advapi32.lib
+ iphlpapi.lib
+ psapi.lib
+ shell32.lib)
endif()
cmake_minimum_required(VERSION 2.8)
-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='<config-for-iotjs.h>'")
+if ("${TARGET_OS}" STREQUAL "TIZENRT")
+ set(MBEDTLS_LIBS "")
+ set(MBEDTLS_INCLUDE_DIR ${TARGET_SYSTEMROOT}/../external/include)
+else()
+ set(DEPS_MBEDTLS deps/mbedtls)
+ set(DEPS_MBEDTLS_SRC ${ROOT_DIR}/${DEPS_MBEDTLS})
+ set(DEPS_MBEDTLS_BUILD_DIR
+ ${CMAKE_BINARY_DIR}/${DEPS_MBEDTLS}/library/${CONFIG_TYPE})
+ set(MODULE_BINARY_DIR ${DEPS_MBEDTLS_BUILD_DIR})
+
+ if("${TARGET_OS}" STREQUAL "TIZEN")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-cpp")
+ endif()
+
+ if(USING_MSVC)
+ set(CONFIG_DELIMITER "")
+ else()
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sign-conversion")
+ set(CONFIG_DELIMITER "'")
+ endif()
-# 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})
+ set(MBED_CONFIG "${CONFIG_DELIMITER}<config-for-iotjs.h>${CONFIG_DELIMITER}")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${ROOT_DIR}/config/mbedtls")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBEDTLS_CONFIG_FILE=${MBED_CONFIG}")
-ExternalProject_Add(mbedtls
- PREFIX ${DEPS_MBEDTLS}
- SOURCE_DIR ${DEPS_MBEDTLS_SRC}
- BUILD_IN_SOURCE 0
- BINARY_DIR ${DEPS_MBEDTLS}
- INSTALL_COMMAND
- COMMAND ${CMAKE_COMMAND} -E copy
- ${DEPS_MBEDTLS_BUILD_DIR}/libmbedx509.a ${ARCHIVE_DIR}
- COMMAND ${CMAKE_COMMAND} -E copy
- ${DEPS_MBEDTLS_BUILD_DIR}/libmbedtls.a ${ARCHIVE_DIR}
- COMMAND ${CMAKE_COMMAND} -E copy
- ${DEPS_MBEDTLS_BUILD_DIR}/libmbedcrypto.a ${ARCHIVE_DIR}
- CMAKE_ARGS
- -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
- -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
- -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
- -DENABLE_PROGRAMS=OFF
- -DENABLE_TESTING=OFF
-)
+ # 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})
-# define external mbedtls target
-add_library(libmbedtls STATIC IMPORTED)
-add_dependencies(libmbedtls mbedtls)
-set_property(TARGET libmbedtls PROPERTY
- IMPORTED_LOCATION ${ARCHIVE_DIR}/libmbedtls.a)
+ build_lib_name(MBED_X509_NAME mbedx509)
+ build_lib_name(MBED_TLS_NAME mbedtls)
+ build_lib_name(MBED_CRYPTO_NAME mbedcrypto)
+ ExternalProject_Add(mbedtls
+ PREFIX ${DEPS_MBEDTLS}
+ SOURCE_DIR ${DEPS_MBEDTLS_SRC}
+ BUILD_IN_SOURCE 0
+ BINARY_DIR ${DEPS_MBEDTLS}
+ INSTALL_COMMAND
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${DEPS_MBEDTLS_BUILD_DIR}/${MBED_X509_NAME} ${ARCHIVE_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${DEPS_MBEDTLS_BUILD_DIR}/${MBED_TLS_NAME} ${ARCHIVE_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${DEPS_MBEDTLS_BUILD_DIR}/${MBED_CRYPTO_NAME} ${ARCHIVE_DIR}
+ CMAKE_ARGS
+ -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
+ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
+ -DENABLE_PROGRAMS=OFF
+ -DENABLE_TESTING=OFF
+ )
-# define external mbedx509 target
-add_library(libmbedx509 STATIC IMPORTED)
-add_dependencies(libmbedx509 mbedx509)
-set_property(TARGET libmbedx509 PROPERTY
- IMPORTED_LOCATION ${ARCHIVE_DIR}/libmbedx509.a)
+ # define external mbedtls target
+ add_library(libmbedtls STATIC IMPORTED)
+ add_dependencies(libmbedtls mbedtls)
+ set_property(TARGET libmbedtls PROPERTY
+ IMPORTED_LOCATION ${ARCHIVE_DIR}/${MBED_TLS_NAME})
-# define external libmbedcrypto target
-add_library(libmbedcrypto STATIC IMPORTED)
-add_dependencies(libmbedcrypto mbedcrypto)
-set_property(TARGET libmbedcrypto PROPERTY
- IMPORTED_LOCATION ${ARCHIVE_DIR}/libmbedcrypto.a)
+ # define external mbedx509 target
+ add_library(libmbedx509 STATIC IMPORTED)
+ add_dependencies(libmbedx509 mbedx509)
+ set_property(TARGET libmbedx509 PROPERTY
+ IMPORTED_LOCATION ${ARCHIVE_DIR}/${MBED_X509_NAME})
-set_property(DIRECTORY APPEND PROPERTY
- ADDITIONAL_MAKE_CLEAN_FILES
- ${ARCHIVE_DIR}/libmbedx509.a
- ${ARCHIVE_DIR}/libmbedtls.a
- ${ARCHIVE_DIR}/libmbedcrypto.a
-)
+ # define external libmbedcrypto target
+ add_library(libmbedcrypto STATIC IMPORTED)
+ add_dependencies(libmbedcrypto mbedcrypto)
+ set_property(TARGET libmbedcrypto PROPERTY
+ IMPORTED_LOCATION ${ARCHIVE_DIR}/${MBED_CRYPTO_NAME})
-set(MBEDTLS_LIBS libmbedtls libmbedx509 libmbedcrypto)
-set(MBEDTLS_INCLUDE_DIR ${DEPS_MBEDTLS}/include)
+ set_property(DIRECTORY APPEND PROPERTY
+ ADDITIONAL_MAKE_CLEAN_FILES
+ ${ARCHIVE_DIR}/${MBED_X509_NAME}
+ ${ARCHIVE_DIR}/${MBED_TLS_NAME}
+ ${ARCHIVE_DIR}/${MBED_CRYPTO_NAME}
+ )
-# 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}")
+ 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}")
+endif()
ASRCS = setjmp.S
CSRCS = jerry_port.c
MAINSRC = iotjs_main.c
-LIBS = libhttpparser.a libiotjs.a libjerry-core.a libtuv.a libjerry-libm.a
+LIBS = libhttpparser.a libiotjs.a libjerry-core.a libtuv.a libjerry-libm.a libjerry-ext.a
AOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))
endif
ifeq ($(CONFIG_WINDOWS_NATIVE),y)
- BIN = ..\..\libapps$(LIBEXT)
+ BIN = $(APPDIR)\libapps$(LIBEXT)
else
ifeq ($(WINTOOL),y)
- BIN = ..\\..\\libapps$(LIBEXT)
+ BIN = $(APPDIR)\\libapps$(LIBEXT)
else
- BIN = ../../libapps$(LIBEXT)
+ BIN = $(APPDIR)/libapps$(LIBEXT)
endif
endif
} /* jerry_port_log */
/**
- * Dummy function to get the time zone.
- *
- * @return true
+ * Dummy function to get local time zone adjustment, in milliseconds,
+ * for the given timestamp.
*/
-bool jerry_port_get_time_zone(jerry_time_zone_t *tz_p) {
- /* We live in UTC. */
- tz_p->offset = 0;
- tz_p->daylight_saving_time = 0;
-
- return true;
-} /* jerry_port_get_time_zone */
+double jerry_port_get_local_time_zone_adjustment(double unix_ms, bool is_utc) {
+ (void)unix_ms;
+ (void)is_utc;
+ return 0.0;
+} /* jerry_port_get_local_time_zone_adjustment */
/**
* Dummy function to get the current time.
+++ /dev/null
-diff --git a/src/iotjs_util.c b/src/iotjs_util.c
-index 62ca214..dd6a978 100644
---- a/src/iotjs_util.c
-+++ b/src/iotjs_util.c
-@@ -58,8 +58,18 @@ iotjs_string_t iotjs_file_read(const char* path) {
- }
-
-
-+#define SIZEOF_MM_ALLOCNODE 8
-+extern void jmem_heap_stat_alloc(size_t size);
-+extern void jmem_heap_stat_free(size_t size);
-+
-+
- char* iotjs_buffer_allocate(size_t size) {
- char* buffer = (char*)(calloc(size, sizeof(char)));
-+
-+ size_t new_size;
-+ memcpy(&new_size, (buffer - SIZEOF_MM_ALLOCNODE), sizeof(size_t));
-+ jmem_heap_stat_alloc(new_size - SIZEOF_MM_ALLOCNODE);
-+
- IOTJS_ASSERT(buffer != NULL);
- return buffer;
- }
-@@ -67,11 +77,26 @@ char* iotjs_buffer_allocate(size_t size) {
-
- char* iotjs_buffer_reallocate(char* buffer, size_t size) {
- IOTJS_ASSERT(buffer != NULL);
-- return (char*)(realloc(buffer, size));
-+
-+ size_t old_size;
-+ memcpy(&old_size, (buffer - SIZEOF_MM_ALLOCNODE), sizeof(size_t));
-+ jmem_heap_stat_free(old_size - SIZEOF_MM_ALLOCNODE);
-+
-+ char* ptr = (char*)(realloc(buffer, size));
-+
-+ size_t new_size;
-+ memcpy(&new_size, (ptr - SIZEOF_MM_ALLOCNODE), sizeof(size_t));
-+ jmem_heap_stat_alloc(new_size - SIZEOF_MM_ALLOCNODE);
-+
-+ return ptr;
- }
-
-
- void iotjs_buffer_release(char* buffer) {
-+ size_t size;
-+ memcpy(&size, (buffer - SIZEOF_MM_ALLOCNODE), sizeof(size_t));
-+ jmem_heap_stat_free(size - SIZEOF_MM_ALLOCNODE);
-+
- IOTJS_ASSERT(buffer != NULL);
- free(buffer);
- }
+++ /dev/null
-diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c
-index 1032881..88db6a3 100644
---- a/jerry-core/api/jerry.c
-+++ b/jerry-core/api/jerry.c
-@@ -149,7 +149,7 @@ jerry_init (jerry_init_flag_t flags) /**< combination of Jerry flags */
- }
-
- /* Zero out all members. */
-- memset (&JERRY_CONTEXT (JERRY_CONTEXT_FIRST_MEMBER), 0, sizeof (jerry_context_t));
-+ // memset (&JERRY_CONTEXT (JERRY_CONTEXT_FIRST_MEMBER), 0, sizeof (jerry_context_t));
-
- JERRY_CONTEXT (jerry_init_flags) = flags;
-
-diff --git a/jerry-core/jmem/jmem-heap.c b/jerry-core/jmem/jmem-heap.c
-index f15ba90..8154880 100644
---- a/jerry-core/jmem/jmem-heap.c
-+++ b/jerry-core/jmem/jmem-heap.c
-@@ -113,8 +113,8 @@ JERRY_STATIC_ASSERT (sizeof (jmem_heap_t) <= JMEM_HEAP_SIZE,
-
- #ifdef JMEM_STATS
- static void jmem_heap_stat_init (void);
--static void jmem_heap_stat_alloc (size_t num);
--static void jmem_heap_stat_free (size_t num);
-+void jmem_heap_stat_alloc (size_t num);
-+void jmem_heap_stat_free (size_t num);
-
- #ifndef JERRY_SYSTEM_ALLOCATOR
- static void jmem_heap_stat_skip (void);
-@@ -580,7 +580,7 @@ jmem_heap_stats_print (void)
- {
- jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
-
-- JERRY_DEBUG_MSG ("Heap stats:\n"
-+ printf ("Heap stats:\n"
- " Heap size = %zu bytes\n"
- " Allocated = %zu bytes\n"
- " Peak allocated = %zu bytes\n"
-@@ -632,7 +632,7 @@ jmem_heap_stat_init (void)
- /**
- * Account allocation
- */
--static void
-+void
- jmem_heap_stat_alloc (size_t size) /**< Size of allocated block */
- {
- const size_t aligned_size = (size + JMEM_ALIGNMENT - 1) / JMEM_ALIGNMENT * JMEM_ALIGNMENT;
-@@ -658,7 +658,7 @@ jmem_heap_stat_alloc (size_t size) /**< Size of allocated block */
- /**
- * Account freeing
- */
--static void
-+void
- jmem_heap_stat_free (size_t size) /**< Size of freed block */
- {
- const size_t aligned_size = (size + JMEM_ALIGNMENT - 1) / JMEM_ALIGNMENT * JMEM_ALIGNMENT;
+++ /dev/null
-diff --git a/src/unix/fs.c b/src/unix/fs.c
-index 4281246..cc0d694 100644
---- a/src/unix/fs.c
-+++ b/src/unix/fs.c
-@@ -98,7 +98,7 @@
- if (cb == NULL) { \
- req->path = path; \
- } else { \
-- req->path = strdup(path); \
-+ req->path = uv__strdup(path); \
- if (req->path == NULL) { \
- uv__req_unregister(loop, req); \
- return -ENOMEM; \
-diff --git a/src/uv-common.c b/src/uv-common.c
-index 813e499..04a7f18 100644
---- a/src/uv-common.c
-+++ b/src/uv-common.c
-@@ -67,7 +67,6 @@ static uv__allocator_t uv__allocator = {
- free,
- };
-
--#if defined(__APPLE__)
- char* uv__strdup(const char* s) {
- size_t len = strlen(s) + 1;
- char* m = uv__malloc(len);
-@@ -75,13 +74,29 @@ char* uv__strdup(const char* s) {
- return NULL;
- return memcpy(m, s, len);
- }
--#endif
-+
-+#define SIZEOF_MM_ALLOCNODE 8
-+extern void jmem_heap_stat_alloc (size_t size);
-+extern void jmem_heap_stat_free (size_t size);
-
- void* uv__malloc(size_t size) {
-- return uv__allocator.local_malloc(size);
-+ char* ptr = (char*)uv__allocator.local_malloc(size);
-+
-+ size_t new_size;
-+ memcpy(&new_size, (ptr - SIZEOF_MM_ALLOCNODE), sizeof(size_t));
-+ jmem_heap_stat_alloc(new_size - SIZEOF_MM_ALLOCNODE);
-+
-+ return (void*)ptr;
- }
-
- void uv__free(void* ptr) {
-+ if (ptr == NULL)
-+ return;
-+
-+ size_t size;
-+ memcpy(&size, (char*)ptr - SIZEOF_MM_ALLOCNODE, sizeof(size_t));
-+ jmem_heap_stat_free(size);
-+
- int saved_errno;
-
- /* Libuv expects that free() does not clobber errno. The system allocator
-@@ -93,11 +108,31 @@ void uv__free(void* ptr) {
- }
-
- void* uv__calloc(size_t count, size_t size) {
-- return uv__allocator.local_calloc(count, size);
-+ char* ptr = (char*)uv__allocator.local_calloc(count, size);
-+
-+ size_t new_size;
-+ memcpy(&new_size, (ptr - SIZEOF_MM_ALLOCNODE), sizeof(size_t));
-+ jmem_heap_stat_alloc(new_size - SIZEOF_MM_ALLOCNODE);
-+
-+ return (void*)ptr;
- }
-
- void* uv__realloc(void* ptr, size_t size) {
-- return uv__allocator.local_realloc(ptr, size);
-+ if (ptr != NULL) {
-+ size_t old_size;
-+ memcpy(&old_size, (char*)ptr - SIZEOF_MM_ALLOCNODE, sizeof(size_t));
-+ jmem_heap_stat_free(old_size - SIZEOF_MM_ALLOCNODE);
-+
-+ char* new_ptr = (char*)uv__allocator.local_realloc(ptr, size);
-+
-+ size_t new_size;
-+ memcpy(&new_size, (new_ptr - SIZEOF_MM_ALLOCNODE), sizeof(size_t));
-+ jmem_heap_stat_alloc(new_size - SIZEOF_MM_ALLOCNODE);
-+
-+ return (void*)new_ptr;
-+ }
-+
-+ return uv__malloc(size);
- }
-
- uv_buf_t uv_buf_init(char* base, unsigned int len) {
-diff --git a/src/uv-common.h b/src/uv-common.h
-index 069b5af..a24de69 100644
---- a/src/uv-common.h
-+++ b/src/uv-common.h
-@@ -239,9 +239,7 @@ void uv__fs_scandir_cleanup(uv_fs_t* req);
-
- /* Allocator prototypes */
- void *uv__calloc(size_t count, size_t size);
--#if defined(__APPLE__)
- char *uv__strdup(const char* s);
--#endif
- void* uv__malloc(size_t size);
- void uv__free(void* ptr);
- void* uv__realloc(void* ptr, size_t size);
+++ /dev/null
-diff --git a/net/socket/getsockname.c b/net/socket/getsockname.c
-index 7bf87c2..79fb7d7 100644
---- a/net/socket/getsockname.c
-+++ b/net/socket/getsockname.c
-@@ -151,10 +151,29 @@ int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
- * a single network device and only the network device knows the IP address.
- */
-
-+ if (lipaddr == 0)
-+ {
-+#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP)
-+ outaddr->sin_family = AF_INET;
-+ outaddr->sin_addr.s_addr = 0;
-+ *addrlen = sizeof(struct sockaddr_in);
-+#endif
-+
-+ return OK;
-+ }
-+
- net_lock();
-
- #ifdef CONFIG_NETDEV_MULTINIC
-- /* Find the device matching the IPv4 address in the connection structure */
-+ /* Find the device matching the IPv4 address in the connection structure.
-+ * NOTE: listening sockets have no ripaddr. Work around is to use the
-+ * lipaddr when ripaddr is not available.
-+ */
-+
-+ if (ripaddr == 0)
-+ {
-+ ripaddr = lipaddr;
-+ }
-
- dev = netdev_findby_ipv4addr(lipaddr, ripaddr);
- #else
-@@ -274,10 +293,29 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
- * a single network device and only the network device knows the IP address.
- */
-
-+ if (net_ipv6addr_cmp(lipaddr, g_ipv6_allzeroaddr))
-+ {
-+#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
-+ outaddr->sin6_family = AF_INET6;
-+ memcpy(outaddr->sin6_addr.in6_u.u6_addr8, g_ipv6_allzeroaddr, 16);
-+ *addrlen = sizeof(struct sockaddr_in6);
-+#endif
-+
-+ return OK;
-+ }
-+
- net_lock();
-
- #ifdef CONFIG_NETDEV_MULTINIC
-- /* Find the device matching the IPv6 address in the connection structure */
-+ /* Find the device matching the IPv6 address in the connection structure.
-+ * NOTE: listening sockets have no ripaddr. Work around is to use the
-+ * lipaddr when ripaddr is not available.
-+ */
-+
-+ if (net_ipv6addr_cmp(ripaddr, g_ipv6_allzeroaddr))
-+ {
-+ ripaddr = lipaddr;
-+ }
-
- dev = netdev_findby_ipv6addr(*lipaddr, *ripaddr);
- #else
-diff --git a/net/socket/listen.c b/net/socket/listen.c
-index 0d91ccb..4409a0e 100644
---- a/net/socket/listen.c
-+++ b/net/socket/listen.c
-@@ -142,7 +142,12 @@ int psock_listen(FAR struct socket *psock, int backlog)
- * accept() is called and enables poll()/select() logic.
- */
-
-- tcp_listen(conn);
-+ errcode = tcp_listen(conn);
-+ if (errcode < 0)
-+ {
-+ errcode = -errcode;
-+ goto errout;
-+ }
- }
- #endif /* CONFIG_NET_TCP */
-
--- /dev/null
+P /.git
+- .git
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"
+ echo " ~/GBS-ROOT/local/repos/tizen50m2/armv7l/RPMS"
else
echo "GBS Build failed!"
ret=1
Source1001: %{name}.manifest
ExclusiveArch: %arm %ix86 x86_64
-
BuildRequires: python
BuildRequires: cmake
BuildRequires: glibc-static
# Initialize the variables
%{!?build_mode: %define build_mode release}
%{!?external_build_options: %define external_build_options %{nil}}
+
%package service
Summary: Development files for %{name}
Group: Network & Connectivity/Service
cat LICENSE
cp %{SOURCE1001} .
-
%build
V=1 VERBOSE=1 ./tools/build.py \
--clean \
--buildtype=%{build_mode} \
--profile=test/profiles/tizen.profile \
+ --jerry-profile $PWD/test/profiles/tizen-jerry.profile \
+ --js-backtrace ON \
--target-arch=noarch \
--target-os=tizen \
%ifarch %{arm}
--external-lib=appcore-agent \
--external-lib=pthread \
--external-lib=curl \
+ --external-lib=glib-2.0 \
--external-include-dir=/usr/include/dlog/ \
--external-include-dir=/usr/include/appcore-agent/ \
--external-include-dir=/usr/include/appfw/ \
--compile-flag="%(pkg-config --cflags glib-2.0)" \
--compile-flag=-D__TIZEN__ \
--compile-flag=-DENABLE_DEBUG_LOG \
- --jerry-cmake-param=-DENABLE_STATIC_LINK=OFF \
--create-shared-lib \
--no-init-submodule \
--no-parallel-build \
--- /dev/null
+#!/bin/bash
+ROOT=`pwd`
+
+# 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.
+
+echo "******************************************************************"
+echo "* Tizen release script *"
+echo "******************************************************************"
+
+repo=$1
+
+if [ "$repo" == "../iotjs_tizen" -o "$repo" == "../iotjs_tizen/" ]; then
+ echo "Syncing with: tizen iotjs"
+else
+ echo "Usage: $0 [ ../iotjs_tizen ]"
+ exit 0
+fi
+
+if [ ! -d ../iotjs_tizen ]; then
+ # echo "cloning..."
+ echo "Error: $repo not exist"
+ exit 0
+fi
+
+cd ..
+echo copy from $OLDPWD to ../iotjs_tizen_org
+cp -ra $OLDPWD iotjs_tizen_org
+cd iotjs_tizen_org
+
+echo -e "\n(1) Now, cloning submodules. "
+git submodule init
+
+echo -e "\n(2) Update submodules... "
+git submodule update
+
+echo -e "\n(3) Modify version... "
+hash=`git log | head -1 | cut -f2 -d' ' | cut -c 1-7`
+today=`date +%y%m%d`
+sed -i "s/\(IOTJS_VERSION \".*\"\)/\1 \"$today\_$hash\"/g" src/iotjs_def.h
+
+echo -e "\n(4) Patch for tizen.org... "
+patch -p1 < config/tizen/iotjs_tizen.patch
+cp -ra config/tizen/packaging .
+
+merge_filter="merge config/tizen/filter.txt"
+rsync -av --delete --delete-excluded --filter="$merge_filter" . $repo
+
+cd $repo
+
+git add -A
+echo "======================================="
+echo git commit -m "IOTJS_Release_$today""_$hash"
+echo "======================================="
+msg="IOTJS_Release_$today""_$hash"
+git commit -m "$msg"
+cd $ROOT
+
+rm -rf ../iotjs_tizen_org
[general]
-profile = profile.tizen_unified_preview2
-#profile = profile.tizen_4.0_unified
-#profile = profile.tizen_unified
+#profile = profile.tizen40m3
+#profile = profile.tizen50
+#profile = profile.tizen50m1
+profile = profile.tizen50m2
+
upstream_branch = ${upstreamversion}
upstream_tag = ${upstreamversion}
packaging_dir = config/tizen/packaging
-[profile.tizen_unified_preview2]
-obs = obs.spin
-repos = repo.tizen_local, repo.tizen_4.0_base_arm_20171222.1, repo.tizen_4.0_unified_20180118.1
-[profile.tizen_4.0_unified]
+[profile.tizen50m2]
obs = obs.spin
-repos = repo.public_4.0_base_arm, repo.tizen_4.0_unified
+repos = repo.tizen50m2_base, repo.tizen50m2_standard
-[profile.tizen_unified]
-obs = obs.spin
-repos = repo.tizen_base_arm, repo.tizen_unified
+[repo.tizen50m2_base]
+url = http://download.tizen.org/releases/milestone/tizen/base/tizen-base_20180928.1/repos/standard/packages/
-[profile.tizen_artik10]
-obs = obs.spin
-repos = repo.public_3.0_base_arm, repo.public_3_arm
+[repo.tizen50m2_standard]
+url = http://download.tizen.org/releases/milestone/tizen/unified/tizen-unified_20181024.1/repos/standard/packages/
-[obs.spin]
-url = http://168.219.209.58:81
-[obs.tizen]
-url = https://api.tizen.org
-user = obs_viewer
-passwdx = QlpoOTFBWSZTWRP5nYMAAB6fgCAAeUA9mr+QBvzF4CAAVGAZDTRoDI0YBlCKeptQBoA0aGZIAottAkltEPOK7BAFXE9mTUzocPMzQRkPoPpNwEZx3rRQhxkXmGHS6wCjHskyVCP4u5IpwoSAn8zsGA==
+[profile.tizen50m1]
+obs = obs.spin
+repos = repo.tizen50m1_base, repo.tizen50m1_standard
-[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.tizen50m1_base]
+url = http://download.tizen.org/releases/milestone/tizen/base/tizen-base_20180518.1/repos/standard/packages/
-[repo.public_3.0_base_arm]
-url = http://download.tizen.org/snapshots/tizen/base/latest/repos/arm/packages/armv7l/
-user =
-passwdx =
+[repo.tizen50m1_standard]
+url = http://download.tizen.org/releases/milestone/tizen/unified/tizen-unified_20180528.1/repos/standard/packages/
-[repo.tizen_unified]
-url = http://download.tizen.org/snapshots/tizen/unified/latest/repos/standard/packages/
-user =
-passwdx =
+# for platform developer
+[profile.tizen50]
+obs = obs.spin
+repos = repo.tizen_local, repo.tizen50_base, repo.tizen50_standard
-[repo.tizen_base_arm]
+[repo.tizen50_base]
url = http://download.tizen.org/snapshots/tizen/base/latest/repos/standard/packages/
-user =
-passwdx =
+
+[repo.tizen50_standard]
+url = http://download.tizen.org/snapshots/tizen/unified/latest/repos/standard/packages/
-[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 =
+[profile.tizen40m3]
+obs = obs.spin
+repos = repo.tizen40m3_base, repo.tizen40m3_standard
+
+[repo.tizen40m3_base]
+url = http://download.tizen.org/releases/milestone/tizen/4.0-base/tizen-4.0-base_20180817.1/repos/arm/packages
+[repo.tizen40m3_standard]
+url = http://download.tizen.org/releases/milestone/tizen/4.0-unified/tizen-4.0-unified_20180821.6/repos/standard/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_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_preview2/
+url = ~/GBS-ROOT/local/repos/tizen50/
+
+[obs.spin]
+url = http://168.219.209.58:81
+
+[obs.tizen]
+url = https://api.tizen.org
+user = obs_viewer
+passwdx = QlpoOTFBWSZTWRP5nYMAAB6fgCAAeUA9mr+QBvzF4CAAVGAZDTRoDI0YBlCKeptQBoA0aGZIAottAkltEPOK7BAFXE9mTUzocPMzQRkPoPpNwEZx3rRQhxkXmGHS6wCjHskyVCP4u5IpwoSAn8zsGA==
+
--- /dev/null
+###########################################################################
+#
+# Copyright 2018 Samsung Electronics All Rights Reserved.
+#
+# 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 $(TOPDIR)/.config
+-include $(TOPDIR)/Make.defs
+
+IOTJS_ROOT_DIR ?= $(TOPDIR)/$(EXTDIR)/iotjs
+IOTJS_BUILD_OPTION ?=
+ifeq ($(CONFIG_DEBUG),y)
+ IOTJS_BUILDTYPE = debug
+else
+ IOTJS_BUILDTYPE = release
+endif
+IOTJS_OS ?= tizenrt
+IOTJS_ARCH ?= arm
+IOTJS_BUILDCONFIG ?= ${IOTJS_ARCH}-${IOTJS_OS}
+IOTJS_LIB_DIR ?= $(IOTJS_ROOT_DIR)/build/${IOTJS_BUILDCONFIG}/$(IOTJS_BUILDTYPE)/lib
+IOTJS_ROOT_DIR ?= .
+IOTJS_PROFILE_FILE ?= ${IOTJS_ROOT_DIR}/test/profiles/tizenrt.profile
+
+all: build
+.PHONY: depend clean distclean
+
+${TOPDIR}/include/sys/uio.h:
+ @mkdir -p ${@D}
+ @echo "#include <uio.h>" > $@
+
+build: $(IOTJS_ROOT_DIR)/tools/build.py ${IOTJS_PROFILE_FILE} ${TOPDIR}/include/sys/uio.h
+ $(Q) python $< \
+ --target-arch=$(CONFIG_ARCH) \
+ --target-os=${IOTJS_OS} \
+ --sysroot=$(TOPDIR) --target-board=$(CONFIG_ARCH_BOARD) --jerry-heaplimit=$(CONFIG_IOTJS_JERRY_HEAP) \
+ --buildtype=$(IOTJS_BUILDTYPE) --no-init-submodule $(IOTJS_BUILD_OPTION) \
+ --profile ${IOTJS_PROFILE_FILE}
+ $(Q) cp $(IOTJS_LIB_DIR)/*.a $(IOTJS_ROOT_DIR)
+
+depend:
+
+clean:
+ $(Q) $(call DELDIR, $(IOTJS_ROOT_DIR)/build)
+ $(Q) $(call DELFILE, $(IOTJS_ROOT_DIR)/*.a)
+
+distclean:
--- /dev/null
+#
+# Automatically generated file; DO NOT EDIT.
+# TinyAra Configuration
+#
+
+#
+# Build Setup
+#
+# CONFIG_EXPERIMENTAL is not set
+# CONFIG_DEFAULT_SMALL is not set
+CONFIG_HOST_LINUX=y
+# CONFIG_HOST_OSX is not set
+# CONFIG_HOST_WINDOWS is not set
+# CONFIG_HOST_OTHER is not set
+# CONFIG_WINDOWS_NATIVE is not set
+
+#
+# Build Configuration
+#
+CONFIG_APPS_DIR="../apps"
+CONFIG_FRAMEWORK_DIR="../framework"
+CONFIG_TOOLS_DIR="../tools"
+CONFIG_BUILD_FLAT=y
+# CONFIG_BUILD_PROTECTED is not set
+# CONFIG_BUILD_2PASS is not set
+
+#
+# Binary Output Formats
+#
+# CONFIG_INTELHEX_BINARY is not set
+# CONFIG_MOTOROLA_SREC is not set
+CONFIG_RAW_BINARY=y
+# CONFIG_UBOOT_UIMAGE is not set
+# CONFIG_DOWNLOAD_IMAGE is not set
+# CONFIG_SMARTFS_IMAGE is not set
+
+#
+# Customize Header Files
+#
+# CONFIG_ARCH_STDINT_H is not set
+# CONFIG_ARCH_STDBOOL_H is not set
+# CONFIG_ARCH_MATH_H is not set
+# CONFIG_ARCH_FLOAT_H is not set
+# CONFIG_ARCH_STDARG_H is not set
+CONFIG_ARCH_HAVE_CUSTOMOPT=y
+# CONFIG_DEBUG_NOOPT is not set
+# CONFIG_DEBUG_CUSTOMOPT is not set
+CONFIG_DEBUG_FULLOPT=y
+
+#
+# Hardware Configuration
+#
+
+#
+# Chip Selection
+#
+CONFIG_ARCH_ARM=y
+CONFIG_ARCH="arm"
+# CONFIG_ARCH_CHIP_LM is not set
+CONFIG_ARCH_CHIP_S5J=y
+# CONFIG_ARCH_CHIP_BCM4390X is not set
+CONFIG_ARCH_CHIP="s5j"
+
+#
+# ARM Options
+#
+# CONFIG_ARCH_CORTEXM3 is not set
+# CONFIG_ARCH_CORTEXM4 is not set
+CONFIG_ARCH_CORTEXR4=y
+CONFIG_ARCH_FAMILY="armv7-r"
+# CONFIG_ARCH_HAVE_FPU is not set
+CONFIG_ARMV7M_MPU=y
+CONFIG_ARMV7M_MPU_NREGIONS=12
+
+#
+# Exception stack options
+#
+CONFIG_ARCH_HAVE_DABORTSTACK=y
+CONFIG_ARCH_DABORTSTACK=0
+
+#
+# ARMv7-R Configuration Options
+#
+CONFIG_ARMV7R_HAVE_GICv2=y
+CONFIG_ARMV7R_MEMINIT=y
+CONFIG_ARMV7R_ICACHE=y
+CONFIG_ARMV7R_DCACHE=y
+# CONFIG_ARMV7R_DCACHE_WRITETHROUGH is not set
+# CONFIG_ARMV7R_HAVE_L2CC is not set
+# CONFIG_ARMV7R_HAVE_L2CC_PL310 is not set
+# CONFIG_ARMV7R_TOOLCHAIN_BUILDROOT is not set
+# CONFIG_ARMV7R_TOOLCHAIN_CODESOURCERYL is not set
+CONFIG_ARMV7R_TOOLCHAIN_GNU_EABIL=y
+# CONFIG_ARMV7R_TOOLCHAIN_GNU_OABI is not set
+# CONFIG_ARMV7R_HAVE_DECODEFIQ is not set
+
+#
+# S5J Configuration Options
+#
+CONFIG_ARCH_CHIP_S5JT200=y
+CONFIG_S5J_S5JT200=y
+
+#
+# S5J Peripheral Support
+#
+CONFIG_S5J_HAVE_ADC=y
+CONFIG_S5J_HAVE_DMA=y
+CONFIG_S5J_HAVE_I2C=y
+CONFIG_S5J_HAVE_I2S=y
+CONFIG_S5J_HAVE_MCT=y
+CONFIG_S5J_HAVE_PWM0=y
+CONFIG_S5J_HAVE_PWM1=y
+CONFIG_S5J_HAVE_PWM2=y
+CONFIG_S5J_HAVE_PWM3=y
+CONFIG_S5J_HAVE_PWM4=y
+CONFIG_S5J_HAVE_PWM5=y
+CONFIG_S5J_HAVE_RTC=y
+CONFIG_S5J_HAVE_SFLASH=y
+CONFIG_S5J_HAVE_SPI=y
+CONFIG_S5J_HAVE_SSS=y
+CONFIG_S5J_HAVE_UART0=y
+CONFIG_S5J_HAVE_UART1=y
+CONFIG_S5J_HAVE_UART2=y
+CONFIG_S5J_HAVE_UART3=y
+CONFIG_S5J_HAVE_UART4=y
+CONFIG_S5J_HAVE_WATCHDOG=y
+CONFIG_S5J_ADC=y
+# CONFIG_S5J_DMA is not set
+CONFIG_S5J_I2C=y
+# CONFIG_S5J_I2S is not set
+CONFIG_S5J_MCT=y
+CONFIG_S5J_TIMER0=y
+# CONFIG_S5J_TIMER1 is not set
+# CONFIG_S5J_TIMER2 is not set
+# CONFIG_S5J_TIMER3 is not set
+# CONFIG_S5J_UART_FLOWCONTROL is not set
+CONFIG_S5J_UART0=y
+CONFIG_S5J_UART1=y
+CONFIG_S5J_UART2=y
+CONFIG_S5J_UART3=y
+CONFIG_S5J_UART4=y
+CONFIG_S5J_PWM=y
+CONFIG_S5J_PWM0=y
+CONFIG_S5J_PWM1=y
+CONFIG_S5J_PWM2=y
+CONFIG_S5J_PWM3=y
+CONFIG_S5J_PWM4=y
+CONFIG_S5J_PWM5=y
+# CONFIG_S5J_SSS is not set
+CONFIG_S5J_SPI=y
+# CONFIG_S5J_WATCHDOG is not set
+CONFIG_S5J_SFLASH=y
+# CONFIG_S5J_SENSOR_PPD42NS is not set
+
+#
+# Architecture Options
+#
+# CONFIG_ARCH_NOINTC is not set
+# CONFIG_ARCH_VECNOTIRQ is not set
+# CONFIG_ARCH_DMA is not set
+# CONFIG_ARCH_HAVE_IRQPRIO is not set
+# CONFIG_ARCH_L2CACHE is not set
+# CONFIG_ARCH_HAVE_COHERENT_DCACHE is not set
+# CONFIG_ARCH_HAVE_ADDRENV is not set
+# CONFIG_ARCH_NEED_ADDRENV_MAPPING is not set
+CONFIG_ARCH_HAVE_VFORK=y
+# CONFIG_ARCH_HAVE_MMU is not set
+CONFIG_ARCH_HAVE_MPU=y
+# CONFIG_ARCH_NAND_HWECC is not set
+# CONFIG_ARCH_HAVE_EXTCLK is not set
+# CONFIG_ARCH_HAVE_POWEROFF is not set
+CONFIG_ARCH_HAVE_RESET=y
+CONFIG_ARCH_USE_MPU=y
+CONFIG_ARCH_STACKDUMP=y
+# CONFIG_DEBUG_DISPLAY_SYMBOL is not set
+# CONFIG_ENDIAN_BIG is not set
+# CONFIG_ARCH_IDLE_CUSTOM is not set
+CONFIG_ARCH_CUSTOM_PMINIT=y
+# CONFIG_ARCH_HAVE_RAMFUNCS is not set
+# CONFIG_ARCH_HAVE_RAMVECTORS is not set
+
+#
+# Board Settings
+#
+CONFIG_BOARD_LOOPSPERMSEC=29100
+# CONFIG_ARCH_CALIBRATION is not set
+
+#
+# Interrupt options
+#
+CONFIG_ARCH_HAVE_INTERRUPTSTACK=y
+CONFIG_ARCH_INTERRUPTSTACK=0
+# CONFIG_ARCH_HAVE_HIPRI_INTERRUPT is not set
+
+#
+# Boot options
+#
+# CONFIG_BOOT_RUNFROMEXTSRAM is not set
+CONFIG_BOOT_RUNFROMFLASH=y
+# CONFIG_BOOT_RUNFROMISRAM is not set
+# CONFIG_BOOT_RUNFROMSDRAM is not set
+# CONFIG_BOOT_COPYTORAM is not set
+
+#
+# Boot Memory Configuration
+#
+CONFIG_RAM_START=0x02023800
+CONFIG_RAM_SIZE=968704
+# CONFIG_DDR is not set
+# CONFIG_ARCH_HAVE_SDRAM is not set
+
+#
+# Board Selection
+#
+CONFIG_ARCH_BOARD_ARTIK053=y
+# CONFIG_ARCH_BOARD_ARTIK053S is not set
+# CONFIG_ARCH_BOARD_ARTIK055S is not set
+# CONFIG_ARCH_BOARD_SIDK_S5JT200 is not set
+CONFIG_ARCH_BOARD_ARTIK05X_FAMILY=y
+CONFIG_ARCH_BOARD="artik05x"
+
+#
+# Common Board Options
+#
+# CONFIG_BOARD_CRASHDUMP is not set
+# CONFIG_BOARD_ASSERT_AUTORESET is not set
+CONFIG_LIB_BOARDCTL=y
+CONFIG_BOARDCTL_RESET=y
+# CONFIG_BOARDCTL_UNIQUEID is not set
+# CONFIG_BOARD_FOTA_SUPPORT is not set
+
+#
+# Board-Specific Options
+#
+CONFIG_ARTIK05X_BOOT_FAILURE_DETECTION=y
+CONFIG_ARTIK05X_BOOT_COUNTS_ADDR=0x80090810
+CONFIG_ARTIK05X_FLASH_CAPACITY=8388608
+CONFIG_ARTIK05X_FLASH_PAGE_SIZE=4096
+CONFIG_ARTIK05X_FLASH_PART=y
+CONFIG_ARTIK05X_FLASH_MINOR=0
+CONFIG_ARTIK05X_FLASH_PART_LIST="16,48,192,32,512,2400,1536,1536,1000,400,8,512,"
+CONFIG_ARTIK05X_FLASH_PART_TYPE="none,ftl,none,none,none,none,none,ftl,smartfs,romfs,config,none,"
+CONFIG_ARTIK05X_FLASH_PART_NAME="bl1,sssro,bl2,sssfw,wlanfw,os,factory,ota,user,rom,nvram,sssrw,"
+CONFIG_ARTIK05X_AUTOMOUNT=y
+CONFIG_ARTIK05X_AUTOMOUNT_USERFS=y
+CONFIG_ARTIK05X_AUTOMOUNT_USERFS_DEVNAME="/dev/smart0p8"
+CONFIG_ARTIK05X_AUTOMOUNT_USERFS_MOUNTPOINT="/mnt"
+# CONFIG_ARTIK05X_AUTOMOUNT_SSSRW is not set
+CONFIG_ARTIK05X_AUTOMOUNT_ROMFS=y
+CONFIG_ARTIK05X_AUTOMOUNT_ROMFS_DEVNAME="/dev/mtdblock9"
+CONFIG_ARTIK05X_AUTOMOUNT_ROMFS_MOUNTPOINT="/rom"
+
+#
+# Kernel Features
+#
+CONFIG_DISABLE_OS_API=y
+# CONFIG_DISABLE_POSIX_TIMERS is not set
+# CONFIG_DISABLE_PTHREAD is not set
+# CONFIG_DISABLE_SIGNALS is not set
+# CONFIG_DISABLE_MQUEUE is not set
+# CONFIG_DISABLE_ENVIRON is not set
+
+#
+# Clocks and Timers
+#
+CONFIG_ARCH_HAVE_TICKLESS=y
+# CONFIG_SCHED_TICKLESS is not set
+CONFIG_USEC_PER_TICK=9979
+CONFIG_SYSTEM_TIME64=y
+CONFIG_CLOCK_MONOTONIC=y
+# CONFIG_JULIAN_TIME is not set
+CONFIG_MAX_WDOGPARMS=4
+CONFIG_PREALLOC_WDOGS=32
+CONFIG_WDOG_INTRESERVE=4
+CONFIG_PREALLOC_TIMERS=8
+
+#
+# Tasks and Scheduling
+#
+CONFIG_INIT_ENTRYPOINT=y
+CONFIG_RR_INTERVAL=100
+CONFIG_TASK_NAME_SIZE=31
+CONFIG_MAX_TASKS=32
+CONFIG_SCHED_HAVE_PARENT=y
+# CONFIG_SCHED_CHILD_STATUS is not set
+CONFIG_SCHED_WAITPID=y
+
+#
+# Pthread Options
+#
+CONFIG_PTHREAD_MUTEX_TYPES=y
+# CONFIG_PTHREAD_MUTEX_ROBUST is not set
+CONFIG_PTHREAD_MUTEX_UNSAFE=y
+# CONFIG_PTHREAD_MUTEX_BOTH is not set
+CONFIG_NPTHREAD_KEYS=4
+CONFIG_NPTHREAD_DESTRUCTOR_ITERATIONS=4
+# CONFIG_PTHREAD_CLEANUP is not set
+# CONFIG_CANCELLATION_POINTS is not set
+
+#
+# Performance Monitoring
+#
+# CONFIG_SCHED_CPULOAD is not set
+
+#
+# Latency optimization
+#
+# CONFIG_SCHED_YIELD_OPTIMIZATION is not set
+
+#
+# Files and I/O
+#
+CONFIG_DEV_CONSOLE=y
+# CONFIG_FDCLONE_DISABLE is not set
+# CONFIG_FDCLONE_STDIO is not set
+# CONFIG_SDCLONE_DISABLE is not set
+CONFIG_NFILE_DESCRIPTORS=16
+CONFIG_NFILE_STREAMS=16
+CONFIG_NAME_MAX=32
+CONFIG_PRIORITY_INHERITANCE=y
+CONFIG_SEM_PREALLOCHOLDERS=16
+CONFIG_SEM_NNESTPRIO=16
+
+#
+# RTOS hooks
+#
+CONFIG_BOARD_INITIALIZE=y
+# CONFIG_BOARD_INITTHREAD is not set
+# CONFIG_SCHED_STARTHOOK is not set
+CONFIG_SCHED_ATEXIT=y
+CONFIG_SCHED_ONEXIT=y
+
+#
+# Signal Numbers
+#
+CONFIG_SIG_SIGUSR1=1
+CONFIG_SIG_SIGUSR2=2
+CONFIG_SIG_SIGALARM=3
+CONFIG_SIG_SIGCHLD=4
+CONFIG_SIG_SIGCONDTIMEDOUT=16
+CONFIG_SIG_SIGWORK=17
+
+#
+# POSIX Message Queue Options
+#
+CONFIG_PREALLOC_MQ_MSGS=4
+CONFIG_MQ_MAXMSGSIZE=600
+
+#
+# Work Queue Support
+#
+CONFIG_SCHED_WORKQUEUE=y
+CONFIG_SCHED_WORKQUEUE_SORTING=y
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_HPWORKPRIORITY=224
+CONFIG_SCHED_HPWORKPERIOD=50000
+CONFIG_SCHED_HPWORKSTACKSIZE=2048
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_LPNTHREADS=1
+CONFIG_SCHED_LPWORKPRIORITY=176
+CONFIG_SCHED_LPWORKPRIOMAX=176
+CONFIG_SCHED_LPWORKPERIOD=50000
+CONFIG_SCHED_LPWORKSTACKSIZE=2048
+
+#
+# Stack size information
+#
+CONFIG_IDLETHREAD_STACKSIZE=1024
+CONFIG_USERMAIN_STACKSIZE=2048
+# CONFIG_MPU_STACKGAURD is not set
+CONFIG_PTHREAD_STACK_MIN=256
+CONFIG_PTHREAD_STACK_DEFAULT=2048
+
+#
+# Device Drivers
+#
+# CONFIG_DISABLE_POLL is not set
+CONFIG_DEV_NULL=y
+CONFIG_DEV_ZERO=y
+# CONFIG_DRVR_WRITEBUFFER is not set
+# CONFIG_DRVR_READAHEAD is not set
+# CONFIG_CAN is not set
+# CONFIG_ARCH_HAVE_PWM_PULSECOUNT is not set
+# CONFIG_ARCH_HAVE_PWM_MULTICHAN is not set
+CONFIG_PWM=y
+# CONFIG_ARCH_HAVE_I2CRESET is not set
+CONFIG_I2C=y
+CONFIG_I2C_SLAVE=y
+CONFIG_I2C_USERIO=y
+CONFIG_I2C_TRANSFER=y
+CONFIG_I2C_POLLED=y
+# CONFIG_I2C_TRACE is not set
+# CONFIG_I2C_WRITEREAD is not set
+CONFIG_SPI=y
+# CONFIG_SPI_OWNBUS is not set
+CONFIG_SPI_EXCHANGE=y
+# CONFIG_SPI_CMDDATA is not set
+# CONFIG_SPI_BITBANG is not set
+CONFIG_GPIO=y
+# CONFIG_I2S is not set
+# CONFIG_AUDIO_DEVICES is not set
+CONFIG_BCH=y
+CONFIG_RTC=y
+CONFIG_RTC_DATETIME=y
+# CONFIG_RTC_ALARM is not set
+CONFIG_RTC_DRIVER=y
+# CONFIG_RTC_IOCTL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_DEVPATH="/dev/watchdog0"
+# CONFIG_TIMER is not set
+CONFIG_ANALOG=y
+CONFIG_ADC=y
+CONFIG_ADC_FIFOSIZE=8
+# CONFIG_DAC is not set
+CONFIG_NETDEVICES=y
+
+#
+# General Ethernet MAC Driver Options
+#
+CONFIG_NETDEV_TELNET=y
+CONFIG_NETDEV_MULTINIC=y
+# CONFIG_NET_DUMPPACKET is not set
+
+#
+# External Ethernet MAC Device Support
+#
+# CONFIG_NET_DM90x0 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ENCX24J600 is not set
+# CONFIG_NET_E1000 is not set
+# CONFIG_NET_SLIP is not set
+# CONFIG_NET_VNET is not set
+# CONFIG_PIPES is not set
+CONFIG_POWER=y
+# CONFIG_BATTERY_CHARGER is not set
+# CONFIG_BATTERY_GAUGE is not set
+CONFIG_SERIAL=y
+# CONFIG_DEV_LOWCONSOLE is not set
+# CONFIG_16550_UART is not set
+# CONFIG_ARCH_HAVE_UART is not set
+CONFIG_ARCH_HAVE_UART0=y
+CONFIG_ARCH_HAVE_UART1=y
+CONFIG_ARCH_HAVE_UART2=y
+CONFIG_ARCH_HAVE_UART3=y
+CONFIG_ARCH_HAVE_UART4=y
+# CONFIG_ARCH_HAVE_UART5 is not set
+# CONFIG_ARCH_HAVE_UART6 is not set
+# CONFIG_ARCH_HAVE_UART7 is not set
+# CONFIG_ARCH_HAVE_UART8 is not set
+# CONFIG_ARCH_HAVE_SCI0 is not set
+# CONFIG_ARCH_HAVE_SCI1 is not set
+# CONFIG_ARCH_HAVE_USART0 is not set
+# CONFIG_ARCH_HAVE_USART1 is not set
+# CONFIG_ARCH_HAVE_USART2 is not set
+# CONFIG_ARCH_HAVE_USART3 is not set
+# CONFIG_ARCH_HAVE_USART4 is not set
+# CONFIG_ARCH_HAVE_USART5 is not set
+# CONFIG_ARCH_HAVE_USART6 is not set
+# CONFIG_ARCH_HAVE_USART7 is not set
+# CONFIG_ARCH_HAVE_USART8 is not set
+# CONFIG_ARCH_HAVE_OTHER_UART is not set
+
+#
+# USART Configuration
+#
+CONFIG_MCU_SERIAL=y
+CONFIG_STANDARD_SERIAL=y
+CONFIG_SERIAL_NPOLLWAITERS=2
+# CONFIG_SERIAL_IFLOWCONTROL is not set
+# CONFIG_SERIAL_OFLOWCONTROL is not set
+# CONFIG_SERIAL_TIOCSERGSTRUCT is not set
+CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y
+CONFIG_SERIAL_TERMIOS=y
+# CONFIG_UART0_SERIAL_CONSOLE is not set
+# CONFIG_UART1_SERIAL_CONSOLE is not set
+# CONFIG_UART2_SERIAL_CONSOLE is not set
+# CONFIG_UART3_SERIAL_CONSOLE is not set
+CONFIG_UART4_SERIAL_CONSOLE=y
+# CONFIG_OTHER_SERIAL_CONSOLE is not set
+# CONFIG_NO_SERIAL_CONSOLE is not set
+
+#
+# UART0 Configuration
+#
+CONFIG_UART0_RXBUFSIZE=64
+CONFIG_UART0_TXBUFSIZE=64
+CONFIG_UART0_BAUD=115200
+CONFIG_UART0_BITS=8
+CONFIG_UART0_PARITY=0
+CONFIG_UART0_2STOP=0
+# CONFIG_UART0_IFLOWCONTROL is not set
+# CONFIG_UART0_OFLOWCONTROL is not set
+
+#
+# UART1 Configuration
+#
+CONFIG_UART1_RXBUFSIZE=256
+CONFIG_UART1_TXBUFSIZE=256
+CONFIG_UART1_BAUD=115200
+CONFIG_UART1_BITS=8
+CONFIG_UART1_PARITY=0
+CONFIG_UART1_2STOP=0
+# CONFIG_UART1_IFLOWCONTROL is not set
+# CONFIG_UART1_OFLOWCONTROL is not set
+
+#
+# UART2 Configuration
+#
+CONFIG_UART2_RXBUFSIZE=256
+CONFIG_UART2_TXBUFSIZE=256
+CONFIG_UART2_BAUD=115200
+CONFIG_UART2_BITS=8
+CONFIG_UART2_PARITY=0
+CONFIG_UART2_2STOP=0
+# CONFIG_UART2_IFLOWCONTROL is not set
+# CONFIG_UART2_OFLOWCONTROL is not set
+
+#
+# UART3 Configuration
+#
+CONFIG_UART3_RXBUFSIZE=256
+CONFIG_UART3_TXBUFSIZE=256
+CONFIG_UART3_BAUD=115200
+CONFIG_UART3_BITS=8
+CONFIG_UART3_PARITY=0
+CONFIG_UART3_2STOP=0
+# CONFIG_UART3_IFLOWCONTROL is not set
+# CONFIG_UART3_OFLOWCONTROL is not set
+
+#
+# UART4 Configuration
+#
+CONFIG_UART4_RXBUFSIZE=256
+CONFIG_UART4_TXBUFSIZE=256
+CONFIG_UART4_BAUD=115200
+CONFIG_UART4_BITS=8
+CONFIG_UART4_PARITY=0
+CONFIG_UART4_2STOP=0
+# CONFIG_UART4_IFLOWCONTROL is not set
+# CONFIG_UART4_OFLOWCONTROL is not set
+# CONFIG_SENSOR is not set
+# CONFIG_USBDEV is not set
+# CONFIG_FOTA_DRIVER is not set
+
+#
+# System Logging
+#
+# CONFIG_RAMLOG is not set
+# CONFIG_SYSLOG_CONSOLE is not set
+
+#
+# T-trace
+#
+# CONFIG_TTRACE is not set
+
+#
+# Wireless Device Options
+#
+CONFIG_DRIVERS_WIRELESS=y
+CONFIG_SCSC_WLAN=y
+# CONFIG_SLSI_RX_PERFORMANCE_TEST is not set
+CONFIG_SCSC_TX_FLOW_CONTROL=y
+CONFIG_SCSC_ENABLE_PORT_CONTROL=y
+# CONFIG_SCSC_WLAN_STA_ONLY is not set
+# CONFIG_SCSC_WLAN_BLOCK_IPV6 is not set
+# CONFIG_SCSC_WLAN_UDP_FLOWCONTROL is not set
+# CONFIG_SCSC_WLAN_AUTO_RECOVERY is not set
+CONFIG_SCSC_WLAN_POWER_SAVE=y
+CONFIG_SCSC_WLAN_MAX_INTERFACES=1
+CONFIG_SCSC_CORE=y
+CONFIG_SCSC_PLATFORM=y
+# CONFIG_SCSC_WLANLITE is not set
+# CONFIG_SCSC_DISABLE_WLAN_RESET is not set
+
+#
+# Networking Support
+#
+CONFIG_ARCH_HAVE_NET=y
+# CONFIG_ARCH_HAVE_PHY is not set
+CONFIG_NET=y
+CONFIG_NET_LWIP=y
+
+#
+# LwIP options
+#
+CONFIG_NET_IPv4=y
+CONFIG_NET_IP_DEFAULT_TTL=255
+# CONFIG_NET_IP_FORWARD is not set
+CONFIG_NET_IP_OPTIONS_ALLOWED=y
+CONFIG_NET_IP_FRAG=y
+CONFIG_NET_IP_REASSEMBLY=y
+CONFIG_NET_IPV4_REASS_MAX_PBUFS=20
+CONFIG_NET_IPV4_REASS_MAXAGE=5
+CONFIG_NET_IPv6=y
+CONFIG_NET_IPv6_NUM_ADDRESSES=3
+# CONFIG_NET_IPv6_FORWARD is not set
+# CONFIG_NET_IPv6_FRAG is not set
+CONFIG_NET_IPv6_REASS=y
+CONFIG_NET_IPV6_REASS_MAXAGE=60
+CONFIG_NET_IPv6_SEND_ROUTER_SOLICIT=y
+CONFIG_NET_IPv6_AUTOCONFIG=y
+CONFIG_NET_IPv6_DUP_DETECT_ATTEMPTS=1
+# CONFIG_NET_IPv6_PMTU_FOR_MULTICAST is not set
+
+#
+# Socket support
+#
+CONFIG_NET_SOCKET=y
+CONFIG_NSOCKET_DESCRIPTORS=20
+CONFIG_NET_TCP_KEEPALIVE=y
+CONFIG_NET_RAW=y
+# CONFIG_NET_SOCKET_OPTION_BROADCAST is not set
+# CONFIG_NET_RANDOMIZE_INITIAL_LOCAL_PORTS is not set
+# CONFIG_NET_SO_SNDTIMEO is not set
+CONFIG_NET_SO_RCVTIMEO=y
+# CONFIG_NET_SO_RCVBUF is not set
+CONFIG_NET_SO_REUSE=y
+# CONFIG_NET_SO_REUSE_RXTOALL is not set
+CONFIG_NET_ARP=y
+CONFIG_NET_ARP_TABLESIZE=10
+CONFIG_NET_ARP_QUEUEING=y
+CONFIG_NET_ETHARP_TRUST_IP_MAC=y
+CONFIG_NET_ETH_PAD_SIZE=0
+# CONFIG_NET_ARP_STATIC_ENTRIES is not set
+CONFIG_NET_IPv6_ND=y
+CONFIG_NET_IPv6_ND_QUEUEING=y
+CONFIG_NET_IPv6_ND_QUEUE=20
+CONFIG_NET_IPv6_ND_NUM_NEIGHBORS=10
+CONFIG_NET_IPv6_ND_NUM_DESTINATIONS=10
+CONFIG_NET_IPv6_ND_NUM_PREFIXES=5
+CONFIG_NET_IPv6_ND_NUM_ROUTERS=3
+CONFIG_NET_IPv6_ND_MAX_MULTICAST_SOLICIT=3
+CONFIG_NET_IPv6_ND_MAX_UNICAST_SOLICIT=3
+CONFIG_NET_IPv6_ND_MAX_SOLICIT_INTERVAL=4000
+CONFIG_NET_IPv6_ND_REACHABLE_TIME=30000
+CONFIG_NET_IPv6_ND_RETRANS_TIMER=1000
+CONFIG_NET_IPv6_ND_DELAY_FIRST_PROBE_TIME=5000
+CONFIG_NET_IPv6_ND_ALLOW_RA_UPDATES=y
+CONFIG_NET_IPv6_ND_TCP_REACHABILITY_HINTS=y
+CONFIG_NET_IPv6_ND_RDNSS_MAX_DNS_SERVERS=0
+CONFIG_NET_UDP=y
+# CONFIG_NET_NETBUF_RECVINFO is not set
+CONFIG_NET_UDP_TTL=255
+# CONFIG_NET_UDPLITE is not set
+CONFIG_NET_TCP=y
+CONFIG_NET_TCP_TTL=255
+CONFIG_NET_TCP_WND=58400
+CONFIG_NET_TCP_MAXRTX=12
+CONFIG_NET_TCP_SYNMAXRTX=6
+CONFIG_NET_TCP_QUEUE_OOSEQ=y
+CONFIG_NET_TCP_MSS=1460
+CONFIG_NET_TCP_CALCULATE_EFF_SEND_MSS=y
+CONFIG_NET_TCP_SND_BUF=29200
+CONFIG_NET_TCP_SND_QUEUELEN=80
+# CONFIG_NET_TCP_LISTEN_BACKLOG is not set
+CONFIG_NET_TCP_OVERSIZE=536
+# CONFIG_NET_TCP_TIMESTAMPS is not set
+CONFIG_NET_TCP_WND_UPDATE_THRESHOLD=536
+CONFIG_NET_ICMP=y
+CONFIG_NET_ICMP_TTL=255
+# CONFIG_NET_BROADCAST_PING is not set
+# CONFIG_NET_MULTICAST_PING4 is not set
+CONFIG_NET_IPv6_ICMP=y
+CONFIG_NET_IPv6_ICMP_DATASIZE=8
+CONFIG_NET_IPv6_ICMP_HL=255
+# CONFIG_NET_MULTICAST_PING6 is not set
+CONFIG_NET_LWIP_IGMP=y
+CONFIG_NET_LWIP_MEMP_NUM_IGMP_GROUP=8
+CONFIG_NET_IPv6_MLD=y
+CONFIG_NET_IPv6_MLD_GROUP=4
+# CONFIG_NET_IPv6_DHCP is not set
+
+#
+# LWIP Mailbox Configurations
+#
+CONFIG_NET_TCPIP_MBOX_SIZE=64
+CONFIG_NET_DEFAULT_ACCEPTMBOX_SIZE=64
+CONFIG_NET_DEFAULT_RAW_RECVMBOX_SIZE=64
+CONFIG_NET_DEFAULT_TCP_RECVMBOX_SIZE=54
+CONFIG_NET_DEFAULT_UDP_RECVMBOX_SIZE=64
+
+#
+# Memory Configurations
+#
+CONFIG_NET_MEM_ALIGNMENT=4
+# CONFIG_NET_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is not set
+# CONFIG_NET_MEM_LIBC_MALLOC is not set
+CONFIG_NET_MEMP_MEM_MALLOC=y
+# CONFIG_NET_MEM_USE_POOLS is not set
+CONFIG_NET_MEM_SIZE=153600
+
+#
+# LWIP Task Configurations
+#
+# CONFIG_NET_TCPIP_CORE_LOCKING is not set
+# CONFIG_NET_TCPIP_CORE_LOCKING_INPUT is not set
+CONFIG_NET_TCPIP_THREAD_NAME="LWIP_TCP/IP"
+CONFIG_NET_TCPIP_THREAD_PRIO=110
+CONFIG_NET_TCPIP_THREAD_STACKSIZE=4096
+CONFIG_NET_COMPAT_MUTEX=y
+CONFIG_NET_SYS_LIGHTWEIGHT_PROT=y
+CONFIG_NET_DEFAULT_THREAD_NAME="lwIP"
+CONFIG_NET_DEFAULT_THREAD_PRIO=1
+CONFIG_NET_DEFAULT_THREAD_STACKSIZE=0
+
+#
+# Debug Options for Network
+#
+# CONFIG_NET_LWIP_ASSERT is not set
+# CONFIG_NET_LWIP_ERROR is not set
+# CONFIG_NET_LWIP_DEBUG is not set
+
+#
+# Enable Statistics
+#
+CONFIG_NET_STATS=y
+CONFIG_NET_STATS_DISPLAY=y
+CONFIG_NET_LINK_STATS=y
+CONFIG_NET_ETHARP_STATS=y
+CONFIG_NET_IP_STATS=y
+# CONFIG_NET_IPFRAG_STATS is not set
+# CONFIG_NET_ICMP_STATS is not set
+CONFIG_NET_UDP_STATS=y
+CONFIG_NET_TCP_STATS=y
+CONFIG_NET_MEM_STATS=y
+CONFIG_NET_SYS_STATS=y
+# CONFIG_NET_IPv6_STATS is not set
+# CONFIG_NET_IPv6_ICMP_STATS is not set
+# CONFIG_NET_IPv6_MLD_STATS is not set
+# CONFIG_NET_IPv6_ND_STATS is not set
+# CONFIG_NET_LWIP_VLAN is not set
+CONFIG_NET_LWIP_LOOPBACK_INTERFACE=y
+# CONFIG_NET_LWIP_SLIP_INTERFACE is not set
+# CONFIG_NET_LWIP_PPP_SUPPORT is not set
+# CONFIG_NET_LWIP_SNMP is not set
+
+#
+# Interface Name
+#
+CONFIG_NET_ETH_IFNAME="en"
+CONFIG_NET_LOOP_IFNAME="lo"
+CONFIG_NET_STA_IFNAME="wl"
+CONFIG_NET_SOFTAP_IFNAME="sa"
+CONFIG_NET_LWIP_NETDB=y
+CONFIG_NET_DNS_TABLE_SIZE=4
+CONFIG_NET_DNS_MAX_NAME_LENGTH=256
+CONFIG_NET_DNS_MAX_SERVERS=2
+# CONFIG_NET_DNS_DOES_NAME_CHECK is not set
+CONFIG_NET_DNS_SECURE=0
+# CONFIG_NET_DNS_LOCAL_HOSTLIST is not set
+
+#
+# Driver buffer configuration
+#
+CONFIG_NET_MULTIBUFFER=y
+CONFIG_NET_ETH_MTU=590
+CONFIG_NET_GUARDSIZE=2
+
+#
+# Data link support
+#
+# CONFIG_NET_MULTILINK is not set
+CONFIG_NET_ETHERNET=y
+
+#
+# Network Device Operations
+#
+# CONFIG_NETDEV_PHY_IOCTL is not set
+
+#
+# Protocols
+#
+CONFIG_NETUTILS_DHCPD=y
+CONFIG_NETUTILS_DHCPD_IGNOREBROADCAST=y
+CONFIG_NETUTILS_DHCPD_INTERFACE="wl1"
+CONFIG_NETUTILS_DHCPD_LEASETIME=864000
+CONFIG_NETUTILS_DHCPD_MINLEASETIME=86400
+CONFIG_NETUTILS_DHCPD_MAXLEASETIME=2592000
+CONFIG_NETUTILS_DHCPD_MAXLEASES=6
+CONFIG_NETUTILS_DHCPD_STARTIP=0xc0a82f02
+CONFIG_NETUTILS_DHCPD_ROUTERIP=0xc0a82f01
+CONFIG_NETUTILS_DHCPD_NETMASK=0xffffff00
+CONFIG_NETUTILS_DHCPD_DNSIP=0x08080808
+CONFIG_NETUTILS_DHCPD_OFFERTIME=3600
+CONFIG_NETUTILS_DHCPD_DECLINETIME=3600
+# CONFIG_NETUTILS_XMLRPC is not set
+# CONFIG_NETUTILS_NTPCLIENT is not set
+# CONFIG_NETUTILS_WEBSERVER is not set
+# CONFIG_NETUTILS_FTPC is not set
+# CONFIG_NETUTILS_MDNS is not set
+# CONFIG_NETUTILS_FTPD is not set
+CONFIG_NETUTILS_DHCPC=y
+# CONFIG_NETUTILS_WEBSOCKET is not set
+# CONFIG_NETUTILS_LIBCOAP is not set
+# CONFIG_NETUTILS_TFTPC is not set
+# CONFIG_NETUTILS_TELNETD is not set
+# CONFIG_NETUTILS_SMTP is not set
+# CONFIG_NETUTILS_MQTT is not set
+CONFIG_NET_SECURITY_TLS=y
+CONFIG_TLS_MPI_MAX_SIZE=512
+
+#
+# Wireless
+#
+CONFIG_WIFI_MANAGER=y
+CONFIG_SELECT_WPA_SUPPLICANT=y
+# CONFIG_SELECT_PROPIETARY_SUPPLICANT is not set
+# CONFIG_SELECT_NO_DRIVER is not set
+CONFIG_SELECT_SCSC_WLAN=y
+# CONFIG_SELECT_PROPIETARY_WLAN is not set
+CONFIG_NETUTILS_WIFI=y
+CONFIG_SLSI_WIFI_DEFAULT_WLAN_COUNTRY_CODE="00"
+CONFIG_SLSI_WIFI_DEFAULT_WLAN_TX_POWER=30
+# CONFIG_SLSI_WIFI_FILESYSTEM_SUPPORT is not set
+
+#
+# wpa_supplicant
+#
+CONFIG_WPA_SUPPLICANT=y
+CONFIG_WPA_SUPPLICANT_PRIORITY=100
+CONFIG_WPA_SUPPLICANT_STACKSIZE=16384
+CONFIG_WPA_SUPPLICANT_ENTRYPOINT="wpa_supplicant_main"
+CONFIG_CTRL_IFACE=y
+CONFIG_CTRL_IFACE_FIFO=y
+CONFIG_WPA_CTRL_FIFO_DEV_REQ="/dev/wpa_ctrl_req"
+CONFIG_WPA_CTRL_FIFO_DEV_CFM="/dev/wpa_ctrl_cfm"
+CONFIG_WPA_CTRL_FIFO_DEV_GLOBAL_REQ="/dev/wpa_ctrl_global_req"
+CONFIG_WPA_CTRL_FIFO_DEV_GLOBAL_CFM="/dev/wpa_ctrl_global_cfm"
+CONFIG_WPA_MONITOR_FIFO_DEV="/dev/wpa_monitor"
+CONFIG_WPA_CTRL_FIFO_MK_MODE=666
+CONFIG_ELOOP_POLL=y
+# CONFIG_WPA_SUPPLICANT_CMD is not set
+CONFIG_DRIVER_T20=y
+# CONFIG_ENABLE_EAP_FOR_SUPPLICANT is not set
+CONFIG_WIFIMGR_SOFTAP_IFNAME="wl1"
+CONFIG_WIFIMGR_STA_IFNAME="wl1"
+# CONFIG_WIFIMGR_DISABLE_AUTO_GET_IP is not set
+# CONFIG_DISABLE_EXTERNAL_AUTOCONNECT is not set
+
+#
+# Network utilities
+#
+CONFIG_NETUTILS_NETLIB=y
+CONFIG_NET_NETMON=y
+
+#
+# Audio Support
+#
+# CONFIG_AUDIO is not set
+
+#
+# Media Support
+#
+
+#
+# File Systems
+#
+# CONFIG_DISABLE_MOUNTPOINT is not set
+# CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set
+CONFIG_FS_READABLE=y
+CONFIG_FS_WRITABLE=y
+# CONFIG_FS_AIO is not set
+# CONFIG_FS_NAMED_SEMAPHORES is not set
+CONFIG_FS_MQUEUE_MPATH="/var/mqueue"
+CONFIG_FS_SMARTFS=y
+
+#
+# SMARTFS options
+#
+CONFIG_SMARTFS_ERASEDSTATE=0xff
+CONFIG_SMARTFS_MAXNAMLEN=32
+# CONFIG_SMARTFS_MULTI_ROOT_DIRS is not set
+CONFIG_SMARTFS_ALIGNED_ACCESS=y
+# CONFIG_SMARTFS_BAD_SECTOR is not set
+# CONFIG_SMARTFS_DYNAMIC_HEADER is not set
+# CONFIG_SMARTFS_JOURNALING is not set
+# CONFIG_SMARTFS_SECTOR_RECOVERY is not set
+CONFIG_FS_PROCFS=y
+# CONFIG_FS_AUTOMOUNT_PROCFS is not set
+
+#
+# Exclude individual procfs entries
+#
+# CONFIG_FS_PROCFS_EXCLUDE_PROCESS is not set
+# CONFIG_FS_PROCFS_EXCLUDE_UPTIME is not set
+# CONFIG_FS_PROCFS_EXCLUDE_VERSION is not set
+# CONFIG_FS_PROCFS_EXCLUDE_MTD is not set
+# CONFIG_FS_PROCFS_EXCLUDE_PARTITIONS is not set
+# CONFIG_FS_PROCFS_EXCLUDE_SMARTFS is not set
+# CONFIG_FS_PROCFS_EXCLUDE_POWER is not set
+CONFIG_FS_ROMFS=y
+# CONFIG_FS_TMPFS is not set
+
+#
+# Block Driver Configurations
+#
+CONFIG_RAMDISK=y
+
+#
+# MTD Configuration
+#
+CONFIG_MTD=y
+CONFIG_MTD_PARTITION=y
+CONFIG_MTD_PARTITION_NAMES=y
+CONFIG_MTD_PROGMEM=y
+CONFIG_MTD_FTL=y
+
+#
+# MTD_FTL Configurations
+#
+CONFIG_MTD_CONFIG=y
+
+#
+# MTD Configurations
+#
+# CONFIG_MTD_CONFIG_RAM_CONSOLIDATE is not set
+CONFIG_MTD_CONFIG_ERASEDVALUE=0xff
+# CONFIG_MTD_BYTE_WRITE is not set
+
+#
+# MTD Device Drivers
+#
+# CONFIG_MTD_M25P is not set
+# CONFIG_RAMMTD is not set
+CONFIG_MTD_SMART=y
+
+#
+# SMART Device options
+#
+CONFIG_MTD_SMART_SECTOR_SIZE=512
+# CONFIG_MTD_SMART_WEAR_LEVEL is not set
+# CONFIG_MTD_SMART_ENABLE_CRC is not set
+# CONFIG_MTD_SMART_SECTOR_ERASE_DEBUG is not set
+# CONFIG_MTD_SMART_ALLOC_DEBUG is not set
+# CONFIG_MTD_W25 is not set
+
+#
+# System Logging
+#
+# CONFIG_SYSLOG is not set
+# CONFIG_SYSLOG_TIMESTAMP is not set
+
+#
+# Database
+#
+# CONFIG_ARASTORAGE is not set
+
+#
+# Memory Management
+#
+# CONFIG_REALLOC_DISABLE_NEIGHBOR_EXTENSION is not set
+# CONFIG_MM_SMALL is not set
+CONFIG_MM_REGIONS=1
+# CONFIG_GRAN is not set
+
+#
+# Power Management
+#
+CONFIG_PM=y
+# CONFIG_DEBUG_PM is not set
+# CONFIG_PM_TEST is not set
+CONFIG_PM_DEVNAME_LEN=32
+# CONFIG_PM_METRICS is not set
+CONFIG_PM_SLICEMS=100
+CONFIG_PM_NDOMAINS=1
+CONFIG_PM_MEMORY=2
+CONFIG_PM_COEFN=1
+CONFIG_PM_COEF1=1
+CONFIG_PM_COEF2=1
+CONFIG_PM_COEF3=1
+CONFIG_PM_COEF4=1
+CONFIG_PM_COEF5=1
+CONFIG_PM_IDLEENTER_THRESH=1
+CONFIG_PM_IDLEEXIT_THRESH=2
+CONFIG_PM_IDLEENTER_COUNT=30
+CONFIG_PM_STANDBYENTER_THRESH=1
+CONFIG_PM_STANDBYEXIT_THRESH=2
+CONFIG_PM_STANDBYENTER_COUNT=50
+CONFIG_PM_SLEEPENTER_THRESH=1
+CONFIG_PM_SLEEPEXIT_THRESH=2
+CONFIG_PM_SLEEPENTER_COUNT=70
+
+#
+# Debug Options
+#
+CONFIG_DEBUG=y
+CONFIG_DEBUG_ERROR=y
+# CONFIG_DEBUG_WARN is not set
+CONFIG_DEBUG_VERBOSE=y
+
+#
+# Subsystem Debug Options
+#
+# CONFIG_DEBUG_LIB is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_IOTBUS is not set
+# CONFIG_DEBUG_MM is not set
+CONFIG_DEBUG_NET=y
+# CONFIG_DEBUG_NET_ERROR is not set
+# CONFIG_DEBUG_NET_INFO is not set
+# CONFIG_DEBUG_SCHED is not set
+# CONFIG_DEBUG_TASH is not set
+CONFIG_DEBUG_WLAN=y
+
+#
+# SLSI WLAN FW Debug Options
+#
+# CONFIG_SCSC_ENABLE_FWFAULT_LOG is not set
+
+#
+# SLSI WLAN Driver Debug Options
+#
+CONFIG_DEBUG_WLAN_DRIVER_ERROR=y
+# CONFIG_DEBUG_WLAN_DRIVER_DEBUG is not set
+# CONFIG_DEBUG_WLAN_DRIVER_MORE is not set
+# CONFIG_DEBUG_WLAN_DRIVER_INFO is not set
+
+#
+# SLSI WPA Supplicant Debug Options
+#
+CONFIG_DEBUG_WLAN_SUPPLICANT_ERROR=y
+# CONFIG_DEBUG_WLAN_SUPPLICANT_DEBUG is not set
+# CONFIG_DEBUG_WLAN_SUPPLICANT_MORE is not set
+# CONFIG_DEBUG_WLAN_SUPPLICANT_INFO is not set
+
+#
+# SLSI Wi-Fi API Debug Options
+#
+CONFIG_DEBUG_WLAN_API_ERROR=y
+# CONFIG_DEBUG_WLAN_API_DEBUG is not set
+# CONFIG_DEBUG_WLAN_API_INFO is not set
+
+#
+# OS Function Debug Options
+#
+# CONFIG_ARCH_HAVE_HEAPCHECK is not set
+CONFIG_DEBUG_MM_HEAPINFO=y
+# CONFIG_DEBUG_IRQ is not set
+
+#
+# Driver Debug Options
+#
+# CONFIG_DEBUG_I2S is not set
+# CONFIG_DEBUG_PWM is not set
+# CONFIG_DEBUG_RTC is not set
+# CONFIG_DEBUG_SPI is not set
+# CONFIG_DEBUG_WATCHDOG is not set
+
+#
+# System Debug Options
+#
+# CONFIG_DEBUG_SYSTEM is not set
+
+#
+# Stack Debug Options
+#
+CONFIG_ARCH_HAVE_STACKCHECK=y
+CONFIG_STACK_COLORATION=y
+
+#
+# Build Debug Options
+#
+CONFIG_DEBUG_SYMBOLS=y
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Logger Module
+#
+CONFIG_LOGM=y
+# CONFIG_PRINTF2LOGM is not set
+CONFIG_SYSLOG2LOGM=y
+# CONFIG_LOGM_TIMESTAMP is not set
+CONFIG_LOGM_BUFFER_SIZE=10240
+CONFIG_LOGM_PRINT_INTERVAL=1000
+CONFIG_LOGM_TASK_PRIORITY=110
+CONFIG_LOGM_TASK_STACKSIZE=2048
+# CONFIG_LOGM_TEST is not set
+
+#
+# Built-in Libraries
+#
+
+#
+# Standard C Library Options
+#
+CONFIG_STDIO_BUFFER_SIZE=64
+CONFIG_STDIO_LINEBUFFER=y
+CONFIG_NUNGET_CHARS=2
+CONFIG_LIB_HOMEDIR="/"
+CONFIG_LIBM=y
+# CONFIG_NOPRINTF_FIELDWIDTH is not set
+CONFIG_LIBC_FLOATINGPOINT=y
+CONFIG_LIBC_FLOATPRECISION=6
+CONFIG_LIBC_SCANSET=y
+# CONFIG_NOPRINTF_LONGLONG_TO_ASCII is not set
+CONFIG_LIBC_IOCTL_VARIADIC=y
+# CONFIG_LIBC_WCHAR is not set
+# CONFIG_LIBC_LOCALE is not set
+CONFIG_LIB_RAND_ORDER=1
+# CONFIG_EOL_IS_CR is not set
+# CONFIG_EOL_IS_LF is not set
+# CONFIG_EOL_IS_BOTH_CRLF is not set
+CONFIG_EOL_IS_EITHER_CRLF=y
+CONFIG_LIBC_STRERROR=y
+# CONFIG_LIBC_STRERROR_SHORT is not set
+# CONFIG_LIBC_PERROR_STDOUT is not set
+CONFIG_LIBC_TMPDIR="/tmp"
+CONFIG_LIBC_MAX_TMPFILE=32
+CONFIG_ARCH_LOWPUTC=y
+# CONFIG_LIBC_LOCALTIME is not set
+# CONFIG_TIME_EXTENDED is not set
+CONFIG_LIB_SENDFILE_BUFSIZE=512
+CONFIG_ARCH_OPTIMIZED_FUNCTIONS=y
+# CONFIG_ARCH_MEMCPY is not set
+CONFIG_MEMCPY_VIK=y
+# CONFIG_MEMCPY_PRE_INC_PTRS is not set
+CONFIG_MEMCPY_INDEXED_COPY=y
+# CONFIG_MEMCPY_64BIT is not set
+# CONFIG_ARCH_MEMCMP is not set
+# CONFIG_ARCH_MEMMOVE is not set
+# CONFIG_ARCH_MEMSET is not set
+# CONFIG_MEMSET_OPTSPEED is not set
+# CONFIG_ARCH_STRCHR is not set
+# CONFIG_ARCH_STRCMP is not set
+# CONFIG_ARCH_STRCPY is not set
+# CONFIG_ARCH_STRNCPY is not set
+# CONFIG_ARCH_STRLEN is not set
+# CONFIG_ARCH_STRNLEN is not set
+# CONFIG_ARCH_BZERO is not set
+
+#
+# Non-standard Library Support
+#
+
+#
+# Basic CXX Support
+#
+# CONFIG_C99_BOOL8 is not set
+# CONFIG_HAVE_CXX is not set
+
+#
+# External Libraries
+#
+# CONFIG_AVS_DEVICE_SDK is not set
+# CONFIG_AWS_SDK is not set
+# CONFIG_NETUTILS_CODECS is not set
+
+#
+# CURL Options
+#
+# CONFIG_ENABLE_CURL is not set
+# CONFIG_ERROR_REPORT is not set
+# CONFIG_ENABLE_IOTIVITY is not set
+CONFIG_NETUTILS_JSON=y
+# CONFIG_LIBTUV is not set
+# CONFIG_LWM2M_WAKAAMA is not set
+# CONFIG_STRESS_TOOL is not set
+# CONFIG_VOICE_SOFTWARE_EPD is not set
+
+#
+# Application Configuration
+#
+
+#
+# Application entry point list
+#
+# CONFIG_ENTRY_MANUAL is not set
+# CONFIG_ENTRY_HELLO is not set
+CONFIG_ENTRY_IOTJS_STARTUP=y
+CONFIG_USER_ENTRYPOINT="iotjs_startup_main"
+CONFIG_BUILTIN_APPS=y
+
+#
+# Examples
+#
+# CONFIG_EXAMPLES_AVS_TEST is not set
+# CONFIG_EXAMPLES_AWS is not set
+# CONFIG_EXAMPLES_CURLTEST is not set
+# CONFIG_EXAMPLES_DNSCLIENT_TEST is not set
+# CONFIG_EXAMPLES_DTLS_CLIENT is not set
+# CONFIG_EXAMPLES_DTLS_SERVER is not set
+# CONFIG_EXAMPLES_EEPROM_TEST is not set
+# CONFIG_EXAMPLES_EVENTLOOP is not set
+# CONFIG_EXAMPLES_FOTA_SAMPLE is not set
+# CONFIG_FILESYSTEM_HELPER_ENABLE is not set
+CONFIG_EXAMPLES_HELLO=y
+# CONFIG_EXAMPLES_HELLOXX is not set
+# CONFIG_EXAMPLES_IOTBUS_TEST is not set
+CONFIG_EXAMPLES_IOTJS_STARTUP=y
+CONFIG_EXAMPLES_IOTJS_STARTUP_JS_FILE="/rom/example/index.js"
+# CONFIG_EXAMPLES_IOTJS_STARTUP_WIFI is not set
+# CONFIG_EXAMPLES_KERNEL_SAMPLE is not set
+# CONFIG_EXAMPLES_LIBTUV is not set
+# CONFIG_EXAMPLES_NETTEST is not set
+# CONFIG_EXAMPLES_PROC_TEST is not set
+# CONFIG_EXAMPLES_SELECT_TEST is not set
+# CONFIG_EXAMPLES_SENSORBOARD is not set
+# CONFIG_EXAMPLES_SETJMP_TEST is not set
+CONFIG_EXAMPLES_SLSIWIFI=y
+CONFIG_EXAMPLES_SLSIWIFI_PRIORITY=50
+CONFIG_EXAMPLES_SLSIWIFI_STACKSIZE=2048
+# CONFIG_EXAMPLES_SMART is not set
+# CONFIG_EXAMPLES_SMART_TEST is not set
+# CONFIG_EXAMPLES_SPEECH_DETECTOR_TEST is not set
+# CONFIG_EXAMPLES_ST_THINGS is not set
+# CONFIG_EXAMPLES_TESTCASE is not set
+# CONFIG_EXAMPLES_TLS_BENCHMARK is not set
+# CONFIG_EXAMPLES_TLS_CLIENT is not set
+# CONFIG_EXAMPLES_TLS_SELFTEST is not set
+# CONFIG_EXAMPLES_TLS_SERVER is not set
+# CONFIG_EXAMPLES_WIFIMANAGER_TEST is not set
+
+#
+# Platform-specific Support
+#
+# CONFIG_PLATFORM_CONFIGDATA is not set
+
+#
+# Shell
+#
+CONFIG_TASH=y
+CONFIG_TASH_MAX_COMMANDS=132
+# CONFIG_TASH_USLEEP is not set
+CONFIG_TASH_COMMAND_INTERFACE=y
+CONFIG_TASH_CMDTASK_STACKSIZE=4096
+CONFIG_TASH_CMDTASK_PRIORITY=100
+# CONFIG_TASH_SCRIPT is not set
+
+#
+# System Libraries and Add-Ons
+#
+# CONFIG_SYSTEM_CLE is not set
+# CONFIG_SYSTEM_CUTERM is not set
+# CONFIG_SYSTEM_FLASH_ERASEALL is not set
+# CONFIG_SYSTEM_FOTA_HAL is not set
+# CONFIG_SYSTEM_I2CTOOL is not set
+# CONFIG_SYSTEM_INIFILE is not set
+CONFIG_SYSTEM_PREAPP_INIT=y
+CONFIG_SYSTEM_PREAPP_STACKSIZE=2048
+# CONFIG_SYSTEM_INSTALL is not set
+CONFIG_SYSTEM_IPERF=y
+# CONFIG_SYSTEM_NETDB is not set
+CONFIG_SYSTEM_RAMTEST=y
+CONFIG_SYSTEM_RAMTEST_PRIORITY=100
+CONFIG_SYSTEM_RAMTEST_STACKSIZE=1024
+CONFIG_SYSTEM_READLINE=y
+CONFIG_READLINE_ECHO=y
+CONFIG_SYSTEM_INFORMATION=y
+CONFIG_KERNEL_CMDS=y
+CONFIG_FS_CMDS=y
+CONFIG_FSCMD_BUFFER_LEN=64
+CONFIG_NET_CMDS=y
+CONFIG_NET_PING_CMD=y
+CONFIG_NET_PING_CMD_ICOUNT=5
+CONFIG_ENABLE_DATE_CMD=y
+CONFIG_ENABLE_ENV_GET_CMD=y
+CONFIG_ENABLE_ENV_SET_CMD=y
+CONFIG_ENABLE_ENV_UNSET_CMD=y
+CONFIG_ENABLE_FREE_CMD=y
+CONFIG_ENABLE_HEAPINFO_CMD=y
+# CONFIG_HEAPINFO_USER_GROUP is not set
+# CONFIG_ENABLE_IRQINFO_CMD is not set
+CONFIG_ENABLE_KILL_CMD=y
+CONFIG_ENABLE_KILLALL_CMD=y
+CONFIG_ENABLE_PS_CMD=y
+CONFIG_ENABLE_STACKMONITOR_CMD=y
+CONFIG_STACKMONITOR_PRIORITY=100
+CONFIG_STACKMONITOR_INTERVAL=5
+CONFIG_ENABLE_UPTIME_CMD=y
+# CONFIG_SYSTEM_VI is not set
+
+#
+# Runtime Environment
+#
+CONFIG_ENABLE_IOTJS=y
+CONFIG_IOTJS_PRIORITY=100
+CONFIG_IOTJS_STACKSIZE=32768
+CONFIG_IOTJS_JERRY_HEAP=128
+
+#
+# Device Management
+#
+# CONFIG_DM is not set
+
+#
+# Task manager
+#
+# CONFIG_TASK_MANAGER is not set
+
+#
+# Event Loop Framework
+#
+# CONFIG_EVENTLOOP is not set
+
+#
+# Things Management
+#
+# CONFIG_ST_THINGS is not set
+
+#
+# IoTBus Framework
+#
+CONFIG_IOTBUS=y
+CONFIG_IOTBUS_GPIO=y
+CONFIG_IOTBUS_I2C=y
+CONFIG_IOTBUS_PWM=y
+CONFIG_IOTBUS_SPI=y
+CONFIG_IOTBUS_UART=y
+++ /dev/null
-#
-# Automatically generated file; DO NOT EDIT.
-# TinyAra Configuration
-#
-
-#
-# Build Setup
-#
-# CONFIG_EXPERIMENTAL is not set
-# CONFIG_DEFAULT_SMALL is not set
-CONFIG_HOST_LINUX=y
-# CONFIG_HOST_OSX is not set
-# CONFIG_HOST_WINDOWS is not set
-# CONFIG_HOST_OTHER is not set
-# CONFIG_WINDOWS_NATIVE is not set
-
-#
-# Build Configuration
-#
-CONFIG_APPS_DIR="../apps"
-CONFIG_FRAMEWORK_DIR="../framework"
-CONFIG_TOOLS_DIR="../tools"
-CONFIG_BUILD_FLAT=y
-# CONFIG_BUILD_PROTECTED is not set
-# CONFIG_BUILD_2PASS is not set
-
-#
-# Binary Output Formats
-#
-# CONFIG_INTELHEX_BINARY is not set
-# CONFIG_MOTOROLA_SREC is not set
-CONFIG_RAW_BINARY=y
-CONFIG_SAMSUNG_NS2=y
-# CONFIG_UBOOT_UIMAGE is not set
-# CONFIG_DOWNLOAD_IMAGE is not set
-# CONFIG_SMARTFS_IMAGE is not set
-
-#
-# Customize Header Files
-#
-# CONFIG_ARCH_STDINT_H is not set
-# CONFIG_ARCH_STDBOOL_H is not set
-# CONFIG_ARCH_MATH_H is not set
-# CONFIG_ARCH_FLOAT_H is not set
-# CONFIG_ARCH_STDARG_H is not set
-
-#
-# Debug Options
-#
-CONFIG_DEBUG=y
-CONFIG_DEBUG_ERROR=y
-# CONFIG_DEBUG_WARN is not set
-CONFIG_DEBUG_VERBOSE=y
-
-#
-# Subsystem Debug Options
-#
-# CONFIG_DEBUG_FS is not set
-# CONFIG_DEBUG_LIB is not set
-# CONFIG_DEBUG_MM is not set
-CONFIG_DEBUG_NET=y
-# CONFIG_DEBUG_NET_ERROR is not set
-# CONFIG_DEBUG_NET_INFO is not set
-# CONFIG_DEBUG_SCHED is not set
-CONFIG_DEBUG_WLAN=y
-
-#
-# SLSI WLAN FW Debug Options
-#
-# CONFIG_SCSC_ENABLE_FWFAULT_LOG is not set
-
-#
-# SLSI WLAN Driver Debug Options
-#
-CONFIG_DEBUG_WLAN_DRIVER_ERROR=y
-# CONFIG_DEBUG_WLAN_DRIVER_DEBUG is not set
-# CONFIG_DEBUG_WLAN_DRIVER_MORE is not set
-# CONFIG_DEBUG_WLAN_DRIVER_VERBOSE is not set
-
-#
-# SLSI WPA Supplicant Debug Options
-#
-CONFIG_DEBUG_WLAN_SUPPLICANT_ERROR=y
-# CONFIG_DEBUG_WLAN_SUPPLICANT_DEBUG is not set
-# CONFIG_DEBUG_WLAN_SUPPLICANT_MORE is not set
-# CONFIG_DEBUG_WLAN_SUPPLICANT_VERBOSE is not set
-
-#
-# SLSI Wi-Fi API Debug Options
-#
-CONFIG_DEBUG_WLAN_API_ERROR=y
-# CONFIG_DEBUG_WLAN_API_DEBUG is not set
-# CONFIG_DEBUG_WLAN_API_VERBOSE is not set
-
-#
-# OS Function Debug Options
-#
-# CONFIG_ARCH_HAVE_HEAPCHECK is not set
-CONFIG_DEBUG_MM_HEAPINFO=y
-# CONFIG_DEBUG_IRQ is not set
-
-#
-# Driver Debug Options
-#
-# CONFIG_DEBUG_PWM is not set
-# CONFIG_DEBUG_RTC is not set
-# CONFIG_DEBUG_SPI is not set
-# CONFIG_DEBUG_WATCHDOG is not set
-# CONFIG_DEBUG_TTRACE is not set
-
-#
-# Stack Debug Options
-#
-CONFIG_ARCH_HAVE_STACKCHECK=y
-CONFIG_STACK_COLORATION=y
-
-#
-# Build Debug Options
-#
-CONFIG_DEBUG_SYMBOLS=y
-# CONFIG_FRAME_POINTER is not set
-CONFIG_ARCH_HAVE_CUSTOMOPT=y
-# CONFIG_DEBUG_NOOPT is not set
-# CONFIG_DEBUG_CUSTOMOPT is not set
-CONFIG_DEBUG_FULLOPT=y
-
-#
-# Chip Selection
-#
-CONFIG_ARCH_ARM=y
-CONFIG_ARCH="arm"
-
-#
-# ARM Options
-#
-CONFIG_ARCH_CHIP_S5J=y
-# CONFIG_ARCH_CORTEXM3 is not set
-# CONFIG_ARCH_CORTEXM4 is not set
-CONFIG_ARCH_CORTEXR4=y
-CONFIG_ARCH_FAMILY="armv7-r"
-CONFIG_ARCH_CHIP="s5j"
-# CONFIG_ARCH_HAVE_FPU is not set
-CONFIG_ARMV7M_MPU=y
-CONFIG_ARMV7M_MPU_NREGIONS=12
-
-#
-# Exception stack options
-#
-CONFIG_ARCH_HAVE_DABORTSTACK=y
-CONFIG_ARCH_DABORTSTACK=0
-
-#
-# ARMv7-R Configuration Options
-#
-CONFIG_ARMV7R_HAVE_GICv2=y
-CONFIG_ARMV7R_MEMINIT=y
-CONFIG_ARMV7R_ICACHE=y
-CONFIG_ARMV7R_DCACHE=y
-# CONFIG_ARMV7R_DCACHE_WRITETHROUGH is not set
-# CONFIG_ARMV7R_HAVE_L2CC is not set
-# CONFIG_ARMV7R_HAVE_L2CC_PL310 is not set
-# CONFIG_ARMV7R_TOOLCHAIN_BUILDROOT is not set
-# CONFIG_ARMV7R_TOOLCHAIN_CODESOURCERYL is not set
-CONFIG_ARMV7R_TOOLCHAIN_GNU_EABIL=y
-# CONFIG_ARMV7R_TOOLCHAIN_GNU_OABI is not set
-# CONFIG_ARMV7R_HAVE_DECODEFIQ is not set
-# CONFIG_BOOT_RESULT is not set
-
-#
-# S5J Configuration Options
-#
-CONFIG_ARCH_CHIP_S5JT200=y
-CONFIG_S5J_S5JT200=y
-
-#
-# S5J Peripheral Support
-#
-CONFIG_S5J_HAVE_ADC=y
-CONFIG_S5J_HAVE_I2C=y
-CONFIG_S5J_HAVE_MCT=y
-CONFIG_S5J_HAVE_PWM0=y
-CONFIG_S5J_HAVE_PWM1=y
-CONFIG_S5J_HAVE_PWM2=y
-CONFIG_S5J_HAVE_PWM3=y
-CONFIG_S5J_HAVE_PWM4=y
-CONFIG_S5J_HAVE_PWM5=y
-CONFIG_S5J_HAVE_PWR=y
-CONFIG_S5J_HAVE_RTC=y
-CONFIG_S5J_HAVE_SFLASH=y
-CONFIG_S5J_HAVE_SPI=y
-CONFIG_S5J_HAVE_SSS=y
-CONFIG_S5J_HAVE_UART0=y
-CONFIG_S5J_HAVE_UART1=y
-CONFIG_S5J_HAVE_UART2=y
-CONFIG_S5J_HAVE_UART3=y
-CONFIG_S5J_HAVE_UART4=y
-CONFIG_S5J_HAVE_WATCHDOG=y
-CONFIG_S5J_ADC=y
-CONFIG_S5J_I2C=y
-# CONFIG_S5J_MCT is not set
-# CONFIG_S5J_TIMER0 is not set
-# CONFIG_S5J_TIMER1 is not set
-# CONFIG_S5J_TIMER2 is not set
-# CONFIG_S5J_TIMER3 is not set
-# CONFIG_S5J_UART_FLOWCONTROL is not set
-CONFIG_S5J_UART0=y
-CONFIG_S5J_UART1=y
-CONFIG_S5J_UART2=y
-# CONFIG_S5J_UART2_FLOWCONTROL is not set
-CONFIG_S5J_UART3=y
-# CONFIG_S5J_UART3_FLOWCONTROL is not set
-CONFIG_S5J_UART4=y
-CONFIG_S5J_PWM=y
-CONFIG_S5J_PWM0=y
-CONFIG_S5J_PWM1=y
-CONFIG_S5J_PWM2=y
-CONFIG_S5J_PWM3=y
-CONFIG_S5J_PWM4=y
-CONFIG_S5J_PWM5=y
-CONFIG_S5J_SSS=y
-CONFIG_S5J_SPI=y
-# CONFIG_S5J_WATCHDOG is not set
-CONFIG_S5J_SFLASH=y
-CONFIG_S5J_PWR=y
-
-#
-# PMU Configuration
-#
-CONFIG_S5J_PWR_DSTOP=y
-# CONFIG_S5J_PWR_SLEEP is not set
-
-#
-# Architecture Options
-#
-# CONFIG_ARCH_NOINTC is not set
-# CONFIG_ARCH_VECNOTIRQ is not set
-# CONFIG_ARCH_DMA is not set
-# CONFIG_ARCH_HAVE_IRQPRIO is not set
-# CONFIG_ARCH_L2CACHE is not set
-# CONFIG_ARCH_HAVE_COHERENT_DCACHE is not set
-# CONFIG_ARCH_HAVE_ADDRENV is not set
-# CONFIG_ARCH_NEED_ADDRENV_MAPPING is not set
-CONFIG_ARCH_HAVE_VFORK=y
-# CONFIG_ARCH_HAVE_MMU is not set
-CONFIG_ARCH_HAVE_MPU=y
-# CONFIG_ARCH_NAND_HWECC is not set
-# CONFIG_ARCH_HAVE_EXTCLK is not set
-# CONFIG_ARCH_HAVE_POWEROFF is not set
-CONFIG_ARCH_HAVE_RESET=y
-CONFIG_ARCH_USE_MPU=y
-CONFIG_ARCH_STACKDUMP=y
-# CONFIG_ENDIAN_BIG is not set
-# CONFIG_ARCH_IDLE_CUSTOM is not set
-CONFIG_ARCH_CUSTOM_PMINIT=y
-# CONFIG_ARCH_HAVE_RAMFUNCS is not set
-# CONFIG_ARCH_HAVE_RAMVECTORS is not set
-
-#
-# Board Settings
-#
-CONFIG_BOARD_LOOPSPERMSEC=29100
-# CONFIG_ARCH_CALIBRATION is not set
-
-#
-# Interrupt options
-#
-CONFIG_ARCH_HAVE_INTERRUPTSTACK=y
-CONFIG_ARCH_INTERRUPTSTACK=0
-# CONFIG_ARCH_HAVE_HIPRI_INTERRUPT is not set
-
-#
-# Boot options
-#
-# CONFIG_BOOT_RUNFROMEXTSRAM is not set
-CONFIG_BOOT_RUNFROMFLASH=y
-# CONFIG_BOOT_RUNFROMISRAM is not set
-# CONFIG_BOOT_RUNFROMSDRAM is not set
-# CONFIG_BOOT_COPYTORAM is not set
-
-#
-# Boot Memory Configuration
-#
-CONFIG_RAM_START=0x02023800
-CONFIG_RAM_SIZE=804864
-# CONFIG_ARCH_HAVE_SDRAM is not set
-
-#
-# Board Selection
-#
-CONFIG_ARCH_BOARD_ARTIK053=y
-# CONFIG_ARCH_BOARD_SIDK_S5JT200 is not set
-CONFIG_ARCH_BOARD="artik053"
-
-#
-# Common Board Options
-#
-# CONFIG_BOARD_CRASHDUMP is not set
-CONFIG_LIB_BOARDCTL=y
-CONFIG_BOARDCTL_RESET=y
-# CONFIG_BOARDCTL_UNIQUEID is not set
-# CONFIG_BOARD_COREDUMP_FLASH is not set
-# CONFIG_BOARD_FOTA_SUPPORT is not set
-# CONFIG_BOARD_RAMDUMP_FLASH is not set
-# CONFIG_BOARD_RAMDUMP_UART is not set
-
-#
-# Board-Specific Options
-#
-CONFIG_ARTIK053_BOOT_FAILURE_DETECTION=y
-CONFIG_ARTIK053_BOOT_COUNTS_ADDR=0x80090810
-CONFIG_ARTIK053_FLASH_CAPACITY=8388608
-CONFIG_ARTIK053_FLASH_PAGE_SIZE=4096
-CONFIG_ARTIK053_FLASH_PART=y
-CONFIG_ARTIK053_FLASH_MINOR=0
-CONFIG_ARTIK053_FLASH_PART_LIST="16,48,192,32,512,2400,1536,1536,1000,400,8,512,"
-CONFIG_ARTIK053_FLASH_PART_TYPE="none,ftl,none,none,none,none,none,ftl,smartfs,romfs,config,none,"
-CONFIG_ARTIK053_FLASH_PART_NAME="bl1,sssro,bl2,sssfw,wlanfw,os,factory,ota,user,rom,nvram,sssrw,"
-CONFIG_ARTIK053_AUTOMOUNT=y
-CONFIG_ARTIK053_AUTOMOUNT_USERFS=y
-CONFIG_ARTIK053_AUTOMOUNT_USERFS_DEVNAME="/dev/smart0p8"
-CONFIG_ARTIK053_AUTOMOUNT_USERFS_MOUNTPOINT="/mnt"
-
-#
-# RTOS Features
-#
-CONFIG_DISABLE_OS_API=y
-# CONFIG_DISABLE_POSIX_TIMERS is not set
-# CONFIG_DISABLE_PTHREAD is not set
-# CONFIG_DISABLE_SIGNALS is not set
-# CONFIG_DISABLE_MQUEUE is not set
-# CONFIG_DISABLE_ENVIRON is not set
-
-#
-# Clocks and Timers
-#
-CONFIG_ARCH_HAVE_TICKLESS=y
-# CONFIG_SCHED_TICKLESS is not set
-CONFIG_USEC_PER_TICK=9979
-CONFIG_SYSTEM_TIME64=y
-CONFIG_CLOCK_MONOTONIC=y
-# CONFIG_JULIAN_TIME is not set
-CONFIG_MAX_WDOGPARMS=4
-CONFIG_PREALLOC_WDOGS=32
-CONFIG_WDOG_INTRESERVE=4
-CONFIG_PREALLOC_TIMERS=8
-
-#
-# Tasks and Scheduling
-#
-CONFIG_INIT_ENTRYPOINT=y
-CONFIG_RR_INTERVAL=100
-CONFIG_TASK_NAME_SIZE=31
-CONFIG_MAX_TASKS=32
-CONFIG_SCHED_HAVE_PARENT=y
-# CONFIG_SCHED_CHILD_STATUS is not set
-CONFIG_SCHED_WAITPID=y
-
-#
-# Pthread Options
-#
-CONFIG_PTHREAD_MUTEX_TYPES=y
-# CONFIG_PTHREAD_MUTEX_ROBUST is not set
-CONFIG_PTHREAD_MUTEX_UNSAFE=y
-# CONFIG_PTHREAD_MUTEX_BOTH is not set
-CONFIG_NPTHREAD_KEYS=4
-# CONFIG_PTHREAD_CLEANUP is not set
-# CONFIG_CANCELLATION_POINTS is not set
-
-#
-# Performance Monitoring
-#
-# CONFIG_SCHED_CPULOAD is not set
-# CONFIG_SCHED_INSTRUMENTATION is not set
-
-#
-# Latency optimization
-#
-# CONFIG_SCHED_YIELD_OPTIMIZATION is not set
-
-#
-# Files and I/O
-#
-CONFIG_DEV_CONSOLE=y
-# CONFIG_FDCLONE_DISABLE is not set
-# CONFIG_FDCLONE_STDIO is not set
-# CONFIG_SDCLONE_DISABLE is not set
-CONFIG_NFILE_DESCRIPTORS=16
-CONFIG_NFILE_STREAMS=16
-CONFIG_NAME_MAX=32
-CONFIG_PRIORITY_INHERITANCE=y
-CONFIG_SEM_PREALLOCHOLDERS=16
-CONFIG_SEM_NNESTPRIO=16
-
-#
-# RTOS hooks
-#
-CONFIG_BOARD_INITIALIZE=y
-# CONFIG_BOARD_INITTHREAD is not set
-# CONFIG_SCHED_STARTHOOK is not set
-CONFIG_SCHED_ATEXIT=y
-CONFIG_SCHED_ONEXIT=y
-CONFIG_SCHED_ONEXIT_MAX=1
-
-#
-# Signal Numbers
-#
-CONFIG_SIG_SIGUSR1=1
-CONFIG_SIG_SIGUSR2=2
-CONFIG_SIG_SIGALARM=3
-CONFIG_SIG_SIGCHLD=4
-CONFIG_SIG_SIGCONDTIMEDOUT=16
-CONFIG_SIG_SIGWORK=17
-
-#
-# POSIX Message Queue Options
-#
-CONFIG_PREALLOC_MQ_MSGS=4
-CONFIG_MQ_MAXMSGSIZE=600
-
-#
-# Work Queue Support
-#
-CONFIG_SCHED_WORKQUEUE=y
-CONFIG_SCHED_WORKQUEUE_SORTING=y
-CONFIG_SCHED_HPWORK=y
-CONFIG_SCHED_HPWORKPRIORITY=224
-CONFIG_SCHED_HPWORKPERIOD=50000
-CONFIG_SCHED_HPWORKSTACKSIZE=2048
-CONFIG_SCHED_LPWORK=y
-CONFIG_SCHED_LPNTHREADS=1
-CONFIG_SCHED_LPWORKPRIORITY=176
-CONFIG_SCHED_LPWORKPRIOMAX=176
-CONFIG_SCHED_LPWORKPERIOD=50000
-CONFIG_SCHED_LPWORKSTACKSIZE=2048
-
-#
-# Stack size information
-#
-CONFIG_IDLETHREAD_STACKSIZE=1024
-CONFIG_USERMAIN_STACKSIZE=2048
-# CONFIG_MPU_STACKGAURD is not set
-CONFIG_PTHREAD_STACK_MIN=256
-CONFIG_PTHREAD_STACK_DEFAULT=2048
-
-#
-# System Call
-#
-# CONFIG_LIB_SYSCALL is not set
-
-#
-# Device Drivers
-#
-# CONFIG_DISABLE_POLL is not set
-CONFIG_DEV_NULL=y
-CONFIG_DEV_ZERO=y
-
-#
-# Buffering
-#
-# CONFIG_DRVR_WRITEBUFFER is not set
-# CONFIG_DRVR_READAHEAD is not set
-# CONFIG_CAN is not set
-# CONFIG_ARCH_HAVE_PWM_PULSECOUNT is not set
-# CONFIG_ARCH_HAVE_PWM_MULTICHAN is not set
-CONFIG_PWM=y
-# CONFIG_ARCH_HAVE_I2CRESET is not set
-CONFIG_I2C=y
-CONFIG_I2C_SLAVE=y
-CONFIG_I2C_USERIO=y
-CONFIG_I2C_TRANSFER=y
-CONFIG_I2C_POLLED=y
-# CONFIG_I2C_TRACE is not set
-# CONFIG_I2C_WRITEREAD is not set
-CONFIG_SPI=y
-# CONFIG_SPI_OWNBUS is not set
-CONFIG_SPI_EXCHANGE=y
-# CONFIG_SPI_CMDDATA is not set
-# CONFIG_SPI_BITBANG is not set
-CONFIG_GPIO=y
-CONFIG_I2S=y
-# CONFIG_BCH is not set
-CONFIG_RTC=y
-CONFIG_RTC_DATETIME=y
-# CONFIG_RTC_ALARM is not set
-CONFIG_RTC_DRIVER=y
-# CONFIG_RTC_IOCTL is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_DEVPATH="/dev/watchdog0"
-# CONFIG_TIMER is not set
-CONFIG_ANALOG=y
-CONFIG_ADC=y
-CONFIG_ADC_FIFOSIZE=8
-# CONFIG_DAC is not set
-# CONFIG_AUDIO_DEVICES is not set
-# CONFIG_LCD is not set
-CONFIG_NETDEVICES=y
-
-#
-# General Ethernet MAC Driver Options
-#
-CONFIG_NETDEV_TELNET=y
-CONFIG_NETDEV_MULTINIC=y
-# CONFIG_NET_DUMPPACKET is not set
-
-#
-# External Ethernet MAC Device Support
-#
-# CONFIG_NET_DM90x0 is not set
-# CONFIG_ENC28J60 is not set
-# CONFIG_ENCX24J600 is not set
-# CONFIG_NET_E1000 is not set
-# CONFIG_NET_SLIP is not set
-# CONFIG_NET_VNET is not set
-# CONFIG_PIPES is not set
-CONFIG_POWER=y
-# CONFIG_BATTERY_CHARGER is not set
-# CONFIG_BATTERY_GAUGE is not set
-# CONFIG_SERCOMM_CONSOLE is not set
-CONFIG_SERIAL=y
-# CONFIG_DEV_LOWCONSOLE is not set
-# CONFIG_16550_UART is not set
-# CONFIG_ARCH_HAVE_UART is not set
-CONFIG_ARCH_HAVE_UART0=y
-CONFIG_ARCH_HAVE_UART1=y
-CONFIG_ARCH_HAVE_UART2=y
-CONFIG_ARCH_HAVE_UART3=y
-CONFIG_ARCH_HAVE_UART4=y
-# CONFIG_ARCH_HAVE_UART5 is not set
-# CONFIG_ARCH_HAVE_UART6 is not set
-# CONFIG_ARCH_HAVE_UART7 is not set
-# CONFIG_ARCH_HAVE_UART8 is not set
-# CONFIG_ARCH_HAVE_SCI0 is not set
-# CONFIG_ARCH_HAVE_SCI1 is not set
-# CONFIG_ARCH_HAVE_USART0 is not set
-# CONFIG_ARCH_HAVE_USART1 is not set
-# CONFIG_ARCH_HAVE_USART2 is not set
-# CONFIG_ARCH_HAVE_USART3 is not set
-# CONFIG_ARCH_HAVE_USART4 is not set
-# CONFIG_ARCH_HAVE_USART5 is not set
-# CONFIG_ARCH_HAVE_USART6 is not set
-# CONFIG_ARCH_HAVE_USART7 is not set
-# CONFIG_ARCH_HAVE_USART8 is not set
-# CONFIG_ARCH_HAVE_OTHER_UART is not set
-
-#
-# USART Configuration
-#
-CONFIG_MCU_SERIAL=y
-CONFIG_STANDARD_SERIAL=y
-CONFIG_SERIAL_NPOLLWAITERS=2
-# CONFIG_SERIAL_IFLOWCONTROL is not set
-# CONFIG_SERIAL_OFLOWCONTROL is not set
-# CONFIG_SERIAL_TIOCSERGSTRUCT is not set
-CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y
-CONFIG_SERIAL_TERMIOS=y
-# CONFIG_UART0_SERIAL_CONSOLE is not set
-# CONFIG_UART1_SERIAL_CONSOLE is not set
-# CONFIG_UART2_SERIAL_CONSOLE is not set
-# CONFIG_UART3_SERIAL_CONSOLE is not set
-CONFIG_UART4_SERIAL_CONSOLE=y
-# CONFIG_OTHER_SERIAL_CONSOLE is not set
-# CONFIG_NO_SERIAL_CONSOLE is not set
-
-#
-# UART0 Configuration
-#
-CONFIG_UART0_RXBUFSIZE=64
-CONFIG_UART0_TXBUFSIZE=64
-CONFIG_UART0_BAUD=115200
-CONFIG_UART0_BITS=8
-CONFIG_UART0_PARITY=0
-CONFIG_UART0_2STOP=0
-# CONFIG_UART0_IFLOWCONTROL is not set
-# CONFIG_UART0_OFLOWCONTROL is not set
-
-#
-# UART1 Configuration
-#
-CONFIG_UART1_RXBUFSIZE=256
-CONFIG_UART1_TXBUFSIZE=256
-CONFIG_UART1_BAUD=115200
-CONFIG_UART1_BITS=8
-CONFIG_UART1_PARITY=0
-CONFIG_UART1_2STOP=0
-# CONFIG_UART1_IFLOWCONTROL is not set
-# CONFIG_UART1_OFLOWCONTROL is not set
-
-#
-# UART2 Configuration
-#
-CONFIG_UART2_RXBUFSIZE=256
-CONFIG_UART2_TXBUFSIZE=256
-CONFIG_UART2_BAUD=115200
-CONFIG_UART2_BITS=8
-CONFIG_UART2_PARITY=0
-CONFIG_UART2_2STOP=0
-# CONFIG_UART2_IFLOWCONTROL is not set
-# CONFIG_UART2_OFLOWCONTROL is not set
-
-#
-# UART3 Configuration
-#
-CONFIG_UART3_RXBUFSIZE=256
-CONFIG_UART3_TXBUFSIZE=256
-CONFIG_UART3_BAUD=115200
-CONFIG_UART3_BITS=8
-CONFIG_UART3_PARITY=0
-CONFIG_UART3_2STOP=0
-# CONFIG_UART3_IFLOWCONTROL is not set
-# CONFIG_UART3_OFLOWCONTROL is not set
-
-#
-# UART4 Configuration
-#
-CONFIG_UART4_RXBUFSIZE=256
-CONFIG_UART4_TXBUFSIZE=256
-CONFIG_UART4_BAUD=115200
-CONFIG_UART4_BITS=8
-CONFIG_UART4_PARITY=0
-CONFIG_UART4_2STOP=0
-# CONFIG_UART4_IFLOWCONTROL is not set
-# CONFIG_UART4_OFLOWCONTROL is not set
-# CONFIG_USBDEV is not set
-# CONFIG_FOTA_DRIVER is not set
-
-#
-# System Logging
-#
-# CONFIG_RAMLOG is not set
-# CONFIG_SYSLOG_CONSOLE is not set
-
-#
-# T-trace
-#
-# CONFIG_TTRACE is not set
-
-#
-# Wireless Device Options
-#
-CONFIG_DRIVERS_WIRELESS=y
-CONFIG_SCSC_WLAN=y
-# CONFIG_SLSI_RX_PERFORMANCE_TEST is not set
-CONFIG_SCSC_TX_FLOW_CONTROL=y
-CONFIG_SCSC_ENABLE_PORT_CONTROL=y
-# CONFIG_SCSC_WLAN_STA_ONLY is not set
-# CONFIG_SCSC_WLAN_BLOCK_IPV6 is not set
-# CONFIG_SCSC_WLAN_UDP_FLOWCONTROL is not set
-# CONFIG_SCSC_WLAN_AUTO_RECOVERY is not set
-CONFIG_SCSC_WLAN_POWER_SAVE=y
-CONFIG_SCSC_WLAN_MAX_INTERFACES=1
-CONFIG_SCSC_CORE=y
-CONFIG_SCSC_PLATFORM=y
-# CONFIG_SCSC_WLANLITE is not set
-# CONFIG_SCSC_DISABLE_WLAN_RESET is not set
-
-#
-# Networking Support
-#
-CONFIG_ARCH_HAVE_NET=y
-# CONFIG_ARCH_HAVE_PHY is not set
-CONFIG_NET=y
-CONFIG_NET_LWIP=y
-
-#
-# LwIP options
-#
-CONFIG_NET_IPv4=y
-CONFIG_NET_IP_DEFAULT_TTL=255
-# CONFIG_NET_IP_FORWARD is not set
-CONFIG_NET_IP_OPTIONS_ALLOWED=y
-CONFIG_NET_IP_FRAG=y
-CONFIG_NET_IP_REASSEMBLY=y
-CONFIG_NET_IPV4_REASS_MAX_PBUFS=20
-CONFIG_NET_IPV4_REASS_MAXAGE=5
-
-#
-# Socket support
-#
-CONFIG_NET_SOCKET=y
-CONFIG_NSOCKET_DESCRIPTORS=8
-CONFIG_NET_TCP_KEEPALIVE=y
-CONFIG_NET_RAW=y
-# CONFIG_NET_SOCKET_OPTION_BROADCAST is not set
-# CONFIG_NET_RANDOMIZE_INITIAL_LOCAL_PORTS is not set
-# CONFIG_NET_SO_SNDTIMEO is not set
-CONFIG_NET_SO_RCVTIMEO=y
-# CONFIG_NET_SO_RCVBUF is not set
-CONFIG_NET_SO_REUSE=y
-# CONFIG_NET_SO_REUSE_RXTOALL is not set
-CONFIG_NET_ARP=y
-CONFIG_NET_ARP_TABLESIZE=10
-CONFIG_NET_ARP_QUEUEING=y
-CONFIG_NET_ETHARP_TRUST_IP_MAC=y
-CONFIG_NET_ETH_PAD_SIZE=0
-# CONFIG_NET_ARP_STATIC_ENTRIES is not set
-CONFIG_NET_UDP=y
-# CONFIG_NET_NETBUF_RECVINFO is not set
-CONFIG_NET_UDP_TTL=255
-# CONFIG_NET_UDPLITE is not set
-CONFIG_NET_TCP=y
-CONFIG_NET_TCP_TTL=255
-CONFIG_NET_TCP_WND=58400
-CONFIG_NET_TCP_MAXRTX=12
-CONFIG_NET_TCP_SYNMAXRTX=6
-CONFIG_NET_TCP_QUEUE_OOSEQ=y
-CONFIG_NET_TCP_MSS=1460
-CONFIG_NET_TCP_CALCULATE_EFF_SEND_MSS=y
-CONFIG_NET_TCP_SND_BUF=29200
-CONFIG_NET_TCP_SND_QUEUELEN=80
-# CONFIG_NET_TCP_LISTEN_BACKLOG is not set
-CONFIG_NET_TCP_OVERSIZE=536
-# CONFIG_NET_TCP_TIMESTAMPS is not set
-CONFIG_NET_TCP_WND_UPDATE_THREASHOLD=536
-CONFIG_NET_ICMP=y
-CONFIG_NET_ICMP_TTL=255
-# CONFIG_NET_BROADCAST_PING is not set
-# CONFIG_NET_MULTICAST_PING is not set
-CONFIG_NET_LWIP_IGMP=y
-CONFIG_NET_LWIP_MEMP_NUM_IGMP_GROUP=8
-
-#
-# LWIP Mailbox Configurations
-#
-CONFIG_NET_TCPIP_MBOX_SIZE=64
-CONFIG_NET_DEFAULT_ACCEPTMBOX_SIZE=64
-CONFIG_NET_DEFAULT_RAW_RECVMBOX_SIZE=64
-CONFIG_NET_DEFAULT_TCP_RECVMBOX_SIZE=54
-CONFIG_NET_DEFAULT_UDP_RECVMBOX_SIZE=64
-
-#
-# Memory Configurations
-#
-CONFIG_NET_MEM_ALIGNMENT=4
-# CONFIG_NET_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is not set
-# CONFIG_NET_MEM_LIBC_MALLOC is not set
-CONFIG_NET_MEMP_MEM_MALLOC=y
-# CONFIG_NET_MEM_USE_POOLS is not set
-CONFIG_NET_MEM_SIZE=153600
-
-#
-# LWIP Task Configurations
-#
-# CONFIG_NET_TCPIP_CORE_LOCKING is not set
-# CONFIG_NET_TCPIP_CORE_LOCKING_INPUT is not set
-CONFIG_NET_TCPIP_THREAD_NAME="LWIP_TCP/IP"
-CONFIG_NET_TCPIP_THREAD_PRIO=110
-CONFIG_NET_TCPIP_THREAD_STACKSIZE=4096
-CONFIG_NET_COMPAT_MUTEX=y
-CONFIG_NET_SYS_LIGHTWEIGHT_PROT=y
-CONFIG_NET_DEFAULT_THREAD_NAME="lwIP"
-CONFIG_NET_DEFAULT_THREAD_PRIO=1
-CONFIG_NET_DEFAULT_THREAD_STACKSIZE=0
-
-#
-# Debug Options for Network
-#
-# CONFIG_NET_LWIP_DEBUG is not set
-
-#
-# Enable Statistics
-#
-CONFIG_NET_STATS=y
-CONFIG_NET_STATS_DISPLAY=y
-CONFIG_NET_LINK_STATS=y
-CONFIG_NET_ETHARP_STATS=y
-CONFIG_NET_IP_STATS=y
-# CONFIG_NET_IPFRAG_STATS is not set
-# CONFIG_NET_ICMP_STATS is not set
-CONFIG_NET_UDP_STATS=y
-CONFIG_NET_TCP_STATS=y
-CONFIG_NET_MEM_STATS=y
-CONFIG_NET_SYS_STATS=y
-# CONFIG_NET_LWIP_VLAN is not set
-CONFIG_NET_LWIP_LOOPBACK_INTERFACE=y
-# CONFIG_NET_LWIP_SLIP_INTERFACE is not set
-# CONFIG_NET_LWIP_PPP_SUPPORT is not set
-# CONFIG_NET_LWIP_SNMP is not set
-CONFIG_NET_SECURITY_TLS=y
-# CONFIG_TLS_WITH_SSS is not set
-
-#
-# Driver buffer configuration
-#
-CONFIG_NET_MULTIBUFFER=y
-CONFIG_NET_ETH_MTU=1500
-CONFIG_NET_GUARDSIZE=2
-
-#
-# Data link support
-#
-# CONFIG_NET_MULTILINK is not set
-CONFIG_NET_ETHERNET=y
-
-#
-# Network Device Operations
-#
-# CONFIG_NETDEV_PHY_IOCTL is not set
-
-#
-# Routing Table Configuration
-#
-# CONFIG_NET_ROUTE is not set
-
-#
-# File Systems
-#
-
-#
-# File system configuration
-#
-# CONFIG_DISABLE_MOUNTPOINT is not set
-# CONFIG_FS_AUTOMOUNTER is not set
-# CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set
-CONFIG_FS_READABLE=y
-CONFIG_FS_WRITABLE=y
-# CONFIG_FS_AIO is not set
-# CONFIG_FS_NAMED_SEMAPHORES is not set
-CONFIG_FS_MQUEUE_MPATH="/var/mqueue"
-CONFIG_FS_SMARTFS=y
-
-#
-# SMARTFS options
-#
-CONFIG_SMARTFS_ERASEDSTATE=0xff
-CONFIG_SMARTFS_MAXNAMLEN=32
-# CONFIG_SMARTFS_MULTI_ROOT_DIRS is not set
-CONFIG_SMARTFS_ALIGNED_ACCESS=y
-# CONFIG_SMARTFS_BAD_SECTOR is not set
-# CONFIG_SMARTFS_DYNAMIC_HEADER is not set
-# CONFIG_SMARTFS_JOURNALING is not set
-# CONFIG_SMARTFS_SECTOR_RECOVERY is not set
-CONFIG_FS_PROCFS=y
-
-#
-# Exclude individual procfs entries
-#
-# CONFIG_FS_PROCFS_EXCLUDE_PROCESS is not set
-# CONFIG_FS_PROCFS_EXCLUDE_UPTIME is not set
-# CONFIG_FS_PROCFS_EXCLUDE_VERSION is not set
-# CONFIG_FS_PROCFS_EXCLUDE_MTD is not set
-# CONFIG_FS_PROCFS_EXCLUDE_PARTITIONS is not set
-# CONFIG_FS_PROCFS_EXCLUDE_SMARTFS is not set
-# CONFIG_FS_PROCFS_EXCLUDE_POWER is not set
-CONFIG_FS_ROMFS=y
-
-#
-# Block Driver Configurations
-#
-CONFIG_RAMDISK=y
-
-#
-# MTD Configuration
-#
-CONFIG_MTD=y
-CONFIG_MTD_PARTITION=y
-CONFIG_MTD_PARTITION_NAMES=y
-CONFIG_MTD_PROGMEM=y
-CONFIG_MTD_FTL=y
-
-#
-# MTD_FTL Configurations
-#
-CONFIG_MTD_CONFIG=y
-
-#
-# MTD Configurations
-#
-# CONFIG_MTD_CONFIG_RAM_CONSOLIDATE is not set
-CONFIG_MTD_CONFIG_ERASEDVALUE=0xff
-# CONFIG_MTD_BYTE_WRITE is not set
-
-#
-# MTD Device Drivers
-#
-# CONFIG_MTD_M25P is not set
-# CONFIG_RAMMTD is not set
-CONFIG_MTD_SMART=y
-
-#
-# SMART Device options
-#
-CONFIG_MTD_SMART_SECTOR_SIZE=4096
-# CONFIG_MTD_SMART_WEAR_LEVEL is not set
-# CONFIG_MTD_SMART_ENABLE_CRC is not set
-# CONFIG_MTD_SMART_SECTOR_ERASE_DEBUG is not set
-# CONFIG_MTD_SMART_ALLOC_DEBUG is not set
-
-#
-# System Logging
-#
-# CONFIG_SYSLOG is not set
-# CONFIG_SYSLOG_TIMESTAMP is not set
-
-#
-# Arastorage
-#
-
-#
-# AraStorage database configuration
-#
-# CONFIG_ARASTORAGE is not set
-
-#
-# Memory Management
-#
-# CONFIG_DISABLE_REALLOC_NEIGHBOR_EXTENTION is not set
-# CONFIG_MM_SMALL is not set
-CONFIG_MM_REGIONS=1
-# CONFIG_ARCH_HAVE_HEAP2 is not set
-# CONFIG_GRAN is not set
-
-#
-# Power Management
-#
-CONFIG_PM=y
-# CONFIG_DEBUG_PM is not set
-# CONFIG_PM_TEST is not set
-CONFIG_PM_DEVNAME_LEN=32
-# CONFIG_PM_METRICS is not set
-CONFIG_PM_SLICEMS=100
-CONFIG_PM_NDOMAINS=1
-CONFIG_PM_MEMORY=2
-CONFIG_PM_COEFN=1
-CONFIG_PM_COEF1=1
-CONFIG_PM_COEF2=1
-CONFIG_PM_COEF3=1
-CONFIG_PM_COEF4=1
-CONFIG_PM_COEF5=1
-CONFIG_PM_IDLEENTER_THRESH=1
-CONFIG_PM_IDLEEXIT_THRESH=2
-CONFIG_PM_IDLEENTER_COUNT=30
-CONFIG_PM_STANDBYENTER_THRESH=1
-CONFIG_PM_STANDBYEXIT_THRESH=2
-CONFIG_PM_STANDBYENTER_COUNT=50
-CONFIG_PM_SLEEPENTER_THRESH=1
-CONFIG_PM_SLEEPEXIT_THRESH=2
-CONFIG_PM_SLEEPENTER_COUNT=70
-
-#
-# Logger Module
-#
-CONFIG_LOGM=y
-# CONFIG_PRINTF2LOGM is not set
-CONFIG_SYSLOG2LOGM=y
-# CONFIG_LOGM_TIMESTAMP is not set
-CONFIG_LOGM_BUFFER_SIZE=10240
-CONFIG_LOGM_PRINT_INTERVAL=1000
-CONFIG_LOGM_TASK_PRIORITY=110
-CONFIG_LOGM_TASK_STACKSIZE=2048
-# CONFIG_LOGM_TEST is not set
-
-#
-# Library Routines
-#
-
-#
-# Standard C Library Options
-#
-CONFIG_STDIO_BUFFER_SIZE=64
-CONFIG_STDIO_LINEBUFFER=y
-CONFIG_NUNGET_CHARS=2
-CONFIG_LIB_HOMEDIR="/"
-CONFIG_LIBM=y
-# CONFIG_NOPRINTF_FIELDWIDTH is not set
-CONFIG_LIBC_FLOATINGPOINT=y
-CONFIG_LIBC_IOCTL_VARIADIC=y
-CONFIG_LIB_RAND_ORDER=1
-# CONFIG_EOL_IS_CR is not set
-# CONFIG_EOL_IS_LF is not set
-# CONFIG_EOL_IS_BOTH_CRLF is not set
-CONFIG_EOL_IS_EITHER_CRLF=y
-CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=1024
-CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=2048
-CONFIG_LIBC_STRERROR=y
-# CONFIG_LIBC_STRERROR_SHORT is not set
-# CONFIG_LIBC_PERROR_STDOUT is not set
-CONFIG_LIBC_TMPDIR="/tmp"
-CONFIG_LIBC_MAX_TMPFILE=32
-CONFIG_ARCH_LOWPUTC=y
-# CONFIG_LIBC_LOCALTIME is not set
-# CONFIG_TIME_EXTENDED is not set
-CONFIG_LIB_SENDFILE_BUFSIZE=512
-# CONFIG_ARCH_ROMGETC is not set
-CONFIG_ARCH_OPTIMIZED_FUNCTIONS=y
-# CONFIG_ARCH_MEMCPY is not set
-CONFIG_MEMCPY_VIK=y
-# CONFIG_MEMCPY_PRE_INC_PTRS is not set
-CONFIG_MEMCPY_INDEXED_COPY=y
-# CONFIG_MEMCPY_64BIT is not set
-# CONFIG_ARCH_MEMCMP is not set
-# CONFIG_ARCH_MEMMOVE is not set
-# CONFIG_ARCH_MEMSET is not set
-# CONFIG_MEMSET_OPTSPEED is not set
-# CONFIG_ARCH_STRCHR is not set
-# CONFIG_ARCH_STRCMP is not set
-# CONFIG_ARCH_STRCPY is not set
-# CONFIG_ARCH_STRNCPY is not set
-# CONFIG_ARCH_STRLEN is not set
-# CONFIG_ARCH_STRNLEN is not set
-# CONFIG_ARCH_BZERO is not set
-CONFIG_LIBC_NETDB=y
-# CONFIG_NETDB_HOSTFILE is not set
-CONFIG_NETDB_DNSCLIENT=y
-CONFIG_NETDB_DNSCLIENT_ENTRIES=8
-CONFIG_NETDB_DNSCLIENT_NAMESIZE=32
-CONFIG_NETDB_DNSCLIENT_LIFESEC=3600
-CONFIG_NETDB_DNSCLIENT_MAXRESPONSE=512
-# CONFIG_NETDB_RESOLVCONF is not set
-CONFIG_NETDB_DNSSERVER_BY_DHCP=y
-# CONFIG_NETDB_DNSSERVER_IPv4 is not set
-
-#
-# Non-standard Library Support
-#
-
-#
-# Basic CXX Support
-#
-# CONFIG_C99_BOOL8 is not set
-# CONFIG_HAVE_CXX is not set
-
-#
-# External Functions
-#
-CONFIG_DM=y
-# CONFIG_LWM2M_WAKAAMA is not set
-CONFIG_DM_WIFI=y
-CONFIG_DM_AP_SSID="TizenRT1"
-CONFIG_DM_AP_PASS="tizenrt_tdc2017"
-CONFIG_DM_AP_SECURITY="wpa2_aes"
-
-#
-# IOTIVITY Config Parameters
-#
-# CONFIG_ENABLE_IOTIVITY is not set
-# CONFIG_LIBTUV is not set
-# CONFIG_AWS_SDK is not set
-
-#
-# Application Configuration
-#
-# CONFIG_ENTRY_MANUAL is not set
-
-#
-# Application entry point list
-#
-# CONFIG_ENTRY_HELLO is not set
-# CONFIG_ENTRY_IPERF is not set
-# CONFIG_ENTRY_WIFI_TEST is not set
-CONFIG_ENTRY_IOTJS=y
-CONFIG_USER_ENTRYPOINT="iotjs_main"
-CONFIG_BUILTIN_APPS=y
-
-#
-# Examples
-#
-# CONFIG_EXAMPLES_ARTIK_DEMO is not set
-# CONFIG_EXAMPLES_AWS is not set
-# CONFIG_EXAMPLES_DNSCLIENT_TEST is not set
-# CONFIG_EXAMPLES_DTLS_CLIENT is not set
-# CONFIG_EXAMPLES_DTLS_SERVER is not set
-# CONFIG_EXAMPLES_EEPROM_TEST is not set
-# CONFIG_EXAMPLES_FOTA_SAMPLE is not set
-CONFIG_EXAMPLES_HELLO=y
-# CONFIG_EXAMPLES_HELLO_TASH is not set
-# CONFIG_EXAMPLES_HELLOXX is not set
-# CONFIG_EXAMPLES_IOTBUS_TEST is not set
-CONFIG_EXAMPLES_IPERF=y
-# CONFIG_EXAMPLES_KERNEL_SAMPLE is not set
-# CONFIG_EXAMPLES_LIBTUV is not set
-# CONFIG_EXAMPLES_MTDPART is not set
-# CONFIG_EXAMPLES_NETTEST is not set
-# CONFIG_EXAMPLES_PROC_TEST is not set
-# CONFIG_EXAMPLES_SELECT_TEST is not set
-# CONFIG_EXAMPLES_SENSORBOARD is not set
-CONFIG_EXAMPLES_SLSIWIFI=y
-CONFIG_EXAMPLES_SLSIWIFI_PRIORITY=50
-CONFIG_EXAMPLES_SLSIWIFI_STACKSIZE=2048
-# CONFIG_EXAMPLES_SMART is not set
-# CONFIG_EXAMPLES_SMART_TEST is not set
-# CONFIG_EXAMPLES_SYSIO_TEST is not set
-# CONFIG_EXAMPLES_TESTCASE is not set
-# CONFIG_EXAMPLES_TLS_CLIENT is not set
-# CONFIG_EXAMPLES_TLS_SELFTEST is not set
-# CONFIG_EXAMPLES_TLS_SERVER is not set
-# CONFIG_EXAMPLES_WAKAAMA_CLIENT is not set
-CONFIG_EXAMPLES_WIFI_TEST=y
-# CONFIG_EXAMPLES_WORKQUEUE is not set
-
-#
-# Network Utilities
-#
-# CONFIG_NETUTILS_CODECS is not set
-CONFIG_NETUTILS_DHCPC=y
-CONFIG_NETUTILS_DHCPD=y
-CONFIG_NETUTILS_DHCPD_IGNOREBROADCAST=y
-CONFIG_NETUTILS_DHCPD_INTERFACE="wl1"
-CONFIG_NETUTILS_DHCPD_LEASETIME=864000
-CONFIG_NETUTILS_DHCPD_MINLEASETIME=86400
-CONFIG_NETUTILS_DHCPD_MAXLEASETIME=2592000
-CONFIG_NETUTILS_DHCPD_MAXLEASES=6
-CONFIG_NETUTILS_DHCPD_STARTIP=0xc0a82f02
-CONFIG_NETUTILS_DHCPD_ROUTERIP=0xc0a82f01
-CONFIG_NETUTILS_DHCPD_NETMASK=0xffffff00
-CONFIG_NETUTILS_DHCPD_DNSIP=0x08080808
-CONFIG_NETUTILS_DHCPD_OFFERTIME=3600
-CONFIG_NETUTILS_DHCPD_DECLINETIME=3600
-# CONFIG_NETUTILS_ERCOAP is not set
-# CONFIG_NETUTILS_FTPC is not set
-CONFIG_NETUTILS_FTPD=y
-CONFIG_NETUTILS_JSON=y
-# CONFIG_NETUTILS_MDNS is not set
-# CONFIG_NETUTILS_MQTT is not set
-CONFIG_NETUTILS_NETLIB=y
-# CONFIG_NETUTILS_NTPCLIENT is not set
-# CONFIG_NETUTILS_SMTP is not set
-# CONFIG_NETUTILS_TELNETD is not set
-# CONFIG_NETUTILS_TFTPC is not set
-# CONFIG_NETUTILS_WEBCLIENT is not set
-# CONFIG_NETUTILS_WEBSERVER is not set
-# CONFIG_NETUTILS_WEBSOCKET is not set
-CONFIG_NETUTILS_WIFI=y
-CONFIG_SLSI_WIFI_DEFAULT_WLAN_COUNTRY_CODE="00"
-CONFIG_SLSI_WIFI_DEFAULT_WLAN_TX_POWER=30
-# CONFIG_SLSI_WIFI_FILESYSTEM_SUPPORT is not set
-# CONFIG_NETUTILS_XMLRPC is not set
-
-#
-# Platform-specific Support
-#
-# CONFIG_PLATFORM_CONFIGDATA is not set
-
-#
-# Shell
-#
-CONFIG_TASH=y
-CONFIG_TASH_MAX_COMMANDS=132
-# CONFIG_DEBUG_TASH is not set
-CONFIG_TASH_TELNET_INTERFACE=y
-CONFIG_TASH_CMDTASK_STACKSIZE=4096
-CONFIG_TASH_CMDTASK_PRIORITY=100
-
-#
-# System Libraries and Add-Ons
-#
-# CONFIG_SYSTEM_CLE is not set
-# CONFIG_SYSTEM_CUTERM is not set
-# CONFIG_SYSTEM_FOTA_HAL is not set
-# CONFIG_SYSTEM_I2CTOOL is not set
-# CONFIG_SYSTEM_INIFILE is not set
-CONFIG_SYSTEM_PREAPP_INIT=y
-CONFIG_SYSTEM_PREAPP_STACKSIZE=2048
-# CONFIG_SYSTEM_INSTALL is not set
-CONFIG_SYSTEM_IOTJS=y
-CONFIG_IOTJS_PRIORITY=100
-CONFIG_IOTJS_STACKSIZE=65536
-# CONFIG_SYSTEM_NETDB is not set
-# CONFIG_SYSTEM_POWEROFF is not set
-CONFIG_SYSTEM_RAMTEST=y
-# CONFIG_SYSTEM_RAMTRON is not set
-CONFIG_SYSTEM_READLINE=y
-CONFIG_READLINE_ECHO=y
-CONFIG_SYSTEM_INFORMATION=y
-CONFIG_KERNEL_CMDS=y
-CONFIG_FS_CMDS=y
-CONFIG_FSCMD_BUFFER_LEN=64
-CONFIG_NET_CMDS=y
-CONFIG_ENABLE_DATE=y
-CONFIG_ENABLE_ENV_GET=y
-CONFIG_ENABLE_ENV_SET=y
-CONFIG_ENABLE_ENV_UNSET=y
-CONFIG_ENABLE_FREE=y
-CONFIG_ENABLE_HEAPINFO=y
-CONFIG_ENABLE_KILL=y
-CONFIG_ENABLE_KILLALL=y
-CONFIG_ENABLE_PS=y
-CONFIG_ENABLE_STACKMONITOR=y
-CONFIG_STACKMONITOR_PRIORITY=100
-CONFIG_STACKMONITOR_INTERVAL=5
-CONFIG_ENABLE_UPTIME=y
-CONFIG_SYSTEM_VI=y
-CONFIG_SYSTEM_VI_COLS=64
-CONFIG_SYSTEM_VI_ROWS=16
-CONFIG_SYSTEM_VI_DEBUGLEVEL=0
-
-#
-# wpa_supplicant
-#
-CONFIG_WPA_SUPPLICANT=y
-CONFIG_WPA_SUPPLICANT_PRIORITY=100
-CONFIG_WPA_SUPPLICANT_STACKSIZE=16384
-CONFIG_WPA_SUPPLICANT_ENTRYPOINT="wpa_supplicant_main"
-CONFIG_CTRL_IFACE=y
-CONFIG_CTRL_IFACE_FIFO=y
-CONFIG_WPA_CTRL_FIFO_DEV_REQ="/dev/wpa_ctrl_req"
-CONFIG_WPA_CTRL_FIFO_DEV_CFM="/dev/wpa_ctrl_cfm"
-CONFIG_WPA_CTRL_FIFO_DEV_GLOBAL_REQ="/dev/wpa_ctrl_global_req"
-CONFIG_WPA_CTRL_FIFO_DEV_GLOBAL_CFM="/dev/wpa_ctrl_global_cfm"
-CONFIG_WPA_MONITOR_FIFO_DEV="/dev/wpa_monitor"
-CONFIG_WPA_CTRL_FIFO_MK_MODE=666
-CONFIG_ELOOP_POLL=y
-# CONFIG_WPA_SUPPLICANT_CMD is not set
--- /dev/null
+#
+# Automatically generated file; DO NOT EDIT.
+# TinyAra Configuration
+#
+
+#
+# Build Setup
+#
+# CONFIG_EXPERIMENTAL is not set
+# CONFIG_DEFAULT_SMALL is not set
+CONFIG_HOST_LINUX=y
+# CONFIG_HOST_OSX is not set
+# CONFIG_HOST_WINDOWS is not set
+# CONFIG_HOST_OTHER is not set
+# CONFIG_WINDOWS_NATIVE is not set
+
+#
+# Build Configuration
+#
+CONFIG_APPS_DIR="../apps"
+CONFIG_FRAMEWORK_DIR="../framework"
+CONFIG_TOOLS_DIR="../tools"
+CONFIG_BUILD_FLAT=y
+# CONFIG_BUILD_PROTECTED is not set
+# CONFIG_BUILD_2PASS is not set
+
+#
+# Binary Output Formats
+#
+# CONFIG_INTELHEX_BINARY is not set
+# CONFIG_MOTOROLA_SREC is not set
+CONFIG_RAW_BINARY=y
+# CONFIG_UBOOT_UIMAGE is not set
+# CONFIG_DOWNLOAD_IMAGE is not set
+# CONFIG_SMARTFS_IMAGE is not set
+
+#
+# Customize Header Files
+#
+# CONFIG_ARCH_STDINT_H is not set
+# CONFIG_ARCH_STDBOOL_H is not set
+# CONFIG_ARCH_MATH_H is not set
+# CONFIG_ARCH_FLOAT_H is not set
+# CONFIG_ARCH_STDARG_H is not set
+CONFIG_ARCH_HAVE_CUSTOMOPT=y
+# CONFIG_DEBUG_NOOPT is not set
+# CONFIG_DEBUG_CUSTOMOPT is not set
+# CONFIG_DEBUG_FULLOPT is not set
+
+#
+# Hardware Configuration
+#
+
+#
+# Chip Selection
+#
+CONFIG_ARCH_ARM=y
+CONFIG_ARCH="arm"
+# CONFIG_ARCH_CHIP_LM is not set
+CONFIG_ARCH_CHIP_S5J=y
+# CONFIG_ARCH_CHIP_BCM4390X is not set
+CONFIG_ARCH_CHIP="s5j"
+
+#
+# ARM Options
+#
+# CONFIG_ARCH_CORTEXM3 is not set
+# CONFIG_ARCH_CORTEXM4 is not set
+CONFIG_ARCH_CORTEXR4=y
+CONFIG_ARCH_FAMILY="armv7-r"
+# CONFIG_ARCH_HAVE_FPU is not set
+CONFIG_ARMV7M_MPU=y
+CONFIG_ARMV7M_MPU_NREGIONS=12
+
+#
+# Exception stack options
+#
+CONFIG_ARCH_HAVE_DABORTSTACK=y
+CONFIG_ARCH_DABORTSTACK=0
+
+#
+# ARMv7-R Configuration Options
+#
+CONFIG_ARMV7R_HAVE_GICv2=y
+CONFIG_ARMV7R_MEMINIT=y
+CONFIG_ARMV7R_ICACHE=y
+CONFIG_ARMV7R_DCACHE=y
+# CONFIG_ARMV7R_DCACHE_WRITETHROUGH is not set
+# CONFIG_ARMV7R_HAVE_L2CC is not set
+# CONFIG_ARMV7R_HAVE_L2CC_PL310 is not set
+# CONFIG_ARMV7R_TOOLCHAIN_BUILDROOT is not set
+# CONFIG_ARMV7R_TOOLCHAIN_CODESOURCERYL is not set
+CONFIG_ARMV7R_TOOLCHAIN_GNU_EABIL=y
+# CONFIG_ARMV7R_TOOLCHAIN_GNU_OABI is not set
+# CONFIG_ARMV7R_HAVE_DECODEFIQ is not set
+
+#
+# S5J Configuration Options
+#
+CONFIG_ARCH_CHIP_S5JT200=y
+CONFIG_S5J_S5JT200=y
+
+#
+# S5J Peripheral Support
+#
+CONFIG_S5J_HAVE_ADC=y
+CONFIG_S5J_HAVE_DMA=y
+CONFIG_S5J_HAVE_I2C=y
+CONFIG_S5J_HAVE_I2S=y
+CONFIG_S5J_HAVE_MCT=y
+CONFIG_S5J_HAVE_PWM0=y
+CONFIG_S5J_HAVE_PWM1=y
+CONFIG_S5J_HAVE_PWM2=y
+CONFIG_S5J_HAVE_PWM3=y
+CONFIG_S5J_HAVE_PWM4=y
+CONFIG_S5J_HAVE_PWM5=y
+CONFIG_S5J_HAVE_RTC=y
+CONFIG_S5J_HAVE_SFLASH=y
+CONFIG_S5J_HAVE_SPI=y
+CONFIG_S5J_HAVE_SSS=y
+CONFIG_S5J_HAVE_UART0=y
+CONFIG_S5J_HAVE_UART1=y
+CONFIG_S5J_HAVE_UART2=y
+CONFIG_S5J_HAVE_UART3=y
+CONFIG_S5J_HAVE_UART4=y
+CONFIG_S5J_HAVE_WATCHDOG=y
+CONFIG_S5J_ADC=y
+# CONFIG_S5J_DMA is not set
+CONFIG_S5J_I2C=y
+# CONFIG_S5J_I2S is not set
+CONFIG_S5J_MCT=y
+CONFIG_S5J_TIMER0=y
+# CONFIG_S5J_TIMER1 is not set
+# CONFIG_S5J_TIMER2 is not set
+# CONFIG_S5J_TIMER3 is not set
+# CONFIG_S5J_UART_FLOWCONTROL is not set
+CONFIG_S5J_UART0=y
+CONFIG_S5J_UART1=y
+CONFIG_S5J_UART2=y
+CONFIG_S5J_UART3=y
+CONFIG_S5J_UART4=y
+CONFIG_S5J_PWM=y
+CONFIG_S5J_PWM0=y
+CONFIG_S5J_PWM1=y
+CONFIG_S5J_PWM2=y
+CONFIG_S5J_PWM3=y
+CONFIG_S5J_PWM4=y
+CONFIG_S5J_PWM5=y
+# CONFIG_S5J_SSS is not set
+CONFIG_S5J_SPI=y
+# CONFIG_S5J_WATCHDOG is not set
+CONFIG_S5J_SFLASH=y
+# CONFIG_S5J_SENSOR_PPD42NS is not set
+
+#
+# Architecture Options
+#
+# CONFIG_ARCH_NOINTC is not set
+# CONFIG_ARCH_VECNOTIRQ is not set
+# CONFIG_ARCH_DMA is not set
+# CONFIG_ARCH_HAVE_IRQPRIO is not set
+# CONFIG_ARCH_L2CACHE is not set
+# CONFIG_ARCH_HAVE_COHERENT_DCACHE is not set
+# CONFIG_ARCH_HAVE_ADDRENV is not set
+# CONFIG_ARCH_NEED_ADDRENV_MAPPING is not set
+CONFIG_ARCH_HAVE_VFORK=y
+# CONFIG_ARCH_HAVE_MMU is not set
+CONFIG_ARCH_HAVE_MPU=y
+# CONFIG_ARCH_NAND_HWECC is not set
+# CONFIG_ARCH_HAVE_EXTCLK is not set
+# CONFIG_ARCH_HAVE_POWEROFF is not set
+CONFIG_ARCH_HAVE_RESET=y
+CONFIG_ARCH_USE_MPU=y
+CONFIG_ARCH_STACKDUMP=y
+# CONFIG_DEBUG_DISPLAY_SYMBOL is not set
+# CONFIG_ENDIAN_BIG is not set
+# CONFIG_ARCH_IDLE_CUSTOM is not set
+CONFIG_ARCH_CUSTOM_PMINIT=y
+# CONFIG_ARCH_HAVE_RAMFUNCS is not set
+# CONFIG_ARCH_HAVE_RAMVECTORS is not set
+
+#
+# Board Settings
+#
+CONFIG_BOARD_LOOPSPERMSEC=29100
+# CONFIG_ARCH_CALIBRATION is not set
+
+#
+# Interrupt options
+#
+CONFIG_ARCH_HAVE_INTERRUPTSTACK=y
+CONFIG_ARCH_INTERRUPTSTACK=0
+# CONFIG_ARCH_HAVE_HIPRI_INTERRUPT is not set
+
+#
+# Boot options
+#
+# CONFIG_BOOT_RUNFROMEXTSRAM is not set
+CONFIG_BOOT_RUNFROMFLASH=y
+# CONFIG_BOOT_RUNFROMISRAM is not set
+# CONFIG_BOOT_RUNFROMSDRAM is not set
+# CONFIG_BOOT_COPYTORAM is not set
+
+#
+# Boot Memory Configuration
+#
+CONFIG_RAM_START=0x02023800
+CONFIG_RAM_SIZE=968704
+# CONFIG_DDR is not set
+# CONFIG_ARCH_HAVE_SDRAM is not set
+
+#
+# Board Selection
+#
+CONFIG_ARCH_BOARD_ARTIK053=y
+# CONFIG_ARCH_BOARD_ARTIK053S is not set
+# CONFIG_ARCH_BOARD_ARTIK055S is not set
+# CONFIG_ARCH_BOARD_SIDK_S5JT200 is not set
+CONFIG_ARCH_BOARD_ARTIK05X_FAMILY=y
+CONFIG_ARCH_BOARD="artik05x"
+
+#
+# Common Board Options
+#
+# CONFIG_BOARD_CRASHDUMP is not set
+# CONFIG_BOARD_ASSERT_AUTORESET is not set
+CONFIG_LIB_BOARDCTL=y
+CONFIG_BOARDCTL_RESET=y
+# CONFIG_BOARDCTL_UNIQUEID is not set
+# CONFIG_BOARD_FOTA_SUPPORT is not set
+
+#
+# Board-Specific Options
+#
+CONFIG_ARTIK05X_BOOT_FAILURE_DETECTION=y
+CONFIG_ARTIK05X_BOOT_COUNTS_ADDR=0x80090810
+CONFIG_ARTIK05X_FLASH_CAPACITY=8388608
+CONFIG_ARTIK05X_FLASH_PAGE_SIZE=4096
+CONFIG_ARTIK05X_FLASH_PART=y
+CONFIG_ARTIK05X_FLASH_MINOR=0
+CONFIG_ARTIK05X_FLASH_PART_LIST="16,48,192,32,512,2400,1536,1536,1000,400,8,512,"
+CONFIG_ARTIK05X_FLASH_PART_TYPE="none,ftl,none,none,none,none,none,ftl,smartfs,romfs,config,none,"
+CONFIG_ARTIK05X_FLASH_PART_NAME="bl1,sssro,bl2,sssfw,wlanfw,os,factory,ota,user,rom,nvram,sssrw,"
+CONFIG_ARTIK05X_AUTOMOUNT=y
+CONFIG_ARTIK05X_AUTOMOUNT_USERFS=y
+CONFIG_ARTIK05X_AUTOMOUNT_USERFS_DEVNAME="/dev/smart0p8"
+CONFIG_ARTIK05X_AUTOMOUNT_USERFS_MOUNTPOINT="/mnt"
+# CONFIG_ARTIK05X_AUTOMOUNT_SSSRW is not set
+CONFIG_ARTIK05X_AUTOMOUNT_ROMFS=y
+CONFIG_ARTIK05X_AUTOMOUNT_ROMFS_DEVNAME="/dev/mtdblock9"
+CONFIG_ARTIK05X_AUTOMOUNT_ROMFS_MOUNTPOINT="/rom"
+
+#
+# Kernel Features
+#
+CONFIG_DISABLE_OS_API=y
+# CONFIG_DISABLE_POSIX_TIMERS is not set
+# CONFIG_DISABLE_PTHREAD is not set
+# CONFIG_DISABLE_SIGNALS is not set
+# CONFIG_DISABLE_MQUEUE is not set
+# CONFIG_DISABLE_ENVIRON is not set
+
+#
+# Clocks and Timers
+#
+CONFIG_ARCH_HAVE_TICKLESS=y
+# CONFIG_SCHED_TICKLESS is not set
+CONFIG_USEC_PER_TICK=9979
+CONFIG_SYSTEM_TIME64=y
+CONFIG_CLOCK_MONOTONIC=y
+# CONFIG_JULIAN_TIME is not set
+CONFIG_MAX_WDOGPARMS=4
+CONFIG_PREALLOC_WDOGS=32
+CONFIG_WDOG_INTRESERVE=4
+CONFIG_PREALLOC_TIMERS=8
+
+#
+# Tasks and Scheduling
+#
+CONFIG_INIT_ENTRYPOINT=y
+CONFIG_RR_INTERVAL=100
+CONFIG_TASK_NAME_SIZE=31
+CONFIG_MAX_TASKS=32
+CONFIG_SCHED_HAVE_PARENT=y
+# CONFIG_SCHED_CHILD_STATUS is not set
+CONFIG_SCHED_WAITPID=y
+
+#
+# Pthread Options
+#
+CONFIG_PTHREAD_MUTEX_TYPES=y
+# CONFIG_PTHREAD_MUTEX_ROBUST is not set
+CONFIG_PTHREAD_MUTEX_UNSAFE=y
+# CONFIG_PTHREAD_MUTEX_BOTH is not set
+CONFIG_NPTHREAD_KEYS=4
+CONFIG_NPTHREAD_DESTRUCTOR_ITERATIONS=4
+# CONFIG_PTHREAD_CLEANUP is not set
+# CONFIG_CANCELLATION_POINTS is not set
+
+#
+# Performance Monitoring
+#
+# CONFIG_SCHED_CPULOAD is not set
+
+#
+# Latency optimization
+#
+# CONFIG_SCHED_YIELD_OPTIMIZATION is not set
+
+#
+# Files and I/O
+#
+CONFIG_DEV_CONSOLE=y
+# CONFIG_FDCLONE_DISABLE is not set
+# CONFIG_FDCLONE_STDIO is not set
+# CONFIG_SDCLONE_DISABLE is not set
+CONFIG_NFILE_DESCRIPTORS=16
+CONFIG_NFILE_STREAMS=16
+CONFIG_NAME_MAX=32
+CONFIG_PRIORITY_INHERITANCE=y
+CONFIG_SEM_PREALLOCHOLDERS=16
+CONFIG_SEM_NNESTPRIO=16
+
+#
+# RTOS hooks
+#
+CONFIG_BOARD_INITIALIZE=y
+# CONFIG_BOARD_INITTHREAD is not set
+# CONFIG_SCHED_STARTHOOK is not set
+CONFIG_SCHED_ATEXIT=y
+CONFIG_SCHED_ONEXIT=y
+
+#
+# Signal Numbers
+#
+CONFIG_SIG_SIGUSR1=1
+CONFIG_SIG_SIGUSR2=2
+CONFIG_SIG_SIGALARM=3
+CONFIG_SIG_SIGCHLD=4
+CONFIG_SIG_SIGCONDTIMEDOUT=16
+CONFIG_SIG_SIGWORK=17
+
+#
+# POSIX Message Queue Options
+#
+CONFIG_PREALLOC_MQ_MSGS=4
+CONFIG_MQ_MAXMSGSIZE=600
+
+#
+# Work Queue Support
+#
+CONFIG_SCHED_WORKQUEUE=y
+CONFIG_SCHED_WORKQUEUE_SORTING=y
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_HPWORKPRIORITY=224
+CONFIG_SCHED_HPWORKPERIOD=50000
+CONFIG_SCHED_HPWORKSTACKSIZE=2048
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_LPNTHREADS=1
+CONFIG_SCHED_LPWORKPRIORITY=176
+CONFIG_SCHED_LPWORKPRIOMAX=176
+CONFIG_SCHED_LPWORKPERIOD=50000
+CONFIG_SCHED_LPWORKSTACKSIZE=2048
+
+#
+# Stack size information
+#
+CONFIG_IDLETHREAD_STACKSIZE=1024
+CONFIG_USERMAIN_STACKSIZE=2048
+# CONFIG_MPU_STACKGAURD is not set
+CONFIG_PTHREAD_STACK_MIN=256
+CONFIG_PTHREAD_STACK_DEFAULT=2048
+
+#
+# Device Drivers
+#
+# CONFIG_DISABLE_POLL is not set
+CONFIG_DEV_NULL=y
+CONFIG_DEV_ZERO=y
+# CONFIG_DRVR_WRITEBUFFER is not set
+# CONFIG_DRVR_READAHEAD is not set
+# CONFIG_CAN is not set
+# CONFIG_ARCH_HAVE_PWM_PULSECOUNT is not set
+# CONFIG_ARCH_HAVE_PWM_MULTICHAN is not set
+CONFIG_PWM=y
+# CONFIG_ARCH_HAVE_I2CRESET is not set
+CONFIG_I2C=y
+CONFIG_I2C_SLAVE=y
+CONFIG_I2C_USERIO=y
+CONFIG_I2C_TRANSFER=y
+CONFIG_I2C_POLLED=y
+# CONFIG_I2C_TRACE is not set
+# CONFIG_I2C_WRITEREAD is not set
+CONFIG_SPI=y
+# CONFIG_SPI_OWNBUS is not set
+CONFIG_SPI_EXCHANGE=y
+# CONFIG_SPI_CMDDATA is not set
+# CONFIG_SPI_BITBANG is not set
+CONFIG_GPIO=y
+# CONFIG_I2S is not set
+# CONFIG_AUDIO_DEVICES is not set
+CONFIG_BCH=y
+CONFIG_RTC=y
+CONFIG_RTC_DATETIME=y
+# CONFIG_RTC_ALARM is not set
+CONFIG_RTC_DRIVER=y
+# CONFIG_RTC_IOCTL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_DEVPATH="/dev/watchdog0"
+# CONFIG_TIMER is not set
+CONFIG_ANALOG=y
+CONFIG_ADC=y
+CONFIG_ADC_FIFOSIZE=8
+# CONFIG_DAC is not set
+CONFIG_NETDEVICES=y
+
+#
+# General Ethernet MAC Driver Options
+#
+CONFIG_NETDEV_TELNET=y
+CONFIG_NETDEV_MULTINIC=y
+# CONFIG_NET_DUMPPACKET is not set
+
+#
+# External Ethernet MAC Device Support
+#
+# CONFIG_NET_DM90x0 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ENCX24J600 is not set
+# CONFIG_NET_E1000 is not set
+# CONFIG_NET_SLIP is not set
+# CONFIG_NET_VNET is not set
+# CONFIG_PIPES is not set
+CONFIG_POWER=y
+# CONFIG_BATTERY_CHARGER is not set
+# CONFIG_BATTERY_GAUGE is not set
+CONFIG_SERIAL=y
+# CONFIG_DEV_LOWCONSOLE is not set
+# CONFIG_16550_UART is not set
+# CONFIG_ARCH_HAVE_UART is not set
+CONFIG_ARCH_HAVE_UART0=y
+CONFIG_ARCH_HAVE_UART1=y
+CONFIG_ARCH_HAVE_UART2=y
+CONFIG_ARCH_HAVE_UART3=y
+CONFIG_ARCH_HAVE_UART4=y
+# CONFIG_ARCH_HAVE_UART5 is not set
+# CONFIG_ARCH_HAVE_UART6 is not set
+# CONFIG_ARCH_HAVE_UART7 is not set
+# CONFIG_ARCH_HAVE_UART8 is not set
+# CONFIG_ARCH_HAVE_SCI0 is not set
+# CONFIG_ARCH_HAVE_SCI1 is not set
+# CONFIG_ARCH_HAVE_USART0 is not set
+# CONFIG_ARCH_HAVE_USART1 is not set
+# CONFIG_ARCH_HAVE_USART2 is not set
+# CONFIG_ARCH_HAVE_USART3 is not set
+# CONFIG_ARCH_HAVE_USART4 is not set
+# CONFIG_ARCH_HAVE_USART5 is not set
+# CONFIG_ARCH_HAVE_USART6 is not set
+# CONFIG_ARCH_HAVE_USART7 is not set
+# CONFIG_ARCH_HAVE_USART8 is not set
+# CONFIG_ARCH_HAVE_OTHER_UART is not set
+
+#
+# USART Configuration
+#
+CONFIG_MCU_SERIAL=y
+CONFIG_STANDARD_SERIAL=y
+CONFIG_SERIAL_NPOLLWAITERS=2
+# CONFIG_SERIAL_IFLOWCONTROL is not set
+# CONFIG_SERIAL_OFLOWCONTROL is not set
+# CONFIG_SERIAL_TIOCSERGSTRUCT is not set
+CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y
+CONFIG_SERIAL_TERMIOS=y
+# CONFIG_UART0_SERIAL_CONSOLE is not set
+# CONFIG_UART1_SERIAL_CONSOLE is not set
+# CONFIG_UART2_SERIAL_CONSOLE is not set
+# CONFIG_UART3_SERIAL_CONSOLE is not set
+CONFIG_UART4_SERIAL_CONSOLE=y
+# CONFIG_OTHER_SERIAL_CONSOLE is not set
+# CONFIG_NO_SERIAL_CONSOLE is not set
+
+#
+# UART0 Configuration
+#
+CONFIG_UART0_RXBUFSIZE=64
+CONFIG_UART0_TXBUFSIZE=64
+CONFIG_UART0_BAUD=115200
+CONFIG_UART0_BITS=8
+CONFIG_UART0_PARITY=0
+CONFIG_UART0_2STOP=0
+# CONFIG_UART0_IFLOWCONTROL is not set
+# CONFIG_UART0_OFLOWCONTROL is not set
+
+#
+# UART1 Configuration
+#
+CONFIG_UART1_RXBUFSIZE=256
+CONFIG_UART1_TXBUFSIZE=256
+CONFIG_UART1_BAUD=115200
+CONFIG_UART1_BITS=8
+CONFIG_UART1_PARITY=0
+CONFIG_UART1_2STOP=0
+# CONFIG_UART1_IFLOWCONTROL is not set
+# CONFIG_UART1_OFLOWCONTROL is not set
+
+#
+# UART2 Configuration
+#
+CONFIG_UART2_RXBUFSIZE=256
+CONFIG_UART2_TXBUFSIZE=256
+CONFIG_UART2_BAUD=115200
+CONFIG_UART2_BITS=8
+CONFIG_UART2_PARITY=0
+CONFIG_UART2_2STOP=0
+# CONFIG_UART2_IFLOWCONTROL is not set
+# CONFIG_UART2_OFLOWCONTROL is not set
+
+#
+# UART3 Configuration
+#
+CONFIG_UART3_RXBUFSIZE=256
+CONFIG_UART3_TXBUFSIZE=256
+CONFIG_UART3_BAUD=115200
+CONFIG_UART3_BITS=8
+CONFIG_UART3_PARITY=0
+CONFIG_UART3_2STOP=0
+# CONFIG_UART3_IFLOWCONTROL is not set
+# CONFIG_UART3_OFLOWCONTROL is not set
+
+#
+# UART4 Configuration
+#
+CONFIG_UART4_RXBUFSIZE=256
+CONFIG_UART4_TXBUFSIZE=256
+CONFIG_UART4_BAUD=115200
+CONFIG_UART4_BITS=8
+CONFIG_UART4_PARITY=0
+CONFIG_UART4_2STOP=0
+# CONFIG_UART4_IFLOWCONTROL is not set
+# CONFIG_UART4_OFLOWCONTROL is not set
+# CONFIG_SENSOR is not set
+# CONFIG_USBDEV is not set
+# CONFIG_FOTA_DRIVER is not set
+
+#
+# System Logging
+#
+# CONFIG_RAMLOG is not set
+# CONFIG_SYSLOG_CONSOLE is not set
+
+#
+# T-trace
+#
+# CONFIG_TTRACE is not set
+
+#
+# Wireless Device Options
+#
+CONFIG_DRIVERS_WIRELESS=y
+CONFIG_SCSC_WLAN=y
+# CONFIG_SLSI_RX_PERFORMANCE_TEST is not set
+CONFIG_SCSC_TX_FLOW_CONTROL=y
+CONFIG_SCSC_ENABLE_PORT_CONTROL=y
+# CONFIG_SCSC_WLAN_STA_ONLY is not set
+# CONFIG_SCSC_WLAN_BLOCK_IPV6 is not set
+# CONFIG_SCSC_WLAN_UDP_FLOWCONTROL is not set
+# CONFIG_SCSC_WLAN_AUTO_RECOVERY is not set
+CONFIG_SCSC_WLAN_POWER_SAVE=y
+CONFIG_SCSC_WLAN_MAX_INTERFACES=1
+CONFIG_SCSC_CORE=y
+CONFIG_SCSC_PLATFORM=y
+# CONFIG_SCSC_WLANLITE is not set
+# CONFIG_SCSC_DISABLE_WLAN_RESET is not set
+
+#
+# Networking Support
+#
+CONFIG_ARCH_HAVE_NET=y
+# CONFIG_ARCH_HAVE_PHY is not set
+CONFIG_NET=y
+CONFIG_NET_LWIP=y
+
+#
+# LwIP options
+#
+CONFIG_NET_IPv4=y
+CONFIG_NET_IP_DEFAULT_TTL=255
+# CONFIG_NET_IP_FORWARD is not set
+CONFIG_NET_IP_OPTIONS_ALLOWED=y
+CONFIG_NET_IP_FRAG=y
+CONFIG_NET_IP_REASSEMBLY=y
+CONFIG_NET_IPV4_REASS_MAX_PBUFS=20
+CONFIG_NET_IPV4_REASS_MAXAGE=5
+CONFIG_NET_IPv6=y
+CONFIG_NET_IPv6_NUM_ADDRESSES=3
+# CONFIG_NET_IPv6_FORWARD is not set
+# CONFIG_NET_IPv6_FRAG is not set
+CONFIG_NET_IPv6_REASS=y
+CONFIG_NET_IPV6_REASS_MAXAGE=60
+CONFIG_NET_IPv6_SEND_ROUTER_SOLICIT=y
+CONFIG_NET_IPv6_AUTOCONFIG=y
+CONFIG_NET_IPv6_DUP_DETECT_ATTEMPTS=1
+# CONFIG_NET_IPv6_PMTU_FOR_MULTICAST is not set
+
+#
+# Socket support
+#
+CONFIG_NET_SOCKET=y
+CONFIG_NSOCKET_DESCRIPTORS=20
+CONFIG_NET_TCP_KEEPALIVE=y
+CONFIG_NET_RAW=y
+# CONFIG_NET_SOCKET_OPTION_BROADCAST is not set
+# CONFIG_NET_RANDOMIZE_INITIAL_LOCAL_PORTS is not set
+# CONFIG_NET_SO_SNDTIMEO is not set
+CONFIG_NET_SO_RCVTIMEO=y
+# CONFIG_NET_SO_RCVBUF is not set
+CONFIG_NET_SO_REUSE=y
+# CONFIG_NET_SO_REUSE_RXTOALL is not set
+CONFIG_NET_ARP=y
+CONFIG_NET_ARP_TABLESIZE=10
+CONFIG_NET_ARP_QUEUEING=y
+CONFIG_NET_ETHARP_TRUST_IP_MAC=y
+CONFIG_NET_ETH_PAD_SIZE=0
+# CONFIG_NET_ARP_STATIC_ENTRIES is not set
+CONFIG_NET_IPv6_ND=y
+CONFIG_NET_IPv6_ND_QUEUEING=y
+CONFIG_NET_IPv6_ND_QUEUE=20
+CONFIG_NET_IPv6_ND_NUM_NEIGHBORS=10
+CONFIG_NET_IPv6_ND_NUM_DESTINATIONS=10
+CONFIG_NET_IPv6_ND_NUM_PREFIXES=5
+CONFIG_NET_IPv6_ND_NUM_ROUTERS=3
+CONFIG_NET_IPv6_ND_MAX_MULTICAST_SOLICIT=3
+CONFIG_NET_IPv6_ND_MAX_UNICAST_SOLICIT=3
+CONFIG_NET_IPv6_ND_MAX_SOLICIT_INTERVAL=4000
+CONFIG_NET_IPv6_ND_REACHABLE_TIME=30000
+CONFIG_NET_IPv6_ND_RETRANS_TIMER=1000
+CONFIG_NET_IPv6_ND_DELAY_FIRST_PROBE_TIME=5000
+CONFIG_NET_IPv6_ND_ALLOW_RA_UPDATES=y
+CONFIG_NET_IPv6_ND_TCP_REACHABILITY_HINTS=y
+CONFIG_NET_IPv6_ND_RDNSS_MAX_DNS_SERVERS=0
+CONFIG_NET_UDP=y
+# CONFIG_NET_NETBUF_RECVINFO is not set
+CONFIG_NET_UDP_TTL=255
+# CONFIG_NET_UDPLITE is not set
+CONFIG_NET_TCP=y
+CONFIG_NET_TCP_TTL=255
+CONFIG_NET_TCP_WND=58400
+CONFIG_NET_TCP_MAXRTX=12
+CONFIG_NET_TCP_SYNMAXRTX=6
+CONFIG_NET_TCP_QUEUE_OOSEQ=y
+CONFIG_NET_TCP_MSS=1460
+CONFIG_NET_TCP_CALCULATE_EFF_SEND_MSS=y
+CONFIG_NET_TCP_SND_BUF=29200
+CONFIG_NET_TCP_SND_QUEUELEN=80
+# CONFIG_NET_TCP_LISTEN_BACKLOG is not set
+CONFIG_NET_TCP_OVERSIZE=536
+# CONFIG_NET_TCP_TIMESTAMPS is not set
+CONFIG_NET_TCP_WND_UPDATE_THRESHOLD=536
+CONFIG_NET_ICMP=y
+CONFIG_NET_ICMP_TTL=255
+# CONFIG_NET_BROADCAST_PING is not set
+# CONFIG_NET_MULTICAST_PING4 is not set
+CONFIG_NET_IPv6_ICMP=y
+CONFIG_NET_IPv6_ICMP_DATASIZE=8
+CONFIG_NET_IPv6_ICMP_HL=255
+# CONFIG_NET_MULTICAST_PING6 is not set
+CONFIG_NET_LWIP_IGMP=y
+CONFIG_NET_LWIP_MEMP_NUM_IGMP_GROUP=8
+CONFIG_NET_IPv6_MLD=y
+CONFIG_NET_IPv6_MLD_GROUP=4
+# CONFIG_NET_IPv6_DHCP is not set
+
+#
+# LWIP Mailbox Configurations
+#
+CONFIG_NET_TCPIP_MBOX_SIZE=64
+CONFIG_NET_DEFAULT_ACCEPTMBOX_SIZE=64
+CONFIG_NET_DEFAULT_RAW_RECVMBOX_SIZE=64
+CONFIG_NET_DEFAULT_TCP_RECVMBOX_SIZE=54
+CONFIG_NET_DEFAULT_UDP_RECVMBOX_SIZE=64
+
+#
+# Memory Configurations
+#
+CONFIG_NET_MEM_ALIGNMENT=4
+# CONFIG_NET_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is not set
+# CONFIG_NET_MEM_LIBC_MALLOC is not set
+CONFIG_NET_MEMP_MEM_MALLOC=y
+# CONFIG_NET_MEM_USE_POOLS is not set
+CONFIG_NET_MEM_SIZE=153600
+
+#
+# LWIP Task Configurations
+#
+# CONFIG_NET_TCPIP_CORE_LOCKING is not set
+# CONFIG_NET_TCPIP_CORE_LOCKING_INPUT is not set
+CONFIG_NET_TCPIP_THREAD_NAME="LWIP_TCP/IP"
+CONFIG_NET_TCPIP_THREAD_PRIO=110
+CONFIG_NET_TCPIP_THREAD_STACKSIZE=4096
+CONFIG_NET_COMPAT_MUTEX=y
+CONFIG_NET_SYS_LIGHTWEIGHT_PROT=y
+CONFIG_NET_DEFAULT_THREAD_NAME="lwIP"
+CONFIG_NET_DEFAULT_THREAD_PRIO=1
+CONFIG_NET_DEFAULT_THREAD_STACKSIZE=0
+
+#
+# Debug Options for Network
+#
+# CONFIG_NET_LWIP_ASSERT is not set
+# CONFIG_NET_LWIP_ERROR is not set
+# CONFIG_NET_LWIP_DEBUG is not set
+
+#
+# Enable Statistics
+#
+CONFIG_NET_STATS=y
+CONFIG_NET_STATS_DISPLAY=y
+CONFIG_NET_LINK_STATS=y
+CONFIG_NET_ETHARP_STATS=y
+CONFIG_NET_IP_STATS=y
+# CONFIG_NET_IPFRAG_STATS is not set
+# CONFIG_NET_ICMP_STATS is not set
+CONFIG_NET_UDP_STATS=y
+CONFIG_NET_TCP_STATS=y
+CONFIG_NET_MEM_STATS=y
+CONFIG_NET_SYS_STATS=y
+# CONFIG_NET_IPv6_STATS is not set
+# CONFIG_NET_IPv6_ICMP_STATS is not set
+# CONFIG_NET_IPv6_MLD_STATS is not set
+# CONFIG_NET_IPv6_ND_STATS is not set
+# CONFIG_NET_LWIP_VLAN is not set
+CONFIG_NET_LWIP_LOOPBACK_INTERFACE=y
+# CONFIG_NET_LWIP_SLIP_INTERFACE is not set
+# CONFIG_NET_LWIP_PPP_SUPPORT is not set
+# CONFIG_NET_LWIP_SNMP is not set
+
+#
+# Interface Name
+#
+CONFIG_NET_ETH_IFNAME="en"
+CONFIG_NET_LOOP_IFNAME="lo"
+CONFIG_NET_STA_IFNAME="wl"
+CONFIG_NET_SOFTAP_IFNAME="sa"
+CONFIG_NET_LWIP_NETDB=y
+CONFIG_NET_DNS_TABLE_SIZE=4
+CONFIG_NET_DNS_MAX_NAME_LENGTH=256
+CONFIG_NET_DNS_MAX_SERVERS=2
+# CONFIG_NET_DNS_DOES_NAME_CHECK is not set
+CONFIG_NET_DNS_SECURE=0
+# CONFIG_NET_DNS_LOCAL_HOSTLIST is not set
+
+#
+# Driver buffer configuration
+#
+CONFIG_NET_MULTIBUFFER=y
+CONFIG_NET_ETH_MTU=590
+CONFIG_NET_GUARDSIZE=2
+
+#
+# Data link support
+#
+# CONFIG_NET_MULTILINK is not set
+CONFIG_NET_ETHERNET=y
+
+#
+# Network Device Operations
+#
+# CONFIG_NETDEV_PHY_IOCTL is not set
+
+#
+# Protocols
+#
+CONFIG_NETUTILS_DHCPD=y
+CONFIG_NETUTILS_DHCPD_IGNOREBROADCAST=y
+CONFIG_NETUTILS_DHCPD_INTERFACE="wl1"
+CONFIG_NETUTILS_DHCPD_LEASETIME=864000
+CONFIG_NETUTILS_DHCPD_MINLEASETIME=86400
+CONFIG_NETUTILS_DHCPD_MAXLEASETIME=2592000
+CONFIG_NETUTILS_DHCPD_MAXLEASES=6
+CONFIG_NETUTILS_DHCPD_STARTIP=0xc0a82f02
+CONFIG_NETUTILS_DHCPD_ROUTERIP=0xc0a82f01
+CONFIG_NETUTILS_DHCPD_NETMASK=0xffffff00
+CONFIG_NETUTILS_DHCPD_DNSIP=0x08080808
+CONFIG_NETUTILS_DHCPD_OFFERTIME=3600
+CONFIG_NETUTILS_DHCPD_DECLINETIME=3600
+# CONFIG_NETUTILS_XMLRPC is not set
+# CONFIG_NETUTILS_NTPCLIENT is not set
+# CONFIG_NETUTILS_WEBSERVER is not set
+# CONFIG_NETUTILS_FTPC is not set
+# CONFIG_NETUTILS_MDNS is not set
+# CONFIG_NETUTILS_FTPD is not set
+CONFIG_NETUTILS_DHCPC=y
+# CONFIG_NETUTILS_WEBSOCKET is not set
+# CONFIG_NETUTILS_LIBCOAP is not set
+# CONFIG_NETUTILS_TFTPC is not set
+# CONFIG_NETUTILS_TELNETD is not set
+# CONFIG_NETUTILS_SMTP is not set
+# CONFIG_NETUTILS_MQTT is not set
+CONFIG_NET_SECURITY_TLS=y
+CONFIG_TLS_MPI_MAX_SIZE=512
+
+#
+# Wireless
+#
+CONFIG_WIFI_MANAGER=y
+CONFIG_SELECT_WPA_SUPPLICANT=y
+# CONFIG_SELECT_PROPIETARY_SUPPLICANT is not set
+# CONFIG_SELECT_NO_DRIVER is not set
+CONFIG_SELECT_SCSC_WLAN=y
+# CONFIG_SELECT_PROPIETARY_WLAN is not set
+CONFIG_NETUTILS_WIFI=y
+CONFIG_SLSI_WIFI_DEFAULT_WLAN_COUNTRY_CODE="00"
+CONFIG_SLSI_WIFI_DEFAULT_WLAN_TX_POWER=30
+# CONFIG_SLSI_WIFI_FILESYSTEM_SUPPORT is not set
+
+#
+# wpa_supplicant
+#
+CONFIG_WPA_SUPPLICANT=y
+CONFIG_WPA_SUPPLICANT_PRIORITY=100
+CONFIG_WPA_SUPPLICANT_STACKSIZE=16384
+CONFIG_WPA_SUPPLICANT_ENTRYPOINT="wpa_supplicant_main"
+CONFIG_CTRL_IFACE=y
+CONFIG_CTRL_IFACE_FIFO=y
+CONFIG_WPA_CTRL_FIFO_DEV_REQ="/dev/wpa_ctrl_req"
+CONFIG_WPA_CTRL_FIFO_DEV_CFM="/dev/wpa_ctrl_cfm"
+CONFIG_WPA_CTRL_FIFO_DEV_GLOBAL_REQ="/dev/wpa_ctrl_global_req"
+CONFIG_WPA_CTRL_FIFO_DEV_GLOBAL_CFM="/dev/wpa_ctrl_global_cfm"
+CONFIG_WPA_MONITOR_FIFO_DEV="/dev/wpa_monitor"
+CONFIG_WPA_CTRL_FIFO_MK_MODE=666
+CONFIG_ELOOP_POLL=y
+# CONFIG_WPA_SUPPLICANT_CMD is not set
+CONFIG_DRIVER_T20=y
+# CONFIG_ENABLE_EAP_FOR_SUPPLICANT is not set
+CONFIG_WIFIMGR_SOFTAP_IFNAME="wl1"
+CONFIG_WIFIMGR_STA_IFNAME="wl1"
+# CONFIG_WIFIMGR_DISABLE_AUTO_GET_IP is not set
+# CONFIG_DISABLE_EXTERNAL_AUTOCONNECT is not set
+
+#
+# Network utilities
+#
+CONFIG_NETUTILS_NETLIB=y
+CONFIG_NET_NETMON=y
+
+#
+# Audio Support
+#
+# CONFIG_AUDIO is not set
+
+#
+# Media Support
+#
+
+#
+# File Systems
+#
+# CONFIG_DISABLE_MOUNTPOINT is not set
+# CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set
+CONFIG_FS_READABLE=y
+CONFIG_FS_WRITABLE=y
+# CONFIG_FS_AIO is not set
+# CONFIG_FS_NAMED_SEMAPHORES is not set
+CONFIG_FS_MQUEUE_MPATH="/var/mqueue"
+CONFIG_FS_SMARTFS=y
+
+#
+# SMARTFS options
+#
+CONFIG_SMARTFS_ERASEDSTATE=0xff
+CONFIG_SMARTFS_MAXNAMLEN=32
+# CONFIG_SMARTFS_MULTI_ROOT_DIRS is not set
+CONFIG_SMARTFS_ALIGNED_ACCESS=y
+# CONFIG_SMARTFS_BAD_SECTOR is not set
+# CONFIG_SMARTFS_DYNAMIC_HEADER is not set
+# CONFIG_SMARTFS_JOURNALING is not set
+# CONFIG_SMARTFS_SECTOR_RECOVERY is not set
+CONFIG_FS_PROCFS=y
+# CONFIG_FS_AUTOMOUNT_PROCFS is not set
+
+#
+# Exclude individual procfs entries
+#
+# CONFIG_FS_PROCFS_EXCLUDE_PROCESS is not set
+# CONFIG_FS_PROCFS_EXCLUDE_UPTIME is not set
+# CONFIG_FS_PROCFS_EXCLUDE_VERSION is not set
+# CONFIG_FS_PROCFS_EXCLUDE_MTD is not set
+# CONFIG_FS_PROCFS_EXCLUDE_PARTITIONS is not set
+# CONFIG_FS_PROCFS_EXCLUDE_SMARTFS is not set
+# CONFIG_FS_PROCFS_EXCLUDE_POWER is not set
+CONFIG_FS_ROMFS=y
+# CONFIG_FS_TMPFS is not set
+
+#
+# Block Driver Configurations
+#
+CONFIG_RAMDISK=y
+
+#
+# MTD Configuration
+#
+CONFIG_MTD=y
+CONFIG_MTD_PARTITION=y
+CONFIG_MTD_PARTITION_NAMES=y
+CONFIG_MTD_PROGMEM=y
+CONFIG_MTD_FTL=y
+
+#
+# MTD_FTL Configurations
+#
+CONFIG_MTD_CONFIG=y
+
+#
+# MTD Configurations
+#
+# CONFIG_MTD_CONFIG_RAM_CONSOLIDATE is not set
+CONFIG_MTD_CONFIG_ERASEDVALUE=0xff
+# CONFIG_MTD_BYTE_WRITE is not set
+
+#
+# MTD Device Drivers
+#
+# CONFIG_MTD_M25P is not set
+# CONFIG_RAMMTD is not set
+CONFIG_MTD_SMART=y
+
+#
+# SMART Device options
+#
+CONFIG_MTD_SMART_SECTOR_SIZE=512
+# CONFIG_MTD_SMART_WEAR_LEVEL is not set
+# CONFIG_MTD_SMART_ENABLE_CRC is not set
+# CONFIG_MTD_SMART_SECTOR_ERASE_DEBUG is not set
+# CONFIG_MTD_SMART_ALLOC_DEBUG is not set
+# CONFIG_MTD_W25 is not set
+
+#
+# System Logging
+#
+# CONFIG_SYSLOG is not set
+# CONFIG_SYSLOG_TIMESTAMP is not set
+
+#
+# Database
+#
+# CONFIG_ARASTORAGE is not set
+
+#
+# Memory Management
+#
+# CONFIG_REALLOC_DISABLE_NEIGHBOR_EXTENSION is not set
+# CONFIG_MM_SMALL is not set
+CONFIG_MM_REGIONS=1
+# CONFIG_GRAN is not set
+
+#
+# Power Management
+#
+CONFIG_PM=y
+# CONFIG_DEBUG_PM is not set
+# CONFIG_PM_TEST is not set
+CONFIG_PM_DEVNAME_LEN=32
+# CONFIG_PM_METRICS is not set
+CONFIG_PM_SLICEMS=100
+CONFIG_PM_NDOMAINS=1
+CONFIG_PM_MEMORY=2
+CONFIG_PM_COEFN=1
+CONFIG_PM_COEF1=1
+CONFIG_PM_COEF2=1
+CONFIG_PM_COEF3=1
+CONFIG_PM_COEF4=1
+CONFIG_PM_COEF5=1
+CONFIG_PM_IDLEENTER_THRESH=1
+CONFIG_PM_IDLEEXIT_THRESH=2
+CONFIG_PM_IDLEENTER_COUNT=30
+CONFIG_PM_STANDBYENTER_THRESH=1
+CONFIG_PM_STANDBYEXIT_THRESH=2
+CONFIG_PM_STANDBYENTER_COUNT=50
+CONFIG_PM_SLEEPENTER_THRESH=1
+CONFIG_PM_SLEEPEXIT_THRESH=2
+CONFIG_PM_SLEEPENTER_COUNT=70
+
+#
+# Debug Options
+#
+# CONFIG_DEBUG is not set
+# CONFIG_DEBUG_ERROR is not set
+# CONFIG_DEBUG_WARN is not set
+# CONFIG_DEBUG_VERBOSE is not set
+
+#
+# Subsystem Debug Options
+#
+# CONFIG_DEBUG_LIB is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_IOTBUS is not set
+# CONFIG_DEBUG_MM is not set
+# CONFIG_DEBUG_NET is not set
+# CONFIG_DEBUG_NET_ERROR is not set
+# CONFIG_DEBUG_NET_INFO is not set
+# CONFIG_DEBUG_SCHED is not set
+# CONFIG_DEBUG_TASH is not set
+# CONFIG_DEBUG_WLAN is not set
+
+#
+# SLSI WLAN FW Debug Options
+#
+# CONFIG_SCSC_ENABLE_FWFAULT_LOG is not set
+
+#
+# SLSI WLAN Driver Debug Options
+#
+# CONFIG_DEBUG_WLAN_DRIVER_ERROR is not set
+# CONFIG_DEBUG_WLAN_DRIVER_DEBUG is not set
+# CONFIG_DEBUG_WLAN_DRIVER_MORE is not set
+# CONFIG_DEBUG_WLAN_DRIVER_INFO is not set
+
+#
+# SLSI WPA Supplicant Debug Options
+#
+# CONFIG_DEBUG_WLAN_SUPPLICANT_ERROR is not set
+# CONFIG_DEBUG_WLAN_SUPPLICANT_DEBUG is not set
+# CONFIG_DEBUG_WLAN_SUPPLICANT_MORE is not set
+# CONFIG_DEBUG_WLAN_SUPPLICANT_INFO is not set
+
+#
+# SLSI Wi-Fi API Debug Options
+#
+# CONFIG_DEBUG_WLAN_API_ERROR is not set
+# CONFIG_DEBUG_WLAN_API_DEBUG is not set
+# CONFIG_DEBUG_WLAN_API_INFO is not set
+
+#
+# OS Function Debug Options
+#
+# CONFIG_ARCH_HAVE_HEAPCHECK is not set
+# CONFIG_DEBUG_MM_HEAPINFO is not set
+# CONFIG_DEBUG_IRQ is not set
+
+#
+# Driver Debug Options
+#
+# CONFIG_DEBUG_I2S is not set
+# CONFIG_DEBUG_PWM is not set
+# CONFIG_DEBUG_RTC is not set
+# CONFIG_DEBUG_SPI is not set
+# CONFIG_DEBUG_WATCHDOG is not set
+
+#
+# System Debug Options
+#
+# CONFIG_DEBUG_SYSTEM is not set
+
+#
+# Stack Debug Options
+#
+CONFIG_ARCH_HAVE_STACKCHECK=y
+CONFIG_STACK_COLORATION=y
+
+#
+# Build Debug Options
+#
+# CONFIG_DEBUG_SYMBOLS is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Logger Module
+#
+CONFIG_LOGM=y
+# CONFIG_PRINTF2LOGM is not set
+CONFIG_SYSLOG2LOGM=y
+# CONFIG_LOGM_TIMESTAMP is not set
+CONFIG_LOGM_BUFFER_SIZE=10240
+CONFIG_LOGM_PRINT_INTERVAL=1000
+CONFIG_LOGM_TASK_PRIORITY=110
+CONFIG_LOGM_TASK_STACKSIZE=2048
+# CONFIG_LOGM_TEST is not set
+
+#
+# Built-in Libraries
+#
+
+#
+# Standard C Library Options
+#
+CONFIG_STDIO_BUFFER_SIZE=64
+CONFIG_STDIO_LINEBUFFER=y
+CONFIG_NUNGET_CHARS=2
+CONFIG_LIB_HOMEDIR="/"
+CONFIG_LIBM=y
+# CONFIG_NOPRINTF_FIELDWIDTH is not set
+CONFIG_LIBC_FLOATINGPOINT=y
+CONFIG_LIBC_FLOATPRECISION=6
+CONFIG_LIBC_SCANSET=y
+# CONFIG_NOPRINTF_LONGLONG_TO_ASCII is not set
+CONFIG_LIBC_IOCTL_VARIADIC=y
+# CONFIG_LIBC_WCHAR is not set
+# CONFIG_LIBC_LOCALE is not set
+CONFIG_LIB_RAND_ORDER=1
+# CONFIG_EOL_IS_CR is not set
+# CONFIG_EOL_IS_LF is not set
+# CONFIG_EOL_IS_BOTH_CRLF is not set
+CONFIG_EOL_IS_EITHER_CRLF=y
+CONFIG_LIBC_STRERROR=y
+# CONFIG_LIBC_STRERROR_SHORT is not set
+# CONFIG_LIBC_PERROR_STDOUT is not set
+CONFIG_LIBC_TMPDIR="/tmp"
+CONFIG_LIBC_MAX_TMPFILE=32
+CONFIG_ARCH_LOWPUTC=y
+# CONFIG_LIBC_LOCALTIME is not set
+# CONFIG_TIME_EXTENDED is not set
+CONFIG_LIB_SENDFILE_BUFSIZE=512
+CONFIG_ARCH_OPTIMIZED_FUNCTIONS=y
+# CONFIG_ARCH_MEMCPY is not set
+CONFIG_MEMCPY_VIK=y
+# CONFIG_MEMCPY_PRE_INC_PTRS is not set
+CONFIG_MEMCPY_INDEXED_COPY=y
+# CONFIG_MEMCPY_64BIT is not set
+# CONFIG_ARCH_MEMCMP is not set
+# CONFIG_ARCH_MEMMOVE is not set
+# CONFIG_ARCH_MEMSET is not set
+# CONFIG_MEMSET_OPTSPEED is not set
+# CONFIG_ARCH_STRCHR is not set
+# CONFIG_ARCH_STRCMP is not set
+# CONFIG_ARCH_STRCPY is not set
+# CONFIG_ARCH_STRNCPY is not set
+# CONFIG_ARCH_STRLEN is not set
+# CONFIG_ARCH_STRNLEN is not set
+# CONFIG_ARCH_BZERO is not set
+
+#
+# Non-standard Library Support
+#
+
+#
+# Basic CXX Support
+#
+# CONFIG_C99_BOOL8 is not set
+# CONFIG_HAVE_CXX is not set
+
+#
+# External Libraries
+#
+# CONFIG_AVS_DEVICE_SDK is not set
+# CONFIG_AWS_SDK is not set
+# CONFIG_NETUTILS_CODECS is not set
+
+#
+# CURL Options
+#
+# CONFIG_ENABLE_CURL is not set
+# CONFIG_ERROR_REPORT is not set
+# CONFIG_ENABLE_IOTIVITY is not set
+CONFIG_NETUTILS_JSON=y
+# CONFIG_LIBTUV is not set
+# CONFIG_LWM2M_WAKAAMA is not set
+# CONFIG_STRESS_TOOL is not set
+# CONFIG_VOICE_SOFTWARE_EPD is not set
+
+#
+# Application Configuration
+#
+
+#
+# Application entry point list
+#
+# CONFIG_ENTRY_MANUAL is not set
+# CONFIG_ENTRY_HELLO is not set
+CONFIG_ENTRY_IOTJS_STARTUP=y
+CONFIG_USER_ENTRYPOINT="iotjs_startup_main"
+CONFIG_BUILTIN_APPS=y
+
+#
+# Examples
+#
+# CONFIG_EXAMPLES_AVS_TEST is not set
+# CONFIG_EXAMPLES_AWS is not set
+# CONFIG_EXAMPLES_CURLTEST is not set
+# CONFIG_EXAMPLES_DNSCLIENT_TEST is not set
+# CONFIG_EXAMPLES_DTLS_CLIENT is not set
+# CONFIG_EXAMPLES_DTLS_SERVER is not set
+# CONFIG_EXAMPLES_EEPROM_TEST is not set
+# CONFIG_EXAMPLES_EVENTLOOP is not set
+# CONFIG_EXAMPLES_FOTA_SAMPLE is not set
+# CONFIG_FILESYSTEM_HELPER_ENABLE is not set
+CONFIG_EXAMPLES_HELLO=y
+# CONFIG_EXAMPLES_HELLOXX is not set
+# CONFIG_EXAMPLES_IOTBUS_TEST is not set
+CONFIG_EXAMPLES_IOTJS_STARTUP=y
+CONFIG_EXAMPLES_IOTJS_STARTUP_JS_FILE="/rom/example/index.js"
+# CONFIG_EXAMPLES_IOTJS_STARTUP_WIFI is not set
+# CONFIG_EXAMPLES_KERNEL_SAMPLE is not set
+# CONFIG_EXAMPLES_LIBTUV is not set
+# CONFIG_EXAMPLES_NETTEST is not set
+# CONFIG_EXAMPLES_PROC_TEST is not set
+# CONFIG_EXAMPLES_SELECT_TEST is not set
+# CONFIG_EXAMPLES_SENSORBOARD is not set
+# CONFIG_EXAMPLES_SETJMP_TEST is not set
+CONFIG_EXAMPLES_SLSIWIFI=y
+CONFIG_EXAMPLES_SLSIWIFI_PRIORITY=50
+CONFIG_EXAMPLES_SLSIWIFI_STACKSIZE=2048
+# CONFIG_EXAMPLES_SMART is not set
+# CONFIG_EXAMPLES_SMART_TEST is not set
+# CONFIG_EXAMPLES_SPEECH_DETECTOR_TEST is not set
+# CONFIG_EXAMPLES_ST_THINGS is not set
+# CONFIG_EXAMPLES_TESTCASE is not set
+# CONFIG_EXAMPLES_TLS_BENCHMARK is not set
+# CONFIG_EXAMPLES_TLS_CLIENT is not set
+# CONFIG_EXAMPLES_TLS_SELFTEST is not set
+# CONFIG_EXAMPLES_TLS_SERVER is not set
+# CONFIG_EXAMPLES_WIFIMANAGER_TEST is not set
+
+#
+# Platform-specific Support
+#
+# CONFIG_PLATFORM_CONFIGDATA is not set
+
+#
+# Shell
+#
+CONFIG_TASH=y
+CONFIG_TASH_MAX_COMMANDS=132
+# CONFIG_TASH_USLEEP is not set
+CONFIG_TASH_COMMAND_INTERFACE=y
+CONFIG_TASH_CMDTASK_STACKSIZE=4096
+CONFIG_TASH_CMDTASK_PRIORITY=100
+# CONFIG_TASH_SCRIPT is not set
+
+#
+# System Libraries and Add-Ons
+#
+# CONFIG_SYSTEM_CLE is not set
+# CONFIG_SYSTEM_CUTERM is not set
+# CONFIG_SYSTEM_FLASH_ERASEALL is not set
+# CONFIG_SYSTEM_FOTA_HAL is not set
+# CONFIG_SYSTEM_I2CTOOL is not set
+# CONFIG_SYSTEM_INIFILE is not set
+CONFIG_SYSTEM_PREAPP_INIT=y
+CONFIG_SYSTEM_PREAPP_STACKSIZE=2048
+# CONFIG_SYSTEM_INSTALL is not set
+CONFIG_SYSTEM_IPERF=y
+# CONFIG_SYSTEM_NETDB is not set
+CONFIG_SYSTEM_RAMTEST=y
+CONFIG_SYSTEM_RAMTEST_PRIORITY=100
+CONFIG_SYSTEM_RAMTEST_STACKSIZE=1024
+CONFIG_SYSTEM_READLINE=y
+CONFIG_READLINE_ECHO=y
+CONFIG_SYSTEM_INFORMATION=y
+CONFIG_KERNEL_CMDS=y
+CONFIG_FS_CMDS=y
+CONFIG_FSCMD_BUFFER_LEN=64
+CONFIG_NET_CMDS=y
+CONFIG_NET_PING_CMD=y
+CONFIG_NET_PING_CMD_ICOUNT=5
+CONFIG_ENABLE_DATE_CMD=y
+CONFIG_ENABLE_ENV_GET_CMD=y
+CONFIG_ENABLE_ENV_SET_CMD=y
+CONFIG_ENABLE_ENV_UNSET_CMD=y
+CONFIG_ENABLE_FREE_CMD=y
+CONFIG_ENABLE_HEAPINFO_CMD=y
+# CONFIG_HEAPINFO_USER_GROUP is not set
+# CONFIG_ENABLE_IRQINFO_CMD is not set
+CONFIG_ENABLE_KILL_CMD=y
+CONFIG_ENABLE_KILLALL_CMD=y
+CONFIG_ENABLE_PS_CMD=y
+CONFIG_ENABLE_STACKMONITOR_CMD=y
+CONFIG_STACKMONITOR_PRIORITY=100
+CONFIG_STACKMONITOR_INTERVAL=5
+CONFIG_ENABLE_UPTIME_CMD=y
+# CONFIG_SYSTEM_VI is not set
+
+#
+# Runtime Environment
+#
+CONFIG_ENABLE_IOTJS=y
+CONFIG_IOTJS_PRIORITY=100
+CONFIG_IOTJS_STACKSIZE=32768
+CONFIG_IOTJS_JERRY_HEAP=128
+
+#
+# Device Management
+#
+# CONFIG_DM is not set
+
+#
+# Task manager
+#
+# CONFIG_TASK_MANAGER is not set
+
+#
+# Event Loop Framework
+#
+# CONFIG_EVENTLOOP is not set
+
+#
+# Things Management
+#
+# CONFIG_ST_THINGS is not set
+
+#
+# IoTBus Framework
+#
+CONFIG_IOTBUS=y
+CONFIG_IOTBUS_GPIO=y
+CONFIG_IOTBUS_I2C=y
+CONFIG_IOTBUS_PWM=y
+CONFIG_IOTBUS_SPI=y
+CONFIG_IOTBUS_UART=y
FOR##_mark = NULL; \
} \
} while (0)
-
+
/* Run the data callback FOR and consume the current byte */
#define CALLBACK_DATA(FOR) \
CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
#define CLOSE "close"
-static const char *method_strings[] =
+static const char * const method_strings[] =
{
#define XX(num, name, string) #string,
HTTP_METHOD_MAP(XX)
static struct {
const char *name;
const char *description;
-} http_strerror_tab[] = {
+} const http_strerror_tab[] = {
HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
};
#undef HTTP_STRERROR_GEN
# targets
jerry-targetjs.h
-targets/mbed/libjerry
-targets/mbed/build
-targets/mbed/yotta_modules
-targets/mbed/yotta_targets
.output
targets/esp8266/output.map
targets/esp8266/libs
# Tests
tests/test262/
-tests/unit-doc/*.c
+.vs
language: c
-# Default test platform: Ubuntu Trusty with sudo support.
+# Default environment: Container-based (sudo-less) Ubuntu Trusty 14.04.
os: linux
dist: trusty
-sudo: required
+sudo: false
-# Default dependency installation step #1: install dependencies for linux.
-# Other platforms can change this by redefining the 'before_install' stage in
-# the matrix below.
-before_install: tools/apt-get-install-deps.sh
-
-# Default dependency installation step #2: nop intentionally.
-# Jobs can add their own dependencies on top of 'before_install' by redefinig
-# the 'install' stage in the matrix below.
-install: true
+# Default dependency installation step: nop intentionally.
+# Jobs can add their own dependencies by redefinig the 'install' stage in the matrix below.
+install: skip
# Default job task: run tests as defined in the $OPT environment variable.
# Jobs can redefine the 'script' stage in the matrix below.
# 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 --check-pylint"
+ - name: "Checks"
+ 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="--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="--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
- - os: osx
- before_install: tools/brew-install-deps.sh
- 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-
+ addons:
+ apt:
+ packages: [doxygen, cppcheck, vera++]
+
+ - name: "Linux/x86-64 Build & Correctness Tests"
+ env:
+ - OPTS="--quiet --jerry-tests --jerry-test-suite"
+
+ - name: "Linux/x86 (cpointer-32bit) Build & Correctness Tests"
+ env:
+ - OPTS="--quiet --jerry-tests --jerry-test-suite --buildoptions=--compile-flag=-m32,--cpointer-32bit=on"
+ addons:
+ apt:
+ packages: [gcc-multilib]
+
+ - name: "Linux/ARM Build & Correctness Tests"
+ env:
+ - OPTS="--quiet --jerry-tests --jerry-test-suite --toolchain=cmake/toolchain_linux_armv7l.cmake --buildoptions=--linker-flag=-static"
+ - RUNTIME=qemu-arm-static
+ - TIMEOUT=300
+ addons:
+ apt:
+ packages: [gcc-arm-linux-gnueabihf, libc6-dev-armhf-cross, qemu-user-static]
+
+ - name: "OSX/x86-64 Build, Correctness & Unit Tests"
+ env:
+ - OPTS="--quiet --jerry-tests --jerry-test-suite --unittests"
+ os: osx
+ install: tools/brew-install-deps.sh
+
+ - name: "Build Tests"
+ env:
+ - OPTS="--buildoption-test"
+ addons:
+ apt:
+ packages: [gcc-multilib]
+
+ - name: "Unit Tests"
+ env:
+ - OPTS="--unittests"
+
+ - name: "Unit Tests (INIT_FINI)"
+ env:
+ - OPTS="--unittests --buildoptions=--cmake-param=-DFEATURE_INIT_FINI=ON"
+
+ - name: "Debugger Tests"
+ env:
+ - OPTS="--jerry-debugger"
+
+ - name: "Conformance Tests"
+ env:
+ - OPTS="--test262"
+
+ - name: "ASAN Tests"
+ env:
+ - OPTS="--quiet --jerry-tests --jerry-test-suite --skip-list=parser-oom.js,parser-oom2.js --buildoptions=--compile-flag=-fsanitize=address,--compile-flag=-m32,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--compile-flag=-O2,--debug,--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:
+ sources: ubuntu-toolchain-r-test
+ packages: [gcc-5, gcc-5-multilib]
+
+ - name: "UBSAN Tests"
+ env:
+ - OPTS="--quiet --jerry-tests --jerry-test-suite --skip-list=parser-oom.js,parser-oom2.js --buildoptions=--compile-flag=-fsanitize=undefined,--compile-flag=-m32,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--debug,--system-allocator=on,--linker-flag=-fuse-ld=gold"
+ - UBSAN_OPTIONS=print_stacktrace=1
+ - TIMEOUT=600
+ compiler: gcc-5
+ addons:
+ apt:
+ sources: ubuntu-toolchain-r-test
+ packages: [gcc-5, gcc-5-multilib]
+
+ - name: "Coverity Scan"
env:
# Declaration of the encrypted COVERITY_SCAN_TOKEN, created via the
# "travis encrypt" command using the project repo's public key.
notification_email: rsipka.uszeged@partner.samsung.com
build_command: "tools/build.py --clean"
branch_pattern: master
- script: true # Changed to nop, Coverity Scan has already built the project by the time 'script' stage is reached.
- - compiler: gcc-5
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - gcc-5
- - gcc-5-multilib
- 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
+ script: skip # Changed to nop, Coverity Scan has already built the project by the time 'script' stage is reached.
+
+ - name: "SonarQube"
addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - gcc-5
- - gcc-5-multilib
- 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
+ sonarcloud:
+ organization: "jerryscript-project"
+ token:
+ secure: "C1QD99nllAQndSDj4uIQPWCK0jBYrC5P0IrpdhfG7li7uvdzphUM++z3zkhYeeTJR3flw/cr8d9saYlbMjGw2eZ7AdJPFy4FJ1doBXD2amIuepaG1e829SLnJner9VA+d/8j28m7lZNtvZF5efbrS4KOicijNixmJy2PKG0K2035fs6MHLdywF8cJhyMaoRiMvYahIZEjXMvPBSgG1m4+A3PpzyN8XijwOT47cVtCLav4L21Mc7LcHsrc3LeyhtEJ+cs7Lx9WDQDwXX9iCRTA5ByqrXsS4rBV/N3lJI5M9p68Yj94Qy2OvVeCmUZ4ezwuuwkX00vBUk2f4eZx3oFAp973ekA8EGm/5qEvHVcbjHoHLbfUxsAKQHVoExXGdM5r1KeVgxLDT2FSQnBZLoxIrtGOUqFEOL4WX5YaQNoUKvYFO+CNvsMQkNg65QzLinRfqcH20KjzAsVeFwVI/j87J2VjooM8910savpw53iVBNPqmO/lG3kzFL7L2p1FeOuyEg9ANAbMhAXt3SL2srT0xni+ysg4Iwq+IkU+hkQWsvM8Voz+QJmiotFsi1Pzakcu3IOlT8lVVyn5q0z59YVDht/6if7acqkZ3X5vldeNIZYkImmYhMebScxVhzAa8AS6/81A+zJ8lW1+RWJQtP3uPM1+Dq18iFkPrCEMZwtoXI="
+ script: tools/check-sonarqube.sh
+ cache:
+ directories:
+ - '${HOME}/.sonar/cache'
- - env: JOBNAME="ESP8266 Build Test"
+ - name: "ESP8266 Build Test"
cache: ccache
- install: make -f ./targets/esp8266/Makefile.travis install
+ install: make -f ./targets/esp8266/Makefile.travis install-noapt
script: make -f ./targets/esp8266/Makefile.travis script
- - env: JOBNAME="Mbed/K64F Build Test"
addons:
apt:
- sources:
- - sourceline: ppa:team-gcc-arm-embedded/ppa
- packages:
- - gcc-arm-embedded
- install: make -f ./targets/mbed/Makefile.travis install
- script: make -f ./targets/mbed/Makefile.travis script
- - env: JOBNAME="Mbed OS 5/K64F Build Test"
+ packages: [gperf, texinfo, wget]
+
+ - name: "Mbed OS 5/K64F Build Test"
addons:
apt:
sources:
- sourceline: ppa:team-gcc-arm-embedded/ppa
- packages:
- - gcc-arm-embedded
+ packages: [gcc-arm-embedded]
install: make -f ./targets/mbedos5/Makefile.travis install
script: make -f ./targets/mbedos5/Makefile.travis script
- - env: JOBNAME="NuttX/STM32F4 Build Test"
- install: make -f targets/nuttx-stm32f4/Makefile.travis install
+
+ - name: "NuttX/STM32F4 Build Test"
+ install: make -f targets/nuttx-stm32f4/Makefile.travis install-noapt
script: make -f targets/nuttx-stm32f4/Makefile.travis script
- - env: JOBNAME="RIOT/STM32F4 Build Test"
- install: make -f ./targets/riot-stm32f4/Makefile.travis install
+ addons:
+ apt:
+ packages: [gcc-arm-none-eabi, libnewlib-arm-none-eabi, gperf]
+
+ - name: "RIOT/STM32F4 Build Test"
+ install: make -f ./targets/riot-stm32f4/Makefile.travis install-noapt
script: make -f ./targets/riot-stm32f4/Makefile.travis script
- - env: JOBNAME="Tizen RT/Artik053 Build Test"
+ compiler: clang-3.9
+ addons:
+ apt:
+ sources:
+ - sourceline: ppa:team-gcc-arm-embedded/ppa
+ packages: [clang-3.9, gcc-arm-embedded, gcc-multilib]
+
+ - name: "Tizen RT/Artik053 Build Test"
addons:
apt:
sources:
- sourceline: ppa:team-gcc-arm-embedded/ppa
- packages:
- - gcc-arm-embedded
+ packages: [gcc-arm-embedded]
install: make -f ./targets/tizenrt-artik053/Makefile.travis install
script: make -f ./targets/tizenrt-artik053/Makefile.travis script
- - env: JOBNAME="Zephyr/Arduino 101 Build Test"
- install: make -f ./targets/zephyr/Makefile.travis install
+
+ - name: "Zephyr/Arduino 101 Build Test"
+ install: make -f ./targets/zephyr/Makefile.travis install-noapt
script: make -f ./targets/zephyr/Makefile.travis script
- allow_failures:
- - env: JOBNAME="Mbed/K64F Build Test"
- - env: JOBNAME="Zephyr/Arduino 101 Build Test"
+ addons:
+ apt:
+ packages: [gperf, dfu-util, device-tree-compiler, python3-ply, python3-pip]
+
fast_finish: true
# The channel name "chat.freenode.net#jerryscript"
# limitations under the License.
cmake_minimum_required (VERSION 2.8.12)
-project (Jerry C ASM)
+project (Jerry C)
# Determining platform
set(PLATFORM "${CMAKE_SYSTEM_NAME}")
set(USING_TI 1)
endif()
+if(CMAKE_C_COMPILER_ID MATCHES "MSVC")
+ set(USING_MSVC 1)
+endif()
+
# Determining build type
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "MinSizeRel")
set(JERRY_CMDLINE_SNAPSHOT OFF CACHE BOOL "Build jerry snapshot command line tool?")
set(JERRY_PORT_DEFAULT ON CACHE BOOL "Build default jerry port implementation?")
set(JERRY_EXT ON CACHE BOOL "Build jerry-ext?")
-set(JERRY_LIBC ON CACHE BOOL "Build and use jerry-libc?")
set(JERRY_LIBM ON CACHE BOOL "Build and use jerry-libm?")
set(UNITTESTS OFF CACHE BOOL "Build unit tests?")
set(DOCTESTS OFF CACHE BOOL "Build doc tests?")
# Optional build settings
-set(ENABLE_ALL_IN_ONE OFF CACHE BOOL "Enable all-in-one build?")
+set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries?")
set(ENABLE_LTO ON CACHE BOOL "Enable LTO build?")
-if(NOT DEFINED ENABLE_STATIC_LINK)
- set(ENABLE_STATIC_LINK ON CACHE BOOL "Enable static linking?")
-endif()
set(ENABLE_STRIP ON CACHE BOOL "Enable stripping all symbols from release binary?")
-# Optional features
-set(FEATURE_INIT_FINI OFF CACHE BOOL "Enable init/fini arrays?")
-
# Option overrides
if(JERRY_CMDLINE OR JERRY_CMDLINE_TEST OR JERRY_CMDLINE_SNAPSHOT OR UNITTESTS OR DOCTESTS)
set(JERRY_PORT_DEFAULT ON)
endif()
if("${PLATFORM}" STREQUAL "DARWIN")
- set(JERRY_LIBC OFF)
set(JERRY_LIBM OFF)
- set(ENABLE_ALL_IN_ONE ON)
set(ENABLE_LTO OFF)
- set(ENABLE_STATIC_LINK OFF)
set(ENABLE_STRIP OFF)
- set(JERRY_LIBC_MESSAGE " (FORCED BY PLATFORM)")
set(JERRY_LIBM_MESSAGE " (FORCED BY PLATFORM)")
- set(ENABLE_ALL_IN_ONE_MESSAGE " (FORCED BY PLATFORM)")
set(ENABLE_LTO_MESSAGE " (FORCED BY PLATFORM)")
- set(ENABLE_STATIC_LINK_MESSAGE " (FORCED BY PLATFORM)")
set(ENABLE_STRIP_MESSAGE " (FORCED BY PLATFORM)")
endif()
if(USING_TI)
- set(ENABLE_STATIC_LINK ON)
set(ENABLE_STRIP OFF)
- set(ENABLE_STATIC_LINK_MESSAGE " (FORCED BY COMPILER)")
set(ENABLE_STRIP_MESSAGE " (FORCED BY COMPILER)")
endif()
-# Status messages
-message(STATUS "CMAKE_BUILD_TYPE " ${CMAKE_BUILD_TYPE})
-message(STATUS "CMAKE_SYSTEM_NAME " ${CMAKE_SYSTEM_NAME})
-message(STATUS "CMAKE_SYSTEM_PROCESSOR " ${CMAKE_SYSTEM_PROCESSOR})
-message(STATUS "ENABLE_ALL_IN_ONE " ${ENABLE_ALL_IN_ONE} ${ENABLE_ALL_IN_ONE_MESSAGE})
-message(STATUS "ENABLE_LTO " ${ENABLE_LTO} ${ENABLE_LTO_MESSAGE})
-message(STATUS "ENABLE_STATIC_LINK " ${ENABLE_STATIC_LINK} ${ENABLE_STATIC_LINK_MESSAGE})
-message(STATUS "ENABLE_STRIP " ${ENABLE_STRIP} ${ENABLE_STRIP_MESSAGE})
-message(STATUS "JERRY_CMDLINE " ${JERRY_CMDLINE})
-message(STATUS "JERRY_CMDLINE_TEST " ${JERRY_CMDLINE_TEST})
-message(STATUS "JERRY_CMDLINE_SNAPSHOT " ${JERRY_CMDLINE_SNAPSHOT})
-message(STATUS "JERRY_PORT_DEFAULT " ${JERRY_PORT_DEFAULT} ${JERRY_PORT_DEFAULT_MESSAGE})
-message(STATUS "JERRY_EXT " ${JERRY_EXT} ${JERRY_EXT_MESSAGE})
-message(STATUS "JERRY_LIBC " ${JERRY_LIBC} ${JERRY_LIBC_MESSAGE})
-message(STATUS "JERRY_LIBM " ${JERRY_LIBM} ${JERRY_LIBM_MESSAGE})
-message(STATUS "UNITTESTS " ${UNITTESTS})
-message(STATUS "DOCTESTS " ${DOCTESTS})
-message(STATUS "FEATURE_INIT_FINI " ${FEATURE_INIT_FINI})
-
-# Setup directories
-# Project binary dir
-set(PROJECT_BINARY_DIR "${CMAKE_BINARY_DIR}")
+if(USING_MSVC)
+ set(JERRY_LIBM OFF)
+ set(ENABLE_STRIP OFF)
-# Library output directory
-set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib/")
+ set(JERRY_LIBM_MESSAGE " (FORCED BY COMPILER)")
+ set(ENABLE_STRIP_MESSAGE " (FORCED BY COMPILER)")
+endif()
-# Executable output directory
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/")
+# Status messages
+message(STATUS "CMAKE_BUILD_TYPE " ${CMAKE_BUILD_TYPE})
+message(STATUS "CMAKE_C_COMPILER_ID " ${CMAKE_C_COMPILER_ID})
+message(STATUS "CMAKE_SYSTEM_NAME " ${CMAKE_SYSTEM_NAME})
+message(STATUS "CMAKE_SYSTEM_PROCESSOR " ${CMAKE_SYSTEM_PROCESSOR})
+message(STATUS "BUILD_SHARED_LIBS " ${BUILD_SHARED_LIBS})
+message(STATUS "ENABLE_LTO " ${ENABLE_LTO} ${ENABLE_LTO_MESSAGE})
+message(STATUS "ENABLE_STRIP " ${ENABLE_STRIP} ${ENABLE_STRIP_MESSAGE})
+message(STATUS "JERRY_CMDLINE " ${JERRY_CMDLINE})
+message(STATUS "JERRY_CMDLINE_TEST " ${JERRY_CMDLINE_TEST})
+message(STATUS "JERRY_CMDLINE_SNAPSHOT " ${JERRY_CMDLINE_SNAPSHOT})
+message(STATUS "JERRY_PORT_DEFAULT " ${JERRY_PORT_DEFAULT} ${JERRY_PORT_DEFAULT_MESSAGE})
+message(STATUS "JERRY_EXT " ${JERRY_EXT} ${JERRY_EXT_MESSAGE})
+message(STATUS "JERRY_LIBM " ${JERRY_LIBM} ${JERRY_LIBM_MESSAGE})
+message(STATUS "UNITTESTS " ${UNITTESTS})
+message(STATUS "DOCTESTS " ${DOCTESTS})
-# Archive targets output Directory
-set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib/")
+# Setup directories
+# Note: This mimics a conventional file system layout in the build directory for
+# the sake of convenient location of build artefacts. Proper installation to
+# traditional locations is also supported, e.g., to /usr/local.
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/")
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/")
# Remove rdynamic option
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS )
macro(jerry_add_compile_warnings)
foreach(_warning ${ARGV})
jerry_add_compile_flags(-W${_warning})
- if(USING_GCC)
- jerry_add_compile_flags(-Werror=${_warning})
- endif()
+ jerry_add_compile_flags(-Werror=${_warning})
endforeach()
endmacro()
jerry_add_compile_flags(${FLAGS_COMMON_ARCH})
jerry_add_flags(CMAKE_EXE_LINKER_FLAGS ${FLAGS_COMMON_ARCH})
-# Enable static build
-if(ENABLE_STATIC_LINK)
- if (USING_GCC OR USING_CLANG)
- jerry_add_link_flags("-static")
- endif()
-endif()
-
# LTO
if(ENABLE_LTO)
- if (USING_GCC OR USING_CLANG)
+ if(USING_GCC OR USING_CLANG)
jerry_add_compile_flags(-flto)
jerry_add_link_flags(-flto)
endif()
endif()
# Compiler / Linker flags
-if (USING_GCC OR USING_CLANG)
- jerry_add_compile_flags(-fno-builtin)
-endif()
-if(("${PLATFORM}" STREQUAL "DARWIN"))
+if("${PLATFORM}" STREQUAL "DARWIN")
jerry_add_link_flags(-lSystem)
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Sqc <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
-else()
+ set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup")
+elseif(USING_GCC OR USING_CLANG)
jerry_add_link_flags(-Wl,-z,noexecstack)
endif()
-# Turn off linking to compiler's default libc, in case jerry-libc is used
-if(JERRY_LIBC)
- jerry_add_link_flags(-nostdlib)
-endif()
-
-# Turn off stack protector
-if (USING_GCC OR USING_CLANG)
-jerry_add_compile_flags(-fno-stack-protector)
-endif()
-
-if (USING_GCC OR USING_CLANG)
+if(USING_GCC OR USING_CLANG)
+ jerry_add_compile_flags(-std=c99 -pedantic)
+ # Turn off stack protector
+ jerry_add_compile_flags(-fno-builtin -fno-stack-protector)
jerry_add_compile_warnings(all extra format-nonliteral init-self conversion sign-conversion format-security missing-declarations shadow strict-prototypes undef old-style-definition)
- jerry_add_compile_flags(-Wno-stack-protector -Wno-attributes)
+ jerry_add_compile_flags(-Wno-stack-protector -Wno-attributes -Werror)
endif()
if(USING_GCC)
jerry_add_compile_warnings(logical-op)
-elseif(USING_CLANG)
- jerry_add_compile_flags(-Wno-nested-anon-types -Wno-static-in-inline)
+ # TODO: Remove workaround for gcc 7 bug if the fallthrough comment detection is fixed.
+ if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 7.0)
+ jerry_add_compile_flags(-Wno-implicit-fallthrough)
+ endif()
endif()
-if(JERRY_LIBC)
- jerry_add_compile_flags(-Werror)
+if(USING_CLANG)
+ jerry_add_compile_flags(-Wno-nested-anon-types -Wno-static-in-inline)
endif()
-# C
-if (USING_GCC OR USING_CLANG)
- jerry_add_compile_flags(-std=c99 -pedantic)
-elseif(USING_TI)
+if(USING_TI)
jerry_add_compile_flags(--c99)
endif()
+if(USING_MSVC)
+ jerry_add_link_flags(/OPT:NOREF)
+ # Disable MSVC warning 4996 globally because it stops us from using standard C functions.
+ jerry_add_compile_flags(/wd4996)
+endif()
+
# Strip binary
if(ENABLE_STRIP AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
jerry_add_link_flags(-s)
endif()
-# TODO: Remove workaround for gcc 7 bug if the
-# fallthrough comment detection is fixed.
-if (USING_GCC AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 7.0)
- jerry_add_compile_flags(-Wno-implicit-fallthrough)
-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)
jerry_add_link_flags(${EXTERNAL_LINKER_FLAGS})
endif()
-# Jerry's libc
-if(JERRY_LIBC)
- add_subdirectory(jerry-libc)
-endif()
-
# Jerry's libm
if(JERRY_LIBM)
add_subdirectory(jerry-libm)
# Jerry's core
add_subdirectory(jerry-core)
-# Jerry's default port implementation
-if(JERRY_PORT_DEFAULT)
- add_subdirectory(jerry-port/default)
-endif()
-
# Jerry's extension tools
if(JERRY_EXT)
add_subdirectory(jerry-ext)
endif()
+# Jerry's default port implementation
+if(JERRY_PORT_DEFAULT)
+ add_subdirectory(jerry-port/default)
+endif()
+
# Jerry command line tool
if(JERRY_CMDLINE OR JERRY_CMDLINE_TEST OR JERRY_CMDLINE_SNAPSHOT)
add_subdirectory(jerry-main)
# all members of a group must be documented explicitly.
# The default value is: NO.
-DISTRIBUTE_GROUP_DOC = NO
+DISTRIBUTE_GROUP_DOC = YES
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
-EXTRACT_ALL = YES
+EXTRACT_ALL = NO
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
# *.qsf, *.as and *.js.
-FILE_PATTERNS = *.h, *.c
+FILE_PATTERNS = *.h *.c
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
# Note that relative paths are relative to the directory from which doxygen is
# run.
-EXCLUDE =
+# FIXME: None of these files are excluded light-heartedly. They should be
+# removed one-by-one and warnings reported by doxygen should be fixed by those
+# who are familiar with the undocumented parts.
+EXCLUDE = \
+ jerry-core/ecma/base/ecma-globals.h \
+ jerry-core/ecma/base/ecma-helpers.h \
+ jerry-core/ecma/operations/ecma-exceptions.h \
+ jerry-core/include/jerryscript-debugger-transport.h \
+ jerry-core/jcontext/jcontext.h \
+ jerry-core/parser/js/byte-code.h \
+ jerry-core/parser/js/common.h \
+ jerry-core/parser/js/js-lexer.h \
+ jerry-core/parser/js/js-parser-internal.h \
+ jerry-core/parser/regexp/re-parser.h \
+ jerry-core/vm/vm-stack.h
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
-EXCLUDE_PATTERNS =
+EXCLUDE_PATTERNS = *.inc.h
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-MACRO_EXPANSION = NO
+MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-EXPAND_ONLY_PREDEF = NO
+EXPAND_ONLY_PREDEF = YES
# If the SEARCH_INCLUDES tag is set to YES, the include files in the
# INCLUDE_PATH will be searched if a #include is found.
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-PREDEFINED =
+PREDEFINED = JERRY_STATIC_ASSERT(x,y)= JERRY_ATTR_FORMAT(x,y,z)=
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The

# JerryScript: JavaScript engine for the Internet of Things
[](LICENSE)
-[](https://travis-ci.org/jerryscript-project/jerryscript)
+[](https://travis-ci.org/jerryscript-project/jerryscript)
+[](https://ci.appveyor.com/project/jerryscript-project/jerryscript/branch/master)
[](https://scan.coverity.com/projects/jerryscript-project)
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fjerryscript-project%2Fjerryscript?ref=badge_shield)
+[](https://sonarcloud.io/dashboard?id=jerryscript)
[](https://kiwiirc.com/client/irc.freenode.net/#jerryscript)
JerryScript is a lightweight JavaScript engine for resource-constrained devices such as microcontrollers. It can run on devices with less than 64 KB of RAM and less than 200 KB of flash memory.
The following table shows the latest results on the devices:
-| STM32F4-Discovery | [](https://jerryscript-project.github.io/jerryscript-test-results/?view=stm32) |
+| STM32F4-Discovery | [](https://jerryscript-project.github.io/jerryscript-test-results/?view=stm32f4dis) |
| :---: | :---: |
-| **Raspberry Pi 2** | [](https://jerryscript-project.github.io/jerryscript-test-results/?view=rpi2) |
+| **Raspberry Pi 2** | [](https://jerryscript-project.github.io/jerryscript-test-results/?view=rpi2) |
+| **Artik053** | [](https://jerryscript-project.github.io/jerryscript-test-results/?view=artik053) |
IRC channel: #jerryscript on [freenode](https://freenode.net)
Mailing list: jerryscript-dev@groups.io, you can subscribe [here](https://groups.io/g/jerryscript-dev) and access the mailing list archive [here](https://groups.io/g/jerryscript-dev/topics).
--- /dev/null
+version: 1.0.{build}
+pull_requests:
+ do_not_increment_build_number: true
+branches:
+ except:
+ - coverity_scan
+ - gh_pages
+skip_tags: true
+
+# Build matrix setup.
+image:
+ - Visual Studio 2017
+configuration:
+ - Debug
+ - Release
+platform:
+ - x64
+ - Win32
+
+# Steps of a job.
+init:
+ - cmake -version
+before_build:
+ - if "%PLATFORM%"=="Win32" cmake -G"Visual Studio 15 2017" -Bbuild -H.
+ - if "%PLATFORM%"=="x64" cmake -G"Visual Studio 15 2017 Win64" -Bbuild -H.
+build:
+ project: build\Jerry.sln
+ parallel: true
+ verbosity: minimal
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(FLAGS_COMMON_ARCH -mcpu=cortex-r4 -mthumb -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)
python tools/build.py --profile=es5.1|es2015-subset|minimal
```
-**Use (jerry, compiler-default, external) libc**
+See also the related [README.md](https://github.com/jerryscript-project/jerryscript/blob/master/jerry-core/profiles/README.md).
-The default libc is jerry-libc, but you can use compiler-default libc or an external libc:
+**Use (compiler-default, external) libc**
+
+The default libc is the compiler-default libc but you can use an external libc as well:
- compiler-default libc:
```bash
-python tools/build.py --jerry-libc=off
+python tools/build.py
```
- external libc:
```bash
-python tools/build.py --jerry-libc=off --compile-flag="-nostdlib -I/path/to/ext-libc/include" --link-lib="ext-c"
+python tools/build.py --compile-flag="-nostdlib -I/path/to/ext-libc/include" --link-lib="ext-c"
```
**Add toolchain file**
**Use system memory allocator**
```bash
-python tools/build.py --system-allocator=on --jerry-libc=off
+python tools/build.py --system-allocator=on
```
*Note*: System allocator is only supported on 32 bit systems.
## jerry_type_t
-Enum that contains a set of elements to represent JavaScript type:
+Enum that contains JerryScript API value types:
- 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_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_ERROR - error/abort type
## jerry_error_t
- JERRY_FEATURE_DATE - Date support
- JERRY_FEATURE_REGEXP - RegExp support
- JERRY_FEATURE_LINE_INFO - line info available
+ - JERRY_FEATURE_LOGGING - logging
+
+## jerry_regexp_flags_t
+
+RegExp object optional flags:
+
+ - JERRY_REGEXP_FLAG_GLOBAL - global match; find all matches rather than stopping after the first match
+ - JERRY_REGEXP_FLAG_IGNORE_CASE - ignore case
+ - JERRY_REGEXP_FLAG_MULTILINE - multiline; treat beginning and end characters (^ and $) as working over
+ multiple lines (i.e., match the beginning or end of each line (delimited by \n or \r), not only the
+ very beginning or end of the whole input string)
## jerry_parse_opts_t
- JERRY_PARSE_NO_OPTS - no options passed
- JERRY_PARSE_STRICT_MODE - enable strict mode
+## jerry_gc_mode_t
+
+Set garbage collection operational mode
+
+ - JERRY_GC_SEVERITY_LOW - free unused objects
+ - JERRY_GC_SEVERITY_HIGH - free as much memory as possible
+
+The difference between `JERRY_GC_SEVERITY_LOW` and `JERRY_GC_SEVERITY_HIGH`
+is that the former keeps memory allocated for performance improvements such
+as property hash tables for large objects. The latter frees all possible
+memory blocks but the performance may drop after the garbage collection.
+
## jerry_generate_snapshot_opts_t
Flags for [jerry_generate_snapshot](#jerry_generate_snapshot) and
typedef uint8_t jerry_char_t;
```
-## jerry_char_ptr_t
-
-**Summary**
-
-Pointer to an array of character values
-
-**Prototype**
-
-```c
-typedef jerry_char_t *jerry_char_ptr_t;
-```
-
## jerry_size_t
**Summary**
} jerry_context_data_manager_t;
```
+## jerry_context_alloc_t
+
+**Summary**
+
+Function type for allocating buffer for JerryScript context.
+
+**Prototype**
+
+```c
+typedef void *(*jerry_context_alloc_t) (size_t size, void *cb_data_p);
+```
+
+- `size` - allocation size
+- `cb_data_p` - pointer to user data
+
+
+## jerry_context_t
+
+**Summary**
+
+An opaque declaration of the JerryScript context structure.
+
+**Prototype**
+
+```c
+typedef struct jerry_context_t jerry_context_t;
+```
+
## jerry_property_descriptor_t
**Summary**
const jerry_length_t args_count);
```
-## jerry_object_free_callback_t
-
-**Summary**
-
-**Deprecated: Please use jerry_object_native_free_callback_t instead.**
-
-Native free callback of an object.
-
-**Prototype**
-
-```c
-typedef void (*jerry_object_free_callback_t) (const uintptr_t native_p);
-```
-
## jerry_object_native_free_callback_t
**Summary**
**Summary**
-The type infomation of the native pointer.
+The type information of the native pointer.
It includes the free callback that will be called when associated JavaScript object is garbage collected. It can be left NULL in case it is not needed.
Typically, one would create a `static const jerry_object_native_info_t` for
```c
void
-jerry_register_magic_strings (const jerry_char_ptr_t *ex_str_items_p,
+jerry_register_magic_strings (const jerry_char_t * const *ex_str_items_p,
uint32_t count,
const jerry_length_t *str_lengths_p);
```
// must be static, because 'jerry_register_magic_strings' does not copy
// the items must be sorted by size at first, then lexicographically
- static const jerry_char_ptr_t magic_string_items[] = {
- (const jerry_char_ptr_t) "magicstring1",
- (const jerry_char_ptr_t) "magicstring2",
- (const jerry_char_ptr_t) "magicstring3"
- };
- uint32_t num_magic_string_items = (uint32_t) (sizeof (magic_string_items) / sizeof (jerry_char_ptr_t));
+ static const jerry_char_t * const magic_string_items[] = {
+ (const jerry_char_t *) "magicstring1",
+ (const jerry_char_t *) "magicstring2",
+ (const jerry_char_t *) "magicstring3"
+ };
+ uint32_t num_magic_string_items = (uint32_t) (sizeof (magic_string_items) / sizeof (jerry_char_t *));
// must be static, because 'jerry_register_magic_strings' does not copy
static const jerry_length_t magic_string_lengths[] = {
- [jerry_init](#jerry_init)
- [jerry_cleanup](#jerry_cleanup)
-- [jerry_parse_and_save_literals](#jerry_parse_and_save_literals)
-
-
-## jerry_get_memory_limits
-
-**Summary**
-
-Gets configured memory limits of JerryScript.
-
-**Prototype**
-
-```c
-void
-jerry_get_memory_limits (size_t *out_data_bss_brk_limit_p,
- size_t *out_stack_limit_p);
-```
-
-- `out_data_bss_brk_limit_p` - out parameter, that gives the maximum size of data + bss + brk sections.
-- `out_stack_limit_p` - out parameter, that gives the maximum size of the stack.
-
-**Example**
-
-[doctest]: # ()
-
-```c
-#include "jerryscript.h"
-
-int
-main (void)
-{
- jerry_init (JERRY_INIT_EMPTY);
-
- size_t stack_limit;
- size_t data_bss_brk_limit;
- jerry_get_memory_limits (&stack_limit, &data_bss_brk_limit);
-}
-```
-
-**See also**
-
-- [jerry_init](#jerry_init)
-- [jerry_cleanup](#jerry_cleanup)
+- [jerry_get_literals_from_snapshot](#jerry_get_literals_from_snapshot)
## jerry_get_memory_stats
```c
void
-jerry_gc (void);
+jerry_gc (jerry_gc_mode_t mode);
```
+- `mode` - operational mode, see [jerry_gc_mode_t](#jerry_gc_mode_t)
+
**Example**
+[doctest]: # ()
+
```c
-jerry_gc ();
+#include "jerryscript.h"
+
+int
+main (void)
+{
+ jerry_init (JERRY_INIT_EMPTY);
+
+ jerry_value_t object_value = jerry_create_object ();
+ jerry_release_value (object_value);
+
+ jerry_gc (JERRY_GC_SEVERITY_LOW);
+
+ jerry_cleanup ();
+}
```
**See also**
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
int
main (void)
{
- const jerry_char_t *script = (const jerry_char_t *) "print ('Hello, World!');";
+ const jerry_char_t script[] = "print ('Hello, World!');";
- jerry_run_simple (script, strlen ((const char *) script), JERRY_INIT_EMPTY);
+ jerry_run_simple (script, sizeof (script) - 1, JERRY_INIT_EMPTY);
}
```
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
int
jerry_init (JERRY_INIT_EMPTY);
const jerry_char_t script[] = "print ('Hello, World!');";
- size_t script_size = strlen ((const char *) script);
- jerry_value_t parsed_code = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS);
+ jerry_value_t parsed_code = jerry_parse (NULL, 0, script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
jerry_release_value (parsed_code);
jerry_cleanup ();
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
int
main (void)
{
const jerry_char_t script[] = "print ('Hello, World!');";
- size_t script_size = strlen ((const char *) script);
/* Initialize engine */
jerry_init (JERRY_INIT_EMPTY);
/* Setup Global scope code */
- jerry_value_t parsed_code = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS);
+ jerry_value_t parsed_code = jerry_parse (NULL, 0, script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
- if (!jerry_value_has_error_flag (parsed_code))
+ if (!jerry_value_is_error (parsed_code))
{
/* Execute the parsed source code in the Global scope */
jerry_value_t ret_value = jerry_run (parsed_code);
jerry_value_t
jerry_eval (const jerry_char_t *source_p,
size_t source_size,
- bool is_strict);
+ uint32_t parse_opts);
```
- `source_p` - source code to evaluate, it must be a valid utf8 string.
- `source_size` - length of the source code
-- `is_strict` - perform `eval` as it is called from "strict mode" code.
+- `parse_opts` - any combination of [jerry_parse_opts_t](#jerry_parse_opts_t) flags.
- return value - result of eval, may be error value.
**Example**
{
jerry_value_t ret_val = jerry_eval (str_to_eval,
strlen (str_to_eval),
- false);
+ JERRY_PARSE_NO_OPTS);
}
```
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
int
jerry_init (JERRY_INIT_EMPTY);
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 (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS);
+ jerry_value_t parsed_code = jerry_parse (NULL, 0, script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
jerry_value_t script_value = jerry_run (parsed_code);
jerry_value_t job_value = jerry_run_all_enqueued_jobs ();
Functions to check the type of an API value ([jerry_value_t](#jerry_value_t)).
+## jerry_value_is_abort
+
+**Summary**
+
+Returns whether the given `jerry_value_t` has the error and abort value set.
+
+**Prototype**
+
+```c
+bool
+jerry_value_is_abort (const jerry_value_t value);
+```
+
+- `value` - api value
+- return value
+ - true, if the given `jerry_value_t` has the error and abort value set
+ - false, otherwise
+
+**Example**
+
+```c
+{
+ jerry_value_t value;
+ ... // create or acquire value
+
+ if (jerry_value_is_abort (value))
+ {
+ ...
+ }
+
+ jerry_release_value (value);
+}
+```
+
+**See also**
+
+- [jerry_value_t](#jerry_value_t)
+- [jerry_value_is_error](#jerry_value_is_error)
+
## jerry_value_is_array
**Summary**
- [jerry_release_value](#jerry_release_value)
+## jerry_value_is_error
+
+**Summary**
+
+Returns whether the given `jerry_value_t` is error value.
+
+**Prototype**
+
+```c
+bool
+jerry_value_is_error (const jerry_value_t value);
+```
+
+- `value` - api value
+- return value
+ - true, if the given `jerry_value_t` is error value.
+ - false, otherwise
+
+**Example**
+
+```c
+{
+ jerry_value_t value;
+ ... // create or acquire value
+
+ if (jerry_value_is_error (value))
+ {
+ ...
+ }
+
+ jerry_release_value (value);
+}
+```
+
+**See also**
+
+- [jerry_value_t](#jerry_value_t)
+- [jerry_value_is_abort](#jerry_value_is_abort)
## jerry_value_is_function
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
+This is a similar operation to the 'typeof' operator
in the standard with an exception that the 'null'
value has its own enum value.
# Error manipulation functions
-## jerry_get_error_type
+## jerry_create_abort_from_value
**Summary**
-Returns the type of the Error object if possible.
+Create (api) abort from a value.
-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.
+This function creates an API abort value from an API value. The second argument defines
+whether the input value must be released or not. If it is set to `true`,
+then a [`jerry_release_value`](#jerry_release_value) function will be called
+for the first argument, so the api value won't be available after the call of
+`jerry_create_abort_from_value`. The second argument should be false if both value
+and created abort value are needed.
**Prototype**
```c
-jerry_error_t
-jerry_get_error_type (const jerry_value_t value);
+jerry_value_t
+jerry_create_abort_from_value (jerry_value_t value, bool release);
```
-- `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
+- `value` - api value
+- `release` - raw boolean, defines whether input value must be released
+- return value - abort (api) value
-**Example**
+**Example 1**
```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);
+ jerry_value_t value;
+ ... // create or acquire value
- // error_type is now JERRY_ERROR_RANGE.
+ jerry_value_t abort = jerry_create_abort_from_value (value, true);
+ // using the 'value' variable after release is invalid.
- jerry_release_value (error_obj);
+ jerry_release_value (abort);
}
```
-**See also**
-
-- [jerry_create_error](#jerry_create_error)
-- [jerry_value_has_error_flag](#jerry_value_has_error_flag)
-
-## jerry_value_has_error_flag
-
-**Summary**
-
-Returns whether the given `jerry_value_t` has the error flag set.
-
-**Prototype**
-
-```c
-bool
-jerry_value_has_error_flag (const jerry_value_t value);
-```
-
-- `value` - api value
-- return value
- - true, if the given `jerry_value_t` has the error flag set
- - false, otherwise
-
-**Example**
+**Example 2**
```c
{
jerry_value_t value;
... // create or acquire value
- if (jerry_value_has_error_flag (value))
- {
- ...
- }
+ jerry_value_t abort = jerry_create_abort_from_value (value, false);
+ // both 'abort' and 'value' can be used and must be released when they are no longer needed
+ jerry_release_value (abort);
jerry_release_value (value);
}
```
**See also**
- [jerry_value_t](#jerry_value_t)
-- [jerry_value_has_abort_flag](#jerry_value_has_abort_flag)
-
+- [jerry_get_value_from_error](#jerry_get_value_from_error)
+- [jerry_create_error_from_value](#jerry_create_error_from_value)
-## jerry_value_has_abort_flag
+## jerry_create_error_from_value
**Summary**
-Returns whether the given `jerry_value_t` has the error and abort flags set.
+Create (api) error from a value.
+
+This function creates an API error value from an API value. The second argument defines
+whether the input value must be released or not. If it is set to `true`,
+then a [`jerry_release_value`](#jerry_release_value) function will be called
+for the first argument, so the api value won't be available after the call of
+`jerry_create_error_from_value`. The second argument should be false if both value
+and created error value are needed.
**Prototype**
```c
-bool
-jerry_value_has_abort_flag (const jerry_value_t value);
+jerry_value_t
+jerry_create_error_from_value (jerry_value_t value, bool release);
```
- `value` - api value
-- return value
- - true, if the given `jerry_value_t` has the error and abort flags set
- - false, otherwise
+- `release` - raw boolean, defines whether input value must be released
+- return value - error (api) value
-**Example**
+**Example 1**
```c
{
jerry_value_t value;
... // create or acquire value
- if (jerry_value_has_abort_flag (value))
- {
- ...
- }
-
- jerry_release_value (value);
-}
-```
-
-**See also**
-
-- [jerry_value_t](#jerry_value_t)
-- [jerry_value_has_error_flag](#jerry_value_has_error_flag)
+ jerry_value_t error = jerry_create_error_from_value (value, true);
+ // using the 'value' variable after release is invalid.
-## jerry_value_clear_error_flag
-
-**Summary**
-
-Clear both the error and abort flags.
-
-**Prototype**
-
-```c
-void
-jerry_value_clear_error_flag (jerry_value_t *value_p);
+ jerry_release_value (error);
+}
```
-- `value_p` - pointer to an api value
-
-**Example**
+**Example 2**
```c
{
jerry_value_t value;
... // create or acquire value
- jerry_value_clear_error_flag (&value);
+ jerry_value_t error = jerry_create_error_from_value (value, false);
+ // both 'error' and 'value' can be used and must be released when they are no longer needed
+ jerry_release_value (error);
jerry_release_value (value);
}
```
**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_from_error](#jerry_get_value_from_error)
+- [jerry_create_abort_from_value](#jerry_create_abort_from_value
-
-## jerry_value_set_error_flag
+## jerry_get_error_type
**Summary**
-Set the error flag.
+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_is_error](#jerry_value_is_error) method.
**Prototype**
```c
-void
-jerry_value_set_error_flag (jerry_value_t *value_p);
+jerry_error_t
+jerry_get_error_type (const jerry_value_t value);
```
-- `value_p` - pointer to an api 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 value;
- ... // create or acquire value
+ 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);
- jerry_value_set_error_flag (&value);
+ // error_type is now JERRY_ERROR_RANGE.
- jerry_release_value (value);
+ jerry_release_value (error_obj);
}
```
**See also**
-- [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)
-
+- [jerry_create_error](#jerry_create_error)
+- [jerry_value_is_error](#jerry_value_is_error)
-## jerry_value_set_abort_flag
+## jerry_get_value_from_error
**Summary**
-Set both the error and abort flags.
+Get the value from an error.
+
+Many API functions cannot be called with an error value.
+This function extracts the API value from an error. The second argument defines
+whether the input error value must be released or not. If it is set to `true`,
+then a [`jerry_release_value`](#jerry_release_value) function will be called
+for the first argument, so the error value won't be available after the call of
+`jerry_get_value_from_error`. The second argument should be false if both error
+and its represented value are needed.
+
+*Note*: Returned value must be freed with [jerry_release_value](#jerry_release_value) when it
+is no longer needed.
**Prototype**
```c
-void
-jerry_value_set_abort_flag (jerry_value_t *value_p);
+jerry_value_t
+jerry_get_value_from_error (jerry_value_t value, bool release)
```
-- `value_p` - pointer to an api value
+- `value` - error (api) value
+- `release` - raw boolean, defines whether input value must be released
+- return value - api value
-**Example**
+**Example 1**
```c
{
jerry_value_t value;
... // create or acquire value
- jerry_value_set_abort_flag (&value);
+ jerry_value_t error = jerry_create_error_from_value (value, true);
+ jerry_value_t value_from_error = jerry_get_value_from_error (error, true);
+ // using the 'error' variable after release is invalid.
- jerry_release_value (value);
+ jerry_release_value (value_from_error);
}
```
-**See also**
-
-- [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_value_without_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.
-
-**Prototype**
-
-```c
-jerry_value_t
-jerry_get_value_without_error_flag (jerry_value_t value)
-```
-
-- `value` - api value
-
-**Example**
+**Example 2**
```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_value_t error = jerry_create_error_from_value (value, true);
+ jerry_value_t value_from_error = jerry_get_value_from_error (error, false);
+ // both 'error' and 'value_from_error' can be used and must be released when they are no longer needed
- jerry_release_value (value);
- jerry_release_value (real_value);
+ jerry_release_value (value_from_error);
+ jerry_release_value (error);
}
```
**See also**
-- [jerry_acquire_value](#jerry_acquire_value)
-- [jerry_value_clear_error_flag](#jerry_value_clear_error_flag)
+- [jerry_value_t](#jerry_value_t)
+- [jerry_create_error_from_value](#jerry_create_error_from_value)
+- [jerry_create_abort_from_value](#jerry_create_abort_from_value)
# Getter functions of 'jerry_value_t'
argument,
is_resolve);
- if (jerry_value_has_error_flag (is_ok))
+ if (jerry_value_is_error (is_ok))
{
// handle the error.
}
**See also**
- [jerry_release_value](#jerry_release_value)
-- [jerry_value_has_error_flag](#jerry_value_has_error_flag)
+- [jerry_value_is_error](#jerry_value_is_error)
# Acquire and release API values
**See also**
-- [jerry_value_has_error_flag](#jerry_value_has_error_flag)
-- [jerry_value_clear_error_flag](#jerry_value_clear_error_flag)
-- [jerry_value_set_error_flag](#jerry_value_set_error_flag)
+- [jerry_value_is_error](#jerry_value_is_error)
+- [jerry_get_value_from_error](#jerry_get_value_from_error)
+- [jerry_create_error_from_value](#jerry_create_error_from_value)
## jerry_create_error_sz
```c
{
- const jerry_char_t *message = "error";
+ const jerry_char_t message[] = "error";
jerry_value_t error_obj = jerry_create_error_sz (JERRY_ERROR_COMMON,
message,
- strlen ((const char *) message));
+ sizeof (message) - 1);
... // usage of error_obj
{
const jerry_char_t char_array[] = "a string";
jerry_value_t string_value = jerry_create_string_sz (char_array,
- strlen ((const char *) char_array));
+ sizeof (char_array) - 1);
... // usage of string_value
{
const jerry_char_t char_array[] = "a string";
jerry_value_t string_value = jerry_create_string_sz_from_utf8 (char_array,
- strlen ((const char *) char_array));
+ sizeof (char_array) - 1);
... // usage of string_value
- [jerry_create_string_from_utf8](#jerry_create_string_from_utf8)
+## jerry_create_regexp
+
+**Summary**
+
+Returns a jerry_value_t RegExp object or an error, if the construction of the object fails.
+Optional flags can be set using [jerry_regexp_flags_t](#jerry_regexp_flags_t);
+
+**Prototype**
+```c
+jerry_value_t
+jerry_create_regexp (const jerry_char_t *pattern_p, jerry_regexp_flags_t flags);
+```
+
+- `pattern_p` - the RegExp pattern as a zero-terminated UTF-8 string
+- `flags` - optional flags for the RegExp object
+- return value - the RegExp object as a `jerry_value_t`
+
+**Example**
+
+```c
+{
+ jerry_char_t pattern_p = "[cgt]gggtaaa|tttaccc[acg]";
+ jerry_regexp_flags_t pattern_flags = JERRY_REGEXP_FLAG_IGNORE_CASE;
+
+ jerry_value_t regexp = jerry_create_regexp (pattern_p, pattern_flags);
+
+ ...
+
+ jerry_release_value (regexp);
+}
+```
+
+
+## jerry_create_regexp_sz
+
+**Summary**
+
+Returns a jerry_value_t RegExp object or an error, if the construction of the object fails.
+Optional flags can be set using [jerry_regexp_flags_t](#jerry_regexp_flags_t);
+
+**Prototype**
+```c
+jerry_value_t
+jerry_create_regexp_sz (const jerry_char_t *pattern_p, jerry_size_t pattern_size, jerry_regexp_flags_t flags);
+```
+
+- `pattern_p` - the RegExp pattern as a zero-terminated UTF-8 string
+- `pattern_size` - size of the `pattern`
+- `flags` - optional flags for the RegExp object
+- return value - the RegExp object as a `jerry_value_t`
+
+**Example**
+
+```c
+{
+ jerry_char_t pattern_p = "[cgt]gggtaaa|tttaccc[acg]";
+ jerry_size_t pattern_size = sizeof (pattern_p) - 1;
+ jerry_regexp_flags_t pattern_flags = JERRY_REGEXP_FLAG_IGNORE_CASE;
+
+ jerry_value_t regexp = jerry_create_regexp_sz (pattern_p, pattern_size, pattern_flags);
+
+ ...
+
+ jerry_release_value (regexp);
+}
+```
+
+
## jerry_create_typedarray
**Summary**
jerry_value_t global_object = jerry_get_global_object ();
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "my_prop");
- jerry_value_t prop_value = jerry_get_property (obj_val, prop_name);
+ jerry_value_t prop_value = jerry_get_property (global_object, prop_name);
jerry_release_value (prop_name);
jerry_release_value (global_object);
jerry_value_t this_val = jerry_create_undefined ();
jerry_value_t ret_val = jerry_call_function (val, this_val, NULL, 0);
- if (!jerry_value_has_error_flag (ret_val))
+ if (!jerry_value_is_error (ret_val))
{
... // handle return value
}
{
jerry_value_t ret_val = jerry_construct_object (val, NULL, 0);
- if (!jerry_value_has_error_flag (ret_val))
+ if (!jerry_value_is_error (ret_val))
{
... // handle return value
}
- [jerry_get_prototype](#jerry_get_prototype)
-## jerry_get_object_native_handle
-
-**Summary**
-
-**Deprecated: Please use jerry_get_object_native_pointer instead.**
-
-Get native handle, previously associated with specified object.
-
-**Prototype**
-
-```c
-bool
-jerry_get_object_native_handle (const jerry_value_t obj_val,
- uintptr_t *out_handle_p);
-```
-
-- `obj_val` - object value
-- `out_handle_p` - handle value (output parameter).
-- return value
- - true, if there is handle associated with the object
- - false, otherwise
-
-**Example**
-
-```c
-{
- jerry_value_t object;
- uintptr_t handle_set;
-
- ... // receive or construct object and handle_set value
-
- jerry_set_object_native_handle (object, handle_set, NULL);
-
- ...
-
- uintptr_t handle_get;
- bool is_there_associated_handle = jerry_get_object_native_handle (object, &handle_get);
-}
-```
-
-**See also**
-
-- [jerry_create_object](#jerry_create_object)
-- [jerry_set_object_native_handle](#jerry_set_object_native_handle)
-- [jerry_get_object_native_pointer](#jerry_get_object_native_pointer)
-
-
-## jerry_set_object_native_handle
-
-**Summary**
-
-**Deprecated: Please use jerry_set_object_native_pointer instead.**
-
-Set native handle and an optional free callback for the specified object.
-
-*Note*: If native handle was already set for the object, its value is updated.
-
-*Note*: If a non-NULL free callback is specified, it will be called
- by the garbage collector when the object is freed. The free
- callback always overwrites the previous value, so passing
- a NULL value deletes the current free callback.
-
-**Prototype**
-
-```c
-void
-jerry_set_object_native_handle (const jerry_value_t obj_val,
- uintptr_t handle_p,
- jerry_object_free_callback_t freecb_p);
-```
-
-- `obj_val` - object value to set handle in
-- `handle_p` - handle value
-- `freecb_p` - pointer to "free" callback or NULL
-
-**Example**
-
-```c
-{
- jerry_value_t object;
- uintptr_t handle_set;
-
- ... // receive or construct object and handle_set value
-
- jerry_set_object_native_handle (object, handle_set, NULL);
-
- ...
-
- uintptr_t handle_get;
- bool is_there_associated_handle = jerry_get_object_native_handle (object, &handle_get);
-}
-```
-
-**See also**
-
-- [jerry_create_object](#jerry_create_object)
-- [jerry_get_object_native_handle](#jerry_get_object_native_handle)
-- [jerry_set_object_native_pointer](#jerry_set_object_native_pointer)
-
-
## jerry_get_object_native_pointer
**Summary**
and dereferencing `out_native_pointer_p`.
*Note*: `out_native_pointer_p` and `out_native_info_p` can be NULL, and it means the
- caller doesn't want to get the native_pointer or type infomation.
+ caller doesn't want to get the native_pointer or type information.
**Prototype**
- `obj_val` - object value to get native pointer from.
- `out_native_pointer_p` - native pointer (output parameter).
-- `out_native_info_p` - native pointer's type infomation (output parameter).
+- `out_native_info_p` - native pointer's type information (output parameter).
- return value
- true, if there is native pointer associated with the object
- false, otherwise
- `obj_val` - object to set native pointer in.
- `native_p` - native pointer.
-- `info_p` - native pointer's type infomation or NULL. When used, this should
+- `info_p` - native pointer's type information or NULL. When used, this should
be a long-lived pointer, usually a pointer to a
`static const jerry_object_native_info_t` makes most sense.
{
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 ());
+ bool keep_searching = (jerry_value_is_error (has_property) || !jerry_get_boolean_value ());
if (!keep_searching)
{
/* We found it, so we acquire the value and record it. */
void *user_data_p);
```
-- `native_info_p` - native pointer's type infomation.
+- `native_info_p` - native pointer's type information.
- return value
- `true`, if the search function terminated the traversal by returning `false`
- `false`, if the end of the list of objects was reached
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
int
main (void)
{
const jerry_char_t script[] = "print ('Hello, World!');";
- size_t script_size = strlen ((const char *) script);
+ const jerry_size_t script_size = sizeof (script) - 1;
- if (jerry_is_valid_utf8_string (script, (jerry_size_t) script_size))
+ if (jerry_is_valid_utf8_string (script, script_size))
{
jerry_run_simple (script, script_size, JERRY_INIT_EMPTY);
}
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
int
jerry_init (JERRY_INIT_EMPTY);
const jerry_char_t script[] = "Hello, World!";
- size_t script_size = strlen ((const char *) script);
+ const jerry_size_t script_size = sizeof (script) - 1;
- if (jerry_is_valid_cesu8_string (script, (jerry_size_t) script_size))
+ if (jerry_is_valid_cesu8_string (script, script_size))
{
jerry_value_t string_value = jerry_create_string_sz (script,
- (jerry_size_t) script_size);
+ script_size);
// usage of string_value
- [jerry_substring_to_char_buffer](#jerry_substring_to_char_buffer)
+# Dynamic memory management functions
+
+## jerry_heap_alloc
+
+**Summary**
+
+Allocate memory on the engine's heap.
+
+*Note*: This function may take away memory from the executed JavaScript code.
+If any other dynamic memory allocation API is available (e.g., libc malloc), it
+should be used instead.
+
+**Prototype**
+
+```c
+void *jerry_heap_alloc (size_t size);
+```
+
+- `size`: size of the memory block.
+- return value: non-NULL pointer, if the memory is successfully allocated,
+ NULL otherwise.
+
+**See also**
+
+- [jerry_heap_free](#jerry_heap_free)
+
+## jerry_heap_free
+
+**Summary**
+
+Free memory allocated on the engine's heap.
+
+**Prototype**
+
+```c
+void jerry_heap_free (void *mem_p, size_t size);
+```
+
+- `mem_p`: value returned by `jerry_heap_alloc`.
+- `size`: same size as passed to `jerry_heap_alloc`.
+
+**See also**
+
+- [jerry_heap_alloc](#jerry_heap_alloc)
+
+
+# External context functions
+
+## jerry_create_context
+
+**Summary**
+
+Create an external JerryScript engine context.
+
+**Prototype**
+
+```c
+jerry_context_t *
+jerry_create_context (uint32_t heap_size,
+ jerry_context_alloc_t alloc,
+ void *cb_data_p);
+```
+
+- `heap_size` - requested heap size of the JerryScript context
+- `alloc` - function for allocation
+- `cb_data_p` - user data
+- return value
+ - pointer to the newly created JerryScript context if success
+ - NULL otherwise.
+
+**Example**
+
+[doctest]: # (test="compile")
+
+```c
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "jerryscript.h"
+#include "jerryscript-port.h"
+
+/* A different Thread Local Storage variable for each jerry context. */
+__thread jerry_context_t *tls_context;
+
+jerry_context_t *
+jerry_port_get_current_context (void)
+{
+ /* Returns the context assigned to the thread. */
+ return tls_context;
+}
+
+/* Allocate JerryScript heap for each thread. */
+static void *
+context_alloc_fn (size_t size, void *cb_data)
+{
+ (void) cb_data;
+ return malloc (size);
+}
+
+static void *
+thread_function (void *param)
+{
+ tls_context = jerry_create_context (512 * 1024,
+ context_alloc_fn,
+ NULL);
+ jerry_init (JERRY_INIT_EMPTY);
+ /* Run JerryScript in the context (e.g.: jerry_parse & jerry_run) */
+ jerry_cleanup ();
+
+ /* Deallocate JerryScript context */
+ free (tls_context);
+
+ return NULL;
+}
+
+#define NUM_OF_THREADS 8
+
+int
+main (void)
+{
+ pthread_t threads[NUM_OF_THREADS];
+
+ /* Create the threads. */
+ for (int i = 0; i < NUM_OF_THREADS; i++)
+ {
+ pthread_create (&threads[i], NULL, thread_function, (void *) (intptr_t) i);
+ }
+
+ /* Wait for the threads to complete, and release their resources. */
+ for (int i = 0; i < NUM_OF_THREADS; i++)
+ {
+ pthread_join (threads[i], NULL);
+ }
+
+ return 0;
+}
+```
+
+**See also**
+
+- [jerry_context_t](#jerry_context_t)
+- [jerry_context_alloc_t](#jerry_context_alloc_t)
+- [jerry_port_get_current_context](05.PORT-API.md#jerry_port_get_current_context)
+
+
# Snapshot functions
## jerry_generate_snapshot
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
int
jerry_init (JERRY_INIT_EMPTY);
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'; }) ();";
+ const jerry_char_t script_to_snapshot[] = "(function () { return 'string from snapshot'; }) ();";
jerry_value_t generate_result;
generate_result = jerry_generate_snapshot (NULL,
0,
- code_to_snapshot_p,
- strlen ((const char *) code_to_snapshot_p),
+ script_to_snapshot,
+ sizeof (script_to_snapshot) - 1,
0,
global_mode_snapshot_buffer,
sizeof (global_mode_snapshot_buffer) / sizeof (uint32_t));
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
int
jerry_init (JERRY_INIT_EMPTY);
static uint32_t func_snapshot_buffer[256];
- 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;";
+ const jerry_char_t args[] = "a, b";
+ const jerry_char_t src[] = "return a + b;";
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),
+ src,
+ sizeof (src) - 1,
+ args,
+ sizeof (args) - 1,
0,
func_snapshot_buffer,
sizeof (func_snapshot_buffer) / sizeof (uint32_t));
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
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'; }) ();";
+ const jerry_char_t script_to_snapshot[] = "(function () { return 'string from snapshot'; }) ();";
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t generate_result;
generate_result = jerry_generate_snapshot (NULL,
0,
- code_to_snapshot_p,
- strlen ((const char *) code_to_snapshot_p),
+ script_to_snapshot,
+ sizeof (script_to_snapshot) - 1,
0,
global_mode_snapshot_buffer,
sizeof (global_mode_snapshot_buffer) / sizeof (uint32_t));
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
int
main (void)
{
static uint32_t snapshot_buffer[256];
- 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;";
+ const jerry_char_t func_args[] = "a, b";
+ const jerry_char_t func_src[] = "return a + b;";
jerry_init (JERRY_INIT_EMPTY);
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),
+ func_src,
+ sizeof (func_src) - 1,
+ func_args,
+ sizeof (func_args) - 1,
false,
snapshot_buffer,
sizeof (snapshot_buffer) / sizeof (uint32_t));
- [jerry_parse_and_save_function_snapshot](#jerry_parse_and_save_function_snapshot)
-## jerry_parse_and_save_literals
+## jerry_get_literals_from_snapshot
**Summary**
-Collect the used literals from the given source code and save them into a specific file in a list or C format.
-These literals are generated by the parser, they are valid identifiers and none of them are magic string.
+Collect the used literals from the given snapshot and save them into a buffer in list or C format.
+None of these literals are magic strings. In C format only valid identifiers are collected.
**Prototype**
```c
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);
+jerry_get_literals_from_snapshot (const uint32_t *snapshot_p,
+ size_t snapshot_size,
+ jerry_char_t *lit_buf_p,
+ size_t lit_buf_size,
+ bool is_c_format);
```
-- `source_p` - script source, it must be a valid utf8 string.
-- `source_size` - script source size, in bytes.
-- `is_strict` - strict mode.
-- `buffer_p` - buffer to save literals to.
-- `buffer_size` - the buffer's size.
+- `snapshot_p` - input snapshot buffer.
+- `snapshot_size` - snapshot size, in bytes.
+- `lit_buf_p` - buffer to save literals to.
+- `lit_buf_size` - the buffer's size.
- `is_c_format` - the output format would be C-style (true) or a simple list (false).
- return value
- the size of the literal-list, if it was generated succesfully (i.e. the list of literals isn't empty,
```c
#include <stdio.h>
-#include <string.h>
#include "jerryscript.h"
int
{
jerry_init (JERRY_INIT_EMPTY);
- static uint32_t save_literal_buffer[256];
- const jerry_char_t *code_for_literal_save_p = (const jerry_char_t *) "var obj = { a:'aa', bb:'Bb' }";
+ static jerry_char_t literal_buffer[256];
+ static uint32_t snapshot_buffer[256];
+ const jerry_char_t script_for_literal_save[] = "var obj = { a:'aa', bb:'Bb' }";
+
+ jerry_value_t generate_result = jerry_generate_snapshot (NULL,
+ 0,
+ script_for_literal_save,
+ sizeof (script_for_literal_save) - 1,
+ 0,
+ snapshot_buffer,
+ 256);
+ size_t snapshot_size = (size_t) jerry_get_number_value (generate_result);
+ jerry_release_value (generate_result);
- size_t literal_sizes = jerry_parse_and_save_literals (code_for_literal_save_p,
- strlen ((const char *) code_for_literal_save_p),
- false,
- save_literal_buffer,
- sizeof (save_literal_buffer) / sizeof (uint32_t),
- true);
+ const size_t literal_size = jerry_get_literals_from_snapshot (snapshot_buffer,
+ snapshot_size,
+ literal_buffer,
+ 256,
+ true);
- if (literal_sizes != 0)
+ if (literal_size != 0)
{
- FILE *literal_file_p = fopen ("literals.txt", "w");
- fwrite (save_literal_buffer, sizeof (uint8_t), literal_sizes, literal_file_p);
+ FILE *literal_file_p = fopen ("literals.h", "wb");
+ fwrite (literal_buffer, sizeof (uint8_t), literal_size, literal_file_p);
fclose (literal_file_p);
}
[doctest]: # (test="link")
```c
-#include <string.h>
#include "jerryscript.h"
static int countdown = 10;
jerry_set_vm_exec_stop_callback (vm_exec_stop_callback, &countdown, 16);
// Inifinte loop.
- const char *src_p = "while(true) {}";
+ const jerry_char_t script[] = "while(true) {}";
- 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_value_t parsed_code = jerry_parse (NULL, 0, script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
+ jerry_release_value (jerry_run (parsed_code));
+ jerry_release_value (parsed_code);
jerry_cleanup ();
}
```
```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);
+ const jerry_char_t data[] = "{\"name\": \"John\", \"age\": 5}";
+ jerry_value_t parsed_json = jerry_json_parse (data, sizeof (data) - 1);
// parsed_json now conatins all data stored in data_in_json
}
```
-## jerry_stringify
+## jerry_json_stringify
**Summary**
**Prototype**
```c
-jerry_value_t jerry_json_stringfy (const jerry_value_t object_to_stringify)
+jerry_value_t jerry_json_stringify (const jerry_value_t object_to_stringify)
```
- `object_to_stringify` - a jerry_value_t object to stringify
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);
+ jerry_value_t stringified = jerry_json_stringify (obj);
//stringified now contains a json formated string
jerry_release_value (value);
jerry_release_value (stringified);
}
-```
\ No newline at end of file
+```
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
int
main (void)
{
const jerry_char_t script[] = "var str = 'Hello, World!';";
- size_t script_size = strlen ((const char *) script);
- bool ret_value = jerry_run_simple (script, script_size, JERRY_INIT_EMPTY);
+ bool ret_value = jerry_run_simple (script, sizeof (script) - 1, JERRY_INIT_EMPTY);
return (ret_value ? 0 : 1);
}
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
#include "jerryscript-ext/handler.h"
main (void)
{
const jerry_char_t script[] = "print ('Hello, World!');";
- size_t script_size = strlen ((const char *) script);
/* Initialize engine */
jerry_init (JERRY_INIT_EMPTY);
jerryx_handler_print);
/* Setup Global scope code */
- jerry_value_t parsed_code = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS);
+ jerry_value_t parsed_code = jerry_parse (NULL, 0, script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
- if (!jerry_value_has_error_flag (parsed_code))
+ if (!jerry_value_is_error (parsed_code))
{
/* Execute the parsed source code in the Global scope */
jerry_value_t ret_value = jerry_run (parsed_code);
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
#include "jerryscript-ext/handler.h"
/* Evaluate script1 */
eval_ret = jerry_eval (script_1,
- strlen ((const char *) script_1),
- false);
+ sizeof (script_1) - 1,
+ JERRY_PARSE_NO_OPTS);
/* Free JavaScript value, returned by eval */
jerry_release_value (eval_ret);
/* Evaluate script2 */
eval_ret = jerry_eval (script_2,
- strlen ((const char *) script_2),
- false);
+ sizeof (script_2) - 1,
+ JERRY_PARSE_NO_OPTS);
/* Free JavaScript value, returned by eval */
jerry_release_value (eval_ret);
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
#include "jerryscript-ext/handler.h"
/* Now starting script that would output value of just initialized field */
jerry_value_t eval_ret = jerry_eval (script,
- strlen ((const char *) script),
- false);
+ sizeof (script) - 1,
+ JERRY_PARSE_NO_OPTS);
/* Free JavaScript value, returned by eval */
jerry_release_value (eval_ret);
```c
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include "jerryscript.h"
static void
}
/* If the command is "quit", break the loop */
- if (!strncmp (cmd, "quit\n", strlen ("quit\n")))
+ if (!strncmp (cmd, "quit\n", sizeof ("quit\n") - 1))
{
break;
}
/* Evaluate entered command */
ret_val = jerry_eval ((const jerry_char_t *) cmd,
len,
- false);
+ JERRY_PARSE_NO_OPTS);
/* If command evaluated successfully, print value, returned by eval */
- if (jerry_value_has_error_flag (ret_val))
+ if (jerry_value_is_error (ret_val))
{
/* Evaluated JS code thrown an exception
* and didn't handle it with try-catch-finally */
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
#include "jerryscript-ext/handler.h"
var str = MyObject.myFunc (); \
print (str); \
";
- size_t script_size = strlen ((const char *) script);
/* Evaluate script */
- jerry_value_t eval_ret = jerry_eval (script, script_size, false);
+ jerry_value_t eval_ret = jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
/* Free JavaScript value, returned by eval */
jerry_release_value (eval_ret);
[doctest]: # ()
```c
-#include <string.h>
#include "jerryscript.h"
#include "jerryscript-ext/handler.h"
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "x");
jerry_value_t x_val = jerry_get_property (this_val, prop_name);
- if (!jerry_value_has_error_flag (x_val))
+ if (!jerry_value_is_error (x_val))
{
/* Convert Jerry API values to double */
double x = jerry_get_number_value (x_val);
/* Evaluate script */
my_js_obj_val = jerry_eval (my_js_object,
- strlen ((const char *) my_js_object),
- false);
+ sizeof (my_js_object) - 1,
+ JERRY_PARSE_NO_OPTS);
/* Create a JS function object and wrap into a jerry value */
jerry_value_t add_func_obj = jerry_create_external_function (add_handler);
MyObject.add2x (5); \
print (MyObject.foo ()); \
";
- size_t script_size = strlen ((const char *) script);
/* Evaluate script */
- jerry_value_t eval_ret = jerry_eval (script, script_size, false);
+ jerry_value_t eval_ret = jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
/* Free JavaScript value, returned by eval */
jerry_release_value (eval_ret);
[doctest]: # ()
```c
-#include <string.h>
#include <stdlib.h>
#include "jerryscript.h"
#include "jerryscript-port.h"
/* Generate a random number, and print it */
const jerry_char_t script[] = "var a = Math.random (); print(a)";
- size_t script_size = strlen ((const char *) script);
/* Initialize the engine */
jerry_init (JERRY_INIT_EMPTY);
jerryx_handler_print);
/* Evaluate the script */
- jerry_value_t eval_ret = jerry_eval (script, script_size, false);
+ jerry_value_t eval_ret = jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
/* Free the JavaScript value returned by eval */
jerry_release_value (eval_ret);
*
* @param code gives the cause of the error.
*
- * Note: jerry expects the function not to return.
+ * Note:
+ * Jerry expects the function not to return.
*
* Example: a libc-based port may implement this with exit() or abort(), or both.
*/
*
* Example: a libc-based port may implement this with vfprintf(stderr) or
* vfprintf(logfile), or both, depending on log level.
+ *
+ * Note:
+ * This port function is called by jerry-core when JERRY_ENABLE_LOGGING is
+ * defined. It is also common practice though to use this function in
+ * application code.
*/
void jerry_port_log (jerry_log_level_t level, const char *fmt, ...);
```
```c
/**
- * Jerry time zone structure
- */
-typedef struct
-{
- int offset; /**< minutes from west */
- int daylight_saving_time; /**< daylight saving time (1 - DST applies, 0 - not on DST) */
-} jerry_time_zone_t;
-
-/**
- * Get timezone and daylight saving data
+ * Get local time zone adjustment, in milliseconds, for the given timestamp.
+ * The timestamp can be specified in either UTC or local time, depending on
+ * the value of is_utc. Adding the value returned from this function to
+ * a timestamp in UTC time should result in local time for the current time
+ * zone, and subtracting it from a timestamp in local time should result in
+ * UTC time.
*
- * @return true - if success
- * false - otherwise
+ * Ideally, this function should satisfy the stipulations applied to LocalTZA
+ * in section 20.3.1.7 of the ECMAScript version 9.0 spec.
+ *
+ * See Also:
+ * ECMA-262 v9, 20.3.1.7
+ *
+ * Note:
+ * This port function is called by jerry-core when
+ * CONFIG_DISABLE_DATE_BUILTIN is _not_ defined. Otherwise this function is
+ * not used.
+ *
+ * @param unix_ms The unix timestamp we want an offset for, given in
+ * millisecond precision (could be now, in the future,
+ * or in the past). As with all unix timestamps, 0 refers to
+ * 1970-01-01, a day is exactly 86 400 000 milliseconds, and
+ * leap seconds cause the same second to occur twice.
+ * @param is_utc Is the given timestamp in UTC time? If false, it is in local
+ * time.
+ *
+ * @return milliseconds between local time and UTC for the given timestamp,
+ * if available
+ *. 0 if not available / we are in UTC.
*/
-bool jerry_port_get_time_zone (jerry_time_zone_t *);
+double jerry_port_get_local_time_zone_adjustment (double unix_ms, bool is_utc);
/**
* Get system time
*
+ * Note:
+ * This port function is called by jerry-core when
+ * CONFIG_DISABLE_DATE_BUILTIN is _not_ defined. It is also common practice
+ * in application code to use this function for the initialization of the
+ * random number generator.
+ *
* @return milliseconds since Unix epoch
*/
double jerry_port_get_current_time (void);
```
-## External instance
+## External context
-Allow user to provide external buffer for jerry instance (which includes an isolated context and heap with other instances), so that user can config the heap size in runtime and run multiple JS apps simultaneously.
+Allow user to provide external buffer for isolated engine contexts, so that user
+can configure the heap size at runtime and run multiple JS applications
+simultaneously.
```c
/**
- * Get the current instance, which contains the current context, heap and other infomation.
- * Each port should provide its own implementation of this interface.
+ * Get the current context of the engine. Each port should provide its own
+ * implementation of this interface.
*
- *Note:
- * This port function will be called automatically by jerry-core
- * when JERRY_ENABLE_EXTERNAL_CONTEXT is defined. If not, this function will never be called.
+ * Note:
+ * This port function is called by jerry-core when
+ * JERRY_ENABLE_EXTERNAL_CONTEXT is defined. Otherwise this function is not
+ * used.
*
- * @return the pointer to the jerry instance.
+ * @return the pointer to the engine context.
*/
-struct jerry_instance_t *jerry_port_get_current_instance (void);
+struct jerry_context_t *jerry_port_get_current_context (void);
```
## Sleep
```c
/**
* Makes the process sleep for a given time.
+ *
+ * Note:
+ * This port function is called by jerry-core when JERRY_DEBUGGER is
+ * defined. Otherwise this function is not used.
+ *
+ * @param sleep_time milliseconds to sleep.
*/
void jerry_port_sleep (uint32_t sleep_time);
```
## Date
```c
+#include <time.h>
#include <sys/time.h>
#include "jerryscript-port.h"
/**
- * Default implementation of jerry_port_get_time_zone.
+ * Default implementation of jerry_port_get_local_time_zone_adjustment.
*/
-bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
+double jerry_port_get_local_time_zone_adjustment (double unix_ms, /**< ms since unix epoch */
+ bool is_utc) /**< is the time above in UTC? */
{
- struct timeval tv;
- struct timezone tz;
-
- /* gettimeofday may not fill tz, so zero-initializing */
- tz.tz_minuteswest = 0;
- tz.tz_dsttime = 0;
-
- if (gettimeofday (&tv, &tz) != 0)
+ struct tm tm;
+ time_t now = (time_t) (unix_ms / 1000);
+ localtime_r (&now, &tm);
+ if (!is_utc)
{
- return false;
+ now -= tm.tm_gmtoff;
+ localtime_r (&now, &tm);
}
-
- tz_p->offset = tz.tz_minuteswest;
- tz_p->daylight_saving_time = tz.tz_dsttime > 0 ? 1 : 0;
-
- return true;
-} /* jerry_port_get_time_zone */
+ return ((double) tm.tm_gmtoff) * 1000;
+} /* jerry_port_get_local_time_zone_adjustment */
/**
* Default implementation of jerry_port_get_current_time.
return ((double) tv.tv_sec) * 1000.0 + ((double) tv.tv_usec) / 1000.0;
} /* jerry_port_get_current_time */
```
-## External instance
+
+## External context
```c
#include "jerryscript-port.h"
#include "jerryscript-port-default.h"
/**
- * Pointer to the current instance.
+ * Pointer to the current context.
* Note that it is a global variable, and is not a thread safe implementation.
*/
-static jerry_instance_t *current_instance_p = NULL;
+static jerry_context_t *current_context_p = NULL;
/**
- * Set the current_instance_p as the passed pointer.
+ * Set the current_context_p as the passed pointer.
*/
void
-jerry_port_default_set_instance (jerry_instance_t *instance_p) /**< points to the created instance */
+jerry_port_default_set_current_context (jerry_context_t *context_p) /**< points to the created context */
{
- current_instance_p = instance_p;
-} /* jerry_port_default_set_instance */
+ current_context_p = context_p;
+} /* jerry_port_default_set_current_context */
/**
- * Get the current instance.
+ * Get the current context.
*
- * @return the pointer to the current instance
+ * @return the pointer to the current context
*/
-jerry_instance_t *
-jerry_port_get_current_instance (void)
+jerry_context_t *
+jerry_port_get_current_context (void)
{
- return current_instance_p;
-} /* jerry_port_get_current_instance */
+ return current_context_p;
+} /* jerry_port_get_current_context */
```
## Sleep
#ifdef HAVE_TIME_H
nanosleep (&(const struct timespec)
{
- sleep_time / 1000, (sleep_time % 1000) * 1000000L /* Seconds, nanoseconds */
+ (time_t) sleep_time / 1000, ((long int) sleep_time % 1000) * 1000000L /* Seconds, nanoseconds */
}
, NULL);
#elif defined (HAVE_UNISTD_H)
* prop_value contains a live reference to an error object.
* This reference must be released as well. */
- if (jerry_value_has_error_flag (prop_value))
+ if (jerry_value_is_error (prop_value))
{
/* Errors can be handled here. */
}
/* The reference stored in the 'result' variable is live whether
* the operation is successful or not, and must also be freed. */
- if (jerry_value_has_error_flag (result))
+ if (jerry_value_is_error (result))
{
/* Errors can be handled here. */
}
JerryScript provides a remote debugger which allows debugging
JavaScript programs. The debugger has two main components:
a server which is part of the JerryScript binary and a
-separate client application. Currently two debugger clients
-are available in the /jerry-debugger subdirectory: an HTML
-and a Python application. These simple applications demonstrate
-the communication protocol between the client and server and can
-be reused by integrated development environments.
+separate client application. Currently a Python-based debugger
+client is available in the /jerry-debugger subdirectory.
+This simple application demonstrates the communication protocol
+between the client and server, and can be reused by integrated
+development environments.
## Setting up the debugger server
The following arguments must be passed to `tools/build.py`:
-`--jerry-debugger=on --jerry-libc=off`
+`--jerry-debugger=on`
-At the moment only a Websocket-based implementation is provided
-by JerryScript which transmits messages over TCP/IP networks.
-This implementation requires a socket API which is not yet
-supported by jerry-libc so the standard libc is used instead.
-In the future any reliable stream or datagram based protocol
-can be used for transmitting debugger messages.
+The transport layer of the communication protocol is pluggable.
+At the moment, a WebSocket-based implementation is provided as a
+JerryScript extension, which transmits messages over TCP/IP networks.
+If necessary/implemented, any reliable stream or datagram based
+protocol can be used for transmitting debugger messages.
## Debugging JavaScript applications
`--log-level 2`
-The HTML client can connect to the IP address of the server with
-the `connect` command. The IP address can be localhost
+The Python client can connect to the server by specifying its
+IP address on the command line. The address can be localhost
if the server and the client are running on the same machine.
After the connection is established the execution can be
## Integrating debugger support into applications using JerryScript
-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 using the extension-provided WebSocket transport layer, the
+debugger can be enabled by calling `jerryx_debugger_after_connect
+(jerryx_debugger_tcp_create (debug_port) && jerryx_debugger_ws_create ())`
+after the `jerry_init ()` function. It initializes the debugger and
+blocks until a client connects. (Custom transport layers may be
+implemented and initialized similarly.)
The resource name provided to `jerry_parse ()` is used by the client
to identify the resource name of the source code. This resource name
## JerryScript debugger C-API interface
The following section describes the debugger functions
-available for the host application.
+available to the host application.
## JerryScript debugger types
## JerryScript debugger functions
-### jerry_debugger_init
-
-**Summary**
-
-Debugger server initialization. Must be called after `jerry_init`.
-
-**Prototype**
-
-```c
-void
-jerry_debugger_init (uint16_t port);
-```
-
-- `port` - Server port number
-
-
-**Example**
-
-```c
-{
- jerry_init (JERRY_INIT_EMPTY);
- jerry_debugger_init (5001);
-
- // ...
-
- jerry_cleanup ();
-}
-```
-
-
### jerry_debugger_is_connected
**Summary**
**Example**
+[doctest]: # (test="link")
+
```c
+#include "jerryscript.h"
+#include "jerryscript-ext/debugger.h"
+
+int
+main (void)
{
jerry_init (JERRY_INIT_EMPTY);
- jerry_debugger_init (5001);
+ jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001)
+ && jerryx_debugger_ws_create ());
if (jerry_debugger_is_connected ())
{
**Example**
+[doctest]: # (test="link")
+
```c
+#include "jerryscript.h"
+#include "jerryscript-ext/debugger.h"
+
+int
+main (void)
{
jerry_init (JERRY_INIT_EMPTY);
- jerry_debugger_init (5001);
+ jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001)
+ && jerryx_debugger_ws_create ());
jerry_debugger_stop ();
**Example**
+[doctest]: # (test="link")
+
```c
+#include "jerryscript.h"
+#include "jerryscript-ext/debugger.h"
+
+int
+main (void)
{
jerry_init (JERRY_INIT_EMPTY);
- jerry_debugger_init (5001);
+ jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001)
+ && jerryx_debugger_ws_create ());
jerry_debugger_continue ();
- [jerry_debugger_stop](#jerry_debugger_stop)
-### jerry_debugger_disable_stop_at_breakpoint
+### jerry_debugger_stop_at_breakpoint
**Summary**
**Example**
+[doctest]: # (test="link")
+
```c
+#include "jerryscript.h"
+#include "jerryscript-ext/debugger.h"
+
+int
+main (void)
{
jerry_init (JERRY_INIT_EMPTY);
- jerry_debugger_init (5001);
+ jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001)
+ && jerryx_debugger_ws_create ());
jerry_debugger_stop_at_breakpoint (true);
// Protected execution of JavaScript code.
- jerry_eval (...);
+ const jerry_char_t script[] = "42";
+ jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
jerry_debugger_stop_at_breakpoint (false);
**Example**
+[doctest]: # (test="link")
+
```c
+#include "jerryscript.h"
+#include "jerryscript-ext/debugger.h"
+
/**
* Runs the source code received by jerry_debugger_wait_for_client_source.
*/
source_size,
JERRY_PARSE_NO_OPTS);
- if (!jerry_value_has_error_flag (ret_val))
+ if (!jerry_value_is_error (ret_val))
{
jerry_value_t func_val = ret_val;
ret_val = jerry_run (func_val);
return ret_val;
} /* wait_for_source_callback */
-int main ()
+int
+main (void)
{
+ jerry_debugger_wait_for_source_status_t receive_status;
+
do
{
/* Create a new JerryScript instance when a context reset is
* received. Applications usually registers their core bindings
* here as well (e.g. print, setTimeout). */
jerry_init (JERRY_INIT_EMPTY);
- jerry_debugger_init (5001);
+ jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001)
+ && jerryx_debugger_ws_create ());
do
{
jerry_value_t run_result;
- jerry_debugger_wait_for_source_status_t receive_status;
receive_status = jerry_debugger_wait_for_client_source (wait_for_source_callback,
NULL,
**Prototype**
```c
- void
- jerry_debugger_send_output (jerry_char_t buffer[], jerry_size_t string_size, uint8_t type)
+void
+jerry_debugger_send_output (const jerry_char_t *buffer, jerry_size_t string_size)
```
**Example**
+[doctest]: # (test="link")
+
```c
+#include "jerryscript.h"
+#include "jerryscript-ext/debugger.h"
+
+int
+main (void)
+{
jerry_init (JERRY_INIT_EMPTY);
- jerry_debugger_init (5001);
+ jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001)
+ && jerryx_debugger_ws_create ());
- jerry_char_t my_output = "Hey, this should be sent too!";
+ jerry_char_t my_output[] = "Hey, this should be sent too!";
jerry_size_t my_output_size = sizeof (my_output);
- jerry_debugger_send_output (my_output, my_output_size, JERRY_DEBUGGER_OUTPUT_OK);
+ jerry_debugger_send_output (my_output, my_output_size);
+
+ jerry_cleanup ();
+}
+```
+
+### jerry_debugger_send_log
+
+**Summary**
+
+Sends the program's log to the debugger client.
+
+**Prototype**
+
+```c
+void
+jerry_debugger_send_log (jerry_log_level_t level, const jerry_char_t *buffer, jerry_size_t string_size)
+```
+
+**Example**
+
+[doctest]: # (test="link")
+
+```c
+#include "jerryscript.h"
+#include "jerryscript-ext/debugger.h"
+
+int
+main (void)
+{
+ jerry_init (JERRY_INIT_EMPTY);
+ jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001)
+ && jerryx_debugger_ws_create ());
+
+ jerry_char_t my_log[] = "Custom diagnostics";
+ jerry_size_t my_log_size = sizeof (my_log);
+
+ jerry_debugger_send_log (JERRY_LOG_LEVEL_DEBUG, my_log, my_log_size);
jerry_cleanup ();
+}
```
mapping,
4);
- if (jerry_value_has_error_flag (rv))
+ if (jerry_value_is_error (rv))
{
/* Handle error. */
return rv;
mapping,
1);
- if (jerry_value_has_error_flag (rv))
+ if (jerry_value_is_error (rv))
{
/* Handle error. */
return rv;
mapping,
1);
- if (jerry_value_has_error_flag (rv))
+ if (jerry_value_is_error (rv))
{
/* Handle error. */
return rv;
# Common external function handlers
-## jerryx_handler_assert
+## jerryx_handler_assert_fatal
**Summary**
-Assert for scripts. The routine calls `jerry_port_fatal` on assertion failure.
+Hard assert for scripts. The routine calls `jerry_port_fatal` on assertion failure.
**Prototype**
```c
jerry_value_t
-jerryx_handler_assert (const jerry_value_t func_obj_val, const jerry_value_t this_p,
- const jerry_value_t args_p[], const jerry_length_t args_cnt);
+jerryx_handler_assert_fatal (const jerry_value_t func_obj_val, const jerry_value_t this_p,
+ const jerry_value_t args_p[], const jerry_length_t args_cnt);
```
- `func_obj_val` - the function object that was called (unused).
- [jerryx_handler_register_global](#jerryx_handler_register_global)
+## jerryx_handler_assert_throw
+
+**Summary**
+
+Soft assert for scripts. The routine throws an error on assertion failure.
+
+**Prototype**
+
+```c
+jerry_value_t
+jerryx_handler_assert_throw (const jerry_value_t func_obj_val, const jerry_value_t this_p,
+ const jerry_value_t args_p[], const jerry_length_t args_cnt);
+```
+
+- `func_obj_val` - the function object that was called (unused).
+- `this_p` - the `this` value of the call (unused).
+- `args_p` - the array of function arguments.
+- `args_cnt` - the number of function arguments.
+- return value - `jerry_value_t` representing boolean true, if only one argument
+ was passed and that argument was a boolean true, an error otherwise.
+
+**See also**
+
+- [jerryx_handler_register_global](#jerryx_handler_register_global)
+
+
+## jerryx_handler_assert
+
+**Summary**
+
+An alias to `jerryx_handler_assert_fatal`.
+
+**See also**
+
+- [jerryx_handler_assert_fatal](#jerryx_handler_assert_fatal)
+
+
## jerryx_handler_gc
**Summary**
-Expose garbage collector to scripts.
+Expose garbage collector to scripts. If the first argument of the function
+is logical true, it performs a high severity gc. Otherwise a low severity
+gc is performed, which is also the default if no parameters passed.
**Prototype**
{
jerry_value_t ret = jerry_create_undefined ();
- for (int i = 0; common_functions[i].name_p != NULL && !jerry_value_has_error_flag (ret); i++)
+ for (int i = 0; common_functions[i].name_p != NULL && !jerry_value_is_error (ret); i++)
{
ret = jerryx_handler_register_global ((const jerry_char_t *) common_functions[i].name_p,
common_functions[i].handler_p);
differently and thus, for each type of module a module resolver must be supplied at the point where an instance of that
type of module is requested.
+Individual modules may be removed from the cache by calling `jerryx_module_clear_cache`. This function behaves
+identically to `jerryx_module_resolve` in that it first checks the cache for the requested module, except that it
+removes the module if found. Additionally, it clears the entire cache of all modules if called using a JavaScript value
+of `undefined` as its first parameter.
+
Additionally, this extension provides a means of easily defining so-called "native" JerryScript modules which can be
resolved using the native JerryScript module resolver `jerryx_module_native_resolver`, which can be passed to
`jerryx_module_resolve()`. Native modules are registered during application startup and by calling `dlopen()` by means
```c
jerry_value_t
-jerryx_module_resolve (const jerry_char_t *name,
+jerryx_module_resolve (const jerry_value_t name,
const jerryx_module_resolver_t *resolvers_p,
size_t resolver_count);
```
- return value - `jerry_value_t` representing the module that was loaded, or the error that occurred in the process.
+## jerryx_module_clear_cache
+
+**Summary**
+
+Remove a module from the current context's cache, or clear the cache entirely.
+
+**Prototype**
+
+```c
+void
+jerryx_module_clear_cache (const jerry_value_t name,
+ const jerryx_module_resolver_t *resolvers_p,
+ size_t resolver_count);
+```
+
+- `name` - the name of the module to remove from cache or a JavaScript `undefined` to clear the entire cache
+- `resolvers_p` - the list of resolvers to call in sequence
+- `resolver_count` - the number of resolvers in `resolvers_p`
+
+
## jerryx_module_native_resolver
**Summary**
{
/* We read the file into memory and call jerry_eval (), assigning the result to the out-parameter. */
fread (js_file_contents, file_size, 1, js_file);
- (*result) = jerry_eval (js_file_contents, file_size, false);
+ (*result) = jerry_eval (js_file_contents, file_size, JERRY_PARSE_NO_OPTS);
/* We release the memory holding the contents of the file. */
free (js_file_contents);
--- /dev/null
+# JerryScript debugger transport interface
+
+The transport interface support allows dynamic selection of transportation
+layers which can encode/decode or send/receive messages transmitted between
+the debugger client and server.
+
+# Types
+
+## jerry_debugger_transport_receive_context_t
+
+**Summary**
+
+This context represents the current status of processing received data.
+The final state is returned by
+[jerry_debugger_transport_receive](#jerry_debugger_transport_receive)
+and must be passed to
+[jerry_debugger_transport_receive_completed](#jerry_debugger_transport_receive_completed)
+after the message is processed.
+
+**Prototype**
+
+```c
+typedef struct
+{
+ uint8_t *buffer_p; /**< buffer for storing the received data */
+ size_t received_length; /**< number of currently received bytes */
+ uint8_t *message_p; /**< start of the received message */
+ size_t message_length; /**< length of the received message */
+ size_t message_total_length; /**< total length for datagram protocols,
+ * 0 for stream protocols */
+} jerry_debugger_transport_receive_context_t;
+```
+
+## jerry_debugger_transport_header_t
+
+**Summary**
+
+Shared header for each transport interface. It mostly contains callback functions
+used by the JerryScript debugger server.
+
+**Prototype**
+
+```c
+typedef struct jerry_debugger_transport_layer_t
+{
+ /* The following fields must be filled before calling jerry_debugger_transport_add(). */
+ jerry_debugger_transport_close_t close; /**< close connection callback */
+ jerry_debugger_transport_send_t send; /**< send data callback */
+ jerry_debugger_transport_receive_t receive; /**< receive data callback */
+
+ /* The following fields are filled by jerry_debugger_transport_add(). */
+ struct jerry_debugger_transport_layer_t *next_p; /**< next transport layer */
+} jerry_debugger_transport_header_t;
+```
+
+## jerry_debugger_transport_close_t
+
+**Summary**
+
+Called when the connection is closed. Must release all resources (including the
+memory area for the transport interface) allocated for the transport interface.
+
+**Prototype**
+
+```c
+typedef void (*jerry_debugger_transport_close_t) (struct jerry_debugger_transport_interface_t *header_p);
+```
+
+## jerry_debugger_transport_send_t
+
+**Summary**
+
+Called when a message needs to be sent. Must either transmit the message or call
+the `header_p->next_p->send()` method.
+
+**Prototype**
+
+```c
+typedef bool (*jerry_debugger_transport_send_t) (struct jerry_debugger_transport_interface_t *header_p,
+ uint8_t *message_p, size_t message_length);
+```
+
+## jerry_debugger_transport_receive_t
+
+**Summary**
+
+Called during message processing. If messages are available it must return with
+the next message.
+
+**Prototype**
+
+```c
+typedef bool (*jerry_debugger_transport_receive_t) (struct jerry_debugger_transport_interface_t *header_p,
+ jerry_debugger_transport_receive_context_t *context_p);
+```
+
+# Transport interface API functions
+
+## jerry_debugger_transport_add
+
+**Summary**
+
+Add a new interface to the transporation interface chain. The interface
+will be the first item of the interface chain.
+
+**Prototype**
+
+```c
+void jerry_debugger_transport_add (jerry_debugger_transport_header_t *header_p,
+ size_t send_message_header_size, size_t max_send_message_size,
+ size_t receive_message_header_size, size_t max_receive_message_size);
+```
+
+- `header_p`: header of a transporation interface.
+- `send_message_header_size`: size of the outgoing message header, can be 0.
+- `max_send_message_size`: maximum outgoing message size supported by the interface.
+- `receive_message_header_size`: size of the incoming message header, can be 0.
+- `max_receive_message_size`: maximum incoming message size supported by the interface.
+
+## jerry_debugger_transport_start
+
+**Summary**
+
+Starts the communication to the debugger client. Must be called after the
+connection is successfully established.
+
+**Prototype**
+
+```c
+void jerry_debugger_transport_start (void);
+```
+
+## jerry_debugger_transport_is_connected
+
+**Summary**
+
+Tells whether a debugger client is connected to the debugger server.
+
+**Prototype**
+
+```c
+bool jerry_debugger_transport_is_connected (void);
+```
+
+- return value: `true`, if a client is connected, `false` otherwise.
+
+## jerry_debugger_transport_close
+
+**Summary**
+
+Disconnect from the current debugger client. It does nothing if a client is
+not connected.
+
+**Prototype**
+
+```c
+void jerry_debugger_transport_close (void);
+```
+
+## jerry_debugger_transport_send
+
+**Summary**
+
+Send message to the client.
+
+**Prototype**
+
+```c
+bool jerry_debugger_transport_send (const uint8_t *message_p, size_t message_length);
+```
+
+- `message_p`: message to be sent.
+- `message_length`: message length in bytes.
+- return value: `true`, if a client is still connected, `false` otherwise.
+
+## jerry_debugger_transport_receive
+
+**Summary**
+
+Receive message from the client.
+
+**Prototype**
+
+```c
+bool jerry_debugger_transport_receive (jerry_debugger_transport_receive_context_t *context_p);
+```
+
+- `context_p`: an unused [jerry_debugger_transport_receive_context_t](#jerry_debugger_transport_receive_context_t).
+- return value: `true`, if a client is still connected, `false` otherwise.
+
+## jerry_debugger_transport_receive_completed
+
+**Summary**
+
+Must be called after [jerry_debugger_transport_receive](#jerry_debugger_transport_receive)
+returns with a valid message. Must not be called otherwise.
+
+**Prototype**
+
+```c
+void jerry_debugger_transport_receive_completed (jerry_debugger_transport_receive_context_t *context_p);
+```
+
+- `context_p`: a [jerry_debugger_transport_receive_context_t](#jerry_debugger_transport_receive_context_t)
+ passed to [jerry_debugger_transport_receive](#jerry_debugger_transport_receive).
+
+## jerry_debugger_transport_sleep
+
+**Summary**
+
+Can be used to wait for incoming messages. Currently the delay is 100ms.
+
+**Prototype**
+
+```c
+void jerry_debugger_transport_sleep (void);
+```
set(JERRY_CORE_NAME jerry-core)
project (${JERRY_CORE_NAME} C)
+# Optional build settings
+set(ENABLE_ALL_IN_ONE OFF CACHE BOOL "Enable all-in-one build?")
+
# 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_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_LOGGING OFF CACHE BOOL "Enable logging?")
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_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(USING_MSVC)
+ set(ENABLE_ALL_IN_ONE ON) # FIXME: This should not be needed but right now it is. To be tracked down and followed up.
+
+ set(ENABLE_ALL_IN_ONE_MESSAGE " (FORCED BY COMPILER)")
+endif()
+
if(FEATURE_SYSTEM_ALLOCATOR)
set(FEATURE_CPOINTER_32_BIT ON)
set(FEATURE_SNAPSHOT_SAVE_MESSAGE " (FORCED BY SNAPSHOT TOOL)")
endif()
+if(FEATURE_MEM_STATS OR FEATURE_PARSER_DUMP OR FEATURE_REGEXP_DUMP)
+ set(FEATURE_LOGGING ON)
+
+ set(FEATURE_LOGGING_MESSAGE " (FORCED BY STATS OR DUMP)")
+endif()
+
# Status messages
+message(STATUS "ENABLE_ALL_IN_ONE " ${ENABLE_ALL_IN_ONE} ${ENABLE_ALL_IN_ONE_MESSAGE})
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_LOGGING " ${FEATURE_LOGGING} ${FEATURE_LOGGING_MESSAGE})
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_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
+set(INCLUDE_CORE_PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
+set(INCLUDE_CORE_PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/api"
"${CMAKE_CURRENT_SOURCE_DIR}/debugger"
"${CMAKE_CURRENT_SOURCE_DIR}/ecma/builtin-objects"
"${CMAKE_CURRENT_SOURCE_DIR}/ecma/builtin-objects/typedarray"
"${CMAKE_CURRENT_SOURCE_DIR}/ecma/operations"
- "${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/jcontext"
"${CMAKE_CURRENT_SOURCE_DIR}/jmem"
"${CMAKE_CURRENT_SOURCE_DIR}/jrt"
"${CMAKE_CURRENT_SOURCE_DIR}/parser/regexp"
"${CMAKE_CURRENT_SOURCE_DIR}/vm")
+set(INCLUDE_CORE_PUBLIC ${INCLUDE_CORE_PUBLIC} PARENT_SCOPE) # for jerry-port
+set(INCLUDE_CORE_PRIVATE ${INCLUDE_CORE_PRIVATE} PARENT_SCOPE) # for tests/unit-core
+
# Sources
# Jerry core
file(GLOB SOURCE_CORE_API api/*.c)
set(INCLUDE_THIRD_PARTY_VALGRIND "${CMAKE_SOURCE_DIR}/third-party/valgrind")
# build mode specific compile/link flags
-if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
- set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_NDEBUG)
-endif()
+set(DEFINES_JERRY ${DEFINES_JERRY} $<$<NOT:$<CONFIG:Debug>>:JERRY_NDEBUG>)
# Jerry heap-section
if(DEFINED JERRY_HEAP_SECTION_ATTR)
set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_ENABLE_LINE_INFO)
endif()
+# Logging
+if(FEATURE_LOGGING)
+ set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_ENABLE_LOGGING)
+endif()
+
# Memory statistics
if(FEATURE_MEM_STATS)
set(DEFINES_JERRY ${DEFINES_JERRY} JMEM_STATS)
# Enable debugger
if(FEATURE_DEBUGGER)
- if(JERRY_LIBC)
- message(FATAL_ERROR "This configuration is not supported. Please build against your system libc to enable the JerryScript debugger.")
- endif()
-
- # Sleep function availability check
- INCLUDE (CheckIncludeFiles)
- CHECK_INCLUDE_FILES (time.h HAVE_TIME_H)
- CHECK_INCLUDE_FILES (unistd.h HAVE_UNISTD_H)
- if(HAVE_TIME_H)
- set(DEFINES_JERRY ${DEFINES_JERRY} HAVE_TIME_H)
- elseif(HAVE_UNISTD_H)
- set(DEFINES_JERRY ${DEFINES_JERRY} HAVE_UNISTD_H)
- endif()
-
set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_DEBUGGER)
endif()
message(FATAL_ERROR "Profile file: '${FEATURE_PROFILE}' doesn't exist!")
endif()
-if(JERRY_LIBC AND FEATURE_SYSTEM_ALLOCATOR)
- MESSAGE(FATAL_ERROR "This configuration is not supported. Please build against your system libc to enable the system allocator.")
-endif()
-
# RegExp strict mode
if(FEATURE_REGEXP_STRICT_MODE)
set(DEFINES_JERRY ${DEFINES_JERRY} ENABLE_REGEXP_STRICT_MODE)
# Valgrind
if(FEATURE_VALGRIND)
set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_VALGRIND)
- set(INCLUDE_CORE ${INCLUDE_CORE} ${INCLUDE_THIRD_PARTY_VALGRIND})
-endif()
-
-# Valgrind Freya
-if(FEATURE_VALGRIND_FREYA)
- set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_VALGRIND_FREYA)
- set(INCLUDE_CORE ${INCLUDE_CORE} ${INCLUDE_THIRD_PARTY_VALGRIND})
+ set(INCLUDE_CORE_PRIVATE ${INCLUDE_CORE_PRIVATE} ${INCLUDE_THIRD_PARTY_VALGRIND})
endif()
# Enable VM execution stopping
math(EXPR MEM_HEAP_AREA_SIZE "${MEM_HEAP_SIZE_KB} * 1024")
set(DEFINES_JERRY ${DEFINES_JERRY} CONFIG_MEM_HEAP_AREA_SIZE=${MEM_HEAP_AREA_SIZE})
-add_library(${JERRY_CORE_NAME} STATIC ${SOURCE_CORE_FILES})
+add_library(${JERRY_CORE_NAME} ${SOURCE_CORE_FILES})
target_compile_definitions(${JERRY_CORE_NAME} PUBLIC ${DEFINES_JERRY})
-target_include_directories(${JERRY_CORE_NAME} PUBLIC ${INCLUDE_CORE})
+target_include_directories(${JERRY_CORE_NAME} PUBLIC ${INCLUDE_CORE_PUBLIC})
+target_include_directories(${JERRY_CORE_NAME} PRIVATE ${INCLUDE_CORE_PRIVATE})
if(JERRY_LIBM)
target_link_libraries(${JERRY_CORE_NAME} jerry-libm)
endif()
-if(JERRY_LIBC)
- target_link_libraries(${JERRY_CORE_NAME} jerry-libc)
-endif()
-
separate_arguments(EXTERNAL_LINK_LIBS)
foreach(EXT_LIB ${EXTERNAL_LINK_LIBS})
target_link_libraries(${JERRY_CORE_NAME} ${EXT_LIB})
endforeach()
install(TARGETS ${JERRY_CORE_NAME} DESTINATION lib)
-install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION include)
+install(DIRECTORY ${INCLUDE_CORE_PUBLIC}/ DESTINATION include)
--- /dev/null
+/* 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 "debugger.h"
+#include "jcontext.h"
+#include "jerryscript.h"
+
+#ifdef JERRY_DEBUGGER
+
+/**
+ * Minimum number of bytes transmitted or received.
+ */
+#define JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE 64
+
+/**
+ * Sleep time in milliseconds between each jerry_debugger_receive call
+ */
+#define JERRY_DEBUGGER_TRANSPORT_TIMEOUT 100
+
+/**
+ * Add a new transport layer.
+ */
+void
+jerry_debugger_transport_add (jerry_debugger_transport_header_t *header_p, /**< transport implementation */
+ size_t send_message_header_size, /**< header bytes reserved for outgoing messages */
+ size_t max_send_message_size, /**< maximum number of bytes transmitted in a message */
+ size_t receive_message_header_size, /**< header bytes reserved for incoming messages */
+ size_t max_receive_message_size) /**< maximum number of bytes received in a message */
+{
+ JERRY_ASSERT (max_send_message_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE
+ && max_receive_message_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE);
+
+ header_p->next_p = JERRY_CONTEXT (debugger_transport_header_p);
+ JERRY_CONTEXT (debugger_transport_header_p) = header_p;
+
+ uint8_t *payload_p;
+ size_t max_send_size;
+ size_t max_receive_size;
+
+ if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
+ {
+ payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p);
+ max_send_size = JERRY_CONTEXT (debugger_max_send_size);
+ max_receive_size = JERRY_CONTEXT (debugger_max_receive_size);
+ }
+ else
+ {
+ JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CONNECTED);
+ payload_p = JERRY_CONTEXT (debugger_send_buffer);
+ max_send_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE;
+ max_receive_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE;
+ }
+
+ JERRY_ASSERT (max_send_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE + send_message_header_size);
+ JERRY_ASSERT (max_receive_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE + receive_message_header_size);
+
+ JERRY_CONTEXT (debugger_send_buffer_payload_p) = payload_p + send_message_header_size;
+
+ max_send_size = max_send_size - send_message_header_size;
+ max_receive_size = max_receive_size - receive_message_header_size;
+
+ if (max_send_size > max_send_message_size)
+ {
+ max_send_size = max_send_message_size;
+ }
+
+ if (max_receive_size > max_receive_message_size)
+ {
+ max_receive_size = max_receive_message_size;
+ }
+
+ JERRY_CONTEXT (debugger_max_send_size) = (uint8_t) max_send_size;
+ JERRY_CONTEXT (debugger_max_receive_size) = (uint8_t) max_receive_size;
+} /* jerry_debugger_transport_add */
+
+/**
+ * Starts the communication to the debugger client.
+ * Must be called after the connection is successfully established.
+ */
+void
+jerry_debugger_transport_start (void)
+{
+ JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
+
+ if (jerry_debugger_send_configuration (JERRY_CONTEXT (debugger_max_receive_size)))
+ {
+ JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP);
+ JERRY_CONTEXT (debugger_stop_context) = NULL;
+ }
+} /* jerry_debugger_transport_start */
+
+/**
+ * Returns true if a debugger client is connected.
+ *
+ * @return true - a debugger client is connected,
+ * false - otherwise
+ */
+bool
+jerry_debugger_transport_is_connected (void)
+{
+ return (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) != 0;
+} /* jerry_debugger_transport_is_connected */
+
+/**
+ * Notifies the debugger server that the connection is closed.
+ */
+void
+jerry_debugger_transport_close (void)
+{
+ if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED))
+ {
+ return;
+ }
+
+ JERRY_CONTEXT (debugger_flags) = JERRY_DEBUGGER_VM_IGNORE;
+
+ jerry_debugger_transport_header_t *current_p = JERRY_CONTEXT (debugger_transport_header_p);
+
+ JERRY_ASSERT (current_p != NULL);
+
+ do
+ {
+ jerry_debugger_transport_header_t *next_p = current_p->next_p;
+
+ current_p->close (current_p);
+
+ current_p = next_p;
+ }
+ while (current_p != NULL);
+
+ jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Debugger client connection closed.\n");
+
+ jerry_debugger_free_unreferenced_byte_code ();
+} /* jerry_debugger_transport_close */
+
+/**
+ * Send data over the current connection
+ *
+ * @return true - data sent successfully,
+ * false - connection closed
+ */
+bool
+jerry_debugger_transport_send (const uint8_t *message_p, /**< message to be sent */
+ size_t message_length) /**< message length in bytes */
+{
+ JERRY_ASSERT (jerry_debugger_transport_is_connected ());
+ JERRY_ASSERT (message_length > 0);
+
+ jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p);
+ uint8_t *payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p);
+ size_t max_send_size = JERRY_CONTEXT (debugger_max_send_size);
+
+ do
+ {
+ size_t fragment_length = (message_length <= max_send_size ? message_length
+ : max_send_size);
+
+ memcpy (payload_p, message_p, fragment_length);
+
+ if (!header_p->send (header_p, payload_p, fragment_length))
+ {
+ return false;
+ }
+
+ message_p += fragment_length;
+ message_length -= fragment_length;
+ }
+ while (message_length > 0);
+
+ return true;
+} /* jerry_debugger_transport_send */
+
+/**
+ * Receive data from the current connection
+ *
+ * Note:
+ * A message is received if message_start_p is not NULL
+ *
+ * @return true - function successfully completed,
+ * false - connection closed
+ */
+bool
+jerry_debugger_transport_receive (jerry_debugger_transport_receive_context_t *context_p) /**< [out] receive
+ * context */
+{
+ JERRY_ASSERT (jerry_debugger_transport_is_connected ());
+
+ context_p->buffer_p = JERRY_CONTEXT (debugger_receive_buffer);
+ context_p->received_length = JERRY_CONTEXT (debugger_received_length);
+ context_p->message_p = NULL;
+ context_p->message_length = 0;
+ context_p->message_total_length = 0;
+
+ jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p);
+
+ return header_p->receive (header_p, context_p);
+} /* jerry_debugger_transport_receive */
+
+/**
+ * Clear the message buffer after the message is processed
+ */
+void
+jerry_debugger_transport_receive_completed (jerry_debugger_transport_receive_context_t *context_p) /**< receive
+ * context */
+{
+ JERRY_ASSERT (context_p->message_p != NULL);
+ JERRY_ASSERT (context_p->buffer_p == JERRY_CONTEXT (debugger_receive_buffer));
+
+ size_t message_total_length = context_p->message_total_length;
+ size_t received_length = context_p->received_length;
+
+ JERRY_ASSERT (message_total_length <= received_length);
+
+ if (message_total_length == 0 || message_total_length == received_length)
+ {
+ /* All received data is processed. */
+ JERRY_CONTEXT (debugger_received_length) = 0;
+ return;
+ }
+
+ uint8_t *buffer_p = context_p->buffer_p;
+ received_length -= message_total_length;
+
+ memmove (buffer_p, buffer_p + message_total_length, received_length);
+
+ JERRY_CONTEXT (debugger_received_length) = (uint16_t) received_length;
+} /* jerry_debugger_transport_receive_completed */
+
+/**
+ * Suspend execution for a predefined time (JERRY_DEBUGGER_TRANSPORT_TIMEOUT ms).
+ */
+void
+jerry_debugger_transport_sleep (void)
+{
+ jerry_port_sleep (JERRY_DEBUGGER_TRANSPORT_TIMEOUT);
+} /* jerry_debugger_transport_sleep */
+
+#endif /* JERRY_DEBUGGER */
{
#ifdef JERRY_DEBUGGER
return JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED;
-#else
+#else /* !JERRY_DEBUGGER */
return false;
#endif /* JERRY_DEBUGGER */
} /* jerry_debugger_is_connected */
#endif /* JERRY_DEBUGGER */
} /* jerry_debugger_stop_at_breakpoint */
-/**
- * Debugger server initialization. Must be called after jerry_init.
- */
-void
-jerry_debugger_init (uint16_t port) /**< server port number */
-{
-#ifdef JERRY_DEBUGGER
- JERRY_CONTEXT (debugger_port) = port;
- jerry_debugger_accept_connection ();
-#else /* !JERRY_DEBUGGER */
- JERRY_UNUSED (port);
-#endif /* JERRY_DEBUGGER */
-} /* jerry_debugger_init */
-
/**
* Sets whether the engine should wait and run a source.
*
}
}
- jerry_debugger_sleep ();
+ jerry_debugger_transport_sleep ();
}
JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE)
}
return JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED;
-#else
+#else /* !JERRY_DEBUGGER */
JERRY_UNUSED (callback_p);
JERRY_UNUSED (user_p);
* Send the output of the program to the debugger client.
* Currently only sends print output.
*/
-
-#ifdef JERRY_DEBUGGER
void
-jerry_debugger_send_output (jerry_char_t buffer[], /**< buffer */
- jerry_size_t str_size, /**< string size */
- uint8_t type) /**< type of output */
+jerry_debugger_send_output (const jerry_char_t *buffer, /**< buffer */
+ jerry_size_t str_size) /**< string size */
{
+#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
jerry_debugger_send_string (JERRY_DEBUGGER_OUTPUT_RESULT,
- type,
+ JERRY_DEBUGGER_OUTPUT_OK,
(const uint8_t *) buffer,
sizeof (uint8_t) * str_size);
}
+#else /* !JERRY_DEBUGGER */
+ JERRY_UNUSED (buffer);
+ JERRY_UNUSED (str_size);
+#endif /* JERRY_DEBUGGER */
} /* jerry_debugger_send_output */
+
+/**
+ * Send the log of the program to the debugger client.
+ */
+void
+jerry_debugger_send_log (jerry_log_level_t level, /**< level of the diagnostics message */
+ const jerry_char_t *buffer, /**< buffer */
+ jerry_size_t str_size) /**< string size */
+{
+#ifdef JERRY_DEBUGGER
+ if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
+ {
+ jerry_debugger_send_string (JERRY_DEBUGGER_OUTPUT_RESULT,
+ (uint8_t) (level + 2),
+ (const uint8_t *) buffer,
+ sizeof (uint8_t) * str_size);
+ }
+#else /* !JERRY_DEBUGGER */
+ JERRY_UNUSED (level);
+ JERRY_UNUSED (buffer);
+ JERRY_UNUSED (str_size);
#endif /* JERRY_DEBUGGER */
+} /* jerry_debugger_send_log */
*
* @return configuration flags
*/
-static inline uint32_t __attr_always_inline___
-snapshot_get_global_flags (bool has_regex) /**< regex literal is present */
+static inline uint32_t JERRY_ATTR_ALWAYS_INLINE
+snapshot_get_global_flags (bool has_regex, /**< regex literal is present */
+ bool has_class) /**< class literal is present */
{
JERRY_UNUSED (has_regex);
+ JERRY_UNUSED (has_class);
uint32_t flags = 0;
-#ifdef JERRY_CPOINTER_32_BIT
- flags |= JERRY_SNAPSHOT_FOUR_BYTE_CPOINTER;
-#endif /* JERRY_CPOINTER_32_BIT */
#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
flags |= (has_regex ? JERRY_SNAPSHOT_HAS_REGEX_LITERAL : 0);
-#endif /* CONFIG_DISABLE_REGEXP_BUILTIN */
+#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ flags |= (has_class ? JERRY_SNAPSHOT_HAS_CLASS_LITERAL : 0);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
return flags;
} /* snapshot_get_global_flags */
*
* @return true if global_flags accepted, false otherwise
*/
-static inline bool __attr_always_inline___
+static inline bool JERRY_ATTR_ALWAYS_INLINE
snapshot_check_global_flags (uint32_t global_flags) /**< global flags */
{
#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
global_flags &= (uint32_t) ~JERRY_SNAPSHOT_HAS_REGEX_LITERAL;
#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ global_flags &= (uint32_t) ~JERRY_SNAPSHOT_HAS_CLASS_LITERAL;
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
- return global_flags == snapshot_get_global_flags (false);
+ return global_flags == snapshot_get_global_flags (false, false);
} /* snapshot_check_global_flags */
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE || JERRY_ENABLE_SNAPSHOT_EXEC */
size_t snapshot_buffer_write_offset;
ecma_value_t snapshot_error;
bool regex_found;
+ bool class_found;
} snapshot_globals_t;
/** \addtogroup jerrysnapshot Jerry snapshot operations
* @return true - if write was successful, i.e. offset + data_size doesn't exceed buffer size,
* false - otherwise
*/
-static inline bool __attr_always_inline___
+static inline bool JERRY_ATTR_ALWAYS_INLINE
snapshot_write_to_buffer_by_offset (uint8_t *buffer_p, /**< buffer */
size_t buffer_size, /**< size of buffer */
size_t *in_out_buffer_offset_p, /**< [in,out] offset to write to
if (globals_p->snapshot_buffer_write_offset > JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET)
{
- const char *error_message_p = "Maximum snapshot size reached.";
+ const char * const 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;
}
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))
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CONSTRUCTOR)
{
+ globals_p->class_found = true;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
+ if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION))
+ {
/* Regular expression. */
if (globals_p->snapshot_buffer_write_offset + sizeof (ecma_compiled_code_t) > snapshot_buffer_size)
{
copied_code_p->status_flags = compiled_code_p->status_flags;
-#else /* CONFIG_DISABLE_REGEXP_BUILTIN */
- JERRY_UNREACHABLE (); /* RegExp is not supported in the selected profile. */
-#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */
return start_offset;
}
+#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */
+
+ JERRY_ASSERT (compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION);
if (!snapshot_write_to_buffer_by_offset (snapshot_buffer_p,
snapshot_buffer_size,
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: ";
+ const lit_utf8_byte_t error_prefix[] = "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));
+ ecma_string_t *error_message_p = ecma_new_ecma_string_from_utf8 (error_prefix, sizeof (error_prefix) - 1);
literal = ecma_op_to_string (literal);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (literal));
if (globals_p->snapshot_buffer_write_offset >= JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET)
{
- const char *error_message_p = "Maximum snapshot size reached.";
+ const char * const 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;
}
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.";
+ const char * const 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;
}
compiled_code_p,
((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG))
{
- const char *error_message_p = "Snapshot buffer too small.";
+ const char * const 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;
}
}
}
- if (compiled_code_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED)
+ if (CBC_NON_STRICT_ARGUMENTS_NEEDED (compiled_code_p))
{
buffer_p += ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG;
literal_start_p = ((ecma_value_t *) buffer_p) - argument_end;
}
}
- if (bytecode_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED)
+ if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p))
{
uint8_t *byte_p = (uint8_t *) bytecode_p;
byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
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;
+#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION))
{
-#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
const re_compiled_code_t *re_bytecode_p = NULL;
const uint8_t *regex_start_p = ((const uint8_t *) bytecode_p) + sizeof (ecma_compiled_code_t);
ecma_deref_ecma_string (pattern_str_p);
return (ecma_compiled_code_t *) re_bytecode_p;
-#else /* CONFIG_DISABLE_REGEXP_BUILTIN */
- JERRY_UNREACHABLE (); /* RegExp is not supported in the selected profile. */
-#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */
}
+#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */
+
+ JERRY_ASSERT (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION);
size_t header_size;
uint32_t argument_end = 0;
uint8_t *byte_p = (uint8_t *) bytecode_p;
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) byte_p;
- if (bytecode_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED)
+ if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p))
{
argument_end = args_p->argument_end;
}
uint8_t *byte_p = (uint8_t *) bytecode_p;
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) byte_p;
- if (bytecode_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED)
+ if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p))
{
argument_end = args_p->argument_end;
}
globals.snapshot_buffer_write_offset = aligned_header_size;
globals.snapshot_error = ECMA_VALUE_EMPTY;
globals.regex_found = false;
+ globals.class_found = false;
parse_status = parser_parse_script (args_p,
args_size,
return ecma_create_error_reference (JERRY_CONTEXT (error_value), true);
}
+ JERRY_ASSERT (bytecode_data_p != NULL);
+
if (generate_snapshot_opts & JERRY_SNAPSHOT_SAVE_STATIC)
{
static_snapshot_add_compiled_code (bytecode_data_p, (uint8_t *) buffer_p, buffer_size, &globals);
if (!ecma_is_value_empty (globals.snapshot_error))
{
+ ecma_bytecode_deref (bytecode_data_p);
return globals.snapshot_error;
}
jerry_snapshot_header_t header;
header.magic = JERRY_SNAPSHOT_MAGIC;
header.version = JERRY_SNAPSHOT_VERSION;
- header.global_flags = snapshot_get_global_flags (globals.regex_found);
+ header.global_flags = snapshot_get_global_flags (globals.regex_found, globals.class_found);
header.lit_table_offset = (uint32_t) globals.snapshot_buffer_write_offset;
header.number_of_funcs = 1;
header.func_offsets[0] = aligned_header_size;
&literals_num))
{
JERRY_ASSERT (lit_map_p == NULL);
- const char *error_message_p = "Cannot allocate memory for literals.";
+ const char * const error_message_p = "Cannot allocate memory for literals.";
+ ecma_bytecode_deref (bytecode_data_p);
return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) error_message_p);
}
if ((generate_snapshot_opts & ~(allowed_opts)) != 0)
{
- const char *error_message_p = "Unsupported generate snapshot flags specified.";
+ const char * const error_message_p = "Unsupported generate snapshot flags specified.";
return jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
}
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 char * const invalid_version_error_p = "Invalid snapshot version or unsupported features present";
+ 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))
}
else
{
- const uint8_t *literal_base_p = (uint8_t *) (snapshot_data_p + header_p->lit_table_offset);
+ const uint8_t *literal_base_p = snapshot_data_p + header_p->lit_table_offset;
bytecode_p = snapshot_load_compiled_code ((const uint8_t *) bytecode_p,
literal_base_p,
do
{
- ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p;
+ const 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)
&& !(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
{
- ecma_value_t *literal_start_p;
+ const ecma_value_t *literal_start_p;
uint32_t argument_end;
uint32_t const_literal_end;
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)
+ if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p))
{
uint8_t *byte_p = (uint8_t *) bytecode_p;
byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
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);
}
}
* Update all literal offsets in a snapshot data.
*/
static void
-update_literal_offsets (uint8_t *buffer_p, /**< snapshot buffer start */
+update_literal_offsets (uint8_t *buffer_p, /**< [in,out] 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 */
+ const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< literal map */
+ const uint8_t *literal_base_p) /**< start of literal data */
{
JERRY_ASSERT (buffer_end_p > buffer_p);
do
{
- ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p;
+ const 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)
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]))
+ if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
{
- lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
+ ecma_value_t lit_value = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]);
+ const lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
- while (current_p->literal_id != literal_start_p[i])
+ while (current_p->literal_id != lit_value)
{
current_p++;
}
}
}
- if (bytecode_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED)
+ if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p))
{
uint8_t *byte_p = (uint8_t *) bytecode_p;
byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
for (uint32_t i = 0; i < argument_end; i++)
{
- if (literal_start_p[i] != ECMA_VALUE_EMPTY)
+ if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
{
- lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
+ ecma_value_t lit_value = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]);
+ const lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
- while (current_p->literal_id != literal_start_p[i])
+ while (current_p->literal_id != lit_value)
{
current_p++;
}
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 = (uint8_t *) (data_p + header_p->lit_table_offset);
+ const uint8_t *literal_base_p = data_p + header_p->lit_table_offset;
JERRY_ASSERT (header_p->number_of_funcs > 0);
functions_size += header_p->lit_table_offset - start_offset;
scan_snapshot_functions (data_p + start_offset,
- data_p + header_p->lit_table_offset,
+ literal_base_p,
lit_pool_p,
literal_base_p);
}
((const uint8_t *) inp_buffers_p[i]) + start_offset,
current_header_p->lit_table_offset - start_offset);
+ const uint8_t *literal_base_p = ((const uint8_t *) inp_buffers_p[i]) + current_header_p->lit_table_offset;
update_literal_offsets (dst_p,
dst_p + current_header_p->lit_table_offset - start_offset,
- lit_map_p);
+ lit_map_p,
+ literal_base_p);
uint32_t current_offset = (uint32_t) (dst_p - (uint8_t *) out_buffer_p) - start_offset;
uint8_t *buffer_end_p, /**< the end of the buffer */
ecma_string_t *string_p) /**< ecma-string */
{
- uint8_t *new_buffer_p = NULL;
-
ECMA_STRING_TO_UTF8_STRING (string_p, str_buffer_p, str_buffer_size);
/* Append the string to the buffer. */
- new_buffer_p = jerry_append_chars_to_buffer (buffer_p,
- buffer_end_p,
- (const char *) str_buffer_p,
- str_buffer_size);
+ uint8_t *new_buffer_p = jerry_append_chars_to_buffer (buffer_p,
+ buffer_end_p,
+ (const char *) str_buffer_p,
+ str_buffer_size);
ECMA_FINALIZE_UTF8_STRING (str_buffer_p, str_buffer_size);
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
/**
- * Copy certain string literals into the given buffer in a specified format,
- * which are valid identifiers and none of them are magic string.
+ * Get the literals from a snapshot. Copies certain string literals into the given
+ * buffer in a specified format.
+ *
+ * Note:
+ * Only valid identifiers are saved in C format.
*
* @return size of the literal-list in bytes, at most equal to the buffer size,
- * if the source parsed successfully and the list of the literals isn't empty,
+ * if the list of the literals isn't empty,
* 0 - otherwise.
*/
size_t
-jerry_parse_and_save_literals (const jerry_char_t *source_p, /**< script source */
- size_t source_size, /**< script source size */
- bool is_strict, /**< strict mode */
- uint32_t *buffer_p, /**< [out] buffer to save literals to */
- size_t buffer_size, /**< the buffer's size */
- bool is_c_format) /**< format-flag */
+jerry_get_literals_from_snapshot (const uint32_t *snapshot_p, /**< input snapshot buffer */
+ size_t snapshot_size, /**< size of the input snapshot buffer */
+ jerry_char_t *lit_buf_p, /**< [out] buffer to save literals to */
+ size_t lit_buf_size, /**< the buffer's size */
+ bool is_c_format) /**< format-flag */
{
#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,
- source_size,
- is_strict,
- &bytecode_data_p);
+ const uint8_t *snapshot_data_p = (uint8_t *) snapshot_p;
+ const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) snapshot_data_p;
- if (ECMA_IS_VALUE_ERROR (parse_status))
+ if (snapshot_size <= sizeof (jerry_snapshot_header_t)
+ || header_p->magic != JERRY_SNAPSHOT_MAGIC
+ || header_p->version != JERRY_SNAPSHOT_VERSION
+ || !snapshot_check_global_flags (header_p->global_flags))
{
- ecma_free_value (JERRY_CONTEXT (error_value));
+ /* Invalid snapshot format */
return 0;
}
- ecma_free_value (parse_status);
+ JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0);
+ const uint8_t *literal_base_p = snapshot_data_p + header_p->lit_table_offset;
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);
+ scan_snapshot_functions (snapshot_data_p + header_p->func_offsets[0],
+ literal_base_p,
+ lit_pool_p,
+ literal_base_p);
lit_utf8_size_t literal_count = 0;
ecma_value_t *iterator_p = ecma_collection_iterator_init (lit_pool_p);
{
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. */
+ /* NOTE:
+ * We don't save a literal (in C format) which isn't a valid
+ * identifier or it's a magic string.
+ * TODO:
+ * Save all of the literals in C format as well.
+ */
if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT
- && ecma_string_is_valid_identifier (literal_p))
+ && (!is_c_format || ecma_string_is_valid_identifier (literal_p)))
{
literal_count++;
}
return 0;
}
- uint8_t *destination_p = (uint8_t *) buffer_p;
-
- uint8_t *const buffer_start_p = destination_p;
- uint8_t *const buffer_end_p = destination_p + buffer_size;
+ jerry_char_t *const buffer_start_p = lit_buf_p;
+ jerry_char_t *const buffer_end_p = lit_buf_p + lit_buf_size;
JMEM_DEFINE_LOCAL_ARRAY (literal_array, literal_count, ecma_string_t *);
lit_utf8_size_t literal_idx = 0;
{
ecma_string_t *literal_p = ecma_get_string_from_value (*iterator_p);
+ /* NOTE:
+ * We don't save a literal (in C format) which isn't a valid
+ * identifier or it's a magic string.
+ * TODO:
+ * Save all of the literals in C format as well.
+ */
if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT
- && ecma_string_is_valid_identifier (literal_p))
+ && (!is_c_format || ecma_string_is_valid_identifier (literal_p)))
{
literal_array[literal_idx++] = literal_p;
}
if (is_c_format)
{
/* Save literal count. */
- destination_p = jerry_append_chars_to_buffer (destination_p,
- buffer_end_p,
- (const char *) "jerry_length_t literal_count = ",
- 0);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p,
+ buffer_end_p,
+ "jerry_length_t literal_count = ",
+ 0);
- destination_p = jerry_append_number_to_buffer (destination_p, buffer_end_p, literal_count);
+ lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, literal_count);
/* Save the array of literals. */
- destination_p = jerry_append_chars_to_buffer (destination_p,
- buffer_end_p,
- ";\n\njerry_char_ptr_t literals[",
- 0);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p,
+ buffer_end_p,
+ ";\n\njerry_char_t *literals[",
+ 0);
- destination_p = jerry_append_number_to_buffer (destination_p, buffer_end_p, literal_count);
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "] =\n{\n", 0);
+ lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, literal_count);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "] =\n{\n", 0);
for (lit_utf8_size_t i = 0; i < literal_count; i++)
{
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, " \"", 0);
- destination_p = jerry_append_ecma_string_to_buffer (destination_p, buffer_end_p, literal_array[i]);
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "\"", 0);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " \"", 0);
+ lit_buf_p = jerry_append_ecma_string_to_buffer (lit_buf_p, buffer_end_p, literal_array[i]);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\"", 0);
if (i < literal_count - 1)
{
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, ",", 0);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, ",", 0);
}
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "\n", 0);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\n", 0);
}
- destination_p = jerry_append_chars_to_buffer (destination_p,
- buffer_end_p,
- (const char *) "};\n\njerry_length_t literal_sizes[",
- 0);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p,
+ buffer_end_p,
+ "};\n\njerry_length_t literal_sizes[",
+ 0);
- destination_p = jerry_append_number_to_buffer (destination_p, buffer_end_p, literal_count);
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "] =\n{\n", 0);
+ lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, literal_count);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "] =\n{\n", 0);
}
/* Save the literal sizes respectively. */
if (is_c_format)
{
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, " ", 0);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " ", 0);
}
- destination_p = jerry_append_number_to_buffer (destination_p, buffer_end_p, str_size);
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, " ", 0);
+ lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, str_size);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " ", 0);
if (is_c_format)
{
/* Show the given string as a comment. */
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "/* ", 0);
- destination_p = jerry_append_ecma_string_to_buffer (destination_p, buffer_end_p, literal_array[i]);
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, " */", 0);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "/* ", 0);
+ lit_buf_p = jerry_append_ecma_string_to_buffer (lit_buf_p, buffer_end_p, literal_array[i]);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " */", 0);
if (i < literal_count - 1)
{
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, ",", 0);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, ",", 0);
}
}
else
{
- destination_p = jerry_append_ecma_string_to_buffer (destination_p, buffer_end_p, literal_array[i]);
+ lit_buf_p = jerry_append_ecma_string_to_buffer (lit_buf_p, buffer_end_p, literal_array[i]);
}
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "\n", 0);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\n", 0);
}
if (is_c_format)
{
- destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, (const char *) "};\n", 0);
+ lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "};\n", 0);
}
JMEM_FINALIZE_LOCAL_ARRAY (literal_array);
- return destination_p <= buffer_end_p ? (size_t) (destination_p - buffer_start_p) : 0;
+ return lit_buf_p <= buffer_end_p ? (size_t) (lit_buf_p - buffer_start_p) : 0;
#else /* !JERRY_ENABLE_SNAPSHOT_SAVE */
- JERRY_UNUSED (source_p);
- JERRY_UNUSED (source_size);
- JERRY_UNUSED (is_strict);
- JERRY_UNUSED (buffer_p);
- JERRY_UNUSED (buffer_size);
+ JERRY_UNUSED (snapshot_p);
+ JERRY_UNUSED (snapshot_size);
+ JERRY_UNUSED (lit_buf_p);
+ JERRY_UNUSED (lit_buf_size);
JERRY_UNUSED (is_c_format);
return 0;
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
-} /* jerry_parse_and_save_literals */
+} /* jerry_get_literals_from_snapshot */
+
/**
* Generate snapshot function from specified source and arguments
if ((generate_snapshot_opts & ~(allowed_opts)) != 0)
{
- const char *error_message_p = "Unsupported generate snapshot flags specified.";
+ const char * const error_message_p = "Unsupported generate snapshot flags specified.";
return jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
}
*/
#define JERRY_SNAPSHOT_MAGIC (0x5952524Au)
-/**
- * Jerry snapshot format version.
- */
-#define JERRY_SNAPSHOT_VERSION (12u)
-
/**
* Snapshot configuration flags.
*/
{
/* 8 bits are reserved for dynamic features */
JERRY_SNAPSHOT_HAS_REGEX_LITERAL = (1u << 0), /**< byte code has regex literal */
+ JERRY_SNAPSHOT_HAS_CLASS_LITERAL = (1u << 1), /**< byte code has class literal */
/* 24 bits are reserved for compile time features */
- JERRY_SNAPSHOT_FOUR_BYTE_CPOINTER = (1u << 8) /**< compressed pointers are four byte long */
+ JERRY_SNAPSHOT_FOUR_BYTE_CPOINTER = (1u << 8) /**< deprecated, an unused placeholder now */
} jerry_snapshot_global_flags_t;
#endif /* !JERRY_SNAPSHOT_H */
#include "ecma-literal-storage.h"
#include "ecma-objects.h"
#include "ecma-objects-general.h"
+#include "ecma-regexp-object.h"
#include "ecma-promise-object.h"
#include "ecma-typedarray-object.h"
#include "jcontext.h"
#include "jerryscript.h"
+#include "jerryscript-debugger-transport.h"
#include "jmem.h"
#include "js-parser.h"
#include "re-compiler.h"
&& (int) ECMA_INIT_MEM_STATS == (int) JERRY_INIT_MEM_STATS,
ecma_init_flag_t_must_be_equal_to_jerry_init_flag_t);
+#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
+JERRY_STATIC_ASSERT ((int) RE_FLAG_GLOBAL == (int) JERRY_REGEXP_FLAG_GLOBAL
+ && (int) RE_FLAG_MULTILINE == (int) JERRY_REGEXP_FLAG_MULTILINE
+ && (int) RE_FLAG_IGNORE_CASE == (int) JERRY_REGEXP_FLAG_IGNORE_CASE,
+ re_flags_t_must_be_equal_to_jerry_regexp_flags_t);
+#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */
+
#if defined JERRY_DISABLE_JS_PARSER && !defined JERRY_ENABLE_SNAPSHOT_EXEC
#error JERRY_ENABLE_SNAPSHOT_EXEC must be defined if JERRY_DISABLE_JS_PARSER is defined!
#endif /* JERRY_DISABLE_JS_PARSER && !JERRY_ENABLE_SNAPSHOT_EXEC */
* - before jerry_init and after jerry_cleanup
* - between enter to and return from a native free callback
*/
-static inline void __attr_always_inline___
+static inline void JERRY_ATTR_ALWAYS_INLINE
jerry_assert_api_available (void)
{
- if (unlikely (!(JERRY_CONTEXT (status_flags) & ECMA_STATUS_API_AVAILABLE)))
- {
- /* Terminates the execution. */
- JERRY_UNREACHABLE ();
- }
+ JERRY_ASSERT (JERRY_CONTEXT (status_flags) & ECMA_STATUS_API_AVAILABLE);
} /* jerry_assert_api_available */
/**
* Turn on API availability
*/
-static inline void __attr_always_inline___
+static inline void JERRY_ATTR_ALWAYS_INLINE
jerry_make_api_available (void)
{
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_API_AVAILABLE;
/**
* Turn off API availability
*/
-static inline void __attr_always_inline___
+static inline void JERRY_ATTR_ALWAYS_INLINE
jerry_make_api_unavailable (void)
{
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_API_AVAILABLE;
} /* jerry_make_api_unavailable */
-/**
- * Remove the error flag from the argument value.
- *
- * Note:
- * Compatiblity function, should go away with JerryScript 2.0
- *
- * @return return value for Jerry API functions
- */
-static inline jerry_value_t __attr_always_inline___
-jerry_get_arg_value (jerry_value_t value) /**< return value */
-{
- if (unlikely (ecma_is_value_error_reference (value)))
- {
- value = ecma_get_error_reference_from_value (value)->value;
- }
-
- return value;
-} /* jerry_get_arg_value */
-
/**
* Create an API compatible return value.
*
*
* @return return value for Jerry API functions
*/
-static inline jerry_value_t __attr_always_inline___
+static inline jerry_value_t JERRY_ATTR_ALWAYS_INLINE
jerry_throw (jerry_value_t value) /**< return value */
{
JERRY_ASSERT (ECMA_IS_VALUE_ERROR (value));
void
jerry_init (jerry_init_flag_t flags) /**< combination of Jerry flags */
{
- if (unlikely (JERRY_CONTEXT (status_flags) & ECMA_STATUS_API_AVAILABLE))
- {
- /* This function cannot be called twice unless jerry_cleanup is called. */
- JERRY_UNREACHABLE ();
- }
+ /* This function cannot be called twice unless jerry_cleanup is called. */
+ JERRY_ASSERT (!(JERRY_CONTEXT (status_flags) & ECMA_STATUS_API_AVAILABLE));
- /* Zero out all members. */
- memset (&JERRY_CONTEXT (JERRY_CONTEXT_FIRST_MEMBER), 0, sizeof (jerry_context_t));
+ /* Zero out all non-external members. */
+ memset (&JERRY_CONTEXT (JERRY_CONTEXT_FIRST_MEMBER), 0,
+ sizeof (jerry_context_t) - offsetof (jerry_context_t, JERRY_CONTEXT_FIRST_MEMBER));
JERRY_CONTEXT (jerry_init_flags) = flags;
#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
}
#endif /* JERRY_DEBUGGER */
* Register external magic string array
*/
void
-jerry_register_magic_strings (const jerry_char_ptr_t *ex_str_items_p, /**< character arrays, representing
- * external magic strings' contents */
+jerry_register_magic_strings (const jerry_char_t * const *ex_str_items_p, /**< character arrays, representing
+ * external magic strings' contents */
uint32_t count, /**< number of the strings */
const jerry_length_t *str_lengths_p) /**< lengths of all strings */
{
jerry_assert_api_available ();
- lit_magic_strings_ex_set ((const lit_utf8_byte_t **) ex_str_items_p, count, (const lit_utf8_size_t *) str_lengths_p);
+ lit_magic_strings_ex_set ((const lit_utf8_byte_t * const *) ex_str_items_p,
+ count,
+ (const lit_utf8_size_t *) str_lengths_p);
} /* jerry_register_magic_strings */
-/**
- * Get Jerry configured memory limits
- */
-void
-jerry_get_memory_limits (size_t *out_data_bss_brk_limit_p, /**< [out] Jerry's maximum usage of
- * data + bss + brk sections */
- size_t *out_stack_limit_p) /**< [out] Jerry's maximum usage of stack */
-{
- *out_data_bss_brk_limit_p = CONFIG_MEM_HEAP_AREA_SIZE + CONFIG_MEM_DATA_LIMIT_MINUS_HEAP_SIZE;
- *out_stack_limit_p = CONFIG_MEM_STACK_LIMIT;
-} /* jerry_get_memory_limits */
-
/**
* Run garbage collection
*/
void
-jerry_gc (void)
+jerry_gc (jerry_gc_mode_t mode) /**< operational mode */
{
jerry_assert_api_available ();
- ecma_gc_run (JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW);
+ ecma_gc_run (mode == JERRY_GC_SEVERITY_LOW ? JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW
+ : JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH);
} /* jerry_gc */
/**
0,
source_p,
source_size,
- (parse_opts & JERRY_PARSE_STRICT_MODE) != 0,
+ parse_opts,
&bytecode_data_p);
if (ECMA_IS_VALUE_ERROR (parse_status))
arg_list_size,
source_p,
source_size,
- (parse_opts & JERRY_PARSE_STRICT_MODE) != 0,
+ parse_opts,
&bytecode_data_p);
if (ECMA_IS_VALUE_ERROR (parse_status))
jerry_value_t
jerry_eval (const jerry_char_t *source_p, /**< source code */
size_t source_size, /**< length of source code */
- bool is_strict) /**< source must conform with strict mode */
+ uint32_t parse_opts) /**< jerry_parse_opts_t option bits */
{
jerry_assert_api_available ();
return jerry_return (ecma_op_eval_chars_buffer ((const lit_utf8_byte_t *) source_p,
source_size,
- false,
- is_strict));
+ parse_opts));
} /* jerry_eval */
/**
jerry_get_global_object (void)
{
jerry_assert_api_available ();
-
- return ecma_make_object_value (ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL));
+ ecma_object_t *global_obj_p = ecma_builtin_get_global ();
+ ecma_ref_object (global_obj_p);
+ return ecma_make_object_value (global_obj_p);
} /* jerry_get_global_object */
+/**
+ * Check if the specified value is an abort value.
+ *
+ * @return true - if both the error and abort values are set,
+ * false - otherwise
+ */
+bool
+jerry_value_is_abort (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_is_abort */
+
/**
* Check if the specified value is an array object value.
*
{
jerry_assert_api_available ();
- jerry_value_t array = jerry_get_arg_value (value);
- return (ecma_is_value_object (array)
- && ecma_get_object_type (ecma_get_object_from_value (array)) == ECMA_OBJECT_TYPE_ARRAY);
+ return (ecma_is_value_object (value)
+ && ecma_get_object_type (ecma_get_object_from_value (value)) == ECMA_OBJECT_TYPE_ARRAY);
} /* jerry_value_is_array */
/**
{
jerry_assert_api_available ();
- return ecma_is_value_boolean (jerry_get_arg_value (value));
+ return ecma_is_value_boolean (value);
} /* jerry_value_is_boolean */
/**
{
jerry_assert_api_available ();
- return ecma_is_constructor (jerry_get_arg_value (value));
+ return ecma_is_constructor (value);
} /* jerry_value_is_constructor */
+/**
+ * Check if the specified value is an error or abort value.
+ *
+ * @return true - if the specified value is an error value,
+ * false - otherwise
+ */
+bool
+jerry_value_is_error (const jerry_value_t value) /**< api value */
+{
+ jerry_assert_api_available ();
+
+ return ecma_is_value_error_reference (value);
+} /* jerry_value_is_error */
+
/**
* Check if the specified value is a function object value.
*
{
jerry_assert_api_available ();
- return ecma_op_is_callable (jerry_get_arg_value (value));
+ return ecma_op_is_callable (value);
} /* jerry_value_is_function */
/**
{
jerry_assert_api_available ();
- return ecma_is_value_number (jerry_get_arg_value (value));
+ return ecma_is_value_number (value);
} /* jerry_value_is_number */
/**
{
jerry_assert_api_available ();
- return ecma_is_value_null (jerry_get_arg_value (value));
+ return ecma_is_value_null (value);
} /* jerry_value_is_null */
/**
{
jerry_assert_api_available ();
- return ecma_is_value_object (jerry_get_arg_value (value));
+ return ecma_is_value_object (value);
} /* jerry_value_is_object */
/**
{
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
- jerry_value_t promise = jerry_get_arg_value (value);
- return (ecma_is_value_object (promise)
- && ecma_is_promise (ecma_get_object_from_value (promise)));
+ return (ecma_is_value_object (value)
+ && ecma_is_promise (ecma_get_object_from_value (value)));
#else /* CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */
JERRY_UNUSED (value);
return false;
{
jerry_assert_api_available ();
- return ecma_is_value_string (jerry_get_arg_value (value));
+ return ecma_is_value_string (value);
} /* jerry_value_is_string */
/**
{
jerry_assert_api_available ();
- return ecma_is_value_undefined (jerry_get_arg_value (value));
+ return ecma_is_value_undefined (value);
} /* jerry_value_is_undefined */
/**
{
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);
+ if (ecma_is_value_error_reference (value))
+ {
+ return JERRY_TYPE_ERROR;
+ }
+
+ lit_magic_string_id_t lit_id = ecma_get_typeof_lit_id (value);
JERRY_ASSERT (lit_id != LIT_MAGIC_STRING__EMPTY);
{
return JERRY_TYPE_FUNCTION;
}
- case LIT_MAGIC_STRING_OBJECT:
+ default:
{
+ JERRY_ASSERT (lit_id == 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 ecma_is_value_null (value) ? JERRY_TYPE_NULL : JERRY_TYPE_OBJECT;
}
}
-
- return JERRY_TYPE_NONE;
} /* jerry_value_get_type */
/**
* @return true - if the specified feature is enabled,
* false - otherwise
*/
-bool jerry_is_feature_enabled (const jerry_feature_t feature)
+bool
+jerry_is_feature_enabled (const jerry_feature_t feature) /**< feature to check */
{
JERRY_ASSERT (feature < JERRY_FEATURE__COUNT);
#ifdef JERRY_ENABLE_LINE_INFO
|| feature == JERRY_FEATURE_LINE_INFO
#endif /* JERRY_ENABLE_LINE_INFO */
+#ifdef JERRY_ENABLE_LOGGING
+ || feature == JERRY_FEATURE_LOGGING
+#endif /* JERRY_ENABLE_LOGGING */
);
} /* jerry_is_feature_enabled */
/**
- * Check if the specified value is an error or abort value.
+ * Create abort from an api value.
*
- * @return true - if the error flag of the specified value is true,
- * false - otherwise
- */
-bool
-jerry_value_has_error_flag (const jerry_value_t value) /**< api value */
-{
- jerry_assert_api_available ();
-
- return ecma_is_value_error_reference (value);
-} /* jerry_value_has_error_flag */
-
-/**
- * Check if the specified value is an abort value.
+ * Create abort value from an api value. If the second argument is true
+ * it will release the input api value.
*
- * @return true - if both the error and abort flags of the specified value are true,
- * false - otherwise
+ * @return api abort value
*/
-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
- */
-void
-jerry_value_clear_error_flag (jerry_value_t *value_p)
-{
- jerry_assert_api_available ();
-
- if (ecma_is_value_error_reference (*value_p))
- {
- *value_p = ecma_clear_error_reference (*value_p, false);
- }
-} /* jerry_value_clear_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_value_t
+jerry_create_abort_from_value (jerry_value_t value, /**< api value */
+ bool release) /**< release api value */
{
jerry_assert_api_available ();
- if (unlikely (ecma_is_value_error_reference (*value_p)))
+ if (JERRY_UNLIKELY (ecma_is_value_error_reference (value)))
{
/* This is a rare case so it is optimized for
* binary size rather than performance. */
- if (!jerry_value_has_abort_flag (*value_p))
+ if (jerry_value_is_abort (value))
{
- return;
+ return release ? value : jerry_acquire_value (value);
}
- jerry_value_clear_error_flag (value_p);
+ value = jerry_get_value_from_error (value, release);
+ release = true;
+ }
+
+ if (!release)
+ {
+ value = ecma_copy_value (value);
}
- *value_p = ecma_create_error_reference (*value_p, true);
-} /* jerry_value_set_error_flag */
+ return ecma_create_error_reference (value, false);
+} /* jerry_create_abort_from_value */
/**
- * Set both the abort and error flags if the value is not an error reference.
+ * Create error from an api value.
+ *
+ * Create error value from an api value. If the second argument is true
+ * it will release the input api value.
+ *
+ * @return api error value
*/
-void
-jerry_value_set_abort_flag (jerry_value_t *value_p)
+jerry_value_t
+jerry_create_error_from_value (jerry_value_t value, /**< api value */
+ bool release) /**< release api value */
{
jerry_assert_api_available ();
- if (unlikely (ecma_is_value_error_reference (*value_p)))
+ if (JERRY_UNLIKELY (ecma_is_value_error_reference (value)))
{
/* This is a rare case so it is optimized for
* binary size rather than performance. */
- if (jerry_value_has_abort_flag (*value_p))
+ if (!jerry_value_is_abort (value))
{
- return;
+ return release ? value : jerry_acquire_value (value);
}
- jerry_value_clear_error_flag (value_p);
+ value = jerry_get_value_from_error (value, release);
+ release = true;
+ }
+
+ if (!release)
+ {
+ value = ecma_copy_value (value);
}
- *value_p = ecma_create_error_reference (*value_p, false);
-} /* jerry_value_set_abort_flag */
+ return ecma_create_error_reference (value, true);
+} /* jerry_create_error_from_value */
/**
- * 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.
+ * Get the value from an error value.
+ *
+ * Extract the api value from an error. If the second argument is true
+ * it will release the input error value.
*
* Note:
* returned value must be freed with jerry_release_value, when it is no longer needed.
*
- * @return the real value of the jerry_value
+ * @return jerry_value_t value
*/
-jerry_value_t jerry_get_value_without_error_flag (jerry_value_t value) /**< api value */
+jerry_value_t
+jerry_get_value_from_error (jerry_value_t value, /**< api value */
+ bool release) /**< release api value */
{
- return jerry_acquire_value (jerry_get_arg_value (value));
-} /* jerry_get_value_without_error_flag */
+ jerry_assert_api_available ();
+
+ if (!ecma_is_value_error_reference (value))
+ {
+ return release ? value : ecma_copy_value (value);
+ }
+
+ jerry_value_t ret_val = jerry_acquire_value (ecma_get_error_reference_from_value (value)->value);
+
+ if (release)
+ {
+ jerry_release_value (value);
+ }
+ return ret_val;
+} /* jerry_get_value_from_error */
/**
* Return the type of the Error object if possible.
* 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_get_error_type (jerry_value_t value) /**< api value */
{
- jerry_value_t object = jerry_get_arg_value (value);
+ if (JERRY_UNLIKELY (ecma_is_value_error_reference (value)))
+ {
+ value = ecma_get_error_reference_from_value (value)->value;
+ }
- if (!ecma_is_value_object (object))
+ if (!ecma_is_value_object (value))
{
return JERRY_ERROR_NONE;
}
- ecma_object_t *object_p = ecma_get_object_from_value (object);
+ ecma_object_t *object_p = ecma_get_object_from_value (value);
ecma_standard_error_t error_type = ecma_get_error_type (object_p);
return (jerry_error_t) error_type;
{
jerry_assert_api_available ();
- jerry_value_t boolean = jerry_get_arg_value (value);
-
- if (!ecma_is_value_boolean (boolean))
- {
- return false;
- }
-
- return ecma_is_value_true (boolean);
+ return ecma_is_value_true (value);
} /* jerry_get_boolean_value */
/**
{
jerry_assert_api_available ();
- jerry_value_t number = jerry_get_arg_value (value);
-
- if (!ecma_is_value_number (number))
+ if (!ecma_is_value_number (value))
{
return 0;
}
- return (double) ecma_get_number_from_value (number);
+ return (double) ecma_get_number_from_value (value);
} /* jerry_get_number_value */
/**
{
jerry_assert_api_available ();
- if (unlikely (ecma_is_value_error_reference (value)))
+ if (JERRY_UNLIKELY (ecma_is_value_error_reference (value)))
{
ecma_ref_error_reference (ecma_get_error_reference_from_value (value));
return value;
{
jerry_assert_api_available ();
- if (unlikely (ecma_is_value_error_reference (value)))
+ if (JERRY_UNLIKELY (ecma_is_value_error_reference (value)))
{
ecma_deref_error_reference (ecma_get_error_reference_from_value (value));
return;
return ecma_make_string_value (ecma_str_p);
} /* jerry_create_string_sz */
+/**
+ * Calculates the size of the given pattern and creates a RegExp object.
+ *
+ * @return value of the constructed RegExp object.
+ */
+jerry_value_t
+jerry_create_regexp (const jerry_char_t *pattern_p, /**< zero-terminated UTF-8 string as RegExp pattern */
+ jerry_regexp_flags_t flags) /**< optional RegExp flags */
+{
+ return jerry_create_regexp_sz (pattern_p, lit_zt_utf8_string_size (pattern_p), flags);
+} /* jerry_create_regexp */
+
+/**
+ * Creates a RegExp object with the given pattern and flags.
+ *
+ * @return value of the constructed RegExp object.
+ */
+jerry_value_t
+jerry_create_regexp_sz (const jerry_char_t *pattern_p, /**< zero-terminated UTF-8 string as RegExp pattern */
+ jerry_size_t pattern_size, /**< length of the pattern */
+ jerry_regexp_flags_t flags) /**< optional RegExp flags */
+{
+ jerry_assert_api_available ();
+
+#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
+ if (!lit_is_valid_utf8_string (pattern_p, pattern_size))
+ {
+ return jerry_throw (ecma_raise_common_error (ECMA_ERR_MSG ("Input must be a valid utf8 string")));
+ }
+
+ ecma_string_t *ecma_pattern = ecma_new_ecma_string_from_utf8 (pattern_p, pattern_size);
+
+ jerry_value_t ret_val = ecma_op_create_regexp_object (ecma_pattern, flags);
+
+ ecma_deref_ecma_string (ecma_pattern);
+ return ret_val;
+
+#else /* CONFIG_DISABLE_REGEXP_BUILTIN */
+ JERRY_UNUSED (pattern_p);
+ JERRY_UNUSED (pattern_size);
+ JERRY_UNUSED (flags);
+
+ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("RegExp is not supported.")));
+#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */
+} /* jerry_create_regexp_sz */
+
/**
* Get length of an array object
*
* @return length of the given array
*/
uint32_t
-jerry_get_array_length (const jerry_value_t value)
+jerry_get_array_length (const jerry_value_t value) /**< api value */
{
jerry_assert_api_available ();
- jerry_value_t array = jerry_get_arg_value (value);
-
- if (!jerry_value_is_array (array))
+ if (!jerry_value_is_array (value))
{
return 0;
}
- ecma_value_t len_value = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (array),
+ ecma_value_t len_value = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (value),
LIT_MAGIC_STRING_LENGTH);
jerry_length_t length = ecma_number_to_uint32 (ecma_get_number_from_value (len_value));
{
jerry_assert_api_available ();
- jerry_value_t string = jerry_get_arg_value (value);
-
- if (!ecma_is_value_string (string))
+ if (!ecma_is_value_string (value))
{
return 0;
}
- return ecma_string_get_size (ecma_get_string_from_value (string));
+ return ecma_string_get_size (ecma_get_string_from_value (value));
} /* jerry_get_string_size */
/**
* @return number of bytes in the buffer needed to represent the UTF-8 encoded string
*/
jerry_size_t
-jerry_get_utf8_string_size (const jerry_value_t value)
+jerry_get_utf8_string_size (const jerry_value_t value) /**< input string */
{
jerry_assert_api_available ();
- jerry_value_t string = jerry_get_arg_value (value);
-
- if (!ecma_is_value_string (string))
+ if (!ecma_is_value_string (value))
{
return 0;
}
- return ecma_string_get_utf8_size (ecma_get_string_from_value (string));
+ return ecma_string_get_utf8_size (ecma_get_string_from_value (value));
} /* jerry_get_utf8_string_size */
/**
{
jerry_assert_api_available ();
- jerry_value_t string = jerry_get_arg_value (value);
-
- if (!ecma_is_value_string (string))
+ if (!ecma_is_value_string (value))
{
return 0;
}
- return ecma_string_get_length (ecma_get_string_from_value (string));
+ return ecma_string_get_length (ecma_get_string_from_value (value));
} /* jerry_get_string_length */
/**
{
jerry_assert_api_available ();
- jerry_value_t string = jerry_get_arg_value (value);
-
- if (!ecma_is_value_string (string))
+ if (!ecma_is_value_string (value))
{
return 0;
}
- return ecma_string_get_utf8_length (ecma_get_string_from_value (string));
+ return ecma_string_get_utf8_length (ecma_get_string_from_value (value));
} /* jerry_get_utf8_string_length */
/**
{
jerry_assert_api_available ();
- jerry_value_t string = jerry_get_arg_value (value);
-
- if (!ecma_is_value_string (string) || buffer_p == NULL)
+ if (!ecma_is_value_string (value) || buffer_p == NULL)
{
return 0;
}
- ecma_string_t *str_p = ecma_get_string_from_value (string);
+ ecma_string_t *str_p = ecma_get_string_from_value (value);
if (ecma_string_get_size (str_p) > buffer_size)
{
{
jerry_assert_api_available ();
- jerry_value_t string = jerry_get_arg_value (value);
-
- if (!ecma_is_value_string (string) || buffer_p == NULL)
+ if (!ecma_is_value_string (value) || buffer_p == NULL)
{
return 0;
}
- ecma_string_t *str_p = ecma_get_string_from_value (string);
+ ecma_string_t *str_p = ecma_get_string_from_value (value);
if (ecma_string_get_utf8_size (str_p) > buffer_size)
{
{
jerry_assert_api_available ();
- jerry_value_t string = jerry_get_arg_value (value);
-
- if (!ecma_is_value_string (string) || buffer_p == NULL)
+ if (!ecma_is_value_string (value) || buffer_p == NULL)
{
return 0;
}
- ecma_string_t *str_p = ecma_get_string_from_value (string);
+ ecma_string_t *str_p = ecma_get_string_from_value (value);
return ecma_substring_copy_to_cesu8_buffer (str_p,
start_pos,
{
jerry_assert_api_available ();
- jerry_value_t string = jerry_get_arg_value (value);
-
- if (!ecma_is_value_string (string) || buffer_p == NULL)
+ if (!ecma_is_value_string (value) || buffer_p == NULL)
{
return 0;
}
- ecma_string_t *str_p = ecma_get_string_from_value (string);
+ ecma_string_t *str_p = ecma_get_string_from_value (value);
return ecma_substring_copy_to_utf8_buffer (str_p,
start_pos,
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
- jerry_value_t prop_name_value = jerry_get_arg_value (prop_name_val);
-
- if (!ecma_is_value_object (obj_value)
- || !ecma_is_value_string (prop_name_value))
+ if (!ecma_is_value_object (obj_val)
+ || !ecma_is_value_string (prop_name_val))
{
- return ecma_make_boolean_value (false);
+ return ECMA_VALUE_FALSE;
}
- bool has_property = ecma_op_object_has_property (ecma_get_object_from_value (obj_value),
- ecma_get_string_from_value (prop_name_value));
+ bool has_property = ecma_op_object_has_property (ecma_get_object_from_value (obj_val),
+ ecma_get_string_from_value (prop_name_val));
return ecma_make_boolean_value (has_property);
} /* jerry_has_property */
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
- jerry_value_t prop_name_value = jerry_get_arg_value (prop_name_val);
-
- if (!ecma_is_value_object (obj_value)
- || !ecma_is_value_string (prop_name_value))
+ if (!ecma_is_value_object (obj_val)
+ || !ecma_is_value_string (prop_name_val))
{
- return ecma_make_boolean_value (false);
+ return ECMA_VALUE_FALSE;
}
- bool has_property = ecma_op_object_has_own_property (ecma_get_object_from_value (obj_value),
- ecma_get_string_from_value (prop_name_value));
+ bool has_property = ecma_op_object_has_own_property (ecma_get_object_from_value (obj_val),
+ ecma_get_string_from_value (prop_name_val));
return ecma_make_boolean_value (has_property);
} /* jerry_has_own_property */
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
- jerry_value_t prop_name_value = jerry_get_arg_value (prop_name_val);
-
- if (!ecma_is_value_object (obj_value)
- || !ecma_is_value_string (prop_name_value))
+ if (!ecma_is_value_object (obj_val)
+ || !ecma_is_value_string (prop_name_val))
{
return false;
}
- ecma_value_t ret_value = ecma_op_object_delete (ecma_get_object_from_value (obj_value),
- ecma_get_string_from_value (prop_name_value),
+ ecma_value_t ret_value = ecma_op_object_delete (ecma_get_object_from_value (obj_val),
+ ecma_get_string_from_value (prop_name_val),
false);
return ecma_is_value_true (ret_value);
} /* jerry_delete_property */
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
-
- if (!ecma_is_value_object (obj_value))
+ if (!ecma_is_value_object (obj_val))
{
return false;
}
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),
+ ecma_value_t ret_value = ecma_op_object_delete (ecma_get_object_from_value (obj_val),
str_idx_p,
false);
ecma_deref_ecma_string (str_idx_p);
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
- jerry_value_t prop_name_value = jerry_get_arg_value (prop_name_val);
-
- if (!ecma_is_value_object (obj_value)
- || !ecma_is_value_string (prop_name_value))
+ if (!ecma_is_value_object (obj_val)
+ || !ecma_is_value_string (prop_name_val))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
}
- jerry_value_t ret_value = ecma_op_object_get (ecma_get_object_from_value (obj_value),
- ecma_get_string_from_value (prop_name_value));
+ jerry_value_t ret_value = ecma_op_object_get (ecma_get_object_from_value (obj_val),
+ ecma_get_string_from_value (prop_name_val));
return jerry_return (ret_value);
} /* jerry_get_property */
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
-
- if (!ecma_is_value_object (obj_value))
+ if (!ecma_is_value_object (obj_val))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
}
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_value_t ret_value = ecma_op_object_get (ecma_get_object_from_value (obj_val), str_idx_p);
ecma_deref_ecma_string (str_idx_p);
return jerry_return (ret_value);
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
- jerry_value_t prop_name_value = jerry_get_arg_value (prop_name_val);
-
if (ecma_is_value_error_reference (value_to_set)
- || !ecma_is_value_object (obj_value)
- || !ecma_is_value_string (prop_name_value))
+ || !ecma_is_value_object (obj_val)
+ || !ecma_is_value_string (prop_name_val))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
}
- return jerry_return (ecma_op_object_put (ecma_get_object_from_value (obj_value),
- ecma_get_string_from_value (prop_name_value),
+ return jerry_return (ecma_op_object_put (ecma_get_object_from_value (obj_val),
+ ecma_get_string_from_value (prop_name_val),
value_to_set,
true));
} /* jerry_set_property */
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
-
if (ecma_is_value_error_reference (value_to_set)
- || !ecma_is_value_object (obj_value))
+ || !ecma_is_value_object (obj_val))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
}
ecma_string_t *str_idx_p = ecma_new_ecma_string_from_uint32 ((uint32_t) index);
- ecma_value_t ret_value = ecma_op_object_put (ecma_get_object_from_value (obj_value),
+ ecma_value_t ret_value = ecma_op_object_put (ecma_get_object_from_value (obj_val),
str_idx_p,
value_to_set,
true);
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
- jerry_value_t prop_name_value = jerry_get_arg_value (prop_name_val);
-
- if (!ecma_is_value_object (obj_value)
- || !ecma_is_value_string (prop_name_value))
+ if (!ecma_is_value_object (obj_val)
+ || !ecma_is_value_string (prop_name_val))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
}
}
}
- return ecma_op_object_define_own_property (ecma_get_object_from_value (obj_value),
- ecma_get_string_from_value (prop_name_value),
+ return ecma_op_object_define_own_property (ecma_get_object_from_value (obj_val),
+ ecma_get_string_from_value (prop_name_val),
&prop_desc,
true);
} /* jerry_define_own_property */
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
- jerry_value_t prop_name_value = jerry_get_arg_value (prop_name_val);
-
- if (!ecma_is_value_object (obj_value)
- || !ecma_is_value_string (prop_name_value))
+ if (!ecma_is_value_object (obj_val)
+ || !ecma_is_value_string (prop_name_val))
{
return false;
}
ecma_property_descriptor_t prop_desc;
- if (!ecma_op_object_get_own_property_descriptor (ecma_get_object_from_value (obj_value),
- ecma_get_string_from_value (prop_name_value),
+ if (!ecma_op_object_get_own_property_descriptor (ecma_get_object_from_value (obj_val),
+ ecma_get_string_from_value (prop_name_val),
&prop_desc))
{
return false;
JERRY_ASSERT (jerry_value_is_constructor (func_obj_val));
return jerry_return (ecma_op_function_construct (ecma_get_object_from_value (func_obj_val),
+ ECMA_VALUE_UNDEFINED,
args_p,
args_count));
}
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
-
- if (!ecma_is_value_object (obj_value))
+ if (!ecma_is_value_object (obj_val))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
}
- return ecma_builtin_helper_object_get_properties (ecma_get_object_from_value (obj_value), true);
+ return ecma_builtin_helper_object_get_properties (ecma_get_object_from_value (obj_val), true);
} /* jerry_get_object_keys */
/**
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
-
- if (!ecma_is_value_object (obj_value))
+ if (!ecma_is_value_object (obj_val))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
}
- ecma_object_t *proto_obj_p = ecma_get_object_prototype (ecma_get_object_from_value (obj_value));
+ ecma_object_t *proto_obj_p = ecma_get_object_prototype (ecma_get_object_from_value (obj_val));
if (proto_obj_p == NULL)
{
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
-
- if (!ecma_is_value_object (obj_value)
+ if (!ecma_is_value_object (obj_val)
|| ecma_is_value_error_reference (proto_obj_val)
|| (!ecma_is_value_object (proto_obj_val) && !ecma_is_value_null (proto_obj_val)))
{
if (ecma_is_value_null (proto_obj_val))
{
- ECMA_SET_POINTER (ecma_get_object_from_value (obj_value)->prototype_or_outer_reference_cp, NULL);
+ ECMA_SET_POINTER (ecma_get_object_from_value (obj_val)->prototype_or_outer_reference_cp, NULL);
}
else
{
- ECMA_SET_POINTER (ecma_get_object_from_value (obj_value)->prototype_or_outer_reference_cp,
+ ECMA_SET_POINTER (ecma_get_object_from_value (obj_val)->prototype_or_outer_reference_cp,
ecma_get_object_from_value (proto_obj_val));
}
return ECMA_VALUE_TRUE;
} /* jerry_set_prototype */
-/**
- * Get native handle, associated with specified object.
- *
- * Note: This API is deprecated, please use jerry_get_object_native_pointer instaed.
- *
- * @return true - if there is an associated handle (handle is returned through out_handle_p),
- * false - otherwise
- */
-bool
-jerry_get_object_native_handle (const jerry_value_t obj_val, /**< object to get handle from */
- uintptr_t *out_handle_p) /**< [out] handle value */
-{
- jerry_assert_api_available ();
-
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
-
- if (!ecma_is_value_object (obj_value))
- {
- return false;
- }
-
- ecma_native_pointer_t *native_pointer_p;
- native_pointer_p = ecma_get_native_pointer_value (ecma_get_object_from_value (obj_value),
- LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE);
-
- if (native_pointer_p == NULL)
- {
- return false;
- }
-
- *out_handle_p = (uintptr_t) native_pointer_p->data_p;
- return true;
-} /* jerry_get_object_native_handle */
-
-/**
- * Set native handle and an optional free callback for the specified object.
- *
- * Note: This API is deprecated, please use jerry_set_object_native_pointer instaed.
- *
- * Note:
- * If native handle was already set for the object, its value is updated.
- *
- * Note:
- * If a non-NULL free callback is specified, it will be called
- * by the garbage collector when the object is freed. The free
- * callback always overwrites the previous value, so passing
- * a NULL value deletes the current free callback.
- */
-void
-jerry_set_object_native_handle (const jerry_value_t obj_val, /**< object to set handle in */
- uintptr_t handle_p, /**< handle value */
- jerry_object_free_callback_t freecb_p) /**< object free callback or NULL */
-{
- jerry_assert_api_available ();
-
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
-
- if (ecma_is_value_object (obj_value))
- {
- ecma_object_t *object_p = ecma_get_object_from_value (obj_value);
-
- ecma_create_native_handle_property (object_p,
- (void *) handle_p,
- (void *) (ecma_external_pointer_t) freecb_p);
- }
-} /* 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)
+bool
+jerry_objects_foreach (jerry_objects_foreach_t foreach_p, /**< function pointer of the iterator function */
+ void *user_data_p) /**< pointer to user data */
{
jerry_assert_api_available ();
* 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_objects_foreach_by_native_info (const jerry_object_native_info_t *native_info_p, /**< the type info
+ * of the native pointer */
+ jerry_objects_foreach_by_native_info_t foreach_p, /**< function to apply for
+ * each matching object */
+ void *user_data_p) /**< pointer to user data */
{
jerry_assert_api_available ();
{
if (!ecma_is_lexical_environment (iter_p))
{
- native_pointer_p = ecma_get_native_pointer_value (iter_p, LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
+ native_pointer_p = ecma_get_native_pointer_value (iter_p);
if (native_pointer_p
- && ((const jerry_object_native_info_t *) native_pointer_p->u.info_p) == native_info_p
+ && ((const jerry_object_native_info_t *) native_pointer_p->info_p) == native_info_p
&& !foreach_p (ecma_make_object_value (iter_p), native_pointer_p->data_p, user_data_p))
{
return true;
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
-
- if (!ecma_is_value_object (obj_value))
+ if (!ecma_is_value_object (obj_val))
{
return false;
}
ecma_native_pointer_t *native_pointer_p;
- native_pointer_p = ecma_get_native_pointer_value (ecma_get_object_from_value (obj_value),
- LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
+ native_pointer_p = ecma_get_native_pointer_value (ecma_get_object_from_value (obj_val));
if (native_pointer_p == NULL)
{
if (out_native_info_p != NULL)
{
- *out_native_info_p = (const jerry_object_native_info_t *) native_pointer_p->u.info_p;
+ *out_native_info_p = (const jerry_object_native_info_t *) native_pointer_p->info_p;
}
return true;
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
-
- if (ecma_is_value_object (obj_value))
+ if (ecma_is_value_object (obj_val))
{
- ecma_object_t *object_p = ecma_get_object_from_value (obj_value);
+ ecma_object_t *object_p = ecma_get_object_from_value (obj_val);
ecma_create_native_pointer_property (object_p, native_pointer_p, (void *) native_info_p);
}
{
jerry_assert_api_available ();
- jerry_value_t obj_value = jerry_get_arg_value (obj_val);
-
- if (!ecma_is_value_object (obj_value))
+ if (!ecma_is_value_object (obj_val))
{
return false;
}
- 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_object_t *object_p = ecma_get_object_from_value (obj_val);
+ ecma_collection_header_t *names_p = ecma_op_object_get_property_names (object_p, ECMA_LIST_ENUMERABLE_PROTOTYPE);
ecma_value_t *ecma_value_p = ecma_collection_iterator_init (names_p);
ecma_value_t property_value = ECMA_VALUE_EMPTY;
(lit_utf8_size_t) buf_size);
} /* jerry_is_valid_cesu8_string */
-/*
- * Create a jerry instance for external context.
+/**
+ * Allocate memory on the engine's heap.
*
- * @return the pointer to the instance.
+ * Note:
+ * This function may take away memory from the executed JavaScript code.
+ * If any other dynamic memory allocation API is available (e.g., libc
+ * malloc), it should be used instead.
+ *
+ * @return allocated memory on success
+ * NULL otherwise
+ */
+void *
+jerry_heap_alloc (size_t size) /**< size of the memory block */
+{
+ jerry_assert_api_available ();
+
+ return jmem_heap_alloc_block_null_on_error (size);
+} /* jerry_heap_alloc */
+
+/**
+ * Free memory allocated on the engine's heap.
*/
-jerry_instance_t *
-jerry_create_instance (uint32_t heap_size, /**< the size of heap */
- jerry_instance_alloc_t alloc, /**< the alloc function */
- void *cb_data_p) /**< the cb_data for alloc function */
+void
+jerry_heap_free (void *mem_p, /**< value returned by jerry_heap_alloc */
+ size_t size) /**< same size as passed to jerry_heap_alloc */
+{
+ jerry_assert_api_available ();
+
+ jmem_heap_free_block (mem_p, size);
+} /* jerry_heap_free */
+
+/**
+ * Create an external engine context.
+ *
+ * @return the pointer to the context.
+ */
+jerry_context_t *
+jerry_create_context (uint32_t heap_size, /**< the size of heap */
+ jerry_context_alloc_t alloc, /**< the alloc function */
+ void *cb_data_p) /**< the cb_data for alloc function */
{
JERRY_UNUSED (heap_size);
#ifdef JERRY_ENABLE_EXTERNAL_CONTEXT
- size_t total_size = sizeof (jerry_instance_t) + JMEM_ALIGNMENT;
+ size_t total_size = sizeof (jerry_context_t) + JMEM_ALIGNMENT;
#ifndef JERRY_SYSTEM_ALLOCATOR
heap_size = JERRY_ALIGNUP (heap_size, JMEM_ALIGNMENT);
total_size += heap_size;
#endif /* !JERRY_SYSTEM_ALLOCATOR */
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
- total_size += sizeof (jerry_hash_table_t);
-#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
-
total_size = JERRY_ALIGNUP (total_size, JMEM_ALIGNMENT);
- jerry_instance_t *instance_p = (jerry_instance_t *) alloc (total_size, cb_data_p);
+ jerry_context_t *context_p = (jerry_context_t *) alloc (total_size, cb_data_p);
- if (instance_p == NULL)
+ if (context_p == NULL)
{
return NULL;
}
- memset (instance_p, 0, total_size);
+ memset (context_p, 0, total_size);
- uintptr_t instance_ptr = ((uintptr_t) instance_p) + sizeof (jerry_instance_t);
- instance_ptr = JERRY_ALIGNUP (instance_ptr, (uintptr_t) JMEM_ALIGNMENT);
+ uintptr_t context_ptr = ((uintptr_t) context_p) + sizeof (jerry_context_t);
+ context_ptr = JERRY_ALIGNUP (context_ptr, (uintptr_t) JMEM_ALIGNMENT);
- uint8_t *byte_p = (uint8_t *) instance_ptr;
+ uint8_t *byte_p = (uint8_t *) context_ptr;
#ifndef JERRY_SYSTEM_ALLOCATOR
- instance_p->heap_p = (jmem_heap_t *) byte_p;
- instance_p->heap_size = heap_size;
+ context_p->heap_p = (jmem_heap_t *) byte_p;
+ context_p->heap_size = heap_size;
byte_p += heap_size;
#endif /* !JERRY_SYSTEM_ALLOCATOR */
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
- instance_p->lcache_p = byte_p;
- byte_p += sizeof (jerry_hash_table_t);
-#endif /* !JERRY_SYSTEM_ALLOCATOR */
-
- JERRY_ASSERT (byte_p <= ((uint8_t *) instance_p) + total_size);
+ JERRY_ASSERT (byte_p <= ((uint8_t *) context_p) + total_size);
JERRY_UNUSED (byte_p);
- return instance_p;
+ return context_p;
#else /* !JERRY_ENABLE_EXTERNAL_CONTEXT */
return NULL;
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
-} /* jerry_create_instance */
+} /* jerry_create_context */
/**
* If JERRY_VM_EXEC_STOP is defined the callback passed to this function is
* @return array value
*/
jerry_value_t
-jerry_get_backtrace (uint32_t max_depth)
+jerry_get_backtrace (uint32_t max_depth) /**< depth limit of the backtrace */
{
return vm_get_backtrace (max_depth);
} /* jerry_get_backtrace */
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
- jerry_value_t buffer = jerry_get_arg_value (value);
- return ecma_is_arraybuffer (buffer);
+ return ecma_is_arraybuffer (value);
#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
JERRY_UNUSED (value);
return false;
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
- jerry_value_t buffer = jerry_get_arg_value (value);
-
- if (!ecma_is_arraybuffer (buffer))
+ if (!ecma_is_arraybuffer (value))
{
return 0;
}
- ecma_object_t *buffer_p = ecma_get_object_from_value (buffer);
+ ecma_object_t *buffer_p = ecma_get_object_from_value (value);
jerry_length_t length = ecma_arraybuffer_get_length (buffer_p);
if (offset >= length)
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
- jerry_value_t buffer = jerry_get_arg_value (value);
-
- if (!ecma_is_arraybuffer (buffer))
+ if (!ecma_is_arraybuffer (value))
{
return 0;
}
- ecma_object_t *buffer_p = ecma_get_object_from_value (buffer);
+ ecma_object_t *buffer_p = ecma_get_object_from_value (value);
jerry_length_t length = ecma_arraybuffer_get_length (buffer_p);
if (offset >= length)
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
- jerry_value_t buffer = jerry_get_arg_value (value);
- if (ecma_is_arraybuffer (buffer))
+ if (ecma_is_arraybuffer (value))
{
- ecma_object_t *buffer_p = ecma_get_object_from_value (buffer);
+ ecma_object_t *buffer_p = ecma_get_object_from_value (value);
return ecma_arraybuffer_get_length (buffer_p);
}
#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
{
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
- jerry_value_t buffer = jerry_get_arg_value (value);
-
- if (!ecma_is_arraybuffer (buffer))
+ if (!ecma_is_arraybuffer (value))
{
return NULL;
}
- ecma_object_t *buffer_p = ecma_get_object_from_value (buffer);
+ ecma_object_t *buffer_p = ecma_get_object_from_value (value);
if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (buffer_p))
{
jerry_acquire_value (value);
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
- jerry_value_t array = jerry_get_arg_value (value);
- return ecma_is_typedarray (array);
+ return ecma_is_typedarray (value);
#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
JERRY_UNUSED (value);
return false;
} /* jerry_value_is_typedarray */
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
+/**
+ * TypedArray mapping type
+ */
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_type_t api_type; /**< api type */
+ ecma_builtin_id_t prototype_id; /**< prototype ID */
+ lit_magic_string_id_t lit_id; /**< literal ID */
+ uint8_t element_size_shift; /**< element size shift */
} jerry_typedarray_mapping_t;
+/**
+ * List of TypedArray mappings
+ */
static jerry_typedarray_mapping_t jerry_typedarray_mappings[] =
{
#define TYPEDARRAY_ENTRY(NAME, LIT_NAME, SIZE_SHIFT) \
prototype_obj_p,
element_size_shift,
lit_id);
- ecma_deref_object (prototype_obj_p);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (array_value));
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))
+ if (!ecma_is_arraybuffer (arraybuffer))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an ArrayBuffer")));
}
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_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
- jerry_value_t array = jerry_get_arg_value (value);
- if (!ecma_is_typedarray (array))
+ if (!ecma_is_typedarray (value))
{
return JERRY_TYPEDARRAY_INVALID;
}
- ecma_object_t *array_p = ecma_get_object_from_value (array);
+ ecma_object_t *array_p = ecma_get_object_from_value (value);
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++)
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
- jerry_value_t array = jerry_get_arg_value (value);
- if (ecma_is_typedarray (array))
+ if (ecma_is_typedarray (value))
{
- ecma_object_t *array_p = ecma_get_object_from_value (array);
+ ecma_object_t *array_p = ecma_get_object_from_value (value);
return ecma_typedarray_get_length (array_p);
}
#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
- jerry_value_t array = jerry_get_arg_value (value);
- if (!ecma_is_typedarray (array))
+ if (!ecma_is_typedarray (value))
{
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);
+ ecma_object_t *array_p = ecma_get_object_from_value (value);
uint8_t shift = ecma_typedarray_get_element_size_shift (array_p);
if (byte_length != NULL)
* @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_json_stringify (const jerry_value_t object_to_stringify) /**< a jerry_object_t to stringify */
{
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_JSON_BUILTIN
return jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("The JSON has been disabled.")));
#endif /* !CONFIG_DISABLE_JSON_BUILTIN */
-} /* jerry_json_stringfy */
+} /* jerry_json_stringify */
/**
* @}
#ifdef CONFIG_DISABLE_ES2015
# define CONFIG_DISABLE_ES2015_ARROW_FUNCTION
# define CONFIG_DISABLE_ES2015_BUILTIN
+# define CONFIG_DISABLE_ES2015_CLASS
+# define CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
+# define CONFIG_DISABLE_ES2015_MAP_BUILTIN
+# define CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
# define CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
# define CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS
# define CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
#endif /* CONFIG_DISABLE_ES2015 */
-/**
- * Limit of data (system heap, engine's data except engine's own heap)
- */
-#define CONFIG_MEM_DATA_LIMIT_MINUS_HEAP_SIZE (1024)
-
-/**
- * Limit of stack size
- */
-#define CONFIG_MEM_STACK_LIMIT (4096)
-
/**
* Size of heap
*/
*/
#define CONFIG_ECMA_GC_NEW_OBJECTS_SHARE_TO_START_GC (16)
-/**
- * Link Global Environment to an empty declarative lexical environment
- * instead of lexical environment bound to Global Object.
- */
-// #define CONFIG_ECMA_GLOBAL_ENVIRONMENT_DECLARATIVE
-
-/**
- * Number of ecma values inlined into VM stack frame
- */
-#define CONFIG_VM_STACK_FRAME_INLINED_VALUES_NUMBER (16)
-
#endif /* !CONFIG_H */
+++ /dev/null
-/* 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.
- */
-
-/*
- * FIPS-180-1 compliant SHA-1 implementation
- *
- * 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)
- */
-
-/*
- * The SHA-1 standard was published by NIST in 1993.
- *
- * http://www.itl.nist.gov/fipspubs/fip180-1.htm
- */
-
-#include "debugger.h"
-
-#ifdef JERRY_DEBUGGER
-
-/**
- * SHA-1 context structure.
- */
-typedef struct
-{
- uint32_t total[2]; /**< number of bytes processed */
- uint32_t state[5]; /**< intermediate digest state */
- uint8_t buffer[64]; /**< data block being processed */
-} jerry_sha1_context;
-
-/* 32-bit integer manipulation macros (big endian). */
-
-#define JERRY_SHA1_GET_UINT32_BE(n, b, i) \
-{ \
- (n) = (((uint32_t) (b)[(i) + 0]) << 24) \
- | (((uint32_t) (b)[(i) + 1]) << 16) \
- | (((uint32_t) (b)[(i) + 2]) << 8) \
- | ((uint32_t) (b)[(i) + 3]); \
-}
-
-#define JERRY_SHA1_PUT_UINT32_BE(n, b, i) \
-{ \
- (b)[(i) + 0] = (uint8_t) ((n) >> 24); \
- (b)[(i) + 1] = (uint8_t) ((n) >> 16); \
- (b)[(i) + 2] = (uint8_t) ((n) >> 8); \
- (b)[(i) + 3] = (uint8_t) ((n)); \
-}
-
-/**
- * Initialize SHA-1 context.
- */
-static void
-jerry_sha1_init (jerry_sha1_context *sha1_context_p) /**< SHA-1 context */
-{
- memset (sha1_context_p, 0, sizeof (jerry_sha1_context));
-
- sha1_context_p->total[0] = 0;
- sha1_context_p->total[1] = 0;
-
- sha1_context_p->state[0] = 0x67452301;
- sha1_context_p->state[1] = 0xEFCDAB89;
- sha1_context_p->state[2] = 0x98BADCFE;
- sha1_context_p->state[3] = 0x10325476;
- sha1_context_p->state[4] = 0xC3D2E1F0;
-} /* jerry_sha1_init */
-
-#define JERRY_SHA1_P(a, b, c, d, e, x) \
-do { \
- e += JERRY_SHA1_SHIFT (a, 5) + JERRY_SHA1_F (b, c, d) + K + x; \
- b = JERRY_SHA1_SHIFT (b, 30); \
-} while (0)
-
-/**
- * Update SHA-1 internal buffer status.
- */
-static void
-jerry_sha1_process (jerry_sha1_context *sha1_context_p, /**< SHA-1 context */
- const uint8_t data[64]) /**< data buffer */
-{
- uint32_t temp, W[16], A, B, C, D, E;
-
- JERRY_SHA1_GET_UINT32_BE (W[0], data, 0);
- JERRY_SHA1_GET_UINT32_BE (W[1], data, 4);
- JERRY_SHA1_GET_UINT32_BE (W[2], data, 8);
- JERRY_SHA1_GET_UINT32_BE (W[3], data, 12);
- JERRY_SHA1_GET_UINT32_BE (W[4], data, 16);
- JERRY_SHA1_GET_UINT32_BE (W[5], data, 20);
- JERRY_SHA1_GET_UINT32_BE (W[6], data, 24);
- JERRY_SHA1_GET_UINT32_BE (W[7], data, 28);
- JERRY_SHA1_GET_UINT32_BE (W[8], data, 32);
- JERRY_SHA1_GET_UINT32_BE (W[9], data, 36);
- JERRY_SHA1_GET_UINT32_BE (W[10], data, 40);
- JERRY_SHA1_GET_UINT32_BE (W[11], data, 44);
- JERRY_SHA1_GET_UINT32_BE (W[12], data, 48);
- JERRY_SHA1_GET_UINT32_BE (W[13], data, 52);
- JERRY_SHA1_GET_UINT32_BE (W[14], data, 56);
- JERRY_SHA1_GET_UINT32_BE (W[15], data, 60);
-
-#define JERRY_SHA1_SHIFT(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
-
-#define JERRY_SHA1_R(t) \
-( \
- temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ W[t & 0x0F], \
- W[t & 0x0F] = JERRY_SHA1_SHIFT (temp, 1) \
-)
-
- A = sha1_context_p->state[0];
- B = sha1_context_p->state[1];
- C = sha1_context_p->state[2];
- D = sha1_context_p->state[3];
- E = sha1_context_p->state[4];
-
- uint32_t K = 0x5A827999;
-
-#define JERRY_SHA1_F(x, y, z) (z ^ (x & (y ^ z)))
-
- JERRY_SHA1_P (A, B, C, D, E, W[0]);
- JERRY_SHA1_P (E, A, B, C, D, W[1]);
- JERRY_SHA1_P (D, E, A, B, C, W[2]);
- JERRY_SHA1_P (C, D, E, A, B, W[3]);
- JERRY_SHA1_P (B, C, D, E, A, W[4]);
- JERRY_SHA1_P (A, B, C, D, E, W[5]);
- JERRY_SHA1_P (E, A, B, C, D, W[6]);
- JERRY_SHA1_P (D, E, A, B, C, W[7]);
- JERRY_SHA1_P (C, D, E, A, B, W[8]);
- JERRY_SHA1_P (B, C, D, E, A, W[9]);
- JERRY_SHA1_P (A, B, C, D, E, W[10]);
- JERRY_SHA1_P (E, A, B, C, D, W[11]);
- JERRY_SHA1_P (D, E, A, B, C, W[12]);
- JERRY_SHA1_P (C, D, E, A, B, W[13]);
- JERRY_SHA1_P (B, C, D, E, A, W[14]);
- JERRY_SHA1_P (A, B, C, D, E, W[15]);
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (16));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (17));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (18));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (19));
-
-#undef JERRY_SHA1_F
-
- K = 0x6ED9EBA1;
-
-#define JERRY_SHA1_F(x, y, z) (x ^ y ^ z)
-
- JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (20));
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (21));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (22));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (23));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (24));
- JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (25));
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (26));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (27));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (28));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (29));
- JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (30));
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (31));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (32));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (33));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (34));
- JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (35));
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (36));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (37));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (38));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (39));
-
-#undef JERRY_SHA1_F
-
- K = 0x8F1BBCDC;
-
-#define JERRY_SHA1_F(x, y, z) ((x & y) | (z & (x | y)))
-
- JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (40));
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (41));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (42));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (43));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (44));
- JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (45));
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (46));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (47));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (48));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (49));
- JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (50));
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (51));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (52));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (53));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (54));
- JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (55));
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (56));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (57));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (58));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (59));
-
-#undef JERRY_SHA1_F
-
- K = 0xCA62C1D6;
-
-#define JERRY_SHA1_F(x, y, z) (x ^ y ^ z)
-
- JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (60));
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (61));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (62));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (63));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (64));
- JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (65));
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (66));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (67));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (68));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (69));
- JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (70));
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (71));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (72));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (73));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (74));
- JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (75));
- JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (76));
- JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (77));
- JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (78));
- JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (79));
-
-#undef JERRY_SHA1_F
-
- sha1_context_p->state[0] += A;
- sha1_context_p->state[1] += B;
- sha1_context_p->state[2] += C;
- sha1_context_p->state[3] += D;
- sha1_context_p->state[4] += E;
-
-#undef JERRY_SHA1_SHIFT
-#undef JERRY_SHA1_R
-} /* jerry_sha1_process */
-
-#undef JERRY_SHA1_P
-
-/**
- * SHA-1 update buffer.
- */
-static void
-jerry_sha1_update (jerry_sha1_context *sha1_context_p, /**< SHA-1 context */
- const uint8_t *source_p, /**< source buffer */
- size_t source_length) /**< length of source buffer */
-{
- size_t fill;
- uint32_t left;
-
- if (source_length == 0)
- {
- return;
- }
-
- left = sha1_context_p->total[0] & 0x3F;
- fill = 64 - left;
-
- sha1_context_p->total[0] += (uint32_t) source_length;
-
- /* Check overflow. */
- if (sha1_context_p->total[0] < (uint32_t) source_length)
- {
- sha1_context_p->total[1]++;
- }
-
- if (left && source_length >= fill)
- {
- memcpy ((void *) (sha1_context_p->buffer + left), source_p, fill);
- jerry_sha1_process (sha1_context_p, sha1_context_p->buffer);
- source_p += fill;
- source_length -= fill;
- left = 0;
- }
-
- while (source_length >= 64)
- {
- jerry_sha1_process (sha1_context_p, source_p);
- source_p += 64;
- source_length -= 64;
- }
-
- if (source_length > 0)
- {
- memcpy ((void *) (sha1_context_p->buffer + left), source_p, source_length);
- }
-} /* jerry_sha1_update */
-
-/**
- * SHA-1 final digest.
- */
-static void
-jerry_sha1_finish (jerry_sha1_context *sha1_context_p, /**< SHA-1 context */
- uint8_t destination_p[20]) /**< result */
-{
- uint8_t buffer[16];
-
- uint32_t high = (sha1_context_p->total[0] >> 29) | (sha1_context_p->total[1] << 3);
- uint32_t low = (sha1_context_p->total[0] << 3);
-
- uint32_t last = sha1_context_p->total[0] & 0x3F;
- uint32_t padn = (last < 56) ? (56 - last) : (120 - last);
-
- memset (buffer, 0, sizeof (buffer));
- buffer[0] = 0x80;
-
- while (padn > sizeof (buffer))
- {
- jerry_sha1_update (sha1_context_p, buffer, sizeof (buffer));
- buffer[0] = 0;
- padn -= (uint32_t) sizeof (buffer);
- }
-
- jerry_sha1_update (sha1_context_p, buffer, padn);
-
- JERRY_SHA1_PUT_UINT32_BE (high, buffer, 0);
- JERRY_SHA1_PUT_UINT32_BE (low, buffer, 4);
-
- jerry_sha1_update (sha1_context_p, buffer, 8);
-
- JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[0], destination_p, 0);
- JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[1], destination_p, 4);
- JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[2], destination_p, 8);
- JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[3], destination_p, 12);
- JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[4], destination_p, 16);
-} /* jerry_sha1_finish */
-
-#undef JERRY_SHA1_GET_UINT32_BE
-#undef JERRY_SHA1_PUT_UINT32_BE
-
-/**
- * Computes the SHA-1 value of the combination of the two input buffers.
- */
-void
-jerry_debugger_compute_sha1 (const uint8_t *source1_p, /**< first part of the input */
- size_t source1_length, /**< length of the first part */
- const uint8_t *source2_p, /**< second part of the input */
- size_t source2_length, /**< length of the second part */
- uint8_t destination_p[20]) /**< result */
-{
- JMEM_DEFINE_LOCAL_ARRAY (sha1_context_p, 1, jerry_sha1_context);
-
- jerry_sha1_init (sha1_context_p);
- jerry_sha1_update (sha1_context_p, source1_p, source1_length);
- jerry_sha1_update (sha1_context_p, source2_p, source2_length);
- jerry_sha1_finish (sha1_context_p, destination_p);
-
- JMEM_FINALIZE_LOCAL_ARRAY (sha1_context_p);
-} /* jerry_debugger_compute_sha1 */
-
-#endif /* JERRY_DEBUGGER */
+++ /dev/null
-/* 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 "debugger.h"
-#include "jcontext.h"
-#include "jerryscript-port.h"
-
-#ifdef JERRY_DEBUGGER
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-/* 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.
- */
-#define JERRY_DEBUGGER_WEBSOCKET_MASK_BIT 0x80
-
-/**
- * Opcode type mask.
- */
-#define JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK 0x0fu
-
-/**
- * Packet length mask.
- */
-#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.
- */
-typedef struct
-{
- uint8_t ws_opcode; /**< websocket opcode */
- uint8_t size; /**< size of the message */
- uint8_t mask[4]; /**< mask bytes */
-} jerry_debugger_receive_header_t;
-
-/**
- * Close the socket connection to the client.
- */
-static void
-jerry_debugger_close_connection_tcp (bool log_error) /**< log error */
-{
- JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
-
- JERRY_CONTEXT (debugger_flags) = JERRY_DEBUGGER_VM_IGNORE;
-
- if (log_error)
- {
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
- }
-
- jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Debugger client connection closed.\n");
-
- close (JERRY_CONTEXT (debugger_connection));
- JERRY_CONTEXT (debugger_connection) = -1;
-
- jerry_debugger_free_unreferenced_byte_code ();
-} /* jerry_debugger_close_connection_tcp */
-
-/**
- * Send message to the client side.
- *
- * @return true - if the data was sent successfully to the client side
- * false - otherwise
- */
-static bool
-jerry_debugger_send_tcp (const uint8_t *data_p, /**< data pointer */
- size_t data_size) /**< data size */
-{
- JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
-
- do
- {
- ssize_t sent_bytes = send (JERRY_CONTEXT (debugger_connection), data_p, data_size, 0);
-
- if (sent_bytes < 0)
- {
- if (errno == EWOULDBLOCK)
- {
- continue;
- }
-
- jerry_debugger_close_connection_tcp (true);
- return false;
- }
-
- data_size -= (size_t) sent_bytes;
- data_p += sent_bytes;
- }
- while (data_size > 0);
-
- return true;
-} /* jerry_debugger_send_tcp */
-
-/**
- * Convert a 6-bit value to a Base64 character.
- *
- * @return Base64 character
- */
-static uint8_t
-jerry_to_base64_character (uint8_t value) /**< 6-bit value */
-{
- if (value < 26)
- {
- return (uint8_t) (value + 'A');
- }
-
- if (value < 52)
- {
- return (uint8_t) (value - 26 + 'a');
- }
-
- if (value < 62)
- {
- return (uint8_t) (value - 52 + '0');
- }
-
- if (value == 62)
- {
- return (uint8_t) '+';
- }
-
- return (uint8_t) '/';
-} /* jerry_to_base64_character */
-
-/**
- * Encode a byte sequence into Base64 string.
- */
-static void
-jerry_to_base64 (const uint8_t *source_p, /**< source data */
- uint8_t *destination_p, /**< destination buffer */
- size_t length) /**< length of source, must be divisible by 3 */
-{
- while (length >= 3)
- {
- uint8_t value = (source_p[0] >> 2);
- destination_p[0] = jerry_to_base64_character (value);
-
- value = (uint8_t) (((source_p[0] << 4) | (source_p[1] >> 4)) & 0x3f);
- destination_p[1] = jerry_to_base64_character (value);
-
- value = (uint8_t) (((source_p[1] << 2) | (source_p[2] >> 6)) & 0x3f);
- destination_p[2] = jerry_to_base64_character (value);
-
- value = (uint8_t) (source_p[2] & 0x3f);
- destination_p[3] = jerry_to_base64_character (value);
-
- source_p += 3;
- destination_p += 4;
- length -= 3;
- }
-} /* jerry_to_base64 */
-
-/**
- * Process WebSocket handshake.
- *
- * @return true - if the handshake was completed successfully
- * false - otherwise
- */
-static bool
-jerry_process_handshake (int client_socket, /**< client socket */
- uint8_t *request_buffer_p) /**< temporary buffer */
-{
- size_t request_buffer_size = 1024;
- uint8_t *request_end_p = request_buffer_p;
-
- /* Buffer request text until the double newlines are received. */
- while (true)
- {
- size_t length = request_buffer_size - 1u - (size_t) (request_end_p - request_buffer_p);
-
- if (length == 0)
- {
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Handshake buffer too small.\n");
- return false;
- }
-
- ssize_t size = recv (client_socket, request_end_p, length, 0);
-
- if (size < 0)
- {
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
- return false;
- }
-
- request_end_p += (size_t) size;
- *request_end_p = 0;
-
- if (request_end_p > request_buffer_p + 4
- && memcmp (request_end_p - 4, "\r\n\r\n", 4) == 0)
- {
- break;
- }
- }
-
- /* Check protocol. */
- const char *text_p = "GET /jerry-debugger";
- size_t text_len = strlen (text_p);
-
- if ((size_t) (request_end_p - request_buffer_p) < text_len
- || memcmp (request_buffer_p, text_p, text_len) != 0)
- {
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid handshake format.\n");
- return false;
- }
-
- uint8_t *websocket_key_p = request_buffer_p + text_len;
-
- text_p = "Sec-WebSocket-Key:";
- text_len = strlen (text_p);
-
- while (true)
- {
- if ((size_t) (request_end_p - websocket_key_p) < text_len)
- {
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Sec-WebSocket-Key not found.\n");
- return false;
- }
-
- if (websocket_key_p[0] == 'S'
- && websocket_key_p[-1] == '\n'
- && websocket_key_p[-2] == '\r'
- && memcmp (websocket_key_p, text_p, text_len) == 0)
- {
- websocket_key_p += text_len;
- break;
- }
-
- websocket_key_p++;
- }
-
- /* String terminated by double newlines. */
-
- while (*websocket_key_p == ' ')
- {
- websocket_key_p++;
- }
-
- uint8_t *websocket_key_end_p = websocket_key_p;
-
- while (*websocket_key_end_p > ' ')
- {
- websocket_key_end_p++;
- }
-
- /* Since the request_buffer_p is not needed anymore it can
- * be reused for storing the SHA-1 key and Base64 string. */
-
- const size_t sha1_length = 20;
-
- jerry_debugger_compute_sha1 (websocket_key_p,
- (size_t) (websocket_key_end_p - websocket_key_p),
- (const uint8_t *) "258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
- 36,
- request_buffer_p);
-
- /* The SHA-1 key is 20 bytes long but jerry_to_base64 expects
- * a length divisible by 3 so an extra 0 is appended at the end. */
- request_buffer_p[sha1_length] = 0;
-
- jerry_to_base64 (request_buffer_p, request_buffer_p + sha1_length + 1, sha1_length + 1);
-
- /* Last value must be replaced by equal sign. */
-
- text_p = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ";
-
- if (!jerry_debugger_send_tcp ((const uint8_t *) text_p, strlen (text_p))
- || !jerry_debugger_send_tcp (request_buffer_p + sha1_length + 1, 27))
- {
- return false;
- }
-
- text_p = "=\r\n\r\n";
- return jerry_debugger_send_tcp ((const uint8_t *) text_p, strlen (text_p));
-} /* jerry_process_handshake */
-
-/**
- * Initialize the socket connection.
- *
- * @return true - if the connection succeeded
- * false - otherwise
- */
-bool
-jerry_debugger_accept_connection (void)
-{
- int server_socket;
- 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;
-
- if ((server_socket = socket (AF_INET, SOCK_STREAM, 0)) == -1)
- {
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
- return false;
- }
-
- int opt_value = 1;
-
- if (setsockopt (server_socket, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof (int)) == -1)
- {
- close (server_socket);
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
- return false;
- }
-
- if (bind (server_socket, (struct sockaddr *)&addr, sizeof (struct sockaddr)) == -1)
- {
- close (server_socket);
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
- return false;
- }
-
- if (listen (server_socket, 1) == -1)
- {
- close (server_socket);
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
- return false;
- }
-
- jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Waiting for client connection\n");
-
- JERRY_CONTEXT (debugger_connection) = accept (server_socket, (struct sockaddr *)&addr, &sin_size);
-
- if (JERRY_CONTEXT (debugger_connection) == -1)
- {
- close (server_socket);
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
- return false;
- }
-
- close (server_socket);
-
- JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CONNECTED);
-
- bool is_handshake_ok = false;
-
- JMEM_DEFINE_LOCAL_ARRAY (request_buffer_p, 1024, uint8_t);
-
- is_handshake_ok = jerry_process_handshake (JERRY_CONTEXT (debugger_connection),
- request_buffer_p);
-
- JMEM_FINALIZE_LOCAL_ARRAY (request_buffer_p);
-
- if (!is_handshake_ok)
- {
- jerry_debugger_close_connection ();
- return false;
- }
-
- if (!jerry_debugger_send_configuration (max_receive_size))
- {
- return false;
- }
-
- /* Set non-blocking mode. */
- int socket_flags = fcntl (JERRY_CONTEXT (debugger_connection), F_GETFL, 0);
-
- if (socket_flags < 0)
- {
- jerry_debugger_close_connection_tcp (true);
- return false;
- }
-
- if (fcntl (JERRY_CONTEXT (debugger_connection), F_SETFL, socket_flags | O_NONBLOCK) == -1)
- {
- jerry_debugger_close_connection_tcp (true);
- return false;
- }
-
- jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Connected from: %s\n", inet_ntoa (addr.sin_addr));
-
- JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP);
- JERRY_CONTEXT (debugger_stop_context) = NULL;
-
- return true;
-} /* jerry_debugger_accept_connection */
-
-/**
- * Close the socket connection to the client.
- */
-inline void __attr_always_inline___
-jerry_debugger_close_connection (void)
-{
- jerry_debugger_close_connection_tcp (false);
-} /* jerry_debugger_close_connection */
-
-/**
- * Send message to the client side
- *
- * @return true - if the data was sent successfully to the debugger client,
- * false - otherwise
- */
-bool
-jerry_debugger_send (size_t data_size) /**< data size */
-{
- 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;
-
- return jerry_debugger_send_tcp (header_p, data_size + JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE);
-} /* jerry_debugger_send */
-
-/**
- * Receive message from the client.
- *
- * Note:
- * If the function returns with true, the value of
- * JERRY_DEBUGGER_VM_STOP flag should be ignored.
- *
- * @return true - if execution should be resumed,
- * false - otherwise
- */
-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_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE));
-
- JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY;
-
- uint8_t *recv_buffer_p = JERRY_CONTEXT (debugger_receive_buffer);
- bool resume_exec = false;
- uint8_t expected_message_type = 0;
-
- while (true)
- {
- uint32_t offset = JERRY_CONTEXT (debugger_receive_buffer_offset);
-
- ssize_t byte_recv = recv (JERRY_CONTEXT (debugger_connection),
- recv_buffer_p + offset,
- JERRY_DEBUGGER_MAX_BUFFER_SIZE - offset,
- 0);
-
- if (byte_recv < 0)
- {
- if (errno != EWOULDBLOCK)
- {
- jerry_debugger_close_connection_tcp (true);
- return true;
- }
-
- byte_recv = 0;
- }
-
- offset += (uint32_t) byte_recv;
- JERRY_CONTEXT (debugger_receive_buffer_offset) = (uint16_t) offset;
-
- if (offset < sizeof (jerry_debugger_receive_header_t))
- {
- if (expected_message_type != 0)
- {
- continue;
- }
-
- return resume_exec;
- }
-
- 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_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");
- jerry_debugger_close_connection ();
- return true;
- }
-
- if ((recv_buffer_p[0] & JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME)
- {
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unsupported Websocket opcode.\n");
- jerry_debugger_close_connection ();
- return true;
- }
-
- uint32_t message_size = (uint32_t) (recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK);
- uint32_t message_total_size = (uint32_t) (message_size + sizeof (jerry_debugger_receive_header_t));
-
- if (offset < message_total_size)
- {
- if (expected_message_type != 0)
- {
- continue;
- }
-
- return resume_exec;
- }
-
- /* Unmask data bytes. */
- uint8_t *data_p = recv_buffer_p + sizeof (jerry_debugger_receive_header_t);
- const uint8_t *mask_p = data_p - JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE;
- const uint8_t *mask_end_p = data_p;
- const uint8_t *data_end_p = data_p + message_size;
-
- while (data_p < data_end_p)
- {
- /* Invert certain bits with xor operation. */
- *data_p = *data_p ^ *mask_p;
-
- data_p++;
- mask_p++;
-
- if (mask_p >= mask_end_p)
- {
- mask_p -= JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE;
- }
- }
-
- /* The jerry_debugger_process_message function is inlined
- * so passing these arguments is essentially free. */
- if (!jerry_debugger_process_message (recv_buffer_p + sizeof (jerry_debugger_receive_header_t),
- message_size,
- &resume_exec,
- &expected_message_type,
- message_data_p))
- {
- return true;
- }
-
- if (message_total_size < offset)
- {
- memmove (recv_buffer_p,
- recv_buffer_p + message_total_size,
- offset - message_total_size);
- }
-
- JERRY_CONTEXT (debugger_receive_buffer_offset) = (uint16_t) (offset - message_total_size);
- }
-} /* jerry_debugger_receive */
-
-#endif /* JERRY_DEBUGGER */
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DEBUGGER_WS_H
-#define DEBUGGER_WS_H
-
-#include "ecma-globals.h"
-
-#ifdef JERRY_DEBUGGER
-
-/* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */
-
-/**
- * Maximum number of bytes transmitted or received.
- */
-#define JERRY_DEBUGGER_MAX_BUFFER_SIZE 128
-
-/**
- * Incoming message: next message of string data.
- */
-typedef struct
-{
- uint8_t type; /**< type of the message */
-} jerry_debugger_receive_uint8_data_part_t;
-
-/**
- * Byte data for evaluating expressions and receiving client source.
- */
-typedef struct
-{
- uint32_t uint8_size; /**< total size of the client source */
- uint32_t uint8_offset; /**< current offset in the client source */
-} jerry_debugger_uint8_data_t;
-
-bool jerry_debugger_accept_connection (void);
-void jerry_debugger_close_connection (void);
-
-bool jerry_debugger_send (size_t data_size);
-bool jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p);
-
-void jerry_debugger_compute_sha1 (const uint8_t *input1, size_t input1_len,
- const uint8_t *input2, size_t input2_len,
- uint8_t output[20]);
-
-#endif /* JERRY_DEBUGGER */
-
-#endif /* !DEBUGGER_WS_H */
#include "ecma-builtin-helpers.h"
#include "ecma-conversion.h"
#include "ecma-eval.h"
+#include "ecma-function-object.h"
#include "ecma-objects.h"
#include "jcontext.h"
+#include "jerryscript-port.h"
#include "lit-char-helpers.h"
#ifdef JERRY_DEBUGGER
+/**
+ * Incoming message: next message of string data.
+ */
+typedef struct
+{
+ uint8_t type; /**< type of the message */
+} jerry_debugger_receive_uint8_data_part_t;
+
/**
* 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,
+JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 32
+ && JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 21
+ && JERRY_DEBUGGER_VERSION == 8,
debugger_version_correlates_to_message_type_count);
+/**
+ * Waiting for data from the client.
+ */
+#define JERRY_DEBUGGER_RECEIVE_DATA_MODE \
+ (JERRY_DEBUGGER_BREAKPOINT_MODE | JERRY_DEBUGGER_CLIENT_SOURCE_MODE)
+
/**
* Type cast the debugger send buffer into a specific type.
*/
}
} /* jerry_debugger_free_unreferenced_byte_code */
+/**
+ * Send data over an active connection.
+ *
+ * @return true - if the data was sent successfully
+ * false - otherwise
+ */
+static bool
+jerry_debugger_send (size_t message_length) /**< message length in bytes */
+{
+ JERRY_ASSERT (message_length <= JERRY_CONTEXT (debugger_max_send_size));
+
+ jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p);
+ uint8_t *payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p);
+
+ return header_p->send (header_p, payload_p, message_length);
+} /* jerry_debugger_send */
+
/**
* Send backtrace.
*/
static void
-jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer to the received data */
+jerry_debugger_send_backtrace (const uint8_t *recv_buffer_p) /**< pointer to the received data */
{
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_get_backtrace_t, get_backtrace_p);
+ uint32_t min_depth;
+ memcpy (&min_depth, get_backtrace_p->min_depth, sizeof (uint32_t));
uint32_t max_depth;
memcpy (&max_depth, get_backtrace_p->max_depth, sizeof (uint32_t));
max_depth = UINT32_MAX;
}
+ if (get_backtrace_p->get_total_frame_count != 0)
+ {
+ JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_backtrace_total_t, backtrace_total_p);
+ backtrace_total_p->type = JERRY_DEBUGGER_BACKTRACE_TOTAL;
+
+ vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
+ uint32_t frame_count = 0;
+ while (iter_frame_ctx_p != NULL)
+ {
+ if (!(iter_frame_ctx_p->bytecode_header_p->status_flags & (CBC_CODE_FLAGS_STATIC_FUNCTION)))
+ {
+ frame_count++;
+ }
+ iter_frame_ctx_p = iter_frame_ctx_p->prev_context_p;
+ }
+ memcpy (backtrace_total_p->frame_count, &frame_count, sizeof (frame_count));
+
+ jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + sizeof (frame_count));
+ }
+
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_backtrace_t, backtrace_p);
backtrace_p->type = JERRY_DEBUGGER_BACKTRACE;
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)
+ if (min_depth <= max_depth)
{
- if (frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE)
+ uint32_t min_depth_offset = 0;
+
+ while (frame_ctx_p != NULL && min_depth_offset < min_depth)
{
frame_ctx_p = frame_ctx_p->prev_context_p;
- continue;
+ min_depth_offset++;
}
- if (current_frame >= max_frame_count)
+ while (frame_ctx_p != NULL && min_depth_offset++ < max_depth)
{
- if (!jerry_debugger_send (max_message_size))
+ if (frame_ctx_p->bytecode_header_p->status_flags
+ & (CBC_CODE_FLAGS_DEBUGGER_IGNORE | CBC_CODE_FLAGS_STATIC_FUNCTION))
{
- return;
+ frame_ctx_p = frame_ctx_p->prev_context_p;
+ continue;
}
- current_frame = 0;
- }
- jerry_debugger_frame_t *frame_p = backtrace_p->frames + current_frame;
+ if (current_frame >= max_frame_count)
+ {
+ if (!jerry_debugger_send (max_message_size))
+ {
+ return;
+ }
+ current_frame = 0;
+ }
- jmem_cpointer_t byte_code_cp;
- JMEM_CP_SET_NON_NULL_POINTER (byte_code_cp, frame_ctx_p->bytecode_header_p);
- memcpy (frame_p->byte_code_cp, &byte_code_cp, sizeof (jmem_cpointer_t));
+ jerry_debugger_frame_t *frame_p = backtrace_p->frames + current_frame;
- uint32_t offset = (uint32_t) (frame_ctx_p->byte_code_p - (uint8_t *) frame_ctx_p->bytecode_header_p);
- memcpy (frame_p->offset, &offset, sizeof (uint32_t));
+ jmem_cpointer_t byte_code_cp;
+ JMEM_CP_SET_NON_NULL_POINTER (byte_code_cp, frame_ctx_p->bytecode_header_p);
+ memcpy (frame_p->byte_code_cp, &byte_code_cp, sizeof (jmem_cpointer_t));
+
+ uint32_t offset = (uint32_t) (frame_ctx_p->byte_code_p - (uint8_t *) frame_ctx_p->bytecode_header_p);
+ memcpy (frame_p->offset, &offset, sizeof (uint32_t));
- frame_ctx_p = frame_ctx_p->prev_context_p;
- current_frame++;
- max_depth--;
+ frame_ctx_p = frame_ctx_p->prev_context_p;
+ current_frame++;
+ }
}
size_t message_size = current_frame * sizeof (jerry_debugger_frame_t);
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + message_size);
} /* jerry_debugger_send_backtrace */
+/**
+ * Send the scope chain types.
+ */
+static void
+jerry_debugger_send_scope_chain (void)
+{
+ vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
+
+ 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_type_p);
+ message_type_p->type = JERRY_DEBUGGER_SCOPE_CHAIN;
+
+ size_t buffer_pos = 0;
+ bool next_func_is_local = true;
+ ecma_object_t *lex_env_p = iter_frame_ctx_p->lex_env_p;
+
+ while (true)
+ {
+ JERRY_ASSERT (ecma_is_lexical_environment (lex_env_p));
+
+ if (buffer_pos == max_byte_count)
+ {
+ if (!jerry_debugger_send (max_message_size))
+ {
+ return;
+ }
+
+ buffer_pos = 0;
+ }
+
+ if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
+ {
+ if ((lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_NON_CLOSURE) != 0)
+ {
+ message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_NON_CLOSURE;
+ }
+ else if (next_func_is_local)
+ {
+ message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_LOCAL;
+ next_func_is_local = false;
+ }
+ else
+ {
+ message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_CLOSURE;
+ }
+ }
+ else if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND)
+ {
+ if (ecma_get_lex_env_outer_reference (lex_env_p) == NULL)
+ {
+ message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_GLOBAL;
+ break;
+ }
+ else
+ {
+ message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_WITH;
+ }
+ }
+
+ lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
+ }
+
+ message_type_p->type = JERRY_DEBUGGER_SCOPE_CHAIN_END;
+
+ jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + buffer_pos);
+} /* jerry_debugger_send_scope_chain */
+
+/**
+ * Get type of the scope variable property.
+ */
+static jerry_debugger_scope_variable_type_t
+jerry_debugger_get_variable_type (ecma_value_t value) /**< input ecma value */
+{
+ jerry_debugger_scope_variable_type_t ret_value = JERRY_DEBUGGER_VALUE_NONE;
+
+ if (ecma_is_value_undefined (value))
+ {
+ ret_value = JERRY_DEBUGGER_VALUE_UNDEFINED;
+ }
+ else if (ecma_is_value_null (value))
+ {
+ ret_value = JERRY_DEBUGGER_VALUE_NULL;
+ }
+ else if (ecma_is_value_boolean (value))
+ {
+ ret_value = JERRY_DEBUGGER_VALUE_BOOLEAN;
+ }
+ else if (ecma_is_value_number (value))
+ {
+ ret_value = JERRY_DEBUGGER_VALUE_NUMBER;
+ }
+ else if (ecma_is_value_string (value))
+ {
+ ret_value = JERRY_DEBUGGER_VALUE_STRING;
+ }
+ else
+ {
+ JERRY_ASSERT (ecma_is_value_object (value));
+
+ if (ecma_object_get_class_name (ecma_get_object_from_value (value)) == LIT_MAGIC_STRING_ARRAY_UL)
+ {
+ ret_value = JERRY_DEBUGGER_VALUE_ARRAY;
+ }
+ else
+ {
+ ret_value = ecma_op_is_callable (value) ? JERRY_DEBUGGER_VALUE_FUNCTION : JERRY_DEBUGGER_VALUE_OBJECT;
+ }
+ }
+
+ JERRY_ASSERT (ret_value != JERRY_DEBUGGER_VALUE_NONE);
+
+ return ret_value;
+} /* jerry_debugger_get_variable_type */
+
+/**
+ * Helper function for jerry_debugger_send_scope_variables.
+ *
+ * It will copies the given scope values type, length and value into the outgoing message string.
+ *
+ * @return true - if the copy was successfully
+ * false - otherwise
+ */
+static bool
+jerry_debugger_copy_variables_to_string_message (jerry_debugger_scope_variable_type_t variable_type, /**< type */
+ ecma_string_t *value_str, /**< property name or value string */
+ jerry_debugger_send_string_t *message_string_p, /**< msg pointer */
+ size_t *buffer_pos) /**< string data position of the message */
+{
+ 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);
+
+ ECMA_STRING_TO_UTF8_STRING (value_str, str_buff, str_buff_size);
+
+ size_t str_size = 0;
+ size_t str_limit = 255;
+ bool result = true;
+
+ bool type_processed = false;
+
+ while (true)
+ {
+ if (*buffer_pos == max_byte_count)
+ {
+ if (!jerry_debugger_send (max_message_size))
+ {
+ result = false;
+ break;
+ }
+
+ *buffer_pos = 0;
+ }
+
+ if (!type_processed)
+ {
+ if (variable_type != JERRY_DEBUGGER_VALUE_NONE)
+ {
+ message_string_p->string[*buffer_pos] = variable_type;
+ *buffer_pos += 1;
+ }
+ type_processed = true;
+ continue;
+ }
+
+ if (variable_type == JERRY_DEBUGGER_VALUE_FUNCTION)
+ {
+ str_size = 0; // do not copy function values
+ }
+ else
+ {
+ str_size = (str_buff_size > str_limit) ? str_limit : str_buff_size;
+ }
+
+ message_string_p->string[*buffer_pos] = (uint8_t) str_size;
+ *buffer_pos += 1;
+ break;
+ }
+
+ if (result)
+ {
+ size_t free_bytes = max_byte_count - *buffer_pos;
+ const uint8_t *string_p = str_buff;
+
+ while (str_size > free_bytes)
+ {
+ memcpy (message_string_p->string + *buffer_pos, string_p, free_bytes);
+
+ if (!jerry_debugger_send (max_message_size))
+ {
+ result = false;
+ break;
+ }
+
+ string_p += free_bytes;
+ str_size -= free_bytes;
+ free_bytes = max_byte_count;
+ *buffer_pos = 0;
+ }
+
+ if (result)
+ {
+ memcpy (message_string_p->string + *buffer_pos, string_p, str_size);
+ *buffer_pos += str_size;
+ }
+ }
+
+ ECMA_FINALIZE_UTF8_STRING (str_buff, str_buff_size);
+
+ return result;
+} /* jerry_debugger_copy_variables_to_string_message */
+
+/**
+ * Send variables of the given scope chain level.
+ */
+static void
+jerry_debugger_send_scope_variables (const uint8_t *recv_buffer_p) /**< pointer to the received data */
+{
+ JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_get_scope_variables_t, get_scope_variables_p);
+
+ uint32_t chain_index;
+ memcpy (&chain_index, get_scope_variables_p->chain_index, sizeof (uint32_t));
+
+ vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
+ ecma_object_t *lex_env_p = iter_frame_ctx_p->lex_env_p;
+
+ while (chain_index != 0)
+ {
+ lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
+
+ if (JERRY_UNLIKELY (lex_env_p == NULL))
+ {
+ jerry_debugger_send_type (JERRY_DEBUGGER_SCOPE_VARIABLES_END);
+ return;
+ }
+
+ if ((ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND)
+ || (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE))
+ {
+ chain_index--;
+ }
+ }
+
+ ecma_property_header_t *prop_iter_p;
+
+ if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
+ {
+ prop_iter_p = ecma_get_property_list (lex_env_p);
+ }
+ else
+ {
+ JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+ ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
+ prop_iter_p = ecma_get_property_list (binding_obj_p);
+ }
+
+ JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_string_p);
+ message_string_p->type = JERRY_DEBUGGER_SCOPE_VARIABLES;
+
+ size_t buffer_pos = 0;
+
+ while (prop_iter_p != NULL)
+ {
+ JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
+
+ ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
+
+ for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
+ {
+ if (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[i]))
+ {
+ if (ECMA_PROPERTY_GET_NAME_TYPE (prop_iter_p->types[i]) == ECMA_DIRECT_STRING_MAGIC
+ && prop_pair_p->names_cp[i] >= LIT_NON_INTERNAL_MAGIC_STRING__COUNT)
+ {
+ continue;
+ }
+
+ ecma_string_t *prop_name = ecma_string_from_property_name (prop_iter_p->types[i],
+ prop_pair_p->names_cp[i]);
+
+ if (!jerry_debugger_copy_variables_to_string_message (JERRY_DEBUGGER_VALUE_NONE,
+ prop_name,
+ message_string_p,
+ &buffer_pos))
+ {
+ ecma_deref_ecma_string (prop_name);
+ return;
+ }
+
+ ecma_deref_ecma_string (prop_name);
+
+ ecma_property_value_t prop_value_p = prop_pair_p->values[i];
+ ecma_value_t property_value;
+
+ jerry_debugger_scope_variable_type_t variable_type = jerry_debugger_get_variable_type (prop_value_p.value);
+
+ property_value = ecma_op_to_string (prop_value_p.value);
+
+ if (!jerry_debugger_copy_variables_to_string_message (variable_type,
+ ecma_get_string_from_value (property_value),
+ message_string_p,
+ &buffer_pos))
+ {
+ ecma_free_value (property_value);
+ return;
+ }
+
+ ecma_free_value (property_value);
+ }
+ }
+
+ prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
+ prop_iter_p->next_property_cp);
+ }
+
+ message_string_p->type = JERRY_DEBUGGER_SCOPE_VARIABLES_END;
+ jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + buffer_pos);
+} /* jerry_debugger_send_scope_variables */
+
/**
* Send result of evaluated expression or throw an error.
*
JERRY_ASSERT (!(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);
+
+ uint32_t chain_index;
+ memcpy (&chain_index, eval_string_p, sizeof (uint32_t));
+ uint32_t parse_opts = ECMA_PARSE_DIRECT_EVAL | (chain_index << ECMA_PARSE_CHAIN_INDEX_SHIFT);
+
+ ecma_value_t result = ecma_op_eval_chars_buffer (eval_string_p + 5, eval_string_size - 5, parse_opts);
JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE);
if (!ECMA_IS_VALUE_ERROR (result))
{
- if (eval_string_p[0] != JERRY_DEBUGGER_EVAL_EVAL)
+ if (eval_string_p[4] != JERRY_DEBUGGER_EVAL_EVAL)
{
JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
JERRY_CONTEXT (error_value) = result;
JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP);
JERRY_CONTEXT (debugger_stop_context) = NULL;
- if (eval_string_p[0] == JERRY_DEBUGGER_EVAL_THROW)
+ if (eval_string_p[4] == JERRY_DEBUGGER_EVAL_THROW)
{
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION;
}
return false;
} /* jerry_debugger_send_eval */
-/**
- * Suspend execution for a given time.
- * Note: If the platform does not have nanosleep or usleep, this function does not sleep at all.
- */
-void
-jerry_debugger_sleep (void)
-{
- jerry_port_sleep (JERRY_DEBUGGER_TIMEOUT);
-} /* jerry_debugger_sleep */
-
/**
* Check received packet size.
*/
#define JERRY_DEBUGGER_CHECK_PACKET_SIZE(type) \
if (message_size != sizeof (type)) \
{ \
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n"); \
- jerry_debugger_close_connection (); \
+ JERRY_ERROR_MSG ("Invalid message size\n"); \
+ jerry_debugger_transport_close (); \
return false; \
}
* @return true - if message is processed successfully
* false - otherwise
*/
-inline bool __attr_always_inline___
-jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the received data */
+static inline bool JERRY_ATTR_ALWAYS_INLINE
+jerry_debugger_process_message (const 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 */
if (recv_buffer_p[0] >= JERRY_DEBUGGER_CONTINUE
&& !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE))
{
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Message requires breakpoint mode\n");
- jerry_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Message requires breakpoint mode\n");
+ jerry_debugger_transport_close ();
return false;
}
if (recv_buffer_p[0] != *expected_message_type_p)
{
jmem_heap_free_block (uint8_data_p, uint8_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t));
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unexpected message\n");
- jerry_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Unexpected message\n");
+ jerry_debugger_transport_close ();
return false;
}
if (message_size < sizeof (jerry_debugger_receive_uint8_data_part_t) + 1)
{
jmem_heap_free_block (uint8_data_p, uint8_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t));
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n");
- jerry_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Invalid message size\n");
+ jerry_debugger_transport_close ();
return false;
}
if (message_size > expected_data)
{
jmem_heap_free_block (uint8_data_p, uint8_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t));
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n");
- jerry_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Invalid message size\n");
+ jerry_debugger_transport_close ();
return false;
}
if (byte_code_free_cp != JERRY_CONTEXT (debugger_byte_code_free_tail))
{
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid byte code free order\n");
- jerry_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Invalid byte code free order\n");
+ jerry_debugger_transport_close ();
return false;
}
return true;
}
+ case JERRY_DEBUGGER_GET_SCOPE_CHAIN:
+ {
+ JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
+
+ jerry_debugger_send_scope_chain ();
+
+ return true;
+ }
+
+ case JERRY_DEBUGGER_GET_SCOPE_VARIABLES:
+ {
+ JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_get_scope_variables_t);
+
+ jerry_debugger_send_scope_variables (recv_buffer_p);
+
+ return true;
+ }
+
case JERRY_DEBUGGER_EXCEPTION_CONFIG:
{
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_exception_config_t);
if (exception_config_p->enable == 0)
{
JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION);
- jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Stop at exception disabled\n");
+ JERRY_DEBUG_MSG ("Stop at exception disabled\n");
}
else
{
JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION);
- jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Stop at exception enabled\n");
+ JERRY_DEBUG_MSG ("Stop at exception enabled\n");
}
return true;
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");
+ JERRY_DEBUG_MSG ("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");
+ JERRY_DEBUG_MSG ("Waiting after parsing disabled\n");
}
return true;
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 ();
+ JERRY_ERROR_MSG ("Not in parser wait mode\n");
+ jerry_debugger_transport_close ();
return false;
}
case JERRY_DEBUGGER_EVAL:
{
- if (message_size < sizeof (jerry_debugger_receive_eval_first_t) + 1)
+ if (message_size < sizeof (jerry_debugger_receive_eval_first_t) + 5)
{
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n");
- jerry_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Invalid message size\n");
+ jerry_debugger_transport_close ();
return false;
}
{
if (eval_size != message_size - sizeof (jerry_debugger_receive_eval_first_t))
{
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n");
- jerry_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Invalid message size\n");
+ jerry_debugger_transport_close ();
return false;
}
{
if (message_size <= sizeof (jerry_debugger_receive_client_source_first_t))
{
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n");
- jerry_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Invalid message size\n");
+ jerry_debugger_transport_close ();
return false;
}
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE))
{
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Not in client source mode\n");
- jerry_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Not in client source mode\n");
+ jerry_debugger_transport_close ();
return false;
}
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 ();
+ JERRY_ERROR_MSG ("Invalid message size\n");
+ jerry_debugger_transport_close ();
return false;
}
{
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE))
{
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Not in client source mode\n");
- jerry_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Not in client source mode\n");
+ jerry_debugger_transport_close ();
return false;
}
{
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE))
{
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Not in client source mode\n");
- jerry_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Not in client source mode\n");
+ jerry_debugger_transport_close ();
return false;
}
default:
{
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unexpected message.");
- jerry_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Unexpected message.");
+ jerry_debugger_transport_close ();
return false;
}
}
} /* jerry_debugger_process_message */
+/**
+ * Receive message from the client.
+ *
+ * Note:
+ * If the function returns with true, the value of
+ * JERRY_DEBUGGER_VM_STOP flag should be ignored.
+ *
+ * @return true - if execution should be resumed,
+ * false - otherwise
+ */
+bool
+jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p) /**< [out] data received from client */
+{
+ JERRY_ASSERT (jerry_debugger_transport_is_connected ());
+
+ 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;
+
+ bool resume_exec = false;
+ uint8_t expected_message_type = 0;
+
+ while (true)
+ {
+ jerry_debugger_transport_receive_context_t context;
+ if (!jerry_debugger_transport_receive (&context))
+ {
+ JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED));
+ return true;
+ }
+
+ if (context.message_p == NULL)
+ {
+ if (expected_message_type != 0)
+ {
+ jerry_debugger_transport_sleep ();
+ continue;
+ }
+
+ return resume_exec;
+ }
+
+ /* Only datagram packets are supported. */
+ JERRY_ASSERT (context.message_total_length > 0);
+
+ /* The jerry_debugger_process_message function is inlined
+ * so passing these arguments is essentially free. */
+ if (!jerry_debugger_process_message (context.message_p,
+ (uint32_t) context.message_length,
+ &resume_exec,
+ &expected_message_type,
+ message_data_p))
+ {
+ JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED));
+ return true;
+ }
+
+ jerry_debugger_transport_receive_completed (&context);
+ }
+} /* jerry_debugger_receive */
+
+
#undef JERRY_DEBUGGER_CHECK_PACKET_SIZE
/**
while (!jerry_debugger_receive (&uint8_data))
{
- jerry_debugger_sleep ();
+ jerry_debugger_transport_sleep ();
}
if (uint8_data != NULL)
endian_data.uint16_value = 1;
configuration_p->type = JERRY_DEBUGGER_CONFIGURATION;
+ configuration_p->configuration = 0;
+
+ if (endian_data.uint8_value[0] == 1)
+ {
+ configuration_p->configuration |= (uint8_t) JERRY_DEBUGGER_LITTLE_ENDIAN;
+ }
+
+ uint32_t version = JERRY_DEBUGGER_VERSION;
+ memcpy (configuration_p->version, &version, sizeof (uint32_t));
+
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 */
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_type_t, message_type_p);
- message_type_p->type = type;
+ message_type_p->type = (uint8_t) type;
memcpy (message_type_p + 1, data, size);
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + size);
#ifndef DEBUGGER_H
#define DEBUGGER_H
-#include "debugger-ws.h"
#include "ecma-globals.h"
+#include "jerryscript-debugger-transport.h"
#ifdef JERRY_DEBUGGER
/* 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.
*/
#define JERRY_DEBUGGER_MESSAGE_FREQUENCY 5
/**
- * Sleep time in milliseconds between each jerry_debugger_receive call
+ * This constant represents that the string to be sent has no subtype.
*/
-#define JERRY_DEBUGGER_TIMEOUT 100
-
-/**
- * This constant represents that the string to be sent has no subtype.
- */
#define JERRY_DEBUGGER_NO_SUBTYPE 0
/**
* Limited resources available for the engine, so it is important to
* check the maximum buffer size. It needs to be between 64 and 256 bytes.
*/
-#if JERRY_DEBUGGER_MAX_BUFFER_SIZE < 64 || JERRY_DEBUGGER_MAX_BUFFER_SIZE > 256
+#if JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE < 64 || JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE > 256
#error Please define the MAX_BUFFER_SIZE between 64 and 256 bytes.
-#endif /* JERRY_DEBUGGER_MAX_BUFFER_SIZE < 64 || JERRY_DEBUGGER_MAX_BUFFER_SIZE > 256 */
+#endif /* JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE < 64 || JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE > 256 */
/**
* Calculate the maximum number of items for a given type
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_BACKTRACE_TOTAL = 20, /**< number of total frames */
+ JERRY_DEBUGGER_BACKTRACE = 21, /**< backtrace data */
+ JERRY_DEBUGGER_BACKTRACE_END = 22, /**< last backtrace data */
+ JERRY_DEBUGGER_EVAL_RESULT = 23, /**< eval result */
+ JERRY_DEBUGGER_EVAL_RESULT_END = 24, /**< last part of eval result */
+ JERRY_DEBUGGER_WAIT_FOR_SOURCE = 25, /**< engine waiting for source code */
+ JERRY_DEBUGGER_OUTPUT_RESULT = 26, /**< output sent by the program to the debugger */
+ JERRY_DEBUGGER_OUTPUT_RESULT_END = 27, /**< last output result data */
+ JERRY_DEBUGGER_SCOPE_CHAIN = 28, /**< scope chain */
+ JERRY_DEBUGGER_SCOPE_CHAIN_END = 29, /**< last output of scope chain */
+ JERRY_DEBUGGER_SCOPE_VARIABLES = 30, /**< scope variables */
+ JERRY_DEBUGGER_SCOPE_VARIABLES_END = 31, /**< last output of scope variables */
JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT, /**< number of different type of output messages by the debugger */
/* Messages sent by the client to server. */
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_GET_SCOPE_CHAIN = 19, /**< get type names of the scope chain */
+ JERRY_DEBUGGER_GET_SCOPE_VARIABLES = 20, /**< get variables of a scope */
JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT, /**< number of different type of input messages */
} jerry_debugger_header_type_t;
+/**
+ * Debugger option flags.
+ */
+typedef enum
+{
+ JERRY_DEBUGGER_LITTLE_ENDIAN = 1u << 0, /**< little endian */
+} jerry_debugger_configuration_flags_t;
+
/**
* Subtypes of eval.
*/
/**
* Subtypes of output_result.
+ *
+ * Note:
+ * This enum has to be kept in sync with jerry_log_level_t with an offset
+ * of +2.
*/
typedef enum
{
JERRY_DEBUGGER_OUTPUT_TRACE = 5, /**< output result, trace */
} jerry_debugger_output_subtype_t;
+/**
+ * Types of scopes.
+ */
+typedef enum
+{
+ JERRY_DEBUGGER_SCOPE_WITH = 1, /**< with */
+ JERRY_DEBUGGER_SCOPE_LOCAL = 2, /**< local */
+ JERRY_DEBUGGER_SCOPE_CLOSURE = 3, /**< closure */
+ JERRY_DEBUGGER_SCOPE_GLOBAL = 4, /**< global */
+ JERRY_DEBUGGER_SCOPE_NON_CLOSURE = 5 /**< non closure */
+} jerry_debugger_scope_chain_type_t;
+
+/**
+ * Type of scope variables.
+ */
+typedef enum
+{
+ JERRY_DEBUGGER_VALUE_NONE = 1,
+ JERRY_DEBUGGER_VALUE_UNDEFINED = 2,
+ JERRY_DEBUGGER_VALUE_NULL = 3,
+ JERRY_DEBUGGER_VALUE_BOOLEAN = 4,
+ JERRY_DEBUGGER_VALUE_NUMBER = 5,
+ JERRY_DEBUGGER_VALUE_STRING = 6,
+ JERRY_DEBUGGER_VALUE_FUNCTION = 7,
+ JERRY_DEBUGGER_VALUE_ARRAY = 8,
+ JERRY_DEBUGGER_VALUE_OBJECT = 9
+} jerry_debugger_scope_variable_type_t;
+
+/**
+ * Byte data for evaluating expressions and receiving client source.
+ */
+typedef struct
+{
+ uint32_t uint8_size; /**< total size of the client source */
+ uint32_t uint8_offset; /**< current offset in the client source */
+} jerry_debugger_uint8_data_t;
+
/**
* Delayed free of byte code data.
*/
typedef struct
{
uint8_t type; /**< type of the message */
+ uint8_t configuration; /**< configuration option bits */
+ uint8_t version[sizeof (uint32_t)]; /**< debugger version */
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;
/**
jerry_debugger_frame_t frames[]; /**< frames */
} jerry_debugger_send_backtrace_t;
+/**
+ * Outgoing message: scope chain.
+ */
+typedef struct
+{
+ uint8_t type; /**< type of the message */
+ uint8_t scope_types[]; /**< scope types */
+} jerry_debugger_send_scope_chain_t;
+
+/**
+ * Outgoing message: number of total frames in backtrace.
+ */
+typedef struct
+{
+ uint8_t type; /**< type of the message */
+ uint8_t frame_count[sizeof (uint32_t)]; /**< total number of frames */
+} jerry_debugger_send_backtrace_total_t;
+
/**
* Incoming message: set behaviour when exception occures.
*/
typedef struct
{
uint8_t type; /**< type of the message */
+ uint8_t min_depth[sizeof (uint32_t)]; /**< minimum depth*/
uint8_t max_depth[sizeof (uint32_t)]; /**< maximum depth (0 - unlimited) */
+ uint8_t get_total_frame_count; /**< non-zero: if total frame count is also requested */
} jerry_debugger_receive_get_backtrace_t;
/**
uint8_t eval_size[sizeof (uint32_t)]; /**< total size of the message */
} jerry_debugger_receive_eval_first_t;
+/**
+ * Incoming message: get scope variables
+*/
+typedef struct
+{
+ uint8_t type; /**< type of the message */
+ uint8_t chain_index[sizeof (uint32_t)]; /**< index element of the scope */
+} jerry_debugger_receive_get_scope_variables_t;
+
/**
* Incoming message: first message of client source.
*/
void jerry_debugger_free_unreferenced_byte_code (void);
-void jerry_debugger_sleep (void);
+bool jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p);
-bool jerry_debugger_process_message (uint8_t *recv_buffer_p, uint32_t message_size,
- bool *resume_exec_p, uint8_t *expected_message_p,
- jerry_debugger_uint8_data_t **message_data_p);
void jerry_debugger_breakpoint_hit (uint8_t message_type);
void jerry_debugger_send_type (jerry_debugger_header_type_t type);
#include "ecma-alloc.h"
#include "ecma-globals.h"
#include "ecma-gc.h"
-#include "ecma-lcache.h"
#include "jrt.h"
#include "jmem.h"
*/
/**
- * Template of an allocation routine.
- */
-#define ALLOC(ecma_type) ecma_ ## ecma_type ## _t * \
- ecma_alloc_ ## ecma_type (void) \
-{ \
- ecma_ ## ecma_type ## _t *ecma_type ## _p; \
- ecma_type ## _p = (ecma_ ## ecma_type ## _t *) jmem_pools_alloc (sizeof (ecma_ ## ecma_type ## _t)); \
- \
- JERRY_ASSERT (ecma_type ## _p != NULL); \
- \
- return ecma_type ## _p; \
-}
-
-/**
- * Deallocation routine template
+ * Allocate memory for ecma-number
+ *
+ * @return pointer to allocated memory
*/
-#define DEALLOC(ecma_type) void \
- ecma_dealloc_ ## ecma_type (ecma_ ## ecma_type ## _t *ecma_type ## _p) \
-{ \
- jmem_pools_free ((uint8_t *) ecma_type ## _p, sizeof (ecma_ ## ecma_type ## _t)); \
-}
+ecma_number_t *
+ecma_alloc_number (void)
+{
+ return (ecma_number_t *) jmem_pools_alloc (sizeof (ecma_number_t));
+} /* ecma_alloc_number */
/**
- * Declaration of alloc/free routine for specified ecma-type.
+ * Dealloc memory from an ecma-number
*/
-#define DECLARE_ROUTINES_FOR(ecma_type) \
- ALLOC (ecma_type) \
- DEALLOC (ecma_type)
-
-DECLARE_ROUTINES_FOR (number)
+void
+ecma_dealloc_number (ecma_number_t *number_p) /**< number to be freed */
+{
+ jmem_pools_free ((uint8_t *) number_p, sizeof (ecma_number_t));
+} /* ecma_dealloc_number */
/**
* Allocate memory for ecma-object
*
* @return pointer to allocated memory
*/
-inline ecma_object_t * __attr_always_inline___
+inline ecma_object_t * JERRY_ATTR_ALWAYS_INLINE
ecma_alloc_object (void)
{
#ifdef JMEM_STATS
/**
* Dealloc memory from an ecma-object
*/
-inline void __attr_always_inline___
+inline void JERRY_ATTR_ALWAYS_INLINE
ecma_dealloc_object (ecma_object_t *object_p) /**< object to be freed */
{
#ifdef JMEM_STATS
*
* @return pointer to allocated memory
*/
-inline ecma_extended_object_t * __attr_always_inline___
+inline ecma_extended_object_t * JERRY_ATTR_ALWAYS_INLINE
ecma_alloc_extended_object (size_t size) /**< size of object */
{
#ifdef JMEM_STATS
/**
* Dealloc memory of an extended object
*/
-inline void __attr_always_inline___
+inline void JERRY_ATTR_ALWAYS_INLINE
ecma_dealloc_extended_object (ecma_object_t *object_p, /**< extended object */
size_t size) /**< size of object */
{
*
* @return pointer to allocated memory
*/
-inline ecma_string_t * __attr_always_inline___
+inline ecma_string_t * JERRY_ATTR_ALWAYS_INLINE
ecma_alloc_string (void)
{
#ifdef JMEM_STATS
/**
* Dealloc memory from ecma-string descriptor
*/
-inline void __attr_always_inline___
+inline void JERRY_ATTR_ALWAYS_INLINE
ecma_dealloc_string (ecma_string_t *string_p) /**< string to be freed */
{
#ifdef JMEM_STATS
*
* @return pointer to allocated memory
*/
-inline ecma_string_t * __attr_always_inline___
+inline ecma_string_t * JERRY_ATTR_ALWAYS_INLINE
ecma_alloc_string_buffer (size_t size) /**< size of string */
{
#ifdef JMEM_STATS
/**
* Dealloc memory of a string with character data
*/
-inline void __attr_always_inline___
+inline void JERRY_ATTR_ALWAYS_INLINE
ecma_dealloc_string_buffer (ecma_string_t *string_p, /**< string with data */
size_t size) /**< size of string */
{
jmem_heap_free_block (string_p, size);
} /* ecma_dealloc_string_buffer */
-/**
- * Allocate memory for getter-setter pointer pair
- *
- * @return pointer to allocated memory
- */
-inline ecma_getter_setter_pointers_t * __attr_always_inline___
-ecma_alloc_getter_setter_pointers (void)
-{
-#ifdef JMEM_STATS
- jmem_stats_allocate_property_bytes (sizeof (ecma_property_pair_t));
-#endif /* JMEM_STATS */
-
- return (ecma_getter_setter_pointers_t *) jmem_pools_alloc (sizeof (ecma_getter_setter_pointers_t));
-} /* ecma_alloc_getter_setter_pointers */
-
-/**
- * Dealloc memory from getter-setter pointer pair
- */
-inline void __attr_always_inline___
-ecma_dealloc_getter_setter_pointers (ecma_getter_setter_pointers_t *getter_setter_pointers_p) /**< pointer pair
- * to be freed */
-{
-#ifdef JMEM_STATS
- jmem_stats_free_property_bytes (sizeof (ecma_property_pair_t));
-#endif /* JMEM_STATS */
-
- jmem_pools_free (getter_setter_pointers_p, sizeof (ecma_getter_setter_pointers_t));
-} /* ecma_dealloc_getter_setter_pointers */
-
/**
* Allocate memory for ecma-property pair
*
* @return pointer to allocated memory
*/
-inline ecma_property_pair_t * __attr_always_inline___
+inline ecma_property_pair_t * JERRY_ATTR_ALWAYS_INLINE
ecma_alloc_property_pair (void)
{
#ifdef JMEM_STATS
/**
* Dealloc memory of an ecma-property
*/
-inline void __attr_always_inline___
+inline void JERRY_ATTR_ALWAYS_INLINE
ecma_dealloc_property_pair (ecma_property_pair_t *property_pair_p) /**< property pair to be freed */
{
#ifdef JMEM_STATS
*/
void ecma_dealloc_string_buffer (ecma_string_t *string_p, size_t size);
-/**
- * Allocate memory for getter-setter pointer pair
- *
- * @return pointer to allocated memory
- */
-ecma_getter_setter_pointers_t *ecma_alloc_getter_setter_pointers (void);
-
-/**
- * Dealloc memory from getter-setter pointer pair
- */
-void ecma_dealloc_getter_setter_pointers (ecma_getter_setter_pointers_t *getter_setter_pointers_p);
-
/**
* Allocate memory for ecma-property pair
*
#include "ecma-globals.h"
#include "ecma-gc.h"
#include "ecma-helpers.h"
-#include "ecma-lcache.h"
#include "ecma-property-hashmap.h"
#include "jcontext.h"
#include "jrt.h"
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
#include "ecma-typedarray-object.h"
-#endif
+#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
#include "ecma-promise-object.h"
-#endif
+#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+#include "ecma-map-object.h"
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
/* TODO: Extract GC to a separate component */
/**
* Get next object in list of objects with same generation.
+ *
+ * @return pointer to the next ecma-object
+ * NULL - if there is no next ecma-object
*/
static inline ecma_object_t *
ecma_gc_get_object_next (ecma_object_t *object_p) /**< object */
/**
* Get visited flag of the object.
+ *
+ * @return true - if visited
+ * false - otherwise
*/
static inline bool
ecma_gc_is_object_visited (ecma_object_t *object_p) /**< object */
void
ecma_ref_object (ecma_object_t *object_p) /**< object */
{
- if (likely (object_p->type_flags_refs < ECMA_OBJECT_MAX_REF))
+ if (JERRY_LIKELY (object_p->type_flags_refs < ECMA_OBJECT_MAX_REF))
{
object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs + ECMA_OBJECT_REF_ONE);
}
/**
* Decrease reference counter of an object
*/
-inline void __attr_always_inline___
+inline void JERRY_ATTR_ALWAYS_INLINE
ecma_deref_object (ecma_object_t *object_p) /**< object */
{
JERRY_ASSERT (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE);
{
case ECMA_PROPERTY_TYPE_NAMEDDATA:
{
- if (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_DIRECT_STRING_MAGIC
- && property_pair_p->names_cp[index] >= LIT_NEED_MARK_MAGIC_STRING__COUNT)
- {
- break;
- }
-
ecma_value_t value = property_pair_p->values[index].value;
if (ecma_is_value_object (value))
}
break;
}
- case ECMA_PROPERTY_TYPE_SPECIAL:
+ case ECMA_PROPERTY_TYPE_INTERNAL:
{
- JERRY_ASSERT (property == ECMA_PROPERTY_TYPE_HASHMAP
- || property == ECMA_PROPERTY_TYPE_DELETED);
+ JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_DIRECT_STRING_MAGIC
+ && property_pair_p->names_cp[index] >= LIT_FIRST_INTERNAL_MAGIC_STRING);
break;
}
default:
{
- JERRY_UNREACHABLE ();
+ JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_SPECIAL);
+
+ JERRY_ASSERT (property == ECMA_PROPERTY_TYPE_HASHMAP
+ || property == ECMA_PROPERTY_TYPE_DELETED);
break;
}
}
} /* ecma_gc_mark_property */
+#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
+
+/**
+ * Mark objects referenced by Promise built-in.
+ */
+static void
+ecma_gc_mark_promise_object (ecma_extended_object_t *ext_object_p) /**< extended object */
+{
+ /* Mark promise result. */
+ ecma_value_t result = ext_object_p->u.class_prop.u.value;
+
+ if (ecma_is_value_object (result))
+ {
+ ecma_gc_set_object_visited (ecma_get_object_from_value (result));
+ }
+
+ /* Mark all 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_value_p != NULL)
+ {
+ ecma_gc_set_object_visited (ecma_get_object_from_value (*ecma_value_p));
+ ecma_value_p = ecma_collection_iterator_next (ecma_value_p);
+ }
+
+ ecma_value_p = ecma_collection_iterator_init (((ecma_promise_object_t *) ext_object_p)->reject_reactions);
+
+ while (ecma_value_p != NULL)
+ {
+ ecma_gc_set_object_visited (ecma_get_object_from_value (*ecma_value_p));
+ ecma_value_p = ecma_collection_iterator_next (ecma_value_p);
+ }
+} /* ecma_gc_mark_promise_object */
+
+#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */
+
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+
+/**
+ * Mark objects referenced by Map built-in.
+ */
+static void
+ecma_gc_mark_map_object (ecma_extended_object_t *ext_object_p) /**< extended object */
+{
+ ecma_map_object_t *map_object_p = (ecma_map_object_t *) ext_object_p;
+
+ jmem_cpointer_t first_chunk_cp = map_object_p->first_chunk_cp;
+
+ if (JERRY_UNLIKELY (first_chunk_cp == ECMA_NULL_POINTER))
+ {
+ return;
+ }
+
+ ecma_value_t *item_p = ECMA_GET_NON_NULL_POINTER (ecma_map_object_chunk_t, first_chunk_cp)->items;
+
+ while (true)
+ {
+ ecma_value_t item = *item_p++;
+
+ if (!ecma_is_value_pointer (item))
+ {
+ if (ecma_is_value_object (item))
+ {
+ ecma_gc_set_object_visited (ecma_get_object_from_value (item));
+ }
+ }
+ else
+ {
+ item_p = (ecma_value_t *) ecma_get_pointer_from_value (item);
+
+ if (item_p == NULL)
+ {
+ return;
+ }
+ }
+ }
+} /* ecma_gc_mark_map_object */
+
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
+
/**
* Mark objects as visited starting from specified object as root
*/
switch (ecma_get_object_type (object_p))
{
-#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
case ECMA_OBJECT_TYPE_CLASS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
- if (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_PROMISE_UL)
+ switch (ext_object_p->u.class_prop.class_id)
{
- /* Mark promise result. */
- ecma_value_t result = ext_object_p->u.class_prop.u.value;
-
- if (ecma_is_value_object (result))
+#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
+ case LIT_MAGIC_STRING_PROMISE_UL:
{
- ecma_gc_set_object_visited (ecma_get_object_from_value (result));
+ ecma_gc_mark_promise_object (ext_object_p);
+ break;
}
-
- /* Mark all 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_value_p != NULL)
+#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+ case LIT_MAGIC_STRING_MAP_UL:
{
- ecma_gc_set_object_visited (ecma_get_object_from_value (*ecma_value_p));
- ecma_value_p = ecma_collection_iterator_next (ecma_value_p);
+ ecma_gc_mark_map_object (ext_object_p);
+ break;
}
-
- ecma_value_p = ecma_collection_iterator_init (((ecma_promise_object_t *) ext_object_p)->reject_reactions);
-
- while (ecma_value_p != NULL)
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
+ default:
{
- ecma_gc_set_object_visited (ecma_get_object_from_value (*ecma_value_p));
- ecma_value_p = ecma_collection_iterator_next (ecma_value_p);
+ break;
}
}
break;
}
-#endif /*! CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */
case ECMA_OBJECT_TYPE_PSEUDO_ARRAY:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
switch (ext_object_p->u.pseudo_array.type)
{
- case ECMA_PSEUDO_ARRAY_ARGUMENTS:
- {
- ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
- ext_object_p->u.pseudo_array.u2.lex_env_cp);
-
- ecma_gc_set_object_visited (lex_env_p);
- break;
- }
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
case ECMA_PSEUDO_ARRAY_TYPEDARRAY:
case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO:
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
default:
{
- JERRY_UNREACHABLE ();
+ JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS);
+
+ ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
+ ext_object_p->u.pseudo_array.u2.lex_env_cp);
+
+ ecma_gc_set_object_visited (lex_env_p);
break;
}
}
* Free the native handle/pointer by calling its free callback.
*/
static void
-ecma_gc_free_native_pointer (ecma_property_t *property_p, /**< property */
- lit_magic_string_id_t id) /**< identifier of internal property */
+ecma_gc_free_native_pointer (ecma_property_t *property_p) /**< property */
{
JERRY_ASSERT (property_p != NULL);
- JERRY_ASSERT (id == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE
- || id == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
-
ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
ecma_native_pointer_t *native_pointer_p;
native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t,
value_p->value);
- if (id == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE)
+ if (native_pointer_p->info_p != NULL)
{
- if (native_pointer_p->u.callback_p != NULL)
+ ecma_object_native_free_callback_t free_cb = native_pointer_p->info_p->free_cb;
+
+ if (free_cb != NULL)
{
- native_pointer_p->u.callback_p ((uintptr_t) native_pointer_p->data_p);
+ free_cb (native_pointer_p->data_p);
}
}
- else
- {
- if (native_pointer_p->u.info_p != NULL)
- {
- ecma_object_native_free_callback_t free_cb = native_pointer_p->u.info_p->free_cb;
- if (free_cb != NULL)
- {
- free_cb (native_pointer_p->data_p);
- }
- }
- }
+ jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t));
} /* ecma_gc_free_native_pointer */
/**
/* Call the native's free callback. */
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))
+ && (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER))
{
- ecma_gc_free_native_pointer (property_p, (lit_magic_string_id_t) name_cp);
+ ecma_gc_free_native_pointer (property_p);
}
if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED)
switch (ext_object_p->u.class_prop.class_id)
{
- /* The undefined id represents an uninitialized class. */
- case LIT_MAGIC_STRING_UNDEFINED:
- case LIT_MAGIC_STRING_ARGUMENTS_UL:
- case LIT_MAGIC_STRING_BOOLEAN_UL:
- case LIT_MAGIC_STRING_ERROR_UL:
- {
- break;
- }
-
case LIT_MAGIC_STRING_STRING_UL:
case LIT_MAGIC_STRING_NUMBER_UL:
{
return;
}
#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+ case LIT_MAGIC_STRING_MAP_UL:
+ {
+ ecma_op_map_clear_map ((ecma_map_object_t *) object_p);
+ ecma_dealloc_extended_object (object_p, sizeof (ecma_map_object_t));
+ return;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
default:
{
- JERRY_UNREACHABLE ();
+ /* The undefined id represents an uninitialized class. */
+ JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_UNDEFINED
+ || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_ARGUMENTS_UL
+ || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL
+ || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_ERROR_UL);
break;
}
}
switch (ext_object_p->u.pseudo_array.type)
{
- case ECMA_PSEUDO_ARRAY_ARGUMENTS:
+#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
+ case ECMA_PSEUDO_ARRAY_TYPEDARRAY:
+ {
+ ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t));
+ return;
+ }
+ case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO:
{
+ ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_typedarray_object_t));
+ return;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
+ default:
+ {
+ JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS);
+
ecma_length_t formal_params_number = ext_object_p->u.pseudo_array.u1.length;
ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1);
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t) + formal_params_size);
return;
}
-#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
- case ECMA_PSEUDO_ARRAY_TYPEDARRAY:
- {
- ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t));
- return;
- }
- case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO:
- {
- ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_typedarray_object_t));
- return;
- }
-#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
- default:
- {
- JERRY_UNREACHABLE ();
- break;
- }
}
-
- JERRY_UNREACHABLE ();
}
if (object_type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
if (ecma_gc_is_object_visited (obj_iter_p))
{
/* Moving the object to list of marked objects. */
- if (likely (obj_prev_p != NULL))
+ if (JERRY_LIKELY (obj_prev_p != NULL))
{
obj_prev_p->gc_next_cp = obj_iter_p->gc_next_cp;
}
if (ecma_gc_is_object_visited (obj_iter_p))
{
/* Moving the object to list of marked objects */
- if (likely (obj_prev_p != NULL))
+ if (JERRY_LIKELY (obj_prev_p != NULL))
{
obj_prev_p->gc_next_cp = obj_iter_p->gc_next_cp;
}
* @{
*/
-/**
- * Ecma-pointer field is used to calculate ecma value's address.
- *
- * Ecma-pointer contains value's shifted offset from common Ecma-pointers' base.
- * The offset is shifted right by JMEM_ALIGNMENT_LOG.
- * Least significant JMEM_ALIGNMENT_LOG bits of non-shifted offset are zeroes.
- */
-#ifdef JERRY_CPOINTER_32_BIT
-#define ECMA_POINTER_FIELD_WIDTH 32
-#else /* !JERRY_CPOINTER_32_BIT */
-#define ECMA_POINTER_FIELD_WIDTH 16
-#endif /* JERRY_CPOINTER_32_BIT */
-
/**
* The NULL value for compressed pointers
*/
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_ERROR = 7, /**< pointer to description of an error reference (only supported by C API) */
+ ECMA_TYPE_POINTER = ECMA_TYPE_ERROR, /**< a generic aligned pointer */
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;
+#ifdef JERRY_DEBUGGER
+/**
+ * Shift for scope chain index part in ecma_parse_opts
+ */
+#define ECMA_PARSE_CHAIN_INDEX_SHIFT 16
+#endif
+
+/**
+ * Option flags for script parsing.
+ * Note:
+ * The enum members must be kept in sync with parser_general_flags_t
+ * The last 16 bits are reserved for scope chain index
+ */
+typedef enum
+{
+ ECMA_PARSE_NO_OPTS = 0, /**< no options passed */
+ ECMA_PARSE_STRICT_MODE = (1u << 0), /**< enable strict mode */
+ ECMA_PARSE_DIRECT_EVAL = (1u << 1), /**< eval is called directly (ECMA-262 v5, 15.1.2.1.1) */
+ /* These three status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
+ ECMA_PARSE_CLASS_CONSTRUCTOR = (1u << 2), /**< a class constructor is being parsed (this value must be kept in
+ * in sync with PARSER_CLASS_CONSTRUCTOR) */
+ ECMA_PARSE_HAS_SUPER = (1u << 3), /**< the current context has super reference */
+ ECMA_PARSE_HAS_STATIC_SUPER = (1u << 4), /**< the current context is a static class method */
+} ecma_parse_opts_t;
+
/**
* Description of an ecma value
*
*/
#define ECMA_DIRECT_SHIFT 4
-/* ECMA make simple value */
+/**
+ * ECMA make simple value
+ */
#define ECMA_MAKE_VALUE(value) \
((((ecma_value_t) (value)) << ECMA_DIRECT_SHIFT) | ECMA_DIRECT_TYPE_SIMPLE_VALUE)
ECMA_VALUE_UNDEFINED = ECMA_MAKE_VALUE (4), /**< undefined value */
ECMA_VALUE_NULL = ECMA_MAKE_VALUE (5), /**< null value */
ECMA_VALUE_ARRAY_HOLE = ECMA_MAKE_VALUE (6), /**< array hole, used for
- * initialization of an array literal */
+ * initialization of an array literal */
ECMA_VALUE_NOT_FOUND = ECMA_MAKE_VALUE (7), /**< a special value returned by
- * ecma_op_object_find */
+ * ecma_op_object_find */
ECMA_VALUE_REGISTER_REF = ECMA_MAKE_VALUE (8), /**< register reference,
- * a special "base" value for vm */
+ * a special "base" value for vm */
+ ECMA_VALUE_IMPLICIT_CONSTRUCTOR = ECMA_MAKE_VALUE (9), /**< special value for bound class constructors */
};
+#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
/**
* Maximum integer number for an ecma value
*/
-#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
#define ECMA_INTEGER_NUMBER_MAX 0x7fffff
+/**
+ * Maximum integer number for an ecma value (shifted left with ECMA_DIRECT_SHIFT)
+ */
#define ECMA_INTEGER_NUMBER_MAX_SHIFTED 0x7fffff0
#else /* CONFIG_ECMA_NUMBER_TYPE != CONFIG_ECMA_NUMBER_FLOAT32 */
+/**
+ * Maximum integer number for an ecma value
+ */
#define ECMA_INTEGER_NUMBER_MAX 0x7ffffff
+/**
+ * Maximum integer number for an ecma value (shifted left with ECMA_DIRECT_SHIFT)
+ */
#define ECMA_INTEGER_NUMBER_MAX_SHIFTED 0x7ffffff0
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */
+#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
/**
* Minimum integer number for an ecma value
*/
-#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
#define ECMA_INTEGER_NUMBER_MIN -0x7fffff
+/**
+ * Minimum integer number for an ecma value (shifted left with ECMA_DIRECT_SHIFT)
+ */
#define ECMA_INTEGER_NUMBER_MIN_SHIFTED -0x7fffff0
#else /* CONFIG_ECMA_NUMBER_TYPE != CONFIG_ECMA_NUMBER_FLOAT32 */
+/**
+ * Minimum integer number for an ecma value
+ */
#define ECMA_INTEGER_NUMBER_MIN -0x8000000
+/**
+ * Minimum integer number for an ecma value (shifted left with ECMA_DIRECT_SHIFT)
+ */
#define ECMA_INTEGER_NUMBER_MIN_SHIFTED (-0x7fffffff - 1) /* -0x80000000 */
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */
* Checks whether the error flag is set.
*/
#define ECMA_IS_VALUE_ERROR(value) \
- (unlikely ((value) == ECMA_VALUE_ERROR))
+ (JERRY_UNLIKELY ((value) == ECMA_VALUE_ERROR))
/**
* Representation for native external pointer
const ecma_value_t args_p[],
const ecma_length_t args_count);
-/**
- * Native free callback of an object (deprecated).
- */
-typedef void (*ecma_object_free_callback_t) (const uintptr_t native_p);
-
/**
* Native free callback of an object.
*/
typedef struct
{
void *data_p; /**< points to the data of the object */
- union
- {
- ecma_object_free_callback_t callback_p; /**< callback */
- ecma_object_native_info_t *info_p; /**< native info */
- } u;
+ ecma_object_native_info_t *info_p; /**< native info */
} ecma_native_pointer_t;
/**
*/
typedef enum
{
- ECMA_PROPERTY_TYPE_SPECIAL, /**< internal property */
+ ECMA_PROPERTY_TYPE_SPECIAL, /**< special purpose property (deleted / hashmap) */
ECMA_PROPERTY_TYPE_NAMEDDATA, /**< property is named data */
ECMA_PROPERTY_TYPE_NAMEDACCESSOR, /**< property is named accessor */
- ECMA_PROPERTY_TYPE_VIRTUAL, /**< property is virtual */
+ ECMA_PROPERTY_TYPE_INTERNAL, /**< internal property with custom data field */
+ ECMA_PROPERTY_TYPE_VIRTUAL = ECMA_PROPERTY_TYPE_INTERNAL, /**< property is virtual data property */
ECMA_PROPERTY_TYPE__MAX = ECMA_PROPERTY_TYPE_VIRTUAL, /**< highest value for property types. */
} ecma_property_types_t;
+/**
+ * Property name listing options.
+ */
+typedef enum
+{
+ ECMA_LIST_NO_OPTS = (0), /**< no options are provided */
+ ECMA_LIST_ARRAY_INDICES = (1 << 0), /**< exclude properties with names
+ * that are not indices */
+ ECMA_LIST_ENUMERABLE = (1 << 1), /**< exclude non-enumerable properties */
+ ECMA_LIST_PROTOTYPE = (1 << 2), /**< list properties from prototype chain */
+} ecma_list_properties_options_t;
+
+/**
+ * List enumerable properties and include the prototype chain.
+ */
+#define ECMA_LIST_ENUMERABLE_PROTOTYPE (ECMA_LIST_ENUMERABLE | ECMA_LIST_PROTOTYPE)
+
+
/**
* Property type mask.
*/
*/
#define ECMA_PROPERTY_NAME_TYPE_SHIFT (ECMA_PROPERTY_FLAG_SHIFT + 4)
+/**
+ * Convert data property to internal property.
+ */
+#define ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY(property_p) \
+ *(property_p) = (uint8_t) (*(property_p) + (ECMA_PROPERTY_TYPE_INTERNAL - ECMA_PROPERTY_TYPE_NAMEDDATA))
+
+/**
+ * Convert internal property to data property.
+ */
+#define ECMA_CONVERT_INTERNAL_PROPERTY_TO_DATA_PROPERTY(property_p) \
+ *(property_p) = (uint8_t) (*(property_p) - (ECMA_PROPERTY_TYPE_INTERNAL - ECMA_PROPERTY_TYPE_NAMEDDATA))
+
/**
* Special property identifiers.
*/
ECMA_SPECIAL_PROPERTY_DELETED, /**< deleted property */
ECMA_SPECIAL_PROPERTY__COUNT /**< Number of special property types */
-} ecma_internal_property_id_t;
+} ecma_special_property_id_t;
/**
* Define special property type.
*/
#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.
*/
* Returns true if the property pointer is a property pair.
*/
#define ECMA_PROPERTY_IS_PROPERTY_PAIR(property_header_p) \
- (ECMA_PROPERTY_GET_TYPE ((property_header_p)->types[0]) != ECMA_PROPERTY_TYPE_VIRTUAL \
- && (property_header_p)->types[0] != ECMA_PROPERTY_TYPE_HASHMAP)
+ ((property_header_p)->types[0] != ECMA_PROPERTY_TYPE_HASHMAP)
/**
* Returns true if the property is named property.
/* Types between 0 - 12 are ecma_object_type_t which can have a built-in flag. */
ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE = 13, /**< declarative lexical environment */
- ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND = 14, /**< object-bound lexical environment */
- ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND = 15, /**< object-bound lexical environment
- * with provideThis flag */
+ ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND = 14, /**< object-bound lexical environment
+ * with provideThis flag */
+ ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND = 15, /**< object-bound lexical environment
+ * with provided super reference */
ECMA_LEXICAL_ENVIRONMENT_TYPE_START = ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE, /**< first lexical
- * environment type */
- ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX = ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND /**< maximum value */
+ * environment type */
+ ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX = ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND /**< maximum value */
} ecma_lexical_environment_type_t;
+/**
+ * Offset for JERRY_CONTEXT (status_flags) top 8 bits.
+ */
+#define ECMA_SUPER_EVAL_OPTS_OFFSET (32 - 8)
+
+/**
+ * Set JERRY_CONTEXT (status_flags) top 8 bits to the specified 'opts'.
+ */
+#define ECMA_SET_SUPER_EVAL_PARSER_OPTS(opts) \
+ do \
+ { \
+ JERRY_CONTEXT (status_flags) |= ((uint32_t) opts << ECMA_SUPER_EVAL_OPTS_OFFSET) | ECMA_STATUS_DIRECT_EVAL; \
+ } while (0)
+
+/**
+ * Get JERRY_CONTEXT (status_flags) top 8 bits.
+ */
+#define ECMA_GET_SUPER_EVAL_PARSER_OPTS() (JERRY_CONTEXT (status_flags) >> ECMA_SUPER_EVAL_OPTS_OFFSET)
+
+/**
+ * Clear JERRY_CONTEXT (status_flags) top 8 bits.
+ */
+#define ECMA_CLEAR_SUPER_EVAL_PARSER_OPTS() \
+ do \
+ { \
+ JERRY_CONTEXT (status_flags) &= ((1 << ECMA_SUPER_EVAL_OPTS_OFFSET) - 1); \
+ } while (0)
+
/**
* Ecma object type mask for getting the object type.
*/
*/
#define ECMA_OBJECT_FLAG_EXTENSIBLE 0x20
+/**
+ * Non closure flag for debugger.
+ */
+#ifdef JERRY_DEBUGGER
+#define ECMA_OBJECT_FLAG_NON_CLOSURE 0x20
+#endif /* JERRY_DEBUGGER */
+
/**
* Value for increasing or decreasing the object reference counter.
*/
/** type : 4 bit : ecma_object_type_t or ecma_lexical_environment_type_t
depending on ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV
flags : 2 bit : ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV,
- ECMA_OBJECT_FLAG_EXTENSIBLE
+ ECMA_OBJECT_FLAG_EXTENSIBLE or ECMA_OBJECT_FLAG_NON_CLOSURE
refs : 10 bit (max 1023) */
uint16_t type_flags_refs;
{
ecma_object_t object; /**< object header */
- /*
- * Description of extra fields. These extra fields depends on the object type.
+ /**
+ * Description of extra fields. These extra fields depend on the object type.
*/
union
{
ecma_built_in_props_t built_in; /**< built-in object part */
- /*
+ /**
* Description of objects with class.
*/
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) */
+ * e.g. array buffer type info (external/internal) */
- /*
- * Description of extra fields. These extra fields depends on the class_id.
+ /**
+ * Description of extra fields. These extra fields depend on the class_id.
*/
union
{
ecma_value_t value; /**< value of the object (e.g. boolean, number, string, etc.) */
- uint32_t length; /**< length related property (e.g. length of ArrayBuffer) */
+ uint32_t length; /**< length related property (e.g. length of ArrayBuffer) */
} u;
} class_prop;
- /*
+ /**
* Description of function objects.
*/
struct
ecma_value_t bytecode_cp; /**< function byte code */
} function;
- /*
+ /**
* Description of array objects.
*/
struct
ecma_property_t length_prop; /**< length property */
} array;
- /*
+ /**
* Description of pseudo array objects.
*/
struct
{
uint8_t type; /**< pseudo array type, e.g. Arguments, TypedArray*/
- uint8_t extra_info; /**< extra infomations about the object.
- * e.g. element_width_shift for typed arrays */
+ uint8_t extra_info; /**< extra information about the object.
+ * e.g. element_width_shift for typed arrays */
union
{
uint16_t length; /**< for arguments: length of names */
} u2;
} pseudo_array;
- /*
+ /**
* Description of bound function object.
*/
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... */
+ * 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
*/
typedef struct
{
- ecma_extended_object_t header;
- const ecma_compiled_code_t *bytecode_p;
+ ecma_extended_object_t header; /**< header part */
+ const ecma_compiled_code_t *bytecode_p; /**< real byte code pointer */
} ecma_static_function_t;
#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+
+/**
+ * Map item count of chunks
+ */
+#define ECMA_MAP_OBJECT_ITEM_COUNT 3
+
+/**
+ * Description of Map objects.
+ */
+typedef struct
+{
+ ecma_extended_object_t header; /**< header part */
+ jmem_cpointer_t first_chunk_cp; /**< first chunk of item list */
+ jmem_cpointer_t last_chunk_cp; /**< last chunk of item list */
+} ecma_map_object_t;
+
+/**
+ * Description of Map memory chunk.
+ */
+typedef struct
+{
+ ecma_value_t items[ECMA_MAP_OBJECT_ITEM_COUNT + 1]; /**< the last item is always a pointer to the next chunk,
+ * the rest can be ECMA_VALUE_ARRAY_HOLE or any valid value. */
+} ecma_map_object_chunk_t;
+
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
+
/**
* Description of ECMA property descriptor
*
* Description of an ecma-number
*/
typedef float ecma_number_t;
+
#define DOUBLE_TO_ECMA_NUMBER_T(value) (ecma_number_t) (value)
/**
* Description of an ecma-number
*/
typedef double ecma_number_t;
+
#define DOUBLE_TO_ECMA_NUMBER_T(value) value
/**
*/
#define ECMA_NUMBER_MINUS_ONE ((ecma_number_t) -1)
+#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
/**
- * Minimum positive and maximum value of ecma-number
+ * Number.MIN_VALUE (i.e., the smallest positive value of ecma-number)
+ *
+ * See also: ECMA_262 v5, 15.7.3.3
*/
-#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
# define ECMA_NUMBER_MIN_VALUE (FLT_MIN)
+/**
+ * Number.MAX_VALUE (i.e., the maximum value of ecma-number)
+ *
+ * See also: ECMA_262 v5, 15.7.3.2
+ */
# define ECMA_NUMBER_MAX_VALUE (FLT_MAX)
#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
/**
- * Number.MAX_VALUE
+ * Number.MAX_VALUE (i.e., the maximum value of ecma-number)
*
* See also: ECMA_262 v5, 15.7.3.2
*/
# define ECMA_NUMBER_MAX_VALUE ((ecma_number_t) 1.7976931348623157e+308)
/**
- * Number.MIN_VALUE
+ * Number.MIN_VALUE (i.e., the smallest positive value of ecma-number)
*
* See also: ECMA_262 v5, 15.7.3.3
*/
*
* \addtogroup ecmahelpers Helpers for operations with ECMA data types
* @{
- *
+ */
+
+#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
+
+/**
* \addtogroup ecmahelpersbigintegers Helpers for operations intermediate 128-bit integers
* @{
*/
/**
- * Check that parts of 128-bit integer are 32-bit.
+ * 128-bit integer type
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT(name) \
-{ \
- JERRY_ASSERT (name[0] <= UINT32_MAX); \
- JERRY_ASSERT (name[1] <= UINT32_MAX); \
- JERRY_ASSERT (name[2] <= UINT32_MAX); \
- JERRY_ASSERT (name[3] <= UINT32_MAX); \
-}
+typedef struct
+{
+ uint64_t lo; /**< low 64 bits */
+ uint64_t hi; /**< high 64 bits */
+} ecma_uint128_t;
/**
- * Declare 128-bit integer.
+ * Round high part of 128-bit integer to uint64_t
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER(name) uint64_t name[4] = { 0, 0, 0, 0 }
+#define ECMA_UINT128_ROUND_HIGH_TO_UINT64(name) \
+ (name.hi + (name.lo >> 63u))
/**
- * Declare 128-bit in-out argument integer.
+ * Check if 128-bit integer is zero
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_ARG(name) uint64_t name[4]
+#define ECMA_UINT128_IS_ZERO(name) \
+ (name.hi == 0 && name.lo == 0)
/**
- * Initialize 128-bit integer with given 32-bit parts
+ * Left shift 128-bit integer by max 63 bits
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_INIT(name, high, mid_high, mid_low, low) \
+#define ECMA_UINT128_LEFT_SHIFT_MAX63(name, shift) \
{ \
- name[3] = high; \
- name[2] = mid_high; \
- name[1] = mid_low; \
- name[0] = low; \
- \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
+ name.hi = (name.hi << (shift)) | (name.lo >> (64 - (shift))); \
+ name.lo <<= (shift); \
}
/**
- * Copy specified 128-bit integer
+ * Right shift 128-bit integer by max 63 bits
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_COPY(name_copy_to, name_copy_from) \
+#define ECMA_UINT128_RIGHT_SHIFT_MAX63(name, shift) \
{ \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_copy_to); \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_copy_from); \
- \
- name_copy_to[0] = name_copy_from[0]; \
- name_copy_to[1] = name_copy_from[1]; \
- name_copy_to[2] = name_copy_from[2]; \
- name_copy_to[3] = name_copy_from[3]; \
+ name.lo = (name.lo >> (shift)) | (name.hi << (64 - (shift))); \
+ name.hi >>= (shift); \
}
/**
- * Copy high and middle parts of 128-bit integer to specified uint64_t variable
+ * Add 128-bit integer
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_ROUND_HIGH_AND_MIDDLE_TO_UINT64(name, uint64_var) \
+#define ECMA_UINT128_ADD(name_add_to, name_to_add) \
{ \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
- uint64_var = ((name[3] << 32u) | (name[2])) + (((name[1] >> 31u) != 0 ? 1 : 0)); \
+ name_add_to.hi += name_to_add.hi; \
+ name_add_to.lo += name_to_add.lo; \
+ if (name_add_to.lo < name_to_add.lo) \
+ { \
+ name_add_to.hi++; \
+ } \
}
/**
- * Copy middle and low parts of 128-bit integer to specified uint64_t variable
+ * Multiply 128-bit integer by 10
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_ROUND_MIDDLE_AND_LOW_TO_UINT64(name, uint64_var) \
+#define ECMA_UINT128_MUL10(name) \
{ \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
- uint64_var = (name[1] << 32u) | (name[0]); \
+ ECMA_UINT128_LEFT_SHIFT_MAX63 (name, 1u); \
+ \
+ ecma_uint128_t name ## _tmp = name; \
+ \
+ ECMA_UINT128_LEFT_SHIFT_MAX63 (name ## _tmp, 2u); \
+ \
+ ECMA_UINT128_ADD (name, name ## _tmp); \
}
/**
- * Check if specified 128-bit integers are equal
+ * Divide 128-bit integer by 10
+ *
+ * N = N3 *2^96 + N2 *2^64 + N1 *2^32 + N0 *2^0 // 128-bit dividend
+ * T = T3 *2^-32 + T2 *2^-64 + T1 *2^-96 + T0 *2^-128 // 128-bit divisor reciprocal, 1/10 * 2^-128
+ *
+ * N * T = N3*T3 *2^64 + N2*T3 *2^32 + N1*T3 *2^0 + N0*T3 *2^-32
+ * + N3*T2 *2^32 + N2*T2 *2^0 + N1*T2 *2^-32 + N0*T2 *2^-64
+ * + N3*T1 *2^0 + N2*T1 *2^-32 + N1*T1 *2^-64 + N0*T1 *2^-96
+ * + N3*T0 *2^-32 + N2*T0 *2^-64 + N1*T0 *2^-96 + N0*T0 *2^-128
+ *
+ * Q3=carry Q2=^+carry Q1=^+carry Q0=^+carry fraction=^...
+ *
+ * Q = Q3 *2^96 + Q2 *2^64 + Q1 *2^32 + Q0 *2^0 // 128-bit quotient
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_ARE_EQUAL(name1, name2) \
- ((name1)[0] == (name2[0]) \
- && (name1)[1] == (name2[1]) \
- && (name1)[2] == (name2[2]) \
- && (name1)[3] == (name2[3]))
+#define ECMA_UINT128_DIV10(name) \
+{ \
+ /* estimation of reciprocal of 10, 128 bits right of the binary point (T1 == T2) */ \
+ const uint64_t tenth_l = 0x9999999aul; \
+ const uint64_t tenth_m = 0x99999999ul; \
+ const uint64_t tenth_h = 0x19999999ul; \
+ \
+ uint64_t l0 = ((uint32_t) name.lo) * tenth_l; \
+ uint64_t l1 = (name.lo >> 32u) * tenth_l; \
+ uint64_t l2 = ((uint32_t) name.hi) * tenth_l; \
+ uint64_t l3 = (name.hi >> 32u) * tenth_l; \
+ uint64_t m0 = ((uint32_t) name.lo) * tenth_m; \
+ uint64_t m1 = (name.lo >> 32u) * tenth_m; \
+ uint64_t m2 = ((uint32_t) name.hi) * tenth_m; \
+ uint64_t m3 = (name.hi >> 32u) * tenth_m; \
+ uint64_t h0 = ((uint32_t) name.lo) * tenth_h; \
+ uint64_t h1 = (name.lo >> 32u) * tenth_h; \
+ uint64_t h2 = ((uint32_t) name.hi) * tenth_h; \
+ uint64_t h3 = (name.hi >> 32u) * tenth_h; \
+ \
+ uint64_t q0 = l0 >> 32u; \
+ q0 += (uint32_t) l1; \
+ q0 += (uint32_t) m0; \
+ \
+ q0 >>= 32u; \
+ q0 += l1 >> 32u; \
+ q0 += m0 >> 32u; \
+ q0 += (uint32_t) l2; \
+ q0 += (uint32_t) m1; \
+ q0 += (uint32_t) m0; \
+ \
+ q0 >>= 32u; \
+ q0 += l2 >> 32u; \
+ q0 += m1 >> 32u; \
+ q0 += m0 >> 32u; \
+ q0 += (uint32_t) l3; \
+ q0 += (uint32_t) m2; \
+ q0 += (uint32_t) m1; \
+ q0 += (uint32_t) h0; \
+ \
+ q0 >>=32u; \
+ q0 += l3 >> 32u; \
+ q0 += m2 >> 32u; \
+ q0 += m1 >> 32u; \
+ q0 += h0 >> 32u; \
+ q0 += (uint32_t) m3; \
+ q0 += (uint32_t) m2; \
+ q0 += (uint32_t) h1; \
+ \
+ uint64_t q1 = q0 >> 32u; \
+ q1 += m3 >> 32u; \
+ q1 += m2 >> 32u; \
+ q1 += h1 >> 32u; \
+ q1 += (uint32_t) m3; \
+ q1 += (uint32_t) h2; \
+ \
+ uint64_t q32 = q1 >> 32u; \
+ q32 += m3 >> 32u; \
+ q32 += h2 >> 32u; \
+ q32 += h3; \
+ \
+ name.lo = (q1 << 32u) | ((uint32_t) q0); \
+ name.hi = q32; \
+}
+
+#if defined (__GNUC__) || defined (__clang__)
/**
- * Check if bits [lowest_bit, 128) are zero
+ * Count leading zeros in the topmost 64 bits of a 128-bit integer.
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO(name, lowest_bit) \
- ((lowest_bit) >= 96 ? ((name[3] >> ((lowest_bit) - 96)) == 0) : \
- ((lowest_bit) >= 64 ? (name[3] == 0 \
- && ((name[2] >> ((lowest_bit) - 64)) == 0)) : \
- ((lowest_bit) >= 32 ? (name[3] == 0 \
- && name[2] == 0 && ((name[1] >> ((lowest_bit) - 32)) == 0)) : \
- (name[3] == 0 && name[2] == 0 && name[1] == 0 && ((name[0] >> (lowest_bit)) == 0)))))
+#define ECMA_UINT128_CLZ_MAX63(name) \
+ __builtin_clzll (name.hi)
/**
- * Check if bits [0, highest_bit] are zero
+ * Count leading zeros in the topmost 4 bits of a 128-bit integer.
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_LOW_BIT_MASK_ZERO(name, highest_bit) \
- ((highest_bit >= 96) ? (name[2] == 0 && name[1] == 0 && name[0] == 0 \
- && (((uint32_t) name[3] << (127 - (highest_bit))) == 0)) : \
- ((highest_bit >= 64) ? (name[1] == 0 && name[0] == 0 \
- && (((uint32_t) name[2] << (95 - (highest_bit))) == 0)) : \
- ((highest_bit >= 32) ? (name[0] == 0 \
- && (((uint32_t) name[1] << (63 - (highest_bit))) == 0)) : \
- (((uint32_t) name[0] << (31 - (highest_bit))) == 0))))
+#define ECMA_UINT128_CLZ_MAX4(name) \
+ __builtin_clzll (name.hi)
+
+#else /* !__GNUC__ && !__clang__ */
/**
- * Check if 128-bit integer is zero
+ * Count leading zeros in a 64-bit integer. The behaviour is undefined for 0.
+ *
+ * @return number of leading zeros.
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_ZERO(name) \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (name, 0)
+static inline int JERRY_ATTR_ALWAYS_INLINE
+ecma_uint64_clz (uint64_t n) /**< integer to count leading zeros in */
+{
+ JERRY_ASSERT (n != 0);
+
+ int cnt = 0;
+ uint64_t one = 0x8000000000000000ull;
+ while ((n & one) == 0)
+ {
+ cnt++;
+ one >>= 1;
+ }
+ return cnt;
+} /* ecma_uint64_clz */
/**
- * Shift 128-bit integer one bit left
+ * Number of leading zeros in 4-bit integers.
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_LEFT_SHIFT(name) \
-{ \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
- \
- name[3] = (uint32_t) (name[3] << 1u); \
- name[3] |= name[2] >> 31u; \
- name[2] = (uint32_t) (name[2] << 1u); \
- name[2] |= name[1] >> 31u; \
- name[1] = (uint32_t) (name[1] << 1u); \
- name[1] |= name[0] >> 31u; \
- name[0] = (uint32_t) (name[0] << 1u); \
- \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
-}
+static const uint8_t ecma_uint4_clz[] = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
/**
- * Shift 128-bit integer one bit right
+ * Count leading zeros in the topmost 64 bits of a 128-bit integer.
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_RIGHT_SHIFT(name) \
-{ \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
- \
- name[0] >>= 1u; \
- name[0] |= (uint32_t) (name[1] << 31u); \
- name[1] >>= 1u; \
- name[1] |= (uint32_t) (name[2] << 31u); \
- name[2] >>= 1u; \
- name[2] |= (uint32_t) (name[3] << 31u); \
- name[3] >>= 1u; \
- \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
-}
+#define ECMA_UINT128_CLZ_MAX63(name) \
+ ecma_uint64_clz (name.hi)
/**
- * Increment 128-bit integer
+ * Count leading zeros in the topmost 4 bits of a 128-bit integer.
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_INC(name) \
-{ \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
- \
- name[0] += 1ull; \
- name[1] += (name[0] >> 32u); \
- name[0] = (uint32_t) name[0]; \
- name[2] += (name[1] >> 32u); \
- name[1] = (uint32_t) name[1]; \
- name[3] += (name[2] >> 32u); \
- name[2] = (uint32_t) name[2]; \
- \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
-}
+#define ECMA_UINT128_CLZ_MAX4(name) \
+ ecma_uint4_clz[name.hi >> 60]
+
+#endif /* __GNUC__ || __clang__ */
/**
- * Add 128-bit integer
+ * @}
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_ADD(name_add_to, name_to_add) \
-{ \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_add_to); \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_to_add); \
- \
- name_add_to[0] += name_to_add[0]; \
- name_add_to[1] += name_to_add[1]; \
- name_add_to[2] += name_to_add[2]; \
- name_add_to[3] += name_to_add[3]; \
- \
- name_add_to[1] += (name_add_to[0] >> 32u); \
- name_add_to[0] = (uint32_t) name_add_to[0]; \
- name_add_to[2] += (name_add_to[1] >> 32u); \
- name_add_to[1] = (uint32_t) name_add_to[1]; \
- name_add_to[3] += (name_add_to[2] >> 32u); \
- name_add_to[2] = (uint32_t) name_add_to[2]; \
- \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_add_to); \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_to_add); \
-}
/**
- * Multiply 128-bit integer by 10
+ * Number.MAX_VALUE exponent part when using 64 bit float representation.
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_MUL_10(name) \
-{ \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
- \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_LEFT_SHIFT (name); \
- \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER (name ## _tmp); \
- \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_COPY (name ## _tmp, name); \
- \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_LEFT_SHIFT (name ## _tmp); \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_LEFT_SHIFT (name ## _tmp); \
- \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_ADD (name, name ## _tmp); \
- \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
-}
-
+#define NUMBER_MAX_DECIMAL_EXPONENT 308
/**
- * Divide 128-bit integer by 10
+ * Number.MIN_VALUE exponent part when using 64 bit float representation.
*/
-#define ECMA_NUMBER_CONVERSION_128BIT_INTEGER_DIV_10(name) \
-{ \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
- \
- /* estimation of reciprocal of 10 */ \
- const uint64_t div10_p_low = 0x9999999aul; \
- const uint64_t div10_p_mid = 0x99999999ul; \
- const uint64_t div10_p_high = 0x19999999ul; \
- \
- uint64_t intermediate[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; \
- uint64_t l0, l1, l2, l3, m0, m1, m2, m3, h0, h1, h2, h3; \
- l0 = name[0] * div10_p_low; \
- l1 = name[1] * div10_p_low; \
- l2 = name[2] * div10_p_low; \
- l3 = name[3] * div10_p_low; \
- m0 = name[0] * div10_p_mid; \
- m1 = name[1] * div10_p_mid; \
- m2 = name[2] * div10_p_mid; \
- m3 = name[3] * div10_p_mid; \
- h0 = name[0] * div10_p_high; \
- h1 = name[1] * div10_p_high; \
- h2 = name[2] * div10_p_high; \
- h3 = name[3] * div10_p_high; \
- intermediate[0] += (uint32_t) l0; \
- intermediate[1] += l0 >> 32u; \
- \
- intermediate[1] += (uint32_t) l1; \
- intermediate[2] += l1 >> 32u; \
- intermediate[1] += (uint32_t) m0; \
- intermediate[2] += m0 >> 32u; \
- \
- intermediate[2] += (uint32_t) l2; \
- intermediate[3] += l2 >> 32u; \
- intermediate[2] += (uint32_t) m1; \
- intermediate[3] += m1 >> 32u; \
- intermediate[2] += (uint32_t) m0; \
- intermediate[3] += m0 >> 32u; \
- \
- intermediate[3] += (uint32_t) l3; \
- intermediate[4] += l3 >> 32u; \
- intermediate[3] += (uint32_t) m2; \
- intermediate[4] += m2 >> 32u; \
- intermediate[3] += (uint32_t) m1; \
- intermediate[4] += m1 >> 32u; \
- intermediate[3] += (uint32_t) h0; \
- intermediate[4] += h0 >> 32u; \
- \
- intermediate[4] += (uint32_t) m3; \
- intermediate[5] += m3 >> 32u; \
- intermediate[4] += (uint32_t) m2; \
- intermediate[5] += m2 >> 32u; \
- intermediate[4] += (uint32_t) h1; \
- intermediate[5] += h1 >> 32u; \
- \
- intermediate[5] += (uint32_t) m3; \
- intermediate[6] += m3 >> 32u; \
- intermediate[5] += (uint32_t) h2; \
- intermediate[6] += h2 >> 32u; \
- \
- intermediate[6] += (uint32_t) h3; \
- intermediate[7] += h3 >> 32u; \
- \
- intermediate[1] += intermediate[0] >> 32u; \
- intermediate[0] = (uint32_t) intermediate[0]; \
- intermediate[2] += intermediate[1] >> 32u; \
- intermediate[1] = (uint32_t) intermediate[1]; \
- intermediate[3] += intermediate[2] >> 32u; \
- intermediate[2] = (uint32_t) intermediate[2]; \
- intermediate[4] += intermediate[3] >> 32u; \
- intermediate[3] = (uint32_t) intermediate[3]; \
- intermediate[5] += intermediate[4] >> 32u; \
- intermediate[4] = (uint32_t) intermediate[4]; \
- intermediate[6] += intermediate[5] >> 32u; \
- intermediate[5] = (uint32_t) intermediate[5]; \
- intermediate[7] += intermediate[6] >> 32u; \
- intermediate[6] = (uint32_t) intermediate[6]; \
- \
- name[0] = intermediate[4]; \
- name[1] = intermediate[5]; \
- name[2] = intermediate[6]; \
- name[3] = intermediate[7]; \
- \
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \
-}
+#define NUMBER_MIN_DECIMAL_EXPONENT -324
-#define EPSILON 0.0000001
+#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
-#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
/**
- * Number.MAX_VALUE and Number.MIN_VALUE exponent parts while using 64 bit float representation
+ * Number.MAX_VALUE exponent part when using 32 bit float representation.
*/
-# define NUMBER_MAX_DECIMAL_EXPONENT 308
-# define NUMBER_MIN_DECIMAL_EXPONENT -324
-#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
+#define NUMBER_MAX_DECIMAL_EXPONENT 38
/**
- * Number.MAX_VALUE and Number.MIN_VALUE exponent parts while using 32 bit float representation
+ * Number.MIN_VALUE exponent part when using 32 bit float representation.
*/
-# define NUMBER_MAX_DECIMAL_EXPONENT 38
-# define NUMBER_MIN_DECIMAL_EXPONENT -45
+#define NUMBER_MIN_DECIMAL_EXPONENT -45
+
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
/**
- * @}
+ * Value of epsilon
*/
+#define EPSILON 0.0000001
/**
* ECMA-defined conversion of string to Number.
}
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
- int32_t binary_exponent = 33;
-
/*
* 128-bit mantissa storage
*
- * Normalized: |4 bits zero|124-bit mantissa with highest bit set to 1 if mantissa is non-zero|
+ * Normalized: |4 bits zero|124-bit mantissa with highest bit set to 1|
*/
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER (fraction_uint128);
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_INIT (fraction_uint128,
- 0ull,
- fraction_uint64 >> 32u,
- (uint32_t) fraction_uint64,
- 0ull);
+ ecma_uint128_t fraction_uint128 = { 0, fraction_uint64 };
/* Normalizing mantissa */
- JERRY_ASSERT (ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint128, 124));
-
- while (ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint128, 123))
+ int shift = 4 - ECMA_UINT128_CLZ_MAX63 (fraction_uint128);
+ if (shift < 0)
{
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_LEFT_SHIFT (fraction_uint128);
- binary_exponent--;
-
- JERRY_ASSERT (!ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_ZERO (fraction_uint128));
+ ECMA_UINT128_LEFT_SHIFT_MAX63 (fraction_uint128, -shift);
+ }
+ else
+ {
+ ECMA_UINT128_RIGHT_SHIFT_MAX63 (fraction_uint128, shift);
}
+ int32_t binary_exponent = 1 + shift;
if (!e_sign)
{
while (e > 0)
{
- JERRY_ASSERT (ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint128, 124));
+ JERRY_ASSERT (ECMA_UINT128_CLZ_MAX63 (fraction_uint128) == 4);
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_MUL_10 (fraction_uint128);
+ ECMA_UINT128_MUL10 (fraction_uint128);
e--;
/* Normalizing mantissa */
- while (!ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint128, 124))
- {
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_RIGHT_SHIFT (fraction_uint128);
-
- binary_exponent++;
- }
- while (ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint128, 123))
- {
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_LEFT_SHIFT (fraction_uint128);
-
- binary_exponent--;
-
- JERRY_ASSERT (!ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_ZERO (fraction_uint128));
- }
+ shift = 4 - ECMA_UINT128_CLZ_MAX4 (fraction_uint128);
+ JERRY_ASSERT (shift >= 0);
+ ECMA_UINT128_RIGHT_SHIFT_MAX63 (fraction_uint128, shift);
+ binary_exponent += shift;
}
}
else
while (e > 0)
{
- /* Denormalizing mantissa, moving highest 1 to 95-bit */
- while (ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint128, 127))
- {
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_LEFT_SHIFT (fraction_uint128);
+ /* Denormalizing mantissa, moving highest 1 to bit 127 */
+ shift = ECMA_UINT128_CLZ_MAX4 (fraction_uint128);
+ JERRY_ASSERT (shift <= 4);
+ ECMA_UINT128_LEFT_SHIFT_MAX63 (fraction_uint128, shift);
+ binary_exponent -= shift;
- binary_exponent--;
-
- JERRY_ASSERT (!ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_ZERO (fraction_uint128));
- }
+ JERRY_ASSERT (!ECMA_UINT128_IS_ZERO (fraction_uint128));
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_DIV_10 (fraction_uint128);
+ ECMA_UINT128_DIV10 (fraction_uint128);
e--;
}
/* Normalizing mantissa */
- while (!ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint128, 124))
- {
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_RIGHT_SHIFT (fraction_uint128);
-
- binary_exponent++;
- }
- while (ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint128, 123))
- {
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_LEFT_SHIFT (fraction_uint128);
+ shift = 4 - ECMA_UINT128_CLZ_MAX4 (fraction_uint128);
+ JERRY_ASSERT (shift >= 0);
+ ECMA_UINT128_RIGHT_SHIFT_MAX63 (fraction_uint128, shift);
+ binary_exponent += shift;
- binary_exponent--;
-
- JERRY_ASSERT (!ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_ZERO (fraction_uint128));
- }
+ JERRY_ASSERT (ECMA_UINT128_CLZ_MAX63 (fraction_uint128) == 4);
}
- JERRY_ASSERT (!ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_ZERO (fraction_uint128));
- JERRY_ASSERT (ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint128, 124));
+ JERRY_ASSERT (!ECMA_UINT128_IS_ZERO (fraction_uint128));
+ JERRY_ASSERT (ECMA_UINT128_CLZ_MAX63 (fraction_uint128) == 4);
/*
* Preparing mantissa for conversion to 52-bit representation, converting it to:
*
- * |12 zero bits|116 mantissa bits|
+ * |11 zero bits|1|116 mantissa bits|
*/
- while (!ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint128, 116 + 1))
- {
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_RIGHT_SHIFT (fraction_uint128);
-
- binary_exponent++;
- }
- while (ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint128, 116))
- {
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_LEFT_SHIFT (fraction_uint128);
-
- binary_exponent--;
-
- JERRY_ASSERT (!ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_ZERO (fraction_uint128));
- }
+ ECMA_UINT128_RIGHT_SHIFT_MAX63 (fraction_uint128, 7u);
+ binary_exponent += 7;
- JERRY_ASSERT (ECMA_NUMBER_CONVERSION_128BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint128, 116 + 1));
+ JERRY_ASSERT (ECMA_UINT128_CLZ_MAX63 (fraction_uint128) == 11);
- ECMA_NUMBER_CONVERSION_128BIT_INTEGER_ROUND_HIGH_AND_MIDDLE_TO_UINT64 (fraction_uint128, fraction_uint64);
+ fraction_uint64 = ECMA_UINT128_ROUND_HIGH_TO_UINT64 (fraction_uint128);
- return ecma_number_make_from_sign_mantissa_and_exponent (sign,
- fraction_uint64,
- binary_exponent);
+ return ecma_number_make_from_sign_mantissa_and_exponent (sign, fraction_uint64, binary_exponent);
#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
/* Less precise conversion */
ecma_number_t num = (ecma_number_t) (uint32_t) fraction_uint64;
lit_utf8_size_t bytes_copied = (lit_utf8_size_t) (out_buffer_p + buffer_size - buf_p);
- if (likely (buf_p != out_buffer_p))
+ if (JERRY_LIKELY (buf_p != out_buffer_p))
{
memmove (out_buffer_p, buf_p, bytes_copied);
}
} /* ecma_number_to_int32 */
/**
- * Perform conversion of ecma-number to decimal representation with decimal exponent
+ * Perform conversion of ecma-number to decimal representation with decimal exponent.
*
* Note:
* The calculated values correspond to s, n, k parameters in ECMA-262 v5, 9.8.1, item 5:
* - parameter out_digits_p corresponds to s, the digits of the number;
* - parameter out_decimal_exp_p corresponds to n, the decimal exponent;
* - return value corresponds to k, the number of digits.
+ *
+ * @return the number of digits
*/
lit_utf8_size_t
ecma_number_to_decimal (ecma_number_t num, /**< ecma-number */
*
* @return number of digits
*/
-inline static int32_t __attr_always_inline___
+inline static int32_t JERRY_ATTR_ALWAYS_INLINE
ecma_number_of_digits (double val) /**< ecma number */
{
JERRY_ASSERT (fabs (fmod (val, 1.0)) < EPSILON);
/**
* Convert double value to ASCII
*/
-inline static void __attr_always_inline___
+inline static void JERRY_ATTR_ALWAYS_INLINE
ecma_double_to_ascii (double val, /**< ecma number */
lit_utf8_byte_t *buffer_p, /**< buffer to generate digits into */
int32_t num_of_digits, /**< number of digits */
*
* @return number of generated digits
*/
-static inline lit_utf8_size_t __attr_always_inline___
+static inline lit_utf8_size_t JERRY_ATTR_ALWAYS_INLINE
ecma_double_to_binary_floating_point (double val, /**< ecma number */
lit_utf8_byte_t *buffer_p, /**< buffer to generate digits into */
int32_t *exp_p) /**< [out] exponent */
} /* ecma_double_to_binary_floating_point */
/**
- * Perform conversion of ecma-number to equivalent binary floating-point number representation with decimal exponent
- *
- * Note:
- * The calculated values correspond to s, n, k parameters in ECMA-262 v5, 9.8.1, item 5:
- * - parameter out_digits_p corresponds to s, the digits of the number;
- * - parameter out_decimal_exp_p corresponds to n, the decimal exponent;
- * - return value corresponds to k, the number of digits.
- */
+ * Perform conversion of ecma-number to equivalent binary floating-point number representation with decimal exponent.
+ *
+ * Note:
+ * The calculated values correspond to s, n, k parameters in ECMA-262 v5, 9.8.1, item 5:
+ * - parameter out_digits_p corresponds to s, the digits of the number;
+ * - parameter out_decimal_exp_p corresponds to n, the decimal exponent;
+ * - return value corresponds to k, the number of digits.
+ *
+ * @return the number of digits
+ */
lit_utf8_size_t
ecma_number_to_binary_floating_point_number (ecma_number_t num, /**< ecma-number */
lit_utf8_byte_t *out_digits_p, /**< [out] buffer to fill with digits */
*/
/**
- * Floating point format definitions
+ * Floating point format definitions (next float value)
*/
#define ECMA_NEXT_FLOAT(value) (nextafter ((value), INFINITY))
+/**
+ * Floating point format definitions (previous float value)
+ */
#define ECMA_PREV_FLOAT(value) (nextafter ((value), -INFINITY))
+/**
+ * Value of epsilon
+ */
#define ERROL0_EPSILON 0.0000001
/**
/**
* Normalize the number by factoring in the error.
*/
-static inline void __attr_always_inline___
+static inline void JERRY_ATTR_ALWAYS_INLINE
ecma_normalize_high_prec_data (ecma_high_prec_t *hp_data_p) /**< [in, out] float pair */
{
double val = hp_data_p->value;
/**
* Multiply the high-precision number by ten.
*/
-static inline void __attr_always_inline___
+static inline void JERRY_ATTR_ALWAYS_INLINE
ecma_multiply_high_prec_by_10 (ecma_high_prec_t *hp_data_p) /**< [in, out] high-precision number */
{
double value = hp_data_p->value;
*
* @return number of generated digits
*/
-inline lit_utf8_size_t __attr_always_inline___
+inline lit_utf8_size_t JERRY_ATTR_ALWAYS_INLINE
ecma_errol0_dtoa (double val, /**< ecma number */
lit_utf8_byte_t *buffer_p, /**< buffer to generate digits into */
int32_t *exp_p) /**< [out] exponent */
*/
/**
- * Create internal property with specified identifier and store native handle/pointer of the object.
- *
- * Note:
- * property identifier should be one of the following:
- * - LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE
- * - LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER
+ * Create a native pointer property to store the native pointer and its type info.
*
* @return true - if property was just created with specified value,
* false - otherwise, if property existed before the call, it's value was updated
*/
-static bool
-ecma_create_native_property (ecma_object_t *obj_p, /**< object to create property in */
- lit_magic_string_id_t id, /**< identifier of internal
- * property to create */
- void *data_p, /**< native pointer data */
- void *info_p) /**< native pointer's info */
+bool
+ecma_create_native_pointer_property (ecma_object_t *obj_p, /**< object to create property in */
+ void *native_p, /**< native pointer */
+ void *info_p) /**< native pointer's type info */
{
- JERRY_ASSERT (id == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE
- || id == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
-
- ecma_string_t *name_p = ecma_get_magic_string (id);
+ ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
ecma_property_t *property_p = ecma_find_named_property (obj_p, name_p);
bool is_new = (property_p == NULL);
if (is_new)
{
ecma_property_value_t *value_p;
- value_p = ecma_create_named_data_property (obj_p, name_p, ECMA_PROPERTY_FLAG_WRITABLE, NULL);
+ value_p = ecma_create_named_data_property (obj_p, name_p, ECMA_PROPERTY_FLAG_WRITABLE, &property_p);
+
+ ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p);
native_pointer_p = jmem_heap_alloc_block (sizeof (ecma_native_pointer_t));
native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t, value_p->value);
}
- native_pointer_p->data_p = data_p;
- native_pointer_p->u.info_p = info_p;
+ native_pointer_p->data_p = native_p;
+ native_pointer_p->info_p = info_p;
return is_new;
-} /* ecma_create_native_property */
-
-/**
- * Create a native handle property to store the native handle and its free callback.
- *
- * @return true - if property was just created with specified value,
- * false - otherwise, if property existed before the call, it's value was updated
- */
-bool
-ecma_create_native_handle_property (ecma_object_t *obj_p, /**< object to create property in */
- void *handle_p, /**< native handle */
- void *free_cb) /**< native handle's free callback*/
-{
- return ecma_create_native_property (obj_p,
- LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE,
- handle_p,
- free_cb);
-} /* ecma_create_native_handle_property */
-
-/**
- * Create a native pointer property to store the native pointer and its type info.
- *
- * @return true - if property was just created with specified value,
- * false - otherwise, if property existed before the call, it's value was updated
- */
-bool
-ecma_create_native_pointer_property (ecma_object_t *obj_p, /**< object to create property in */
- void *native_p, /**< native pointer */
- void *info_p) /**< native pointer's type info */
-{
- return ecma_create_native_property (obj_p,
- LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER,
- native_p,
- info_p);
} /* ecma_create_native_pointer_property */
/**
*
* Note:
* property identifier should be one of the following:
- * - LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE
* - LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER
*
* @return native pointer data if property exists
* NULL otherwise
*/
ecma_native_pointer_t *
-ecma_get_native_pointer_value (ecma_object_t *obj_p, /**< object to get property value from */
- lit_magic_string_id_t id) /**< identifier of internal property
- * to get value from */
+ecma_get_native_pointer_value (ecma_object_t *obj_p) /**< object to get property value from */
{
- JERRY_ASSERT (id == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE
- || id == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
-
- ecma_property_t *property_p = ecma_find_named_property (obj_p, ecma_get_magic_string (id));
+ ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
+ ecma_property_t *property_p = ecma_find_named_property (obj_p, name_p);
if (property_p == NULL)
{
return ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t, value_p->value);
} /* ecma_get_native_pointer_value */
-/**
- * Free the allocated native package struct.
- */
-void
-ecma_free_native_pointer (ecma_property_t *prop_p) /**< native property */
-{
- ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (prop_p);
-
- ecma_native_pointer_t *native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t,
- value_p->value);
-
- jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t));
-} /* ecma_free_native_pointer */
-
/**
* @}
* @}
JERRY_STATIC_ASSERT (((1 << (ECMA_DIRECT_SHIFT - 1)) | ECMA_TYPE_DIRECT) == ECMA_DIRECT_TYPE_SIMPLE_VALUE,
currently_directly_encoded_values_start_after_direct_type_simple_value);
-
+/**
+ * Position of the sign bit in ecma-numbers
+ */
#define ECMA_NUMBER_SIGN_POS (ECMA_NUMBER_FRACTION_WIDTH + \
ECMA_NUMBER_BIASED_EXP_WIDTH)
fraction is filled with anything but not all zero bits,
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_number_is_nan (ecma_number_t num) /**< ecma-number */
{
bool is_nan = (num != num);
* @return true - if sign bit of ecma-number is set
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_number_is_negative (ecma_number_t num) /**< ecma-number */
{
JERRY_ASSERT (!ecma_number_is_nan (num));
*
* @return shift of dot in the fraction
*/
-int32_t
+static int32_t
ecma_number_get_fraction_and_exponent (ecma_number_t num, /**< ecma-number */
uint64_t *out_fraction_p, /**< [out] fraction of the number */
int32_t *out_exponent_p) /**< [out] exponent of the number */
uint64_t fraction = ecma_number_get_fraction_field (num);
int32_t exponent;
- if (unlikely (biased_exp == 0))
+ if (JERRY_UNLIKELY (biased_exp == 0))
{
/* IEEE-754 2008, 3.4, d */
if (ecma_number_is_zero (num))
*
* @return ecma-number
*/
-ecma_number_t
+static ecma_number_t
ecma_number_make_normal_positive_from_fraction_and_exponent (uint64_t fraction, /**< fraction */
int32_t exponent) /**< exponent */
{
*
* @return number - result of multiplication.
*/
-inline ecma_value_t __attr_always_inline___
+inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_integer_multiply (ecma_integer_value_t left_integer, /**< left operand */
ecma_integer_value_t right_integer) /**< right operand */
{
#if defined (__GNUC__) || defined (__clang__)
/* Check if left_integer is power of 2 */
- if (unlikely ((left_integer & (left_integer - 1)) == 0))
+ if (JERRY_UNLIKELY ((left_integer & (left_integer - 1)) == 0))
{
/* Right shift right_integer with log2 (left_integer) */
return ecma_make_integer_value (right_integer << (__builtin_ctz ((unsigned int) left_integer)));
}
- else if (unlikely ((right_integer & (right_integer - 1)) == 0))
+ else if (JERRY_UNLIKELY ((right_integer & (right_integer - 1)) == 0))
{
/* Right shift left_integer with log2 (right_integer) */
return ecma_make_integer_value (left_integer << (__builtin_ctz ((unsigned int) right_integer)));
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
-#include "ecma-lcache.h"
#include "jrt.h"
#include "jrt-libc-includes.h"
#include "lit-char-helpers.h"
}
} /* ecma_string_get_chars_fast */
+/**
+ * Allocate new ecma-string and fill it with reference to ECMA magic string
+ *
+ * @return pointer to ecma-string descriptor
+ */
+static ecma_string_t *
+ecma_new_ecma_string_from_magic_string_ex_id (lit_magic_string_ex_id_t id) /**< identifier of externl magic string */
+{
+ JERRY_ASSERT (id < lit_get_magic_string_ex_count ());
+
+ if (JERRY_LIKELY (id <= ECMA_DIRECT_STRING_MAX_IMM))
+ {
+ return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_MAGIC_EX, (uintptr_t) id);
+ }
+
+ ecma_string_t *string_desc_p = ecma_alloc_string ();
+
+ 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_string_from_magic_string_ex_id */
+
/**
* Allocate new ecma-string and fill it with characters from the utf8 string
*
ecma_string_t *string_desc_p;
lit_utf8_byte_t *data_p;
- if (likely (string_size <= UINT16_MAX))
+ if (JERRY_LIKELY (string_size <= UINT16_MAX))
{
string_desc_p = ecma_alloc_string_buffer (sizeof (ecma_string_t) + string_size);
lit_utf8_byte_t *data_p;
- if (likely (converted_string_size <= UINT16_MAX))
+ if (JERRY_LIKELY (converted_string_size <= UINT16_MAX))
{
string_desc_p = ecma_alloc_string_buffer (sizeof (ecma_string_t) + converted_string_size);
ecma_string_t *
ecma_new_ecma_string_from_uint32 (uint32_t uint32_number) /**< uint32 value of the string */
{
- if (likely (uint32_number <= ECMA_DIRECT_STRING_MAX_IMM))
+ if (JERRY_LIKELY (uint32_number <= ECMA_DIRECT_STRING_MAX_IMM))
{
return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_UINT, (uintptr_t) uint32_number);
}
* @return pointer to ecma-string descriptor
*/
ecma_string_t *
-ecma_get_ecma_string_from_uint32 (uint32_t uint32_number)
+ecma_get_ecma_string_from_uint32 (uint32_t uint32_number) /**< input number */
{
JERRY_ASSERT (uint32_number <= ECMA_DIRECT_STRING_MAX_IMM);
*
* @return pointer to ecma-string descriptor
*/
-inline ecma_string_t * __attr_always_inline___
+inline ecma_string_t * JERRY_ATTR_ALWAYS_INLINE
ecma_get_magic_string (lit_magic_string_id_t id) /**< identifier of magic string */
{
JERRY_ASSERT (id < LIT_MAGIC_STRING__COUNT);
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
- *
- * @return pointer to ecma-string descriptor
- */
-ecma_string_t *
-ecma_new_ecma_string_from_magic_string_ex_id (lit_magic_string_ex_id_t id) /**< identifier of externl magic string */
-{
- JERRY_ASSERT (id < lit_get_magic_string_ex_count ());
-
- if (likely (id <= ECMA_DIRECT_STRING_MAX_IMM))
- {
- return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_MAGIC_EX, (uintptr_t) id);
- }
-
- ecma_string_t *string_desc_p = ecma_alloc_string ();
-
- 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_string_from_magic_string_ex_id */
-
/**
* Append a cesu8 string after an ecma-string
*
{
JERRY_ASSERT (string1_p != NULL && cesu8_string2_size > 0 && cesu8_string2_length > 0);
- if (unlikely (ecma_string_is_empty (string1_p)))
+ if (JERRY_UNLIKELY (ecma_string_is_empty (string1_p)))
{
return ecma_new_ecma_string_from_utf8 (cesu8_string2_p, cesu8_string2_size);
}
ecma_string_t *string_desc_p;
lit_utf8_byte_t *data_p;
- if (likely (new_size <= UINT16_MAX))
+ if (JERRY_LIKELY (new_size <= UINT16_MAX))
{
string_desc_p = ecma_alloc_string_buffer (sizeof (ecma_string_t) + new_size);
{
JERRY_ASSERT (string1_p != NULL && string2_p != NULL);
- if (unlikely (ecma_string_is_empty (string1_p)))
+ if (JERRY_UNLIKELY (ecma_string_is_empty (string1_p)))
{
ecma_ref_ecma_string (string2_p);
return string2_p;
}
- else if (unlikely (ecma_string_is_empty (string2_p)))
+ else if (JERRY_UNLIKELY (ecma_string_is_empty (string2_p)))
{
return string1_p;
}
* @return concatenation of an ecma-string and a magic string
*/
ecma_string_t *
-ecma_append_magic_string_to_string (ecma_string_t *string1_p,
- lit_magic_string_id_t string2_id)
+ecma_append_magic_string_to_string (ecma_string_t *string1_p, /**< string descriptor */
+ lit_magic_string_id_t string2_id) /**< magic string ID */
{
- if (unlikely (ecma_string_is_empty (string1_p)))
+ if (JERRY_UNLIKELY (ecma_string_is_empty (string1_p)))
{
return ecma_get_magic_string (string2_id);
}
JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE);
- if (likely (string_p->refs_and_container < ECMA_STRING_MAX_REF))
+ if (JERRY_LIKELY (string_p->refs_and_container < ECMA_STRING_MAX_REF))
{
/* Increase reference counter. */
string_p->refs_and_container = (uint16_t) (string_p->refs_and_container + ECMA_STRING_REF_ONE);
ecma_dealloc_string_buffer (string_p, string_p->u.long_utf8_string_size + sizeof (ecma_long_string_t));
return;
}
- case ECMA_STRING_CONTAINER_UINT32_IN_DESC:
- case ECMA_STRING_CONTAINER_MAGIC_STRING_EX:
- {
- /* only the string descriptor itself should be freed */
- break;
- }
case ECMA_STRING_LITERAL_NUMBER:
{
ecma_free_value (string_p->u.lit_number);
}
default:
{
- JERRY_UNREACHABLE ();
+ JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC
+ || ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX);
+
+ /* only the string descriptor itself should be freed */
break;
}
}
/**
* Convert ecma-string to number
+ *
+ * @return converted ecma-number
*/
ecma_number_t
ecma_string_to_number (const ecma_string_t *string_p) /**< ecma-string */
* @return ECMA_STRING_NOT_ARRAY_INDEX if string is not array index
* the array index otherwise
*/
-inline uint32_t __attr_always_inline___
+inline uint32_t JERRY_ATTR_ALWAYS_INLINE
ecma_string_get_array_index (const ecma_string_t *str_p) /**< ecma-string */
{
if (ECMA_IS_DIRECT_STRING (str_p))
*
* @return number of bytes, actually copied to the buffer.
*/
-lit_utf8_size_t __attr_return_value_should_be_checked___
+lit_utf8_size_t JERRY_ATTR_WARN_UNUSED_RESULT
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) */
*
* @return number of bytes, actually copied to the buffer.
*/
-lit_utf8_size_t __attr_return_value_should_be_checked___
+lit_utf8_size_t JERRY_ATTR_WARN_UNUSED_RESULT
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 (ECMA_IS_DIRECT_STRING (string_desc_p) || string_desc_p->refs_and_container >= ECMA_STRING_REF_ONE);
JERRY_ASSERT (buffer_p != NULL || buffer_size == 0);
lit_utf8_size_t size = 0;
* It is the caller's responsibility to make sure that the string fits in the buffer.
* Check if the size of the string is equal with the size of the buffer.
*/
-inline void __attr_always_inline___
+inline void JERRY_ATTR_ALWAYS_INLINE
ecma_string_to_utf8_bytes (const ecma_string_t *string_desc_p, /**< ecma-string descriptor */
lit_utf8_byte_t *buffer_p, /**< destination buffer pointer
* (can be NULL if buffer_size == 0) */
*
* @return size in bytes
*/
-static inline ecma_length_t __attr_always_inline___
+static inline ecma_length_t JERRY_ATTR_ALWAYS_INLINE
ecma_string_get_uint32_size (const uint32_t uint32_number) /**< number in the string-descriptor */
{
uint32_t prev_number = 1;
result_p = lit_get_magic_string_ex_utf8 (id);
length = 0;
- if (unlikely (*flags_p & ECMA_STRING_FLAG_IS_ASCII))
+ if (JERRY_UNLIKELY (*flags_p & ECMA_STRING_FLAG_IS_ASCII))
{
length = lit_utf8_string_length (result_p, size);
}
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))
+ if (JERRY_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);
}
}
*size_p = size;
- if (*flags_p & ECMA_STRING_FLAG_IS_ASCII)
+ if ((*flags_p & ECMA_STRING_FLAG_IS_ASCII)
+ && length != size)
{
- if (length != size)
- {
- *flags_p = (uint8_t) (*flags_p & ~ECMA_STRING_FLAG_IS_ASCII);
- }
+ *flags_p = (uint8_t) (*flags_p & ~ECMA_STRING_FLAG_IS_ASCII);
}
return result_p;
* @return true - if the string equals to the magic string id
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_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 true - if the string is an empty string
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_string_is_empty (const ecma_string_t *string_p) /**< ecma-string */
{
return ecma_compare_ecma_string_to_magic_id (string_p, LIT_MAGIC_STRING__EMPTY);
* @return true - if the string equals to "length"
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
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___
+/**
+ * Converts a property name into a string
+ *
+ * @return pointer to the converted ecma string
+ */
+static inline ecma_string_t * JERRY_ATTR_ALWAYS_INLINE
ecma_property_to_string (ecma_property_t property, /**< property name type */
jmem_cpointer_t prop_name_cp) /**< property name compressed pointer */
{
*
* @return the compressed pointer part of the name
*/
-inline jmem_cpointer_t __attr_always_inline___
+inline jmem_cpointer_t JERRY_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 */
{
*
* @return hash code of property name
*/
-inline lit_string_hash_t __attr_always_inline___
+inline lit_string_hash_t JERRY_ATTR_ALWAYS_INLINE
ecma_string_get_property_name_hash (ecma_property_t property, /**< property name type */
jmem_cpointer_t prop_name_cp) /**< property name compressed pointer */
{
* @return true if they are equals
* false otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_string_compare_to_property_name (ecma_property_t property, /**< property name type */
jmem_cpointer_t prop_name_cp, /**< property name compressed pointer */
const ecma_string_t *string_p) /**< other string */
* @return true - if strings are equal;
* false - otherwise
*/
-static bool __attr_noinline___
+static bool JERRY_ATTR_NOINLINE
ecma_compare_ecma_strings_longpath (const ecma_string_t *string1_p, /**< ecma-string */
const ecma_string_t *string2_p) /**< ecma-string */
{
* @return true - if strings are equal;
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_compare_ecma_strings (const ecma_string_t *string1_p, /**< ecma-string */
const ecma_string_t *string2_p) /**< ecma-string */
{
* @return true - if strings are equal;
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_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 */
{
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 (ecma_length_t) (long_string_p->long_utf8_string_length);
}
- return lit_get_utf8_length_of_cesu8_string ((const lit_utf8_byte_t *) (string_p + 1),
+ return lit_get_utf8_length_of_cesu8_string ((const lit_utf8_byte_t *) (long_string_p + 1),
(lit_utf8_size_t) string_p->u.long_utf8_string_size);
}
default:
default:
{
JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX);
+
return lit_get_magic_string_ex_size (string_p->u.magic_string_ex_id);
}
}
*
* @return calculated hash
*/
-inline lit_string_hash_t __attr_always_inline___
+inline lit_string_hash_t JERRY_ATTR_ALWAYS_INLINE
ecma_string_hash (const ecma_string_t *string_p) /**< ecma-string to calculate hash for */
{
if (!ECMA_IS_DIRECT_STRING (string_p))
#include "ecma-function-object.h"
-/** \addtogroup ecma ECMA
- * @{
- *
- * \addtogroup ecmahelpers Helpers for operations with ECMA data types
- * @{
- */
-
JERRY_STATIC_ASSERT (ECMA_TYPE___MAX <= ECMA_VALUE_TYPE_MASK,
ecma_types_must_be_less_than_mask);
&& ECMA_VALUE_FALSE != ECMA_VALUE_TRUE,
only_the_lowest_bit_must_be_different_for_simple_value_true_and_false);
+/** \addtogroup ecma ECMA
+ * @{
+ *
+ * \addtogroup ecmahelpers Helpers for operations with ECMA data types
+ * @{
+ */
+
/**
* Get type field of ecma value
*
* @return type field
*/
-static inline ecma_type_t __attr_const___ __attr_always_inline___
+static inline ecma_type_t JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_get_value_type_field (ecma_value_t value) /**< ecma value */
{
return value & ECMA_VALUE_TYPE_MASK;
*
* @return ecma value
*/
-static inline ecma_value_t __attr_pure___ __attr_always_inline___
+static inline ecma_value_t JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
ecma_pointer_to_ecma_value (const void *ptr) /**< pointer */
{
#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY
*
* @return pointer
*/
-static inline void * __attr_pure___ __attr_always_inline___
+static inline void * JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
ecma_get_pointer_from_ecma_value (ecma_value_t value) /**< value */
{
#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY
* @return true - if the value is a direct value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_direct (ecma_value_t value) /**< ecma value */
{
return (ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT);
* @return true - if the value is a simple value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_simple (ecma_value_t value) /**< ecma value */
{
return (value & ECMA_DIRECT_TYPE_MASK) == ECMA_DIRECT_TYPE_SIMPLE_VALUE;
* @return true - if the value is equal to the given simple value,
* false - otherwise
*/
-static inline bool __attr_const___ __attr_always_inline___
+static inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_equal_to_simple_value (ecma_value_t value, /**< ecma value */
ecma_value_t simple_value) /**< simple value */
{
* @return true - if the value contains implementation-defined empty simple value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_empty (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_equal_to_simple_value (value, ECMA_VALUE_EMPTY);
* @return true - if the value contains ecma-undefined simple value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_undefined (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_equal_to_simple_value (value, ECMA_VALUE_UNDEFINED);
* @return true - if the value contains ecma-null simple value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_null (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_equal_to_simple_value (value, ECMA_VALUE_NULL);
* @return true - if the value contains ecma-true or ecma-false simple values,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_boolean (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_true (value | (1 << ECMA_DIRECT_SHIFT));
* @return true - if the value contains ecma-true simple value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_true (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_equal_to_simple_value (value, ECMA_VALUE_TRUE);
* @return true - if the value contains ecma-false simple value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_false (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_equal_to_simple_value (value, ECMA_VALUE_FALSE);
* @return true - if the value contains ecma-not-found simple value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_found (ecma_value_t value) /**< ecma value */
{
return value != ECMA_VALUE_NOT_FOUND;
* @return true - if the value contains ecma-array-hole simple value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_array_hole (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_equal_to_simple_value (value, ECMA_VALUE_ARRAY_HOLE);
* @return true - if the value contains an integer ecma-number value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_integer_number (ecma_value_t value) /**< ecma value */
{
return (value & ECMA_DIRECT_TYPE_MASK) == ECMA_DIRECT_TYPE_INTEGER_VALUE;
* @return true - if both values contain integer ecma-number values,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_are_values_integer_numbers (ecma_value_t first_value, /**< first ecma value */
ecma_value_t second_value) /**< second ecma value */
{
* @return true - if the value contains a floating-point ecma-number value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_float_number (ecma_value_t value) /**< ecma value */
{
return (ecma_get_value_type_field (value) == ECMA_TYPE_FLOAT);
* @return true - if the value contains ecma-number value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_number (ecma_value_t value) /**< ecma value */
{
return (ecma_is_value_integer_number (value)
* @return true - if the value contains ecma-string value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_string (ecma_value_t value) /**< ecma value */
{
return ((value & (ECMA_VALUE_TYPE_MASK - 0x4)) == ECMA_TYPE_STRING);
} /* ecma_is_value_string */
/**
- * Check if the value is direct_ecma-string.
+ * Check if the value is direct ecma-string.
*
- * @return true - if the value contains ecma-string value,
+ * @return true - if the value contains direct ecma-string value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_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 non-direct ecma-string.
+ *
+ * @return true - if the value contains non-direct ecma-string value,
+ * false - otherwise
+ */
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
+ecma_is_value_non_direct_string (ecma_value_t value) /**< ecma value */
+{
+ return (ecma_get_value_type_field (value) == ECMA_TYPE_STRING);
+} /* ecma_is_value_non_direct_string */
+
/**
* Check if the value is object.
*
* @return true - if the value contains object value,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_value_object (ecma_value_t value) /**< ecma value */
{
return (ecma_get_value_type_field (value) == ECMA_TYPE_OBJECT);
* @return true - if the value contains an error reference,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
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.
+ * Check if the value is an aligned pointer.
*
- * @return true - if the value contains a collection chunk,
+ * @return true - if the value contains an aligned pointer,
* false - otherwise
*/
-inline bool __attr_const___ __attr_always_inline___
-ecma_is_value_collection_chunk (ecma_value_t value) /**< ecma value */
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
+ecma_is_value_pointer (ecma_value_t value) /**< ecma value */
{
- return (ecma_get_value_type_field (value) == ECMA_TYPE_COLLECTION_CHUNK);
-} /* ecma_is_value_collection_chunk */
+ return (ecma_get_value_type_field (value) == ECMA_TYPE_POINTER);
+} /* ecma_is_value_pointer */
/**
* Debug assertion that specified value's type is one of ECMA-defined
*
* @return boolean ecma_value
*/
-inline ecma_value_t __attr_const___ __attr_always_inline___
+inline ecma_value_t JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_make_boolean_value (bool boolean_value) /**< raw bool value from which the ecma value will be created */
{
return boolean_value ? ECMA_VALUE_TRUE : ECMA_VALUE_FALSE;
*
* @return ecma-value
*/
-inline ecma_value_t __attr_const___ __attr_always_inline___
+inline ecma_value_t JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_make_integer_value (ecma_integer_value_t integer_value) /**< integer number to be encoded */
{
JERRY_ASSERT (ECMA_IS_INTEGER_NUMBER (integer_value));
*
* @return ecma-value
*/
-inline ecma_value_t __attr_always_inline___
+inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_make_nan_value (void)
{
return ecma_create_float_number (ecma_number_make_nan ());
*
* @return true, if it is +0.0, false otherwise
*/
-static inline bool __attr_const___ __attr_always_inline___
+static inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_is_number_equal_to_positive_zero (ecma_number_t ecma_number) /**< number */
{
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
/**
* String value constructor
+ *
+ * @return ecma-value representation of the string argument
*/
-inline ecma_value_t __attr_pure___ __attr_always_inline___
+inline ecma_value_t JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
ecma_make_string_value (const ecma_string_t *ecma_string_p) /**< string to reference in value */
{
JERRY_ASSERT (ecma_string_p != NULL);
/**
* String value constructor
+ *
+ * @return ecma-value representation of the string argument
*/
-inline ecma_value_t __attr_pure___ __attr_always_inline___
+inline ecma_value_t JERRY_ATTR_PURE JERRY_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);
/**
* Object value constructor
+ *
+ * @return ecma-value representation of the object argument
*/
-inline ecma_value_t __attr_pure___ __attr_always_inline___
+inline ecma_value_t JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
ecma_make_object_value (const ecma_object_t *object_p) /**< object to reference in value */
{
JERRY_ASSERT (object_p != NULL);
/**
* Error reference constructor
+ *
+ * @return ecma-value representation of the Error reference
*/
-inline ecma_value_t __attr_pure___ __attr_always_inline___
+inline ecma_value_t JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
ecma_make_error_reference_value (const ecma_error_reference_t *error_ref_p) /**< error reference */
{
JERRY_ASSERT (error_ref_p != NULL);
} /* ecma_make_error_reference_value */
/**
- * Collection chunk constructor
+ * Create an ecma value from an aligned pointer
+ *
+ * @return ecma-value representation of the aligned pointer
*/
-inline ecma_value_t __attr_pure___ __attr_always_inline___
-ecma_make_collection_chunk_value (const ecma_collection_chunk_t *collection_chunk_p) /**< collection chunk */
+inline ecma_value_t JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
+ecma_make_pointer_value (const void *any_p) /**< any aligned pointer */
{
#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY
- uintptr_t uint_ptr = (uintptr_t) collection_chunk_p;
+ uintptr_t uint_ptr = (uintptr_t) any_p;
JERRY_ASSERT ((uint_ptr & ECMA_VALUE_TYPE_MASK) == 0);
- return ((ecma_value_t) uint_ptr) | ECMA_TYPE_COLLECTION_CHUNK;
+ return ((ecma_value_t) uint_ptr) | ECMA_TYPE_POINTER;
#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;
+ ECMA_SET_POINTER (ptr_cp, any_p);
+ return (((ecma_value_t) ptr_cp) << ECMA_VALUE_SHIFT) | ECMA_TYPE_POINTER;
#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
-} /* ecma_make_collection_chunk_value */
+} /* ecma_make_pointer_value */
/**
* Get integer value from an integer ecma value
*
- * @return floating point value
+ * @return integer value
*/
-inline ecma_integer_value_t __attr_const___ __attr_always_inline___
+inline ecma_integer_value_t JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_get_integer_from_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_is_value_integer_number (value));
return ((ecma_integer_value_t) value) >> ECMA_DIRECT_SHIFT;
} /* ecma_get_integer_from_value */
-inline ecma_number_t __attr_pure___ __attr_always_inline___
+/**
+ * Get floating point value from an ecma value
+ *
+ * @return floating point value
+ */
+inline ecma_number_t JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
ecma_get_float_from_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_FLOAT);
*
* @return floating point value
*/
-ecma_number_t __attr_pure___
+ecma_number_t JERRY_ATTR_PURE
ecma_get_number_from_value (ecma_value_t value) /**< ecma value */
{
if (ecma_is_value_integer_number (value))
/**
* Get pointer to ecma-string from ecma value
*
- * @return the pointer
+ * @return the string pointer
*/
-inline ecma_string_t *__attr_pure___ __attr_always_inline___
+inline ecma_string_t *JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
ecma_get_string_from_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_is_value_string (value));
*
* @return the pointer
*/
-inline ecma_object_t *__attr_pure___ __attr_always_inline___
+inline ecma_object_t *JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
ecma_get_object_from_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_is_value_object (value));
*
* @return the pointer
*/
-inline ecma_error_reference_t *__attr_pure___ __attr_always_inline___
+inline ecma_error_reference_t *JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
ecma_get_error_reference_from_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_ERROR);
} /* ecma_get_error_reference_from_value */
/**
- * Get pointer to collection chunk from ecma value
+ * Get an aligned pointer from an ecma value
*
- * @return the pointer
+ * @return pointer value
*/
-inline ecma_collection_chunk_t *__attr_pure___ __attr_always_inline___
-ecma_get_collection_chunk_from_value (ecma_value_t value) /**< ecma value */
+inline void * JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
+ecma_get_pointer_from_value (ecma_value_t value) /**< ecma value */
{
- JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_COLLECTION_CHUNK);
+ JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_POINTER);
#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY
- return (ecma_collection_chunk_t *) (uintptr_t) ((value) & ~ECMA_VALUE_TYPE_MASK);
+ return (void *) (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);
+ return ECMA_GET_POINTER (void, value >> ECMA_VALUE_SHIFT);
#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
-} /* ecma_get_collection_chunk_from_value */
+} /* ecma_get_pointer_from_value */
/**
* Invert a boolean value
*
* @return ecma value
*/
-inline ecma_value_t __attr_const___ __attr_always_inline___
+inline ecma_value_t JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
ecma_invert_boolean_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_is_value_boolean (value));
{
switch (ecma_get_value_type_field (value))
{
- case ECMA_TYPE_DIRECT:
- case ECMA_TYPE_DIRECT_STRING:
- {
- return value;
- }
case ECMA_TYPE_FLOAT:
{
ecma_number_t *num_p = (ecma_number_t *) ecma_get_pointer_from_ecma_value (value);
}
default:
{
- JERRY_UNREACHABLE ();
- return ECMA_VALUE_UNDEFINED;
+ JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT
+ || ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT_STRING);
+
+ return value;
}
}
} /* ecma_copy_value */
*
* @return copy of the given value
*/
-inline ecma_value_t __attr_always_inline___
+inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_fast_copy_value (ecma_value_t value) /**< value description */
{
return (ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT) ? value : ecma_copy_value (value);
{
switch (ecma_get_value_type_field (value))
{
- case ECMA_TYPE_DIRECT:
- case ECMA_TYPE_DIRECT_STRING:
- {
- /* no memory is allocated */
- break;
- }
-
case ECMA_TYPE_FLOAT:
{
ecma_number_t *number_p = (ecma_number_t *) ecma_get_pointer_from_ecma_value (value);
default:
{
- JERRY_UNREACHABLE ();
+ JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT
+ || ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT_STRING);
+
+ /* no memory is allocated */
break;
}
}
* It also increases the binary size so it is recommended for
* critical code paths only.
*/
-inline void __attr_always_inline___
+inline void JERRY_ATTR_ALWAYS_INLINE
ecma_fast_free_value (ecma_value_t value) /**< value description */
{
if (ecma_get_value_type_field (value) != ECMA_TYPE_DIRECT)
/**
* 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);
+JERRY_STATIC_ASSERT (ECMA_TYPE_ERROR == ECMA_TYPE_POINTER,
+ ecma_type_error_must_be_the_same_as_ecma_type_pointer);
/**
* Allocate a collection of ecma values.
{
ecma_value_t *item_p = chunk_p->items;
- JERRY_ASSERT (!ecma_is_value_collection_chunk (*item_p));
+ JERRY_ASSERT (!ecma_is_value_pointer (*item_p));
do
{
item_p++;
}
- while (!ecma_is_value_collection_chunk (*item_p));
+ while (!ecma_is_value_pointer (*item_p));
- ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (*item_p);
+ ecma_collection_chunk_t *next_chunk_p = (ecma_collection_chunk_t *) ecma_get_pointer_from_value (*item_p);
jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t));
ecma_length_t item_index;
ecma_collection_chunk_t *chunk_p;
- if (unlikely (header_p->item_count == 0))
+ if (JERRY_UNLIKELY (header_p->item_count == 0))
{
item_index = 0;
chunk_p = (ecma_collection_chunk_t *) jmem_heap_alloc_block (sizeof (ecma_collection_chunk_t));
chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
header_p->last_chunk_cp);
- if (unlikely (item_index == 0))
+ if (JERRY_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);
+ JERRY_ASSERT (ecma_is_value_pointer (chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS])
+ && ecma_get_pointer_from_value (chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS]) == NULL);
ecma_collection_chunk_t *next_chunk_p;
next_chunk_p = (ecma_collection_chunk_t *) jmem_heap_alloc_block (sizeof (ecma_collection_chunk_t));
- chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS] = ecma_make_collection_chunk_value (next_chunk_p);
+ chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS] = ecma_make_pointer_value ((void *) next_chunk_p);
ECMA_SET_POINTER (header_p->last_chunk_cp, next_chunk_p);
chunk_p = next_chunk_p;
}
else
{
- JERRY_ASSERT (ecma_is_value_collection_chunk (chunk_p->items[item_index])
- && ecma_get_collection_chunk_from_value (chunk_p->items[item_index]) == NULL);
+ JERRY_ASSERT (ecma_is_value_pointer (chunk_p->items[item_index])
+ && ecma_get_pointer_from_value (chunk_p->items[item_index]) == NULL);
}
}
}
chunk_p->items[item_index] = value;
- chunk_p->items[item_index + 1] = ecma_make_collection_chunk_value (NULL);
+ chunk_p->items[item_index + 1] = ecma_make_pointer_value (NULL);
header_p->item_count++;
} /* ecma_append_to_values_collection */
ecma_value_t *
ecma_collection_iterator_init (ecma_collection_header_t *header_p) /**< header of collection */
{
- if (unlikely (!header_p || header_p->item_count == 0))
+ if (JERRY_UNLIKELY (!header_p || header_p->item_count == 0))
{
return NULL;
}
ecma_value_p++;
- if (unlikely (ecma_is_value_collection_chunk (*ecma_value_p)))
+ if (JERRY_UNLIKELY (ecma_is_value_pointer (*ecma_value_p)))
{
- ecma_value_p = ecma_get_collection_chunk_from_value (*ecma_value_p)->items;
+ ecma_value_p = ((ecma_collection_chunk_t *) ecma_get_pointer_from_value (*ecma_value_p))->items;
- JERRY_ASSERT (ecma_value_p == NULL || !ecma_is_value_collection_chunk (*ecma_value_p));
+ JERRY_ASSERT (ecma_value_p == NULL || !ecma_is_value_pointer (*ecma_value_p));
return ecma_value_p;
}
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)
/**
* Create a object lexical environment with specified outer lexical environment
- * (or NULL if the environment is not nested), binding object and provideThis flag.
+ * (or NULL if the environment is not nested), binding object and provided type flag.
*
* See also: ECMA-262 v5, 10.2.1.2
*
ecma_object_t *
ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, /**< outer lexical environment */
ecma_object_t *binding_obj_p, /**< binding object */
- bool provide_this) /**< provideThis flag */
+ ecma_lexical_environment_type_t type) /**< type of the new lexical environment */
{
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ JERRY_ASSERT (type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND
+ || type == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
+#else /* CONFIG_DISABLE_ES2015_CLASS */
+ JERRY_ASSERT (type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
JERRY_ASSERT (binding_obj_p != NULL
&& !ecma_is_lexical_environment (binding_obj_p));
ecma_object_t *new_lexical_environment_p = ecma_alloc_object ();
- uint16_t type;
-
- if (provide_this)
- {
- type = ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND;
- }
- else
- {
- type = ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND;
- }
-
- new_lexical_environment_p->type_flags_refs = type;
+ new_lexical_environment_p->type_flags_refs = (uint16_t) (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | type);
ecma_init_gc_info (new_lexical_environment_p);
/**
* Check if the object is lexical environment.
+ *
+ * @return true - if object is a lexical environment
+ * false - otherwise
*/
-inline bool __attr_pure___
+inline bool JERRY_ATTR_PURE
ecma_is_lexical_environment (const ecma_object_t *object_p) /**< object or lexical environment */
{
JERRY_ASSERT (object_p != NULL);
/**
* Get value of [[Extensible]] object's internal property.
+ *
+ * @return true - if object is extensible
+ * false - otherwise
*/
-inline bool __attr_pure___
+inline bool JERRY_ATTR_PURE
ecma_get_object_extensible (const ecma_object_t *object_p) /**< object */
{
JERRY_ASSERT (object_p != NULL);
/**
* Get object's internal implementation-defined type.
+ *
+ * @return type of the object (ecma_object_type_t)
*/
-inline ecma_object_type_t __attr_pure___
+inline ecma_object_type_t JERRY_ATTR_PURE
ecma_get_object_type (const ecma_object_t *object_p) /**< object */
{
JERRY_ASSERT (object_p != NULL);
/**
* Get object's prototype.
+ *
+ * @return pointer to the prototype object
+ * NULL if there is no prototype
*/
-inline ecma_object_t *__attr_pure___
+inline ecma_object_t *JERRY_ATTR_PURE
ecma_get_object_prototype (const ecma_object_t *object_p) /**< object */
{
JERRY_ASSERT (object_p != NULL);
/**
* Check if the object is a built-in object
*
- * @return true / false
+ * @return true - if object is a built-in object
+ * false - otherwise
*/
-inline bool __attr_pure___
+inline bool JERRY_ATTR_PURE
ecma_get_object_is_builtin (const ecma_object_t *object_p) /**< object */
{
JERRY_ASSERT (object_p != NULL);
} /* ecma_set_object_is_builtin */
/**
- * Get the builtin id of the object.
+ * Get the built-in ID of the object.
* If the object is not builtin, return ECMA_BUILTIN_ID__COUNT
+ *
+ * @return the ID of the built-in
*/
inline uint8_t
ecma_get_object_builtin_id (ecma_object_t *object_p) /**< object */
/**
* Get type of lexical environment.
+ *
+ * @return type of the lexical environment (ecma_lexical_environment_type_t)
*/
-inline ecma_lexical_environment_type_t __attr_pure___
+inline ecma_lexical_environment_type_t JERRY_ATTR_PURE
ecma_get_lex_env_type (const ecma_object_t *object_p) /**< lexical environment */
{
JERRY_ASSERT (object_p != NULL);
/**
* Get outer reference of lexical environment.
+ *
+ * @return pointer to the outer reference
*/
-inline ecma_object_t *__attr_pure___
+inline ecma_object_t *JERRY_ATTR_PURE
ecma_get_lex_env_outer_reference (const ecma_object_t *object_p) /**< lexical environment */
{
JERRY_ASSERT (object_p != NULL);
*
* See also:
* ecma_op_object_get_property_names
+ *
+ * @return pointer to the head of the property list
*/
-inline ecma_property_header_t *__attr_pure___
+inline ecma_property_header_t *JERRY_ATTR_PURE
ecma_get_property_list (const ecma_object_t *object_p) /**< object or lexical environment */
{
JERRY_ASSERT (object_p != NULL);
object_p->property_list_or_bound_object_cp);
} /* ecma_get_property_list */
-/**
- * Get lexical environment's 'provideThis' property
- */
-inline bool __attr_pure___
-ecma_get_lex_env_provide_this (const ecma_object_t *object_p) /**< object-bound lexical environment */
-{
- JERRY_ASSERT (object_p != NULL);
- JERRY_ASSERT (ecma_is_lexical_environment (object_p));
- JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND
- || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
-
- return ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND;
-} /* ecma_get_lex_env_provide_this */
-
/**
* Get lexical environment's bound object.
+ *
+ * @return pointer to ecma object
*/
-inline ecma_object_t *__attr_pure___
+inline ecma_object_t *JERRY_ATTR_PURE
ecma_get_lex_env_binding_object (const ecma_object_t *object_p) /**< object-bound lexical environment */
{
JERRY_ASSERT (object_p != NULL);
JERRY_ASSERT (ecma_is_lexical_environment (object_p));
- JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND
- || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+#ifndef CONFIG_DISABLE_ES2015
+ JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND
+ || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
+#else /* CONFIG_DISABLE_ES2015 */
+ JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+#endif /* !CONFIG_DISABLE_ES2015 */
return ECMA_GET_NON_NULL_POINTER (ecma_object_t,
object_p->property_list_or_bound_object_cp);
/* 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_PROPERTY_DELETED_NAME;
+ first_property_pair_p->names_cp[0] = LIT_INTERNAL_MAGIC_STRING_DELETED;
if (name_p == NULL)
{
JERRY_ASSERT (obj_p != NULL);
JERRY_ASSERT (name_p != NULL);
- ecma_property_t *property_p = ecma_lcache_lookup (obj_p, name_p);
+ ecma_property_t *property_p = NULL;
+#ifndef CONFIG_ECMA_LCACHE_DISABLE
+ property_p = ecma_lcache_lookup (obj_p, name_p);
if (property_p != NULL)
{
return property_p;
}
+#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
ecma_property_header_t *prop_iter_p = ecma_get_property_list (obj_p);
name_p,
&property_real_name_cp);
+#ifndef CONFIG_ECMA_LCACHE_DISABLE
if (property_p != NULL
&& !ecma_is_property_lcached (property_p))
{
ecma_lcache_insert (obj_p, property_real_name_cp, property_p);
}
+#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
return property_p;
}
ecma_property_hashmap_create (obj_p);
}
+#ifndef CONFIG_ECMA_LCACHE_DISABLE
if (property_p != NULL
&& !ecma_is_property_lcached (property_p))
{
ecma_lcache_insert (obj_p, property_name_cp, property_p);
}
+#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
return property_p;
} /* ecma_find_named_property */
{
case ECMA_PROPERTY_TYPE_NAMEDDATA:
{
- 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)
- {
- ecma_free_native_pointer (property_p);
- break;
- }
- }
-
ecma_free_value_if_not_object (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
break;
}
}
default:
{
- JERRY_UNREACHABLE ();
- return;
+ JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL);
+
+ /* Must be a native pointer. */
+ JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC
+ && name_cp >= LIT_FIRST_INTERNAL_MAGIC_STRING);
+ break;
}
}
+#ifndef CONFIG_ECMA_LCACHE_DISABLE
if (ecma_is_property_lcached (property_p))
{
ecma_lcache_invalidate (object_p, name_cp, property_p);
}
+#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_PTR)
{
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;
+ prop_pair_p->names_cp[i] = LIT_INTERNAL_MAGIC_STRING_DELETED;
JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2);
ecma_free_property (object_p, prop_pair_p->names_cp[i], current_prop_p->types + i);
current_prop_p->types[i] = ECMA_PROPERTY_TYPE_DELETED;
- prop_pair_p->names_cp[i] = ECMA_PROPERTY_DELETED_NAME;
+ prop_pair_p->names_cp[i] = LIT_INTERNAL_MAGIC_STRING_DELETED;
}
}
}
prop_iter_p->next_property_cp);
}
- while (prop_iter_p != NULL)
+ while (true)
{
+ JERRY_ASSERT (prop_iter_p != NULL);
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
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);
}
-
- JERRY_UNREACHABLE ();
-
#else /* JERRY_NDEBUG */
JERRY_UNUSED (object_p);
JERRY_UNUSED (prop_value_p);
* Note:
* value previously stored in the property is freed
*/
-inline void __attr_always_inline___
+inline void JERRY_ATTR_ALWAYS_INLINE
ecma_named_data_property_assign_value (ecma_object_t *obj_p, /**< object */
ecma_property_value_t *prop_value_p, /**< property value reference */
ecma_value_t value) /**< value to assign */
* @return true - property is writable,
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_is_property_writable (ecma_property_t property) /**< property */
{
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDDATA
* @return true - property is enumerable,
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_is_property_enumerable (ecma_property_t property) /**< property */
{
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDDATA
* @return true - property is configurable,
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_is_property_configurable (ecma_property_t property) /**< property */
{
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDDATA
}
} /* ecma_set_property_configurable_attr */
+#ifndef CONFIG_ECMA_LCACHE_DISABLE
+
/**
* Check whether the property is registered in LCache
*
* @return true / false
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_is_property_lcached (ecma_property_t *property_p) /**< property */
{
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
- || ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);
+ || ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR
+ || ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL);
return (*property_p & ECMA_PROPERTY_FLAG_LCACHED) != 0;
} /* ecma_is_property_lcached */
/**
* Set value of flag indicating whether the property is registered in LCache
*/
-inline void __attr_always_inline___
+inline void JERRY_ATTR_ALWAYS_INLINE
ecma_set_property_lcached (ecma_property_t *property_p, /**< property */
bool is_lcached) /**< new value for lcached flag */
{
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
- || ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);
+ || ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR
+ || ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL);
if (is_lcached)
{
}
} /* ecma_set_property_lcached */
+#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
+
/**
* Construct empty property descriptor, i.e.:
* property descriptor with all is_defined flags set to false and the rest - to default value.
+ *
+ * @return empty property descriptor
*/
ecma_property_descriptor_t
ecma_make_empty_property_descriptor (void)
*
* @return error reference value
*/
-inline ecma_value_t __attr_always_inline___
+inline ecma_value_t JERRY_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), true);
void
ecma_ref_error_reference (ecma_error_reference_t *error_ref_p) /**< error reference */
{
- if (likely (error_ref_p->refs_and_flags < ECMA_ERROR_MAX_REF))
+ if (JERRY_LIKELY (error_ref_p->refs_and_flags < ECMA_ERROR_MAX_REF))
{
error_ref_p->refs_and_flags += ECMA_ERROR_REF_ONE;
}
#define ECMA_BOOL_TO_BITFIELD(x) ((x) ? 1 : 0)
/* ecma-helpers-value.c */
-bool ecma_is_value_direct (ecma_value_t value) __attr_const___;
-bool ecma_is_value_simple (ecma_value_t value) __attr_const___;
-bool ecma_is_value_empty (ecma_value_t value) __attr_const___;
-bool ecma_is_value_undefined (ecma_value_t value) __attr_const___;
-bool ecma_is_value_null (ecma_value_t value) __attr_const___;
-bool ecma_is_value_boolean (ecma_value_t value) __attr_const___;
-bool ecma_is_value_true (ecma_value_t value) __attr_const___;
-bool ecma_is_value_false (ecma_value_t value) __attr_const___;
-bool ecma_is_value_found (ecma_value_t value) __attr_const___;
-bool ecma_is_value_array_hole (ecma_value_t value) __attr_const___;
-
-bool ecma_is_value_integer_number (ecma_value_t value) __attr_const___;
-bool ecma_are_values_integer_numbers (ecma_value_t first_value, ecma_value_t second_value) __attr_const___;
-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___;
+bool JERRY_ATTR_CONST ecma_is_value_direct (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_simple (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_empty (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_undefined (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_null (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_boolean (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_true (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_false (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_found (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_array_hole (ecma_value_t value);
+
+bool JERRY_ATTR_CONST ecma_is_value_integer_number (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_are_values_integer_numbers (ecma_value_t first_value, ecma_value_t second_value);
+bool JERRY_ATTR_CONST ecma_is_value_float_number (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_number (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_string (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_direct_string (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_non_direct_string (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_object (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_error_reference (ecma_value_t value);
+bool JERRY_ATTR_CONST ecma_is_value_pointer (ecma_value_t value);
void ecma_check_value_type_is_spec_defined (ecma_value_t value);
-ecma_value_t ecma_make_boolean_value (bool boolean_value) __attr_const___;
-ecma_value_t ecma_make_integer_value (ecma_integer_value_t integer_value) __attr_const___;
+ecma_value_t JERRY_ATTR_CONST ecma_make_boolean_value (bool boolean_value);
+ecma_value_t JERRY_ATTR_CONST ecma_make_integer_value (ecma_integer_value_t integer_value);
ecma_value_t ecma_make_nan_value (void);
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 JERRY_ATTR_PURE ecma_make_string_value (const ecma_string_t *ecma_string_p);
+ecma_value_t JERRY_ATTR_PURE ecma_make_magic_string_value (lit_magic_string_id_t id);
+ecma_value_t JERRY_ATTR_PURE ecma_make_object_value (const ecma_object_t *object_p);
+ecma_value_t JERRY_ATTR_PURE ecma_make_error_reference_value (const ecma_error_reference_t *error_ref_p);
+ecma_value_t JERRY_ATTR_PURE ecma_make_pointer_value (const void *any_p);
+ecma_integer_value_t JERRY_ATTR_CONST ecma_get_integer_from_value (ecma_value_t value);
+ecma_number_t JERRY_ATTR_PURE ecma_get_float_from_value (ecma_value_t value);
+ecma_number_t JERRY_ATTR_PURE ecma_get_number_from_value (ecma_value_t value);
+ecma_string_t JERRY_ATTR_PURE *ecma_get_string_from_value (ecma_value_t value);
+ecma_object_t JERRY_ATTR_PURE *ecma_get_object_from_value (ecma_value_t value);
+ecma_error_reference_t JERRY_ATTR_PURE *ecma_get_error_reference_from_value (ecma_value_t value);
+void * JERRY_ATTR_PURE ecma_get_pointer_from_value (ecma_value_t value);
+ecma_value_t JERRY_ATTR_CONST ecma_invert_boolean_value (ecma_value_t value);
ecma_value_t ecma_copy_value (ecma_value_t value);
ecma_value_t ecma_fast_copy_value (ecma_value_t value);
ecma_value_t ecma_copy_value_if_not_object (ecma_value_t value);
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_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_append_chars_to_string (ecma_string_t *string1_p,
const lit_utf8_byte_t *cesu8_string2_p,
lit_utf8_size_t cesu8_string2_size,
ecma_number_t ecma_string_to_number (const ecma_string_t *str_p);
uint32_t ecma_string_get_array_index (const ecma_string_t *str_p);
-lit_utf8_size_t __attr_return_value_should_be_checked___
+lit_utf8_size_t JERRY_ATTR_WARN_UNUSED_RESULT
ecma_string_copy_to_cesu8_buffer (const ecma_string_t *string_desc_p,
lit_utf8_byte_t *buffer_p,
lit_utf8_size_t buffer_size);
-lit_utf8_size_t __attr_return_value_should_be_checked___
+lit_utf8_size_t JERRY_ATTR_WARN_UNUSED_RESULT
ecma_string_copy_to_utf8_buffer (const ecma_string_t *string_desc_p,
lit_utf8_byte_t *buffer_p,
lit_utf8_size_t buffer_size);
bool ecma_number_is_negative (ecma_number_t num);
bool ecma_number_is_zero (ecma_number_t num);
bool ecma_number_is_infinity (ecma_number_t num);
-int32_t
-ecma_number_get_fraction_and_exponent (ecma_number_t num, uint64_t *out_fraction_p, int32_t *out_exponent_p);
-ecma_number_t
-ecma_number_make_normal_positive_from_fraction_and_exponent (uint64_t fraction, int32_t exponent);
ecma_number_t
ecma_number_make_from_sign_mantissa_and_exponent (bool sign, uint64_t mantissa, int32_t exponent);
ecma_number_t ecma_number_get_prev (ecma_number_t num);
ecma_object_t *ecma_create_object (ecma_object_t *prototype_object_p, size_t ext_object_size, ecma_object_type_t type);
ecma_object_t *ecma_create_decl_lex_env (ecma_object_t *outer_lexical_environment_p);
ecma_object_t *ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, ecma_object_t *binding_obj_p,
- bool provide_this);
-bool ecma_is_lexical_environment (const ecma_object_t *object_p) __attr_pure___;
-bool ecma_get_object_extensible (const ecma_object_t *object_p) __attr_pure___;
+ ecma_lexical_environment_type_t type);
+bool JERRY_ATTR_PURE ecma_is_lexical_environment (const ecma_object_t *object_p);
+bool JERRY_ATTR_PURE ecma_get_object_extensible (const ecma_object_t *object_p);
void ecma_set_object_extensible (ecma_object_t *object_p, bool is_extensible);
-ecma_object_type_t ecma_get_object_type (const ecma_object_t *object_p) __attr_pure___;
-ecma_object_t *ecma_get_object_prototype (const ecma_object_t *object_p) __attr_pure___;
-bool ecma_get_object_is_builtin (const ecma_object_t *object_p) __attr_pure___;
+ecma_object_type_t JERRY_ATTR_PURE ecma_get_object_type (const ecma_object_t *object_p);
+ecma_object_t JERRY_ATTR_PURE *ecma_get_object_prototype (const ecma_object_t *object_p);
+bool JERRY_ATTR_PURE ecma_get_object_is_builtin (const ecma_object_t *object_p);
void ecma_set_object_is_builtin (ecma_object_t *object_p);
uint8_t ecma_get_object_builtin_id (ecma_object_t *object_p);
-ecma_lexical_environment_type_t ecma_get_lex_env_type (const ecma_object_t *object_p) __attr_pure___;
-ecma_object_t *ecma_get_lex_env_outer_reference (const ecma_object_t *object_p) __attr_pure___;
-ecma_property_header_t *ecma_get_property_list (const ecma_object_t *object_p) __attr_pure___;
-ecma_object_t *ecma_get_lex_env_binding_object (const ecma_object_t *object_p) __attr_pure___;
-bool ecma_get_lex_env_provide_this (const ecma_object_t *object_p) __attr_pure___;
+ecma_lexical_environment_type_t JERRY_ATTR_PURE ecma_get_lex_env_type (const ecma_object_t *object_p);
+ecma_object_t JERRY_ATTR_PURE *ecma_get_lex_env_outer_reference (const ecma_object_t *object_p);
+ecma_property_header_t JERRY_ATTR_PURE *ecma_get_property_list (const ecma_object_t *object_p);
+ecma_object_t JERRY_ATTR_PURE *ecma_get_lex_env_binding_object (const ecma_object_t *object_p);
ecma_property_value_t *
ecma_create_named_data_property (ecma_object_t *object_p, ecma_string_t *name_p, uint8_t prop_attributes,
bool ecma_is_property_configurable (ecma_property_t property);
void ecma_set_property_configurable_attr (ecma_property_t *property_p, bool is_configurable);
+#ifndef CONFIG_ECMA_LCACHE_DISABLE
bool ecma_is_property_lcached (ecma_property_t *property_p);
void ecma_set_property_lcached (ecma_property_t *property_p, bool is_lcached);
+#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
ecma_property_descriptor_t ecma_make_empty_property_descriptor (void);
void ecma_free_property_descriptor (ecma_property_descriptor_t *prop_desc_p);
void ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p);
/* ecma-helpers-external-pointers.c */
-bool ecma_create_native_handle_property (ecma_object_t *obj_p, void *handle_p, void *free_cb);
bool ecma_create_native_pointer_property (ecma_object_t *obj_p, void *native_p, void *info_p);
-ecma_native_pointer_t *ecma_get_native_pointer_value (ecma_object_t *obj_p, lit_magic_string_id_t id);
-void ecma_free_native_pointer (ecma_property_t *prop_p);
+ecma_native_pointer_t *ecma_get_native_pointer_value (ecma_object_t *obj_p);
/* ecma-helpers-conversion.c */
ecma_number_t ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, lit_utf8_size_t str_size);
#include "ecma-gc.h"
#include "ecma-helpers.h"
#include "ecma-init-finalize.h"
-#include "ecma-lcache.h"
#include "ecma-lex-env.h"
#include "ecma-literal-storage.h"
#include "jmem.h"
void
ecma_init (void)
{
- ecma_lcache_init ();
ecma_init_global_lex_env ();
jmem_register_free_unused_memory_callback (ecma_free_unused_memory);
*/
#define ECMA_LCACHE_HASH_MASK (ECMA_LCACHE_HASH_ROWS_COUNT - 1)
-#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
-
-/**
- * Initialize LCache
- */
-void
-ecma_lcache_init (void)
-{
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
- memset (JERRY_HASH_TABLE_CONTEXT (table), 0, sizeof (jerry_hash_table_t));
-#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
-} /* ecma_lcache_init */
-
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
/**
* Invalidate specified LCache entry
*/
-static inline void __attr_always_inline___
+static inline void JERRY_ATTR_ALWAYS_INLINE
ecma_lcache_invalidate_entry (ecma_lcache_hash_entry_t *entry_p) /**< entry to invalidate */
{
JERRY_ASSERT (entry_p != NULL);
*
* @return row index
*/
-static inline size_t __attr_always_inline___
+static inline size_t JERRY_ATTR_ALWAYS_INLINE
ecma_lcache_row_index (jmem_cpointer_t object_cp, /**< compressed pointer to object */
lit_string_hash_t name_hash) /**< property name hash */
{
* so properties of different objects with the same name can be cached effectively. */
return (size_t) ((name_hash ^ object_cp) & ECMA_LCACHE_HASH_MASK);
} /* ecma_lcache_row_index */
-#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
/**
* Insert an entry into LCache
JERRY_ASSERT (object_p != NULL);
JERRY_ASSERT (prop_p != NULL && !ecma_is_property_lcached (prop_p));
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
- || ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);
+ || ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR
+ || ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_INTERNAL);
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
jmem_cpointer_t object_cp;
ECMA_SET_NON_NULL_POINTER (object_cp, object_p);
lit_string_hash_t name_hash = ecma_string_get_property_name_hash (*prop_p, name_cp);
size_t row_index = ecma_lcache_row_index (object_cp, name_hash);
- ecma_lcache_hash_entry_t *entries_p = JERRY_HASH_TABLE_CONTEXT (table)[row_index];
+ ecma_lcache_hash_entry_t *entries_p = JERRY_CONTEXT (lcache) [row_index];
uint32_t entry_index;
for (entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++)
entry_p->prop_p = prop_p;
ecma_set_property_lcached (entry_p->prop_p, true);
-#else /* CONFIG_ECMA_LCACHE_DISABLE */
- JERRY_UNUSED (name_cp);
-#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
} /* ecma_lcache_insert */
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
-
-
-
-#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
-
/**
* Lookup property in the LCache
*
* @return a pointer to an ecma_property_t if the lookup is successful
* NULL otherwise
*/
-inline ecma_property_t * __attr_always_inline___
+inline ecma_property_t * JERRY_ATTR_ALWAYS_INLINE
ecma_lcache_lookup (ecma_object_t *object_p, /**< object */
const ecma_string_t *prop_name_p) /**< property's name */
{
JERRY_ASSERT (object_p != NULL);
JERRY_ASSERT (prop_name_p != NULL);
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
jmem_cpointer_t object_cp;
ECMA_SET_NON_NULL_POINTER (object_cp, object_p);
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_p = JERRY_CONTEXT (lcache) [row_index];
ecma_lcache_hash_entry_t *entry_end_p = entry_p + ECMA_LCACHE_HASH_ROW_LENGTH;
while (entry_p < entry_end_p)
entry_p++;
}
-#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
return NULL;
} /* ecma_lcache_lookup */
JERRY_ASSERT (object_p != NULL);
JERRY_ASSERT (prop_p != NULL && ecma_is_property_lcached (prop_p));
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
- || ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);
+ || ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR
+ || ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_INTERNAL);
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
jmem_cpointer_t object_cp;
ECMA_SET_NON_NULL_POINTER (object_cp, object_p);
lit_string_hash_t name_hash = ecma_string_get_property_name_hash (*prop_p, name_cp);
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_p = JERRY_CONTEXT (lcache) [row_index];
- for (uint32_t entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++)
+ while (true)
{
+ /* The property must be present. */
+ JERRY_ASSERT (entry_p - JERRY_CONTEXT (lcache) [row_index] < ECMA_LCACHE_HASH_ROW_LENGTH);
+
if (entry_p->object_cp != ECMA_NULL_POINTER && entry_p->prop_p == prop_p)
{
JERRY_ASSERT (entry_p->object_cp == object_cp);
}
entry_p++;
}
+} /* ecma_lcache_invalidate */
- /* The property must be present. */
- JERRY_UNREACHABLE ();
-#else /* CONFIG_ECMA_LCACHE_DISABLE */
- JERRY_UNUSED (name_cp);
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
-} /* ecma_lcache_invalidate */
/**
* @}
* @{
*/
-void ecma_lcache_init (void);
+#ifndef CONFIG_ECMA_LCACHE_DISABLE
+
void ecma_lcache_insert (ecma_object_t *object_p, jmem_cpointer_t name_cp, ecma_property_t *prop_p);
ecma_property_t *ecma_lcache_lookup (ecma_object_t *object_p, const ecma_string_t *prop_name_p);
void ecma_lcache_invalidate (ecma_object_t *object_p, jmem_cpointer_t name_cp, ecma_property_t *prop_p);
+#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
+
/**
* @}
* @}
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 (CBC_NON_STRICT_ARGUMENTS_NEEDED (compiled_code_p))
{
argument_end = args_p->argument_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 (CBC_NON_STRICT_ARGUMENTS_NEEDED (compiled_code_p))
{
argument_end = args_p->argument_end;
}
* Save literals to specified snapshot buffer.
*
* Note:
- * Frees lit_pool_p regardless of success.
+ * Frees 'lit_pool_p' regardless of success.
*
* @return true - if save was performed successfully (i.e. buffer size is sufficient),
* false - otherwise
{
ecma_property_types_t type = ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[i]);
- if (type == ECMA_PROPERTY_TYPE_NAMEDDATA || type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR)
+ if (type != ECMA_PROPERTY_TYPE_SPECIAL)
{
named_property_count++;
}
JERRY_ASSERT (entry_index != start_entry_index);
#endif /* !JERRY_NDEBUG */
}
-
- JERRY_UNREACHABLE ();
}
while (true)
ret_value = ecma_op_object_put (object,
ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH),
length_value,
- true),
+ true);
ecma_free_value (length_value);
return ret_value;
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
-ecma_builtin_array_prototype_object_to_locale_string (const ecma_value_t this_arg) /**< this argument */
+ecma_builtin_array_prototype_object_to_locale_string (ecma_value_t this_arg) /**< this argument */
{
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
ret_value);
/* 2. */
- ecma_value_t new_array = ecma_op_create_array_object (0, 0, false);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ ecma_object_t *obj_p = ecma_get_object_from_value (obj_this);
+ ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
+
+ if (ECMA_IS_VALUE_ERROR (new_array))
+ {
+ ecma_free_value (obj_this);
+ return new_array;
+ }
+#else /* CONFIG_DISABLE_ES2015_CLASS */
+ ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
+ JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
ecma_object_t *new_array_p = ecma_get_object_from_value (new_array);
uint32_t new_length = 0;
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
-ecma_builtin_array_prototype_join (const ecma_value_t this_arg, /**< this argument */
- const ecma_value_t separator_arg) /**< separator argument */
+ecma_builtin_array_prototype_join (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t separator_arg) /**< separator argument */
{
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
JERRY_ASSERT (start <= len && end <= len);
- ecma_value_t new_array = ecma_op_create_array_object (0, 0, false);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
+
+ if (ECMA_IS_VALUE_ERROR (new_array))
+ {
+ ecma_free_value (len_value);
+ ecma_free_value (obj_this);
+ return new_array;
+ }
+#else /* CONFIG_DISABLE_ES2015_CLASS */
+ ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
+ JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
ecma_object_t *new_array_p = ecma_get_object_from_value (new_array);
/* 9. */
ecma_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p,
to_idx_str_p,
get_value,
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
- false);
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (put_comp));
ecma_deref_ecma_string (to_idx_str_p);
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
-ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t j, /**< left value */
- ecma_value_t k, /**< right value */
- ecma_value_t comparefn) /**< compare function */
+ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t lhs, /**< left value */
+ ecma_value_t rhs, /**< right value */
+ ecma_value_t compare_func) /**< compare function */
{
/*
* ECMA-262 v5, 15.4.4.11 NOTE1: Because non-existent property values always
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
ecma_number_t result = ECMA_NUMBER_ZERO;
- bool j_is_undef = ecma_is_value_undefined (j);
- bool k_is_undef = ecma_is_value_undefined (k);
+ bool lhs_is_undef = ecma_is_value_undefined (lhs);
+ bool rhs_is_undef = ecma_is_value_undefined (rhs);
- if (j_is_undef)
+ if (lhs_is_undef)
{
- if (k_is_undef)
+ if (rhs_is_undef)
{
result = ECMA_NUMBER_ZERO;
}
}
else
{
- if (k_is_undef)
+ if (rhs_is_undef)
{
result = ECMA_NUMBER_MINUS_ONE;
}
else
{
- if (ecma_is_value_undefined (comparefn))
+ if (ecma_is_value_undefined (compare_func))
{
- /* Default comparison when no comparefn is passed. */
- ECMA_TRY_CATCH (j_value, ecma_op_to_string (j), ret_value);
- ECMA_TRY_CATCH (k_value, ecma_op_to_string (k), ret_value);
- ecma_string_t *j_str_p = ecma_get_string_from_value (j_value);
- ecma_string_t *k_str_p = ecma_get_string_from_value (k_value);
+ /* Default comparison when no compare_func is passed. */
+ ECMA_TRY_CATCH (lhs_value, ecma_op_to_string (lhs), ret_value);
+ ECMA_TRY_CATCH (rhs_value, ecma_op_to_string (rhs), ret_value);
+ ecma_string_t *lhs_str_p = ecma_get_string_from_value (lhs_value);
+ ecma_string_t *rhs_str_p = ecma_get_string_from_value (rhs_value);
- if (ecma_compare_ecma_strings_relational (j_str_p, k_str_p))
+ if (ecma_compare_ecma_strings_relational (lhs_str_p, rhs_str_p))
{
result = ECMA_NUMBER_MINUS_ONE;
}
- else if (!ecma_compare_ecma_strings (j_str_p, k_str_p))
+ else if (!ecma_compare_ecma_strings (lhs_str_p, rhs_str_p))
{
result = ECMA_NUMBER_ONE;
}
result = ECMA_NUMBER_ZERO;
}
- ECMA_FINALIZE (k_value);
- ECMA_FINALIZE (j_value);
+ ECMA_FINALIZE (rhs_value);
+ ECMA_FINALIZE (lhs_value);
}
else
{
/*
- * comparefn, if not undefined, will always contain a callable function object.
+ * compare_func, if not undefined, will always contain a callable function object.
* We checked this previously, before this function was called.
*/
- JERRY_ASSERT (ecma_op_is_callable (comparefn));
- ecma_object_t *comparefn_obj_p = ecma_get_object_from_value (comparefn);
+ JERRY_ASSERT (ecma_op_is_callable (compare_func));
+ ecma_object_t *comparefn_obj_p = ecma_get_object_from_value (compare_func);
- ecma_value_t compare_args[] = {j, k};
+ ecma_value_t compare_args[] = { lhs, rhs };
ECMA_TRY_CATCH (call_value,
ecma_op_function_call (comparefn_obj_p,
return ret_value;
} /* ecma_builtin_array_prototype_object_sort_compare_helper */
-/**
- * Function used to reconstruct the ordered binary tree.
- * Shifts 'index' down in the tree until it is in the correct position.
- *
- * @return ecma value
- * Returned value must be freed with ecma_free_value.
- */
-static ecma_value_t
-ecma_builtin_array_prototype_object_array_to_heap_helper (ecma_value_t array[], /**< heap data array */
- int index, /**< current item index */
- int right, /**< right index is a maximum index */
- ecma_value_t comparefn) /**< compare function */
-{
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
-
- /* Left child of the current index. */
- int child = index * 2 + 1;
- ecma_value_t swap = array[index];
- bool should_break = false;
-
- while (child <= right && ecma_is_value_empty (ret_value) && !should_break)
- {
- if (child < right)
- {
- /* Compare the two child nodes. */
- ECMA_TRY_CATCH (child_compare_value,
- ecma_builtin_array_prototype_object_sort_compare_helper (array[child],
- array[child + 1],
- comparefn),
- ret_value);
-
- JERRY_ASSERT (ecma_is_value_number (child_compare_value));
-
- /* Use the child that is greater. */
- if (ecma_get_number_from_value (child_compare_value) < ECMA_NUMBER_ZERO)
- {
- child++;
- }
-
- ECMA_FINALIZE (child_compare_value);
- }
-
- if (ecma_is_value_empty (ret_value))
- {
- JERRY_ASSERT (child <= right);
-
- /* Compare current child node with the swap (tree top). */
- ECMA_TRY_CATCH (swap_compare_value,
- ecma_builtin_array_prototype_object_sort_compare_helper (array[child],
- swap,
- comparefn),
- ret_value);
- JERRY_ASSERT (ecma_is_value_number (swap_compare_value));
-
- if (ecma_get_number_from_value (swap_compare_value) <= ECMA_NUMBER_ZERO)
- {
- /* Break from loop if current child is less than swap (tree top) */
- should_break = true;
- }
- else
- {
- /* We have to move 'swap' lower in the tree, so shift current child up in the hierarchy. */
- int parent = (child - 1) / 2;
- JERRY_ASSERT (parent >= 0 && parent <= right);
- array[parent] = array[child];
-
- /* Update child to be the left child of the current node. */
- child = child * 2 + 1;
- }
-
- ECMA_FINALIZE (swap_compare_value);
- }
- }
-
- /*
- * Loop ended, either current child does not exist, or is less than swap.
- * This means that 'swap' should be placed in the parent node.
- */
- int parent = (child - 1) / 2;
- JERRY_ASSERT (parent >= 0 && parent <= right);
- array[parent] = swap;
-
- if (ecma_is_value_empty (ret_value))
- {
- ret_value = ECMA_VALUE_UNDEFINED;
- }
-
- return ret_value;
-} /* ecma_builtin_array_prototype_object_array_to_heap_helper */
-
-/**
- * Heapsort function
- *
- * @return ecma value
- * Returned value must be freed with ecma_free_value.
- */
-static ecma_value_t
-ecma_builtin_array_prototype_object_array_heap_sort_helper (ecma_value_t array[], /**< array to sort */
- int right, /**< right index */
- ecma_value_t comparefn) /**< compare function */
-{
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
-
- /* First, construct the ordered binary tree from the array. */
- for (int i = right / 2; i >= 0 && ecma_is_value_empty (ret_value); i--)
- {
- ECMA_TRY_CATCH (value,
- ecma_builtin_array_prototype_object_array_to_heap_helper (array,
- i,
- right,
- comparefn),
- ret_value);
- ECMA_FINALIZE (value);
- }
-
- /* Sorting elements. */
- for (int i = right; i > 0 && ecma_is_value_empty (ret_value); i--)
- {
- /*
- * The top element will always contain the largest value.
- * Move top to the end, and remove it from the tree.
- */
- ecma_value_t swap = array[0];
- array[0] = array[i];
- array[i] = swap;
-
- /* Rebuild binary tree from the remaining elements. */
- ECMA_TRY_CATCH (value,
- ecma_builtin_array_prototype_object_array_to_heap_helper (array,
- 0,
- i - 1,
- comparefn),
- ret_value);
- ECMA_FINALIZE (value);
- }
-
- return ret_value;
-} /* ecma_builtin_array_prototype_object_array_heap_sort_helper */
-
/**
* The Array.prototype object's 'sort' routine
*
uint32_t len = ecma_number_to_uint32 (len_number);
- ecma_collection_header_t *array_index_props_p = ecma_op_object_get_property_names (obj_p, true, false, false);
+ ecma_collection_header_t *array_index_props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_ARRAY_INDICES);
uint32_t defined_prop_count = 0;
uint32_t copied_num = 0;
/* Sorting. */
if (copied_num > 1 && ecma_is_value_empty (ret_value))
{
+ const ecma_builtin_helper_sort_compare_fn_t sort_cb = &ecma_builtin_array_prototype_object_sort_compare_helper;
ECMA_TRY_CATCH (sort_value,
- ecma_builtin_array_prototype_object_array_heap_sort_helper (values_buffer,
- (int)(copied_num - 1),
- arg1),
+ ecma_builtin_helper_array_heap_sort_helper (values_buffer,
+ (uint32_t) (copied_num - 1),
+ arg1,
+ sort_cb),
ret_value);
ECMA_FINALIZE (sort_value);
}
const uint32_t len = ecma_number_to_uint32 (len_number);
- ecma_value_t new_array = ecma_op_create_array_object (0, 0, false);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
+
+ if (ECMA_IS_VALUE_ERROR (new_array))
+ {
+ ecma_free_value (len_value);
+ ecma_free_value (obj_this);
+ return new_array;
+ }
+#else /* CONFIG_DISABLE_ES2015_CLASS */
+ ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
+ JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
ecma_object_t *new_array_p = ecma_get_object_from_value (new_array);
uint32_t start = 0;
ecma_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p,
idx_str_new_p,
get_value,
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
- false);
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (put_comp));
ecma_deref_ecma_string (idx_str_new_p);
/* 9.a */
ECMA_TRY_CATCH (get_value, ecma_op_object_find (obj_p, idx_str_p), ret_value);
- if (ecma_is_value_found (get_value))
+ /* 9.b.i, 9.b.ii */
+ if (ecma_is_value_found (get_value)
+ && ecma_op_strict_equality_compare (arg1, get_value))
{
- /* 9.b.i, 9.b.ii */
- if (ecma_op_strict_equality_compare (arg1, get_value))
- {
- found_index = ((ecma_number_t) from_idx);
- }
+ found_index = ((ecma_number_t) from_idx);
}
ECMA_FINALIZE (get_value);
/* 8.a */
ECMA_TRY_CATCH (get_value, ecma_op_object_find (obj_p, idx_str_p), ret_value);
- if (ecma_is_value_found (get_value))
+ /* 8.b.i, 8.b.ii */
+ if (ecma_is_value_found (get_value)
+ && ecma_op_strict_equality_compare (search_element, get_value))
{
- /* 8.b.i, 8.b.ii */
- if (ecma_op_strict_equality_compare (search_element, get_value))
- {
- num = ((ecma_number_t) from_idx);
- }
+ num = ((ecma_number_t) from_idx);
}
ECMA_FINALIZE (get_value);
/* 5. arg2 is simply used as T */
/* 6. */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
+
+ if (ECMA_IS_VALUE_ERROR (new_array))
+ {
+ ecma_free_value (len_value);
+ ecma_free_value (obj_this);
+ return new_array;
+ }
+#else /* CONFIG_DISABLE_ES2015_CLASS */
ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
ecma_object_t *new_array_p = ecma_get_object_from_value (new_array);
/* 7-8. */
ecma_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p,
index_str_p,
mapped_value,
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
- false);
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (put_comp));
ECMA_FINALIZE (mapped_value);
ecma_object_t *func_object_p;
/* 6. */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
+
+ if (ECMA_IS_VALUE_ERROR (new_array))
+ {
+ ecma_free_value (len_value);
+ ecma_free_value (obj_this);
+ return new_array;
+ }
+#else /* CONFIG_DISABLE_ES2015_CLASS */
ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
ecma_object_t *new_array_p = ecma_get_object_from_value (new_array);
/* We already checked that arg1 is callable, so it will always be an object. */
ecma_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p,
to_index_string_p,
get_value,
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
- false);
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (put_comp));
ecma_deref_ecma_string (to_index_string_p);
return ecma_builtin_array_reduce_from (this_arg, args, args_number, false);
} /* ecma_builtin_array_prototype_object_reduce_right */
+#ifndef CONFIG_DISABLE_ES2015_BUILTIN
+/**
+ * The Array.prototype object's 'find' routine
+ *
+ * See also:
+ * ECMA-262 v6, 22.1.3.8
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_array_prototype_object_find (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t predicate, /**< callback function */
+ ecma_value_t predicate_this_arg) /**< this argument for
+ * invoke predicate */
+{
+ /* 1. */
+ ecma_value_t obj_this = ecma_op_to_object (this_arg);
+
+ /* 2. */
+ if (ECMA_IS_VALUE_ERROR (obj_this))
+ {
+ return obj_this;
+ }
+
+ ecma_object_t *obj_p = ecma_get_object_from_value (obj_this);
+
+ /* 3 - 4. */
+ ecma_value_t len_value = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_LENGTH);
+
+ if (ECMA_IS_VALUE_ERROR (len_value))
+ {
+ ecma_free_value (obj_this);
+ return len_value;
+ }
+
+ ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+
+ ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value);
+
+ uint32_t len = ecma_number_to_uint32 (len_number);
+
+ /* 5. */
+ if (!ecma_op_is_callable (predicate))
+ {
+ ecma_free_value (len_value);
+ ecma_free_value (obj_this);
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Callback function is not callable."));
+ }
+
+ /* We already checked that predicate is callable, so it will always be an object. */
+ JERRY_ASSERT (ecma_is_value_object (predicate));
+ ecma_object_t *func_object_p = ecma_get_object_from_value (predicate);
+
+ /* 7 - 8. */
+ for (uint32_t index = 0; index < len && ecma_is_value_empty (ret_value); index++)
+ {
+ /* 8.a */
+ ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index);
+
+ /* 8.b - 8.c */
+ ECMA_TRY_CATCH (get_value, ecma_op_object_find (obj_p, index_str_p), ret_value);
+
+ if (ecma_is_value_found (get_value))
+ {
+ /* 8.d - 8.e */
+ uint32_t current_index = ecma_make_uint32_value (index);
+
+ ecma_value_t call_args[] = { get_value, current_index, obj_this };
+
+ ECMA_TRY_CATCH (call_value, ecma_op_function_call (func_object_p, predicate_this_arg, call_args, 3), ret_value);
+
+ if (ecma_op_to_boolean (call_value))
+ {
+ /* 8.f */
+ ret_value = ecma_copy_value (get_value);
+ }
+
+ ECMA_FINALIZE (call_value);
+ }
+
+ ECMA_FINALIZE (get_value);
+
+ ecma_deref_ecma_string (index_str_p);
+ }
+
+ if (ecma_is_value_empty (ret_value))
+ {
+ /* 9. */
+ ret_value = ECMA_VALUE_UNDEFINED;
+ }
+
+ ECMA_OP_TO_NUMBER_FINALIZE (len_number);
+ ecma_free_value (len_value);
+ ecma_free_value (obj_this);
+
+ return ret_value;
+} /* ecma_builtin_array_prototype_object_find */
+#endif /* !CONFIG_DISABLE_ES2015_BUILTIN */
+
/**
* @}
* @}
ROUTINE (LIT_MAGIC_STRING_FILTER, ecma_builtin_array_prototype_object_filter, 2, 1)
ROUTINE (LIT_MAGIC_STRING_REDUCE, ecma_builtin_array_prototype_object_reduce, NON_FIXED, 1)
ROUTINE (LIT_MAGIC_STRING_REDUCE_RIGHT_UL, ecma_builtin_array_prototype_object_reduce_right, NON_FIXED, 1)
+#ifndef CONFIG_DISABLE_ES2015_BUILTIN
+ROUTINE (LIT_MAGIC_STRING_FIND, ecma_builtin_array_prototype_object_find, 2, 1)
+#endif /* !CONFIG_DISABLE_ES2015_BUILTIN */
#endif /* !CONFIG_DISABLE_ARRAY_BUILTIN */
/* TODO: if arg has [[ViewArrayBuffer]], return true */
- return ecma_make_boolean_value (false);
+ return ECMA_VALUE_FALSE;
} /* ecma_builtin_arraybuffer_object_is_view */
/**
arg_value = arguments_list_p[0];
}
- return ecma_op_to_boolean (arg_value) ? ECMA_VALUE_TRUE : ECMA_VALUE_FALSE;
+ return ecma_make_boolean_value (ecma_op_to_boolean (arg_value));
} /* ecma_builtin_boolean_dispatch_call */
/**
default:
{
JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_GET_UTC_TIMEZONE_OFFSET);
+
date_num = ecma_date_timezone_offset (date_num);
break;
}
{
JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_HOURS
|| builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_UTC_HOURS);
+
conversions = 4;
break;
}
{
JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_DATE
|| builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_UTC_DATE);
+
day = converted_number[0];
break;
}
{
JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_UTC_MILLISECONDS
|| builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_MILLISECONDS);
+
ms = converted_number[0];
break;
}
* passed to routine */
ecma_length_t arguments_number) /**< length of arguments' list */
{
- if (unlikely (builtin_routine_id == ECMA_DATE_PROTOTYPE_TO_JSON))
+ if (JERRY_UNLIKELY (builtin_routine_id == ECMA_DATE_PROTOTYPE_TO_JSON))
{
return ecma_builtin_date_prototype_to_json (this_arg);
}
if (!BUILTIN_DATE_FUNCTION_IS_UTC (builtin_routine_id))
{
- this_num += ecma_date_local_time_zone (this_num);
+ this_num += ecma_date_local_time_zone_adjustment (this_num);
}
if (builtin_routine_id <= ECMA_DATE_PROTOTYPE_GET_UTC_TIMEZONE_OFFSET)
default:
{
JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_TO_UTC_STRING);
+
return ecma_date_value_to_utc_string (*prim_value_p);
}
}
* limitations under the License.
*/
+#include <math.h>
+
#include "ecma-alloc.h"
#include "ecma-builtin-helpers.h"
#include "ecma-conversion.h"
#include "ecma-helpers.h"
#include "ecma-try-catch-macro.h"
#include "lit-char-helpers.h"
-#include "math.h"
#ifndef CONFIG_DISABLE_DATE_BUILTIN
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_UNDEFINED;
- ecma_deref_object (prototype_obj_p);
-
if (arguments_list_len == 0)
{
ECMA_TRY_CATCH (parse_res_value,
name_to_str_completion = ecma_op_to_string (name_get_ret_value);
}
- if (unlikely (ECMA_IS_VALUE_ERROR (name_to_str_completion)))
+ if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (name_to_str_completion)))
{
ret_value = ecma_copy_value (name_to_str_completion);
}
msg_to_str_completion = ecma_op_to_string (msg_get_ret_value);
}
- if (unlikely (ECMA_IS_VALUE_ERROR (msg_to_str_completion)))
+ if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (msg_to_str_completion)))
{
ret_value = ecma_copy_value (msg_to_str_completion);
}
/* 4. 11. 18. */
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
- ecma_length_t args_length = arguments_number;
ecma_object_t *function_p;
ecma_extended_object_t *ext_function_p;
if (arguments_number == 0
|| (arguments_number == 1 && !ecma_is_value_integer_number (arguments_list_p[0])))
{
- args_length = 1;
-
function_p = ecma_create_object (prototype_obj_p,
sizeof (ecma_extended_object_t),
ECMA_OBJECT_TYPE_BOUND_FUNCTION);
{
JERRY_ASSERT (arguments_number > 0);
- size_t obj_size = sizeof (ecma_extended_object_t) + (args_length * sizeof (ecma_value_t));
+ size_t obj_size = sizeof (ecma_extended_object_t) + (arguments_number * sizeof (ecma_value_t));
function_p = ecma_create_object (prototype_obj_p,
obj_size,
*args_p++ = ecma_copy_value_if_not_object (arguments_list_p[i]);
}
- ecma_value_t args_len_or_this = ecma_make_integer_value ((ecma_integer_value_t) args_length);
+ ecma_value_t args_len_or_this = ecma_make_integer_value ((ecma_integer_value_t) arguments_number);
ext_function_p->u.bound_function.args_len_or_this = args_len_or_this;
}
- ecma_deref_object (prototype_obj_p);
-
/*
* [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type.
*
arguments_buffer_size,
function_body_buffer_p,
function_body_buffer_size,
- false,
+ ECMA_PARSE_NO_OPTS,
&bytecode_data_p);
if (!ECMA_IS_VALUE_ERROR (ret_value))
JERRY_UNUSED (this_arg);
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
- bool is_direct_eval = vm_is_direct_eval_form_call ();
+ uint32_t parse_opts = vm_is_direct_eval_form_call () ? ECMA_PARSE_DIRECT_EVAL : ECMA_PARSE_NO_OPTS;
/* See also: ECMA-262 v5, 10.1.1 */
- bool is_called_from_strict_mode_code;
- if (is_direct_eval)
+ if (parse_opts && vm_is_strict_mode ())
{
- is_called_from_strict_mode_code = vm_is_strict_mode ();
- }
- else
- {
- is_called_from_strict_mode_code = false;
+ JERRY_ASSERT (parse_opts & ECMA_PARSE_DIRECT_EVAL);
+ parse_opts |= ECMA_PARSE_STRICT_MODE;
}
if (!ecma_is_value_string (x))
{
/* steps 2 to 8 */
ret_value = ecma_op_eval (ecma_get_string_from_value (x),
- is_direct_eval,
- is_called_from_strict_mode_code);
+ parse_opts);
}
return ret_value;
if (ecma_is_value_empty (ret_value))
{
/* 10. */
- if (strip_prefix)
+ if (strip_prefix
+ && ((end_p - start_p) >= 2)
+ && (current == LIT_CHAR_0))
{
- if (end_p - start_p >= 2 && current == LIT_CHAR_0)
+ ecma_char_t next = *string_curr_p;
+ if (next == LIT_CHAR_LOWERCASE_X || next == LIT_CHAR_UPPERCASE_X)
{
- ecma_char_t next = *string_curr_p;
- if (next == LIT_CHAR_LOWERCASE_X || next == LIT_CHAR_UPPERCASE_X)
- {
- /* Skip the 'x' or 'X' characters. */
- start_p = ++string_curr_p;
- rad = 16;
- }
+ /* Skip the 'x' or 'X' characters. */
+ start_p = ++string_curr_p;
+ rad = 16;
}
}
{
current_number = (ecma_number_t) current_char - LIT_CHAR_UPPERCASE_A + 10;
}
- else if (lit_char_is_decimal_digit (current_char))
- {
- current_number = (ecma_number_t) current_char - LIT_CHAR_0;
- }
else
{
- JERRY_UNREACHABLE ();
+ JERRY_ASSERT (lit_char_is_decimal_digit (current_char));
+ current_number = (ecma_number_t) current_char - LIT_CHAR_0;
}
value += current_number * multiplier;
ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value);
- bool is_nan = ecma_number_is_nan (arg_num);
-
- ret_value = is_nan ? ECMA_VALUE_TRUE : ECMA_VALUE_FALSE;
+ ret_value = ecma_make_boolean_value (ecma_number_is_nan (arg_num));
ECMA_OP_TO_NUMBER_FINALIZE (arg_num);
bool is_finite = !(ecma_number_is_nan (arg_num)
|| ecma_number_is_infinity (arg_num));
-
- ret_value = is_finite ? ECMA_VALUE_TRUE : ECMA_VALUE_FALSE;
+ ret_value = ecma_make_boolean_value (is_finite);
ECMA_OP_TO_NUMBER_FINALIZE (arg_num);
return (bitset[character >> 3] & (1u << (character & 0x7))) != 0;
} /* ecma_builtin_global_object_character_is_in */
-/*
+/**
* Unescaped URI characters bitset:
* One bit for each character between 0 - 127.
* Bit is set if the character is in the unescaped URI set.
0xff, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x47
};
-/*
+/**
* Unescaped URI component characters bitset:
* One bit for each character between 0 - 127.
* Bit is set if the character is in the unescaped component URI set.
0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x47
};
-/*
+/**
* Format is a percent sign followed by two hex digits.
*/
#define URI_ENCODED_BYTE_SIZE (3)
-/*
- * These two types shows whether the byte is present in
- * the original stream or decoded from a %xx sequence.
- */
-#define URI_DECODE_ORIGINAL_BYTE 0
-#define URI_DECODE_DECODED_BYTE 1
-
/**
* Helper function to decode URI.
*
#ifndef CONFIG_DISABLE_ANNEXB_BUILTIN
-/*
+/**
* Maximum value of a byte.
*/
#define ECMA_ESCAPE_MAXIMUM_BYTE_VALUE (255)
-/*
+/**
* Format is a percent sign followed by lowercase u and four hex digits.
*/
#define ECMA_ESCAPE_ENCODED_UNICODE_CHARACTER_SIZE (6)
-/*
+/**
* Escape characters bitset:
* One bit for each character between 0 - 127.
* Bit is set if the character does not need to be converted to %xx form.
ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
+
#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
OBJECT_VALUE (LIT_MAGIC_STRING_PROMISE_UL,
ECMA_BUILTIN_ID_PROMISE,
ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+/* ECMA-262 v6, 23.1.1.1 */
+OBJECT_VALUE (LIT_MAGIC_STRING_MAP_UL,
+ ECMA_BUILTIN_ID_MAP,
+ ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
+
/* Routine properties:
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
*
* @return time value for day number
*/
-inline ecma_number_t __attr_always_inline___
+inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_day (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
*
* @return time value within the day
*/
-inline ecma_number_t __attr_always_inline___
+inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_time_within_day (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
*
* @return time value of the start of a year
*/
-static inline ecma_number_t __attr_always_inline___
+static inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_time_from_year (ecma_number_t year) /**< year value */
{
JERRY_ASSERT (!ecma_number_is_nan (year));
} /* ecma_date_week_day */
/**
- * Helper function to get local time zone adjustment.
+ * Helper function to get the local time zone offset at a given UTC timestamp.
+ * You can add this number to the given UTC timestamp to get local time.
*
* See also:
- * ECMA-262 v5, 15.9.1.7
+ * ECMA-262 v5, 15.9.1.9
*
* @return local time zone adjustment
*/
-static inline ecma_number_t __attr_always_inline___
-ecma_date_local_tza (jerry_time_zone_t *tz) /**< time zone information */
+inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
+ecma_date_local_time_zone_adjustment (ecma_number_t time) /**< time value */
{
- return tz->offset * -ECMA_DATE_MS_PER_MINUTE;
-} /* ecma_date_local_tza */
+ return jerry_port_get_local_time_zone_adjustment (time, true);
+} /* ecma_date_local_time_zone_adjustment */
/**
- * Helper function to get the daylight saving time adjustment.
- *
- * See also:
- * ECMA-262 v5, 15.9.1.8
- *
- * @return daylight saving time adjustment
- */
-static inline ecma_number_t __attr_always_inline___
-ecma_date_daylight_saving_ta (jerry_time_zone_t *tz, /**< time zone information */
- ecma_number_t time) /**< time value */
-{
- JERRY_ASSERT (!ecma_number_is_nan (time));
-
- /*
- * TODO: Fix daylight saving calculation.
- * https://github.com/jerryscript-project/jerryscript/issues/1661
- */
- return tz->daylight_saving_time * ECMA_DATE_MS_PER_HOUR;
-} /* ecma_date_daylight_saving_ta */
-
-/**
- * Helper function to get local time from UTC.
+ * Helper function to get UTC time from local time.
*
* See also:
* ECMA-262 v5, 15.9.1.9
*
- * @return local time
- */
-inline ecma_number_t __attr_always_inline___
-ecma_date_local_time_zone (ecma_number_t time) /**< time value */
-{
- jerry_time_zone_t tz;
-
- if (ecma_number_is_nan (time)
- || !jerry_port_get_time_zone (&tz))
- {
- return ecma_number_make_nan ();
- }
-
- return ecma_date_local_tza (&tz) + ecma_date_daylight_saving_ta (&tz, time);
-} /* ecma_date_local_time_zone */
-
-/**
- * Helper function to get utc from local time.
- *
- * See also:
- * ECMA-262 v5, 15.9.1.9
- *
- * @return utc time
+ * @return UTC time
*/
ecma_number_t
ecma_date_utc (ecma_number_t time) /**< time value */
{
- jerry_time_zone_t tz;
-
- if (ecma_number_is_nan (time)
- || !jerry_port_get_time_zone (&tz))
- {
- return ecma_number_make_nan ();
- }
-
- ecma_number_t simple_utc_time = time - ecma_date_local_tza (&tz);
- return simple_utc_time - ecma_date_daylight_saving_ta (&tz, simple_utc_time);
+ return time - jerry_port_get_local_time_zone_adjustment (time, false);
} /* ecma_date_utc */
/**
*
* @return timezone offset
*/
-inline ecma_number_t __attr_always_inline___
+inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_timezone_offset (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
- return (-ecma_date_local_time_zone (time)) / ECMA_DATE_MS_PER_MINUTE;
+ return (-ecma_date_local_time_zone_adjustment (time)) / ECMA_DATE_MS_PER_MINUTE;
} /* ecma_date_timezone_offset */
/**
ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
const char *format_p) /**< format buffer */
{
- const char *day_names_p[8] =
+ static const char * const day_names_p[8] =
{
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
- const char *month_names_p[13] =
+ static const char * const month_names_p[13] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
const uint32_t date_buffer_length = 34;
- lit_utf8_byte_t date_buffer[date_buffer_length];
+ JERRY_VLA (lit_utf8_byte_t, date_buffer, date_buffer_length);
lit_utf8_byte_t *dest_p = date_buffer;
}
case LIT_CHAR_LOWERCASE_Z: /* Time zone minutes part. */
{
- int32_t time_zone = (int32_t) ecma_date_local_time_zone (datetime_number);
+ int32_t time_zone = (int32_t) ecma_date_local_time_zone_adjustment (datetime_number);
if (time_zone >= 0)
{
number_length = 2;
break;
}
- case LIT_CHAR_UPPERCASE_Z: /* Time zone seconds part. */
+ default:
{
- int32_t time_zone = (int32_t) ecma_date_local_time_zone (datetime_number);
+ JERRY_ASSERT (*format_p == LIT_CHAR_UPPERCASE_Z); /* Time zone seconds part. */
+
+ int32_t time_zone = (int32_t) ecma_date_local_time_zone_adjustment (datetime_number);
if (time_zone < 0)
{
number_length = 2;
break;
}
- default:
- {
- JERRY_UNREACHABLE ();
- break;
- }
}
format_p++;
ecma_value_t
ecma_date_value_to_string (ecma_number_t datetime_number) /**< datetime */
{
- datetime_number += ecma_date_local_time_zone (datetime_number);
+ datetime_number += ecma_date_local_time_zone_adjustment (datetime_number);
return ecma_date_to_string_format (datetime_number, "$W $M $D $Y $h:$m:$s GMT$z:$Z");
} /* ecma_date_value_to_string */
* @return pointer to ecma-string
* Returned value must be freed with ecma_deref_ecma_string.
*/
-ecma_string_t *
+static ecma_string_t *
ecma_builtin_helper_json_create_separated_properties (ecma_collection_header_t *partial_p, /**< key-value pairs*/
ecma_string_t *separator_p) /**< separator*/
{
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))
+ if (JERRY_LIKELY (!first))
{
properties_str_p = ecma_concat_ecma_strings (properties_str_p, separator_p);
}
--- /dev/null
+/* 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-builtin-helpers.h"
+#include "ecma-globals.h"
+#include "ecma-try-catch-macro.h"
+
+/**
+ * Function used to reconstruct the ordered binary tree.
+ * Shifts 'index' down in the tree until it is in the correct position.
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_helper_array_to_heap (ecma_value_t *array_p, /**< heap data array */
+ uint32_t index, /**< current item index */
+ uint32_t right, /**< right index is a maximum index */
+ ecma_value_t compare_func, /**< compare function */
+ const ecma_builtin_helper_sort_compare_fn_t sort_cb) /**< sorting cb */
+{
+ ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+
+ /* Left child of the current index. */
+ uint32_t child = index * 2 + 1;
+ ecma_value_t swap = array_p[index];
+ bool should_break = false;
+
+ while (child <= right && ecma_is_value_empty (ret_value) && !should_break)
+ {
+ if (child < right)
+ {
+ /* Compare the two child nodes. */
+ ECMA_TRY_CATCH (child_compare_value, sort_cb (array_p[child], array_p[child + 1], compare_func),
+ ret_value);
+
+ JERRY_ASSERT (ecma_is_value_number (child_compare_value));
+
+ /* Use the child that is greater. */
+ if (ecma_get_number_from_value (child_compare_value) < ECMA_NUMBER_ZERO)
+ {
+ child++;
+ }
+
+ ECMA_FINALIZE (child_compare_value);
+ }
+
+ if (ecma_is_value_empty (ret_value))
+ {
+ JERRY_ASSERT (child <= right);
+
+ /* Compare current child node with the swap (tree top). */
+ ECMA_TRY_CATCH (swap_compare_value, sort_cb (array_p[child], swap, compare_func), ret_value);
+ JERRY_ASSERT (ecma_is_value_number (swap_compare_value));
+
+ if (ecma_get_number_from_value (swap_compare_value) <= ECMA_NUMBER_ZERO)
+ {
+ /* Break from loop if current child is less than swap (tree top) */
+ should_break = true;
+ }
+ else
+ {
+ /* We have to move 'swap' lower in the tree, so shift current child up in the hierarchy. */
+ uint32_t parent = (child - 1) / 2;
+ JERRY_ASSERT (parent <= right);
+ array_p[parent] = array_p[child];
+
+ /* Update child to be the left child of the current node. */
+ child = child * 2 + 1;
+ }
+
+ ECMA_FINALIZE (swap_compare_value);
+ }
+ }
+
+ /*
+ * Loop ended, either current child does not exist, or is less than swap.
+ * This means that 'swap' should be placed in the parent node.
+ */
+ uint32_t parent = (child - 1) / 2;
+ JERRY_ASSERT (parent <= right);
+ array_p[parent] = swap;
+
+ if (ecma_is_value_empty (ret_value))
+ {
+ ret_value = ECMA_VALUE_UNDEFINED;
+ }
+
+ return ret_value;
+} /* ecma_builtin_helper_array_to_heap */
+
+/**
+ * Heapsort function
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_builtin_helper_array_heap_sort_helper (ecma_value_t *array_p, /**< array to sort */
+ uint32_t right, /**< right index */
+ ecma_value_t compare_func, /**< compare function */
+ const ecma_builtin_helper_sort_compare_fn_t sort_cb) /**< sorting cb */
+{
+ ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+
+ /* First, construct the ordered binary tree from the array. */
+ for (uint32_t i = (right / 2) + 1; i > 0 && ecma_is_value_empty (ret_value); i--)
+ {
+ ECMA_TRY_CATCH (value,
+ ecma_builtin_helper_array_to_heap (array_p, i - 1, right, compare_func, sort_cb),
+ ret_value);
+ ECMA_FINALIZE (value);
+ }
+
+ /* Sorting elements. */
+ for (uint32_t i = right; i > 0 && ecma_is_value_empty (ret_value); i--)
+ {
+ /*
+ * The top element will always contain the largest value.
+ * Move top to the end, and remove it from the tree.
+ */
+ ecma_value_t swap = array_p[0];
+ array_p[0] = array_p[i];
+ array_p[i] = swap;
+
+ /* Rebuild binary tree from the remaining elements. */
+ ECMA_TRY_CATCH (value,
+ ecma_builtin_helper_array_to_heap (array_p, 0, i - 1, compare_func, sort_cb),
+ ret_value);
+ ECMA_FINALIZE (value);
+ }
+
+ return ret_value;
+} /* ecma_builtin_helper_array_heap_sort_helper */
'Null' or one of possible object's classes.
The string with null character is maximum 27 characters long. */
const lit_utf8_size_t buffer_size = 27;
- lit_utf8_byte_t str_buffer[buffer_size];
+ JERRY_VLA (lit_utf8_byte_t, str_buffer, buffer_size);
lit_utf8_byte_t *buffer_ptr = str_buffer;
uint32_t index = 0;
- ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p,
- false,
- only_enumerable_properties,
- false);
+ ecma_collection_header_t *props_p;
+ props_p = ecma_op_object_get_property_names (obj_p,
+ only_enumerable_properties ? ECMA_LIST_ENUMERABLE : ECMA_LIST_NO_OPTS);
ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p);
ecma_value_t completion = ecma_builtin_helper_def_prop (new_array_p,
index_string_p,
*ecma_value_p,
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (completion));
ecma_value_t put_comp = ecma_builtin_helper_def_prop (obj_p,
new_array_index_string_p,
get_value,
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
- false); /* Failure handling */
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (put_comp));
ecma_deref_ecma_string (new_array_index_string_p);
ecma_value_t put_comp = ecma_builtin_helper_def_prop (obj_p,
new_array_index_string_p,
value,
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
- false); /* Failure handling */
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (put_comp));
* - The String.prototype.indexOf routine.
* - The String.prototype.lastIndexOf routine.
*
- * @return uint32_t - (last) index of search string
+ * @return ecma_value_t - (last) index of search string as an ecma-value
*/
ecma_value_t
ecma_builtin_helper_string_prototype_object_index_of (ecma_value_t this_arg, /**< this argument */
* - The ecma_builtin_helper_string_prototype_object_index_of helper routine.
* - The ecma_builtin_string_prototype_object_replace_match helper routine.
*
- * @return uint32_t - the normalized value of the index
+ * @return bool - whether there is a match for the search string
*/
bool
ecma_builtin_helper_string_find_index (ecma_string_t *original_str_p, /**< index */
ecma_string_t *search_str_p, /**< string's length */
bool first_index, /**< whether search for first (t) or last (f) index */
ecma_length_t start_pos, /**< start position */
- ecma_length_t *ret_index_p) /**< position found in original string */
+ ecma_length_t *ret_index_p) /**< [out] position found in original string */
{
bool match_found = false;
const ecma_length_t original_len = ecma_string_get_length (original_str_p);
ecma_builtin_helper_def_prop (ecma_object_t *obj_p, /**< object */
ecma_string_t *index_p, /**< index string */
ecma_value_t value, /**< value */
- bool writable, /**< writable */
- bool enumerable, /**< enumerable */
- bool configurable, /**< configurable */
+ uint32_t opts, /**< any combination of ecma_property_flag_t bits */
bool is_throw) /**< is_throw */
{
ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
prop_desc.value = value;
prop_desc.is_writable_defined = true;
- prop_desc.is_writable = ECMA_BOOL_TO_BITFIELD (writable);
+ prop_desc.is_writable = (opts & ECMA_PROPERTY_FLAG_WRITABLE) != 0;
prop_desc.is_enumerable_defined = true;
- prop_desc.is_enumerable = ECMA_BOOL_TO_BITFIELD (enumerable);
+ prop_desc.is_enumerable = (opts & ECMA_PROPERTY_FLAG_ENUMERABLE) != 0;
prop_desc.is_configurable_defined = true;
- prop_desc.is_configurable = ECMA_BOOL_TO_BITFIELD (configurable);
+ prop_desc.is_configurable = (opts & ECMA_PROPERTY_FLAG_CONFIGURABLE) != 0;
return ecma_op_object_define_own_property (obj_p,
index_p,
ecma_length_t start_pos, ecma_length_t *ret_index_p);
ecma_value_t
ecma_builtin_helper_def_prop (ecma_object_t *obj_p, ecma_string_t *index_p, ecma_value_t value,
- bool writable, bool enumerable, bool configurable, bool is_throw);
+ uint32_t opts, bool is_throw);
#ifndef CONFIG_DISABLE_DATE_BUILTIN
ecma_number_t ecma_date_month_from_time (ecma_number_t time);
ecma_number_t ecma_date_date_from_time (ecma_number_t time);
ecma_number_t ecma_date_week_day (ecma_number_t time);
-ecma_number_t ecma_date_local_time_zone (ecma_number_t time);
+ecma_number_t ecma_date_local_time_zone_adjustment (ecma_number_t time);
ecma_number_t ecma_date_utc (ecma_number_t time);
ecma_number_t ecma_date_hour_from_time (ecma_number_t time);
ecma_number_t ecma_date_min_from_time (ecma_number_t time);
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 *
-ecma_builtin_helper_json_create_separated_properties (ecma_collection_header_t *partial_p, ecma_string_t *separator_p);
ecma_value_t
ecma_builtin_helper_json_create_formatted_json (lit_utf8_byte_t left_bracket, lit_utf8_byte_t right_bracket,
ecma_string_t *stepback_p, ecma_collection_header_t *partial_p,
ecma_builtin_helper_error_dispatch_call (ecma_standard_error_t error_type, const ecma_value_t *arguments_list_p,
ecma_length_t arguments_list_len);
+/* ecma-builtin-helpers-sort.c */
+
+/**
+ * Comparison callback function header for sorting helper routines.
+ */
+typedef ecma_value_t (*ecma_builtin_helper_sort_compare_fn_t)(ecma_value_t lhs, /**< left value */
+ ecma_value_t rhs, /**< right value */
+ ecma_value_t compare_func); /**< compare function */
+
+ecma_value_t ecma_builtin_helper_array_heap_sort_helper (ecma_value_t *array_p,
+ uint32_t right,
+ ecma_value_t compare_func,
+ const ecma_builtin_helper_sort_compare_fn_t sort_cb);
+
/**
* @}
* @}
ecma_value_t completion_value = ecma_builtin_helper_def_prop (obj_p,
property_name_p,
value,
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_boolean (completion_value));
ecma_value_t completion = ecma_builtin_helper_def_prop (array_p,
index_str_p,
value,
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (completion));
{
ecma_object_t *object_p = ecma_get_object_from_value (value_get);
- ecma_collection_header_t *props_p = ecma_op_object_get_property_names (object_p, false, true, false);
+ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (object_p, ECMA_LIST_ENUMERABLE);
ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_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);
+
+ if (ecma_is_value_true (put_comp_val))
+ {
+ ret_value = ecma_builtin_json_str (empty_str_p, obj_wrapper_p, &context);
+ }
+ else
+ {
+ ret_value = ECMA_VALUE_UNDEFINED;
+ }
+
ecma_free_value (put_comp_val);
ecma_deref_ecma_string (empty_str_p);
ecma_deref_object (obj_wrapper_p);
static ecma_value_t
ecma_builtin_json_quote (ecma_string_t *string_p) /**< string that should be quoted*/
{
- /* 1. */
- ecma_string_t *product_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_DOUBLE_QUOTE_CHAR);
-
ECMA_STRING_TO_UTF8_STRING (string_p, string_buff, string_buff_size);
-
const lit_utf8_byte_t *str_p = string_buff;
- const lit_utf8_byte_t *str_end_p = string_buff + string_buff_size;
+ const lit_utf8_byte_t *str_end_p = str_p + string_buff_size;
+ size_t n_bytes = 2; /* Start with 2 for surrounding quotes. */
while (str_p < str_end_p)
{
- ecma_char_t current_char = lit_utf8_read_next (&str_p);
+ lit_utf8_byte_t c = *str_p++;
- /* 2.a, b */
- if (current_char == LIT_CHAR_BACKSLASH
- || current_char == LIT_CHAR_DOUBLE_QUOTE
- || current_char == LIT_CHAR_BS
- || current_char == LIT_CHAR_FF
- || current_char == LIT_CHAR_LF
- || current_char == LIT_CHAR_CR
- || current_char == LIT_CHAR_TAB)
+ if (c == LIT_CHAR_BACKSLASH || c == LIT_CHAR_DOUBLE_QUOTE)
+ {
+ n_bytes += 2;
+ }
+ else if (c >= LIT_CHAR_SP && c < LIT_UTF8_1_BYTE_CODE_POINT_MAX)
+ {
+ n_bytes++;
+ }
+ else if (c > LIT_UTF8_1_BYTE_CODE_POINT_MAX)
+ {
+ lit_utf8_size_t sz = lit_get_unicode_char_size_by_utf8_first_byte (c);
+ n_bytes += sz;
+ str_p += sz - 1;
+ }
+ else
{
- lit_utf8_byte_t abbrev = (lit_utf8_byte_t) current_char;
+ switch (c)
+ {
+ case LIT_CHAR_BS:
+ case LIT_CHAR_FF:
+ case LIT_CHAR_LF:
+ case LIT_CHAR_CR:
+ case LIT_CHAR_TAB:
+ {
+ n_bytes += 2;
+ break;
+ }
+ default: /* Hexadecimal. */
+ {
+ n_bytes += 2 + 4;
+ break;
+ }
+ }
+ }
+ }
- switch (current_char)
+ lit_utf8_byte_t *buf_begin = jmem_heap_alloc_block (n_bytes);
+ JERRY_ASSERT (buf_begin != NULL);
+ lit_utf8_byte_t *buf = buf_begin;
+ str_p = string_buff;
+
+ *buf++ = LIT_CHAR_DOUBLE_QUOTE;
+
+ while (str_p < str_end_p)
+ {
+ lit_utf8_byte_t c = *str_p++;
+
+ if (c == LIT_CHAR_BACKSLASH || c == LIT_CHAR_DOUBLE_QUOTE)
+ {
+ *buf++ = LIT_CHAR_BACKSLASH;
+ *buf++ = c;
+ }
+ else if (c >= LIT_CHAR_SP && c < LIT_UTF8_1_BYTE_CODE_POINT_MAX)
+ {
+ *buf++ = c;
+ }
+ else if (c > LIT_UTF8_1_BYTE_CODE_POINT_MAX)
+ {
+ str_p--;
+ ecma_char_t current_char = lit_utf8_read_next (&str_p);
+ buf += lit_code_unit_to_utf8 (current_char, (lit_utf8_byte_t *) buf);
+ }
+ else
+ {
+ switch (c)
{
case LIT_CHAR_BS:
{
- abbrev = LIT_CHAR_LOWERCASE_B;
+ *buf++ = LIT_CHAR_BACKSLASH;
+ *buf++ = LIT_CHAR_LOWERCASE_B;
break;
}
case LIT_CHAR_FF:
{
- abbrev = LIT_CHAR_LOWERCASE_F;
+ *buf++ = LIT_CHAR_BACKSLASH;
+ *buf++ = LIT_CHAR_LOWERCASE_F;
break;
}
case LIT_CHAR_LF:
{
- abbrev = LIT_CHAR_LOWERCASE_N;
+ *buf++ = LIT_CHAR_BACKSLASH;
+ *buf++ = LIT_CHAR_LOWERCASE_N;
break;
}
case LIT_CHAR_CR:
{
- abbrev = LIT_CHAR_LOWERCASE_R;
+ *buf++ = LIT_CHAR_BACKSLASH;
+ *buf++ = LIT_CHAR_LOWERCASE_R;
break;
}
case LIT_CHAR_TAB:
{
- abbrev = LIT_CHAR_LOWERCASE_T;
+ *buf++ = LIT_CHAR_BACKSLASH;
+ *buf++ = LIT_CHAR_LOWERCASE_T;
break;
}
- default:
+ default: /* Hexadecimal. */
{
- JERRY_ASSERT (current_char == LIT_CHAR_BACKSLASH || current_char == LIT_CHAR_DOUBLE_QUOTE);
+ JERRY_ASSERT (c < 0x9f);
+ *buf++ = LIT_CHAR_BACKSLASH;
+ *buf++ = LIT_CHAR_LOWERCASE_U;
+ *buf++ = LIT_CHAR_0;
+ *buf++ = LIT_CHAR_0;
+ *buf++ = (lit_utf8_byte_t) (LIT_CHAR_0 + (c >> 4)); /* Max range 0-9, hex digits unnecessary. */
+ lit_utf8_byte_t c2 = (c & 0xf);
+ *buf++ = (lit_utf8_byte_t) (c2 + ((c2 <= 9) ? LIT_CHAR_0 : (LIT_CHAR_LOWERCASE_A - 10)));
break;
}
}
-
- lit_utf8_byte_t chars[2] = { LIT_CHAR_BACKSLASH, abbrev };
-
- product_str_p = ecma_append_chars_to_string (product_str_p, chars, 2, 2);
}
- /* 2.c */
- else if (current_char < LIT_CHAR_SP)
- {
- lit_utf8_byte_t chars[6] = { LIT_CHAR_BACKSLASH, LIT_CHAR_LOWERCASE_U, LIT_CHAR_0, LIT_CHAR_0 };
-
- JERRY_ASSERT (current_char < 0x9f);
-
- chars[4] = (lit_utf8_byte_t) (LIT_CHAR_0 + (current_char >> 4));
-
- int last_char = current_char & 0xf;
- last_char += (last_char <= 9) ? LIT_CHAR_0 : (LIT_CHAR_LOWERCASE_A - 10);
-
- chars[5] = (lit_utf8_byte_t) last_char;
-
- product_str_p = ecma_append_chars_to_string (product_str_p, chars, 6, 6);
- }
- /* 2.d */
- else if (current_char < LIT_UTF8_1_BYTE_CODE_POINT_MAX)
- {
- /* Fast case for ascii characters. */
- lit_utf8_byte_t chars[1] = { (lit_utf8_byte_t) current_char };
+ }
- product_str_p = ecma_append_chars_to_string (product_str_p, chars, 1, 1);
- }
- else
- {
- ecma_string_t *current_char_str_p = ecma_new_ecma_string_from_code_unit (current_char);
+ *buf++ = LIT_CHAR_DOUBLE_QUOTE;
- product_str_p = ecma_concat_ecma_strings (product_str_p, current_char_str_p);
- ecma_deref_ecma_string (current_char_str_p);
- }
- }
+ /* Make sure we didn't run off the end or allocated more than we actually wanted. */
+ JERRY_ASSERT ((size_t) (buf - buf_begin) == n_bytes);
+ ecma_string_t *product_str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) buf_begin,
+ (lit_utf8_size_t) (buf - buf_begin));
+ jmem_heap_free_block (buf_begin, n_bytes);
ECMA_FINALIZE_UTF8_STRING (string_buff, string_buff_size);
- /* 3. */
- product_str_p = ecma_append_magic_string_to_string (product_str_p, LIT_MAGIC_STRING_DOUBLE_QUOTE_CHAR);
-
- /* 4. */
return ecma_make_string_value (product_str_p);
} /* ecma_builtin_json_quote */
{
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_header_t *props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_ENUMERABLE);
ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p);
--- /dev/null
+/* 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-map-object.h"
+
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+
+#define ECMA_BUILTINS_INTERNAL
+#include "ecma-builtins-internal.h"
+
+#define BUILTIN_INC_HEADER_NAME "ecma-builtin-map-prototype.inc.h"
+#define BUILTIN_UNDERSCORED_ID map_prototype
+#include "ecma-builtin-internal-routines-template.inc.h"
+
+/** \addtogroup ecma ECMA
+ * @{
+ *
+ * \addtogroup ecmabuiltins
+ * @{
+ *
+ * \addtogroup map ECMA Map object built-in
+ * @{
+ */
+
+/**
+ * The Map.prototype object's 'clear' routine
+ *
+ * See also:
+ * ECMA-262 v6, 23.1.3.1
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_map_prototype_object_clear (ecma_value_t this_arg) /**< this argument */
+{
+ return ecma_op_map_clear (this_arg);
+} /* ecma_builtin_map_prototype_object_clear */
+
+/**
+ * The Map.prototype object's 'delete' routine
+ *
+ * See also:
+ * ECMA-262 v6, 23.1.3.3
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_map_prototype_object_delete (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t key_arg) /**< key argument */
+{
+ return ecma_op_map_delete (this_arg, key_arg);
+} /* ecma_builtin_map_prototype_object_delete */
+
+/**
+ * The Map.prototype object's 'get' routine
+ *
+ * See also:
+ * ECMA-262 v6, 23.1.3.6
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_map_prototype_object_get (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t key_arg) /**< key argument */
+{
+ return ecma_op_map_get (this_arg, key_arg);
+} /* ecma_builtin_map_prototype_object_get */
+
+/**
+ * The Map.prototype object's 'has' routine
+ *
+ * See also:
+ * ECMA-262 v6, 23.1.3.7
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_map_prototype_object_has (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t key_arg) /**< key argument */
+{
+ return ecma_op_map_has (this_arg, key_arg);
+} /* ecma_builtin_map_prototype_object_has */
+
+/**
+ * The Map.prototype object's 'set' routine
+ *
+ * See also:
+ * ECMA-262 v6, 23.1.3.9
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_map_prototype_object_set (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t key_arg, /**< key argument */
+ ecma_value_t value_arg) /**< value argument */
+{
+ return ecma_op_map_set (this_arg, key_arg, value_arg);
+} /* ecma_builtin_map_prototype_object_set */
+
+/**
+ * The Map.prototype object's 'size' getter
+ *
+ * See also:
+ * ECMA-262 v6, 23.1.3.10
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_map_prototype_object_size_getter (ecma_value_t this_arg) /**< this argument */
+{
+ return ecma_op_map_size (this_arg);
+} /* ecma_builtin_map_prototype_object_size_getter */
+
+/**
+ * @}
+ * @}
+ * @}
+ */
+
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
--- /dev/null
+/* 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.
+ */
+
+/*
+ * Map.prototype built-in description
+ */
+
+#include "ecma-builtin-helpers-macro-defines.inc.h"
+
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+
+/* Object properties:
+ * (property name, object pointer getter) */
+
+/* ECMA-262 v6, 23.1.3.2 */
+OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
+ ECMA_BUILTIN_ID_MAP,
+ ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
+
+/* ECMA-262 v6, 23.1.3 */
+STRING_VALUE (LIT_MAGIC_STRING_NAME,
+ LIT_MAGIC_STRING_MAP_UL,
+ ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
+
+/* Routine properties:
+ * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
+ROUTINE (LIT_MAGIC_STRING_CLEAR, ecma_builtin_map_prototype_object_clear, 0, 0)
+ROUTINE (LIT_MAGIC_STRING_DELETE, ecma_builtin_map_prototype_object_delete, 1, 1)
+ROUTINE (LIT_MAGIC_STRING_GET, ecma_builtin_map_prototype_object_get, 1, 1)
+ROUTINE (LIT_MAGIC_STRING_HAS, ecma_builtin_map_prototype_object_has, 1, 1)
+ROUTINE (LIT_MAGIC_STRING_SET, ecma_builtin_map_prototype_object_set, 2, 2)
+
+/* ECMA-262 v6, 23.1.3.10 */
+ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_SIZE,
+ ecma_builtin_map_prototype_object_size_getter,
+ ECMA_PROPERTY_FIXED)
+
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
+
+#include "ecma-builtin-helpers-macro-undefs.inc.h"
--- /dev/null
+/* 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-builtins.h"
+#include "ecma-exceptions.h"
+#include "ecma-map-object.h"
+
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+
+#define ECMA_BUILTINS_INTERNAL
+#include "ecma-builtins-internal.h"
+
+#define BUILTIN_INC_HEADER_NAME "ecma-builtin-map.inc.h"
+#define BUILTIN_UNDERSCORED_ID map
+#include "ecma-builtin-internal-routines-template.inc.h"
+
+/** \addtogroup ecma ECMA
+ * @{
+ *
+ * \addtogroup ecmabuiltins
+ * @{
+ *
+ * \addtogroup map ECMA Map object built-in
+ * @{
+ */
+
+/**
+ * Handle calling [[Call]] of built-in Map object
+ *
+ * @return ecma value
+ */
+ecma_value_t
+ecma_builtin_map_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */
+ ecma_length_t arguments_list_len) /**< number of arguments */
+{
+ JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
+
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Constructor Map requires 'new'."));
+} /* ecma_builtin_map_dispatch_call */
+
+/**
+ * Handle calling [[Construct]] of built-in Map object
+ *
+ * @return ecma value
+ */
+ecma_value_t
+ecma_builtin_map_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
+ ecma_length_t arguments_list_len) /**< number of arguments */
+{
+ return ecma_op_map_create (arguments_list_p, arguments_list_len);
+} /* ecma_builtin_map_dispatch_construct */
+
+/**
+ * @}
+ * @}
+ * @}
+ */
+
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
--- /dev/null
+/* 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.
+ */
+
+/*
+ * Map built-in description
+ */
+
+#include "ecma-builtin-helpers-macro-defines.inc.h"
+
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+
+/* Number properties:
+ * (property name, number value, writable, enumerable, configurable) */
+
+/* ECMA-262 v6, 23.1.2 */
+NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
+ 0,
+ ECMA_PROPERTY_FIXED)
+
+/* Object properties:
+ * (property name, object pointer getter) */
+
+/* ECMA-262 v6, 23.1.2.1 */
+OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
+ ECMA_BUILTIN_ID_MAP_PROTOTYPE,
+ ECMA_PROPERTY_FIXED)
+
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
+
+#include "ecma-builtin-helpers-macro-undefs.inc.h"
ecma_fast_free_value (value);
}
- if (unlikely (ecma_number_is_nan (arg_num)))
+ if (JERRY_UNLIKELY (ecma_number_is_nan (arg_num)))
{
result_num = arg_num;
break;
}
}
- if (builtin_routine_id >= ECMA_MATH_OBJECT_ATAN2)
+ if (builtin_routine_id >= ECMA_MATH_OBJECT_ATAN2
+ && arguments_number >= 2)
{
- if (arguments_number >= 2)
+ if (ecma_is_value_number (arguments_list[1]))
{
- if (ecma_is_value_number (arguments_list[1]))
+ y = ecma_get_number_from_value (arguments_list[1]);
+ }
+ else
+ {
+ ecma_value_t value = ecma_op_to_number (arguments_list[1]);
+
+ if (ECMA_IS_VALUE_ERROR (value))
{
- y = ecma_get_number_from_value (arguments_list[1]);
+ return value;
}
- else
- {
- ecma_value_t value = ecma_op_to_number (arguments_list[1]);
-
- if (ECMA_IS_VALUE_ERROR (value))
- {
- return value;
- }
- y = ecma_get_number_from_value (value);
+ y = ecma_get_number_from_value (value);
- ecma_fast_free_value (value);
- }
+ ecma_fast_free_value (value);
}
}
return (lit_utf8_size_t) (p - to_digits_p);
} /* ecma_builtin_number_prototype_helper_to_string */
-static inline lit_utf8_size_t __attr_always_inline___
+/**
+ * Helper function to convert a binary floating point number to string.
+ *
+ * @return size of result string
+ */
+static inline lit_utf8_size_t JERRY_ATTR_ALWAYS_INLINE
ecma_builtin_binary_floating_number_to_string (lit_utf8_byte_t *digits_p, /**< number as string
* in binary-floating point number */
int32_t exponent, /**< decimal exponent */
*
* @return rounded number
*/
-static inline lit_utf8_size_t __attr_always_inline___
+static inline lit_utf8_size_t JERRY_ATTR_ALWAYS_INLINE
ecma_builtin_number_prototype_helper_round (lit_utf8_byte_t *digits_p, /**< [in,out] number as a string in decimal
* form */
lit_utf8_size_t num_digits, /**< length of the string representation */
* cases that can cause incorrect results due to precision issues, so we use a loop instead.
*/
magnitude = 0;
- double counter = this_arg_number;
+ ecma_number_t counter = this_arg_number;
while (counter >= radix)
{
counter /= radix;
num_digits + 1,
exponent + frac_digits,
&exponent,
- ecma_number_is_zero (this_num) ? true : false);
+ ecma_number_is_zero (this_num));
/* Buffer that is used to construct the string. */
int buffer_size = (exponent > 0) ? exponent + frac_digits + 2 : frac_digits + 3;
ecma_object_t *v_obj_p = ecma_get_object_from_value (v_obj_value);
bool is_prototype_of = ecma_op_object_is_prototype_of (obj_p, v_obj_p);
- return_value = is_prototype_of ? ECMA_VALUE_TRUE : ECMA_VALUE_FALSE;
+ return_value = ecma_make_boolean_value (is_prototype_of);
ECMA_FINALIZE (v_obj_value);
ECMA_FINALIZE (obj_value);
*
* See also:
* ES2015 9.1.2
+ *
+ * @return true - if success
+ * false - otherwise
*/
static bool
ecma_set_prototype_of (ecma_value_t o_value, /**< O */
/* 2. */
ecma_object_t *obj_p = ecma_get_object_from_value (arg);
- ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false);
+ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_NO_OPTS);
ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p);
/* 2. */
ecma_object_t *obj_p = ecma_get_object_from_value (arg);
- ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false);
+ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_NO_OPTS);
ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p);
} /* ecma_builtin_object_object_prevent_extensions */
/**
- * The Object object's 'isSealed' routine
+ * Common helper code for the 'isFrozen' and 'isSealed' fuctions of Object.
*
* See also:
- * ECMA-262 v5, 15.2.3.11
+ * Object.isFrozen
+ * Object.isSealed
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
-ecma_builtin_object_object_is_sealed (ecma_value_t this_arg, /**< 'this' argument */
- ecma_value_t arg) /**< routine's argument */
+ecma_builtin_object_frozen_or_sealed_helper (ecma_value_t this_arg, /**< 'this' argument */
+ ecma_value_t arg, /**< routine's argument */
+ bool frozen_mode) /**< routine mode */
{
JERRY_UNUSED (this_arg);
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
{
ecma_object_t *obj_p = ecma_get_object_from_value (arg);
- bool is_sealed;
-
/* 3. */
if (ecma_get_object_extensible (obj_p))
{
- is_sealed = false;
+ ret_value = ECMA_VALUE_FALSE;
}
else
{
/* the value can be updated in the loop below */
- is_sealed = true;
+ ret_value = ECMA_VALUE_TRUE;
/* 2. */
- ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false);
+ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_NO_OPTS);
ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p);
NULL,
ECMA_PROPERTY_GET_NO_OPTIONS);
- /* 2.b */
+ /* 2.b for isFrozen */
+ if (frozen_mode
+ && ECMA_PROPERTY_GET_TYPE (property) != ECMA_PROPERTY_TYPE_NAMEDACCESSOR
+ && ecma_is_property_writable (property))
+ {
+ ret_value = ECMA_VALUE_FALSE;
+ break;
+ }
+
+ /* 2.b for isSealed, 2.c for isFrozen */
if (ecma_is_property_configurable (property))
{
- is_sealed = false;
+ ret_value = ECMA_VALUE_FALSE;
break;
}
}
ecma_free_values_collection (props_p, 0);
}
-
- /* 4. */
- ret_value = is_sealed ? ECMA_VALUE_TRUE : ECMA_VALUE_FALSE;
}
return ret_value;
+} /* ecma_builtin_object_frozen_or_sealed_helper */
+
+/**
+ * The Object object's 'isSealed' routine
+ *
+ * See also:
+ * ECMA-262 v5, 15.2.3.11
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_object_object_is_sealed (ecma_value_t this_arg, /**< 'this' argument */
+ ecma_value_t arg) /**< routine's argument */
+{
+ return ecma_builtin_object_frozen_or_sealed_helper (this_arg, arg, false);
} /* ecma_builtin_object_object_is_sealed */
/**
ecma_builtin_object_object_is_frozen (ecma_value_t this_arg, /**< 'this' argument */
ecma_value_t arg) /**< routine's argument */
{
- JERRY_UNUSED (this_arg);
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
-
- /* 1. */
- if (!ecma_is_value_object (arg))
- {
- ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an object."));
- }
- else
- {
- ecma_object_t *obj_p = ecma_get_object_from_value (arg);
-
- bool is_frozen;
-
- /* 3. */
- if (ecma_get_object_extensible (obj_p))
- {
- is_frozen = false;
- }
- else
- {
- is_frozen = true;
-
- /* 2. */
- 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);
-
- while (ecma_value_p != NULL)
- {
- 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,
- property_name_p,
- NULL,
- ECMA_PROPERTY_GET_NO_OPTIONS);
-
- /* 2.b */
- if (ECMA_PROPERTY_GET_TYPE (property) != ECMA_PROPERTY_TYPE_NAMEDACCESSOR
- && ecma_is_property_writable (property))
- {
- is_frozen = false;
- break;
- }
-
- /* 2.c */
- if (ecma_is_property_configurable (property))
- {
- is_frozen = false;
- break;
- }
- }
-
- ecma_free_values_collection (props_p, 0);
- }
-
- /* 4 */
- ret_value = is_frozen ? ECMA_VALUE_TRUE : ECMA_VALUE_FALSE;
- }
-
- return ret_value;
+ return ecma_builtin_object_frozen_or_sealed_helper (this_arg, arg, true);
} /* ecma_builtin_object_object_is_frozen */
/**
ecma_value_t arg) /**< routine's argument */
{
JERRY_UNUSED (this_arg);
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
if (!ecma_is_value_object (arg))
{
- ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an object."));
- }
- else
- {
- ecma_object_t *obj_p = ecma_get_object_from_value (arg);
-
- bool extensible = ecma_get_object_extensible (obj_p);
-
- ret_value = extensible ? ECMA_VALUE_TRUE : ECMA_VALUE_FALSE;
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an object."));
}
- return ret_value;
+ ecma_object_t *obj_p = ecma_get_object_from_value (arg);
+ return ecma_make_boolean_value (ecma_get_object_extensible (obj_p));
} /* ecma_builtin_object_object_is_extensible */
/**
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);
+ ecma_collection_header_t *prop_names_p = ecma_op_object_get_property_names (props_p, ECMA_LIST_ENUMERABLE);
uint32_t property_number = prop_names_p->item_count;
ecma_value_t *ecma_value_p = ecma_collection_iterator_init (prop_names_p);
if (is_resolve)
{
- property_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE);
+ property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
}
else
{
- property_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT);
+ property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
}
ecma_value_t func = ecma_op_object_get (ecma_get_object_from_value (capability), property_str_p);
ecma_free_value (call_ret);
- ecma_string_t *promise_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE);
+ ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_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);
inline static ecma_value_t
ecma_builtin_promise_reject_abrupt (ecma_value_t capability) /**< reject description */
{
+ ecma_raise_type_error (ECMA_ERR_MSG ("Second argument is not an array."));
ecma_value_t reason = JERRY_CONTEXT (error_value);
- ecma_string_t *reject_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT);
+ ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_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),
&reason,
1);
ecma_free_value (reject);
+ ecma_free_value (reason);
if (ECMA_IS_VALUE_ERROR (call_ret))
{
ecma_free_value (call_ret);
- ecma_string_t *promise_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE);
+ ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_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_length_t len = (ecma_length_t) ecma_get_integer_from_value (len_value);
ecma_fast_free_value (len_value);
- 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 *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
+ ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
+ ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability),
resolve_str_p);
ecma_value_t array_item = ecma_op_object_get (array_p, index_to_str_p);
ecma_deref_ecma_string (index_to_str_p);
+ /* f. */
+ if (ECMA_IS_VALUE_ERROR (array_item))
+ {
+ ret = array_item;
+ break;
+ }
+
/* h. */
ecma_value_t next_promise = ecma_builtin_promise_resolve (ctor, array_item);
ecma_free_value (array_item);
ecma_value_t ret = ECMA_VALUE_UNDEFINED;
/* 1. */
ecma_object_t *function_p = ecma_get_object_from_value (function);
- ecma_string_t *already_called_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_ALREADY_CALLED);
+ ecma_string_t *already_called_str_p;
+ already_called_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_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));
/* 3. */
ecma_op_object_put (function_p,
already_called_str_p,
- ecma_make_boolean_value (true),
+ ECMA_VALUE_TRUE,
false);
- 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);
+ ecma_string_t *str_index_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_INDEX);
+ ecma_string_t *str_value_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_VALUE);
+ ecma_string_t *str_capability_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
+ ecma_string_t *str_remaining_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REMAINING_ELEMENT);
/* 4-7. */
ecma_value_t index_val = ecma_op_object_get (function_p, str_index_p);
/* 9-10. */
if (ecma_builtin_promise_remaining_inc_or_dec (remaining, false) == 0)
{
- ecma_string_t *resolve_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE);
+ ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_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_length_t len = (ecma_length_t) ecma_get_integer_from_value (len_value);
ecma_fast_free_value (len_value);
- 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_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
+ ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
+ ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
+ ecma_string_t *already_called_str_p;
+ already_called_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_ALREADY_CALLED);
+ ecma_string_t *index_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_INDEX);
+ ecma_string_t *value_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_VALUE);
+ ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
+ ecma_string_t *remaining_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REMAINING_ELEMENT);
ecma_value_t undefined_val = ECMA_VALUE_UNDEFINED;
/* String '1' indicates [[Resolve]] and '2' indicates [[Reject]]. */
/* e. h. */
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_to_str_p,
- undefined_val,
- false);
+ ecma_value_t put_ret = ecma_op_object_put (ecma_get_object_from_value (value_array),
+ index_to_str_p,
+ undefined_val,
+ false);
ecma_deref_ecma_string (index_to_str_p);
+
+ if (ECMA_IS_VALUE_ERROR (put_ret))
+ {
+ ecma_free_value (array_item);
+ ret = put_ret;
+ break;
+ }
+
/* i. */
ecma_value_t next_promise = ecma_builtin_promise_resolve (ctor, array_item);
ecma_free_value (array_item);
/* l. */
ecma_op_object_put (res_ele_p,
already_called_str_p,
- ecma_make_boolean_value (false),
+ ECMA_VALUE_FALSE,
false);
/* m. */
ecma_op_object_put (res_ele_p,
}
ecma_value_t capability = ecma_promise_new_capability ();
+
+ if (ECMA_IS_VALUE_ERROR (capability))
+ {
+ return capability;
+ }
+
ecma_value_t ret = ECMA_VALUE_EMPTY;
if (!ecma_is_value_object (array)
|| ecma_get_object_type (ecma_get_object_from_value (array)) != ECMA_OBJECT_TYPE_ARRAY)
{
- ecma_raise_type_error (ECMA_ERR_MSG ("Second argument is not an array."));
ret = ecma_builtin_promise_reject_abrupt (capability);
- ecma_free_value (JERRY_CONTEXT (error_value));
ecma_free_value (capability);
-
return ret;
}
ecma_string_t *pattern_string_p = NULL;
/* Get source string. */
- if (!ecma_is_value_undefined (pattern_arg))
- {
- ECMA_TRY_CATCH (regexp_str_value,
- ecma_op_to_string (pattern_arg),
- ret_value);
-
- if (ecma_string_is_empty (ecma_get_string_from_value (regexp_str_value)))
- {
- pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
- }
- else
- {
- pattern_string_p = ecma_get_string_from_value (regexp_str_value);
- ecma_ref_ecma_string (pattern_string_p);
- }
-
- ECMA_FINALIZE (regexp_str_value);
- }
- else
- {
- pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
- }
+ ret_value = ecma_regexp_read_pattern_str_helper (pattern_arg, &pattern_string_p);
/* Parse flags. */
if (ecma_is_value_empty (ret_value) && !ecma_is_value_undefined (flags_arg))
ecma_string_t *pattern_string_p = NULL;
ecma_string_t *flags_string_p = NULL;
- if (!ecma_is_value_undefined (pattern_value))
- {
- ECMA_TRY_CATCH (regexp_str_value,
- ecma_op_to_string (pattern_value),
- ret_value);
-
- if (ecma_string_is_empty (ecma_get_string_from_value (regexp_str_value)))
- {
- pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
- }
- else
- {
- pattern_string_p = ecma_get_string_from_value (regexp_str_value);
- ecma_ref_ecma_string (pattern_string_p);
- }
-
- ECMA_FINALIZE (regexp_str_value);
- }
- else
- {
- pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
- }
+ ret_value = ecma_regexp_read_pattern_str_helper (pattern_value, &pattern_string_p);
if (ecma_is_value_empty (ret_value) && !ecma_is_value_undefined (flags_value))
{
ECMA_FINALIZE (flags_str_value);
}
+ uint16_t flags = 0;
+ if (ecma_is_value_empty (ret_value) && (flags_string_p != NULL))
+ {
+ ret_value = re_parse_regexp_flags (flags_string_p, &flags);
+ }
+
if (ecma_is_value_empty (ret_value))
{
- ret_value = ecma_op_create_regexp_object (pattern_string_p, flags_string_p);
+ ret_value = ecma_op_create_regexp_object (pattern_string_p, flags);
}
if (pattern_string_p != NULL)
} /* ecma_builtin_string_prototype_object_value_of */
/**
- * The String.prototype object's 'charAt' routine
- *
- * See also:
- * ECMA-262 v5, 15.5.4.4
+ * Helper function for the String.prototype object's 'charAt' and charCodeAt' routine
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
-ecma_builtin_string_prototype_object_char_at (ecma_value_t this_arg, /**< this argument */
- ecma_value_t arg) /**< routine's argument */
+ecma_builtin_string_prototype_char_at_helper (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t arg, /**< routine's argument */
+ bool charcode_mode) /**< routine mode */
{
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
-
/* 1 */
- ECMA_TRY_CATCH (check_coercible_val,
- ecma_op_check_object_coercible (this_arg),
- ret_value);
+ ecma_value_t check_coercible_val = ecma_op_check_object_coercible (this_arg);
- /* 2 */
- ECMA_TRY_CATCH (to_string_val,
- ecma_op_to_string (this_arg),
- ret_value);
+ if (ECMA_IS_VALUE_ERROR (check_coercible_val))
+ {
+ return check_coercible_val;
+ }
+ ecma_free_value (check_coercible_val);
/* 3 */
- ECMA_OP_TO_NUMBER_TRY_CATCH (index_num,
- arg,
- ret_value);
+ ecma_number_t index_num;
+ ecma_value_t to_num_result = ecma_get_number (arg, &index_num);
+
+ if (JERRY_UNLIKELY (!ecma_is_value_empty (to_num_result)))
+ {
+ return to_num_result;
+ }
+ ecma_free_value (to_num_result);
+
+ /* 2 */
+ ecma_value_t to_string_val = ecma_op_to_string (this_arg);
+ if (ECMA_IS_VALUE_ERROR (to_string_val))
+ {
+ return to_string_val;
+ }
/* 4 */
ecma_string_t *original_string_p = ecma_get_string_from_value (to_string_val);
const ecma_length_t len = ecma_string_get_length (original_string_p);
/* 5 */
- if (index_num < 0 || index_num >= len || !len)
- {
- ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
- }
- else
+ // When index_num is NaN, then the first two comparisons are false
+ if (index_num < 0 || index_num >= len || (ecma_number_is_nan (index_num) && len == 0))
{
- /* 6 */
- ecma_char_t new_ecma_char = ecma_string_get_char_at_pos (original_string_p, ecma_number_to_uint32 (index_num));
- ret_value = ecma_make_string_value (ecma_new_ecma_string_from_code_unit (new_ecma_char));
+ ecma_free_value (to_string_val);
+ return (charcode_mode ? ecma_make_nan_value ()
+ : ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY));
}
- ECMA_OP_TO_NUMBER_FINALIZE (index_num);
+ /* 6 */
+ /*
+ * String length is currently uint32_t, but index_num may be bigger,
+ * ToInteger performs floor, while ToUInt32 performs modulo 2^32,
+ * hence after the check 0 <= index_num < len we assume to_uint32 can be used.
+ * We assume to_uint32 (NaN) is 0.
+ */
+ JERRY_ASSERT (ecma_number_is_nan (index_num) || ecma_number_to_uint32 (index_num) == ecma_number_trunc (index_num));
- ECMA_FINALIZE (to_string_val);
- ECMA_FINALIZE (check_coercible_val);
+ ecma_char_t new_ecma_char = ecma_string_get_char_at_pos (original_string_p, ecma_number_to_uint32 (index_num));
+ ecma_free_value (to_string_val);
- return ret_value;
+ return (charcode_mode ? ecma_make_uint32_value (new_ecma_char)
+ : ecma_make_string_value (ecma_new_ecma_string_from_code_unit (new_ecma_char)));
+} /* ecma_builtin_string_prototype_char_at_helper */
+
+/**
+ * The String.prototype object's 'charAt' routine
+ *
+ * See also:
+ * ECMA-262 v5, 15.5.4.4
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_string_prototype_object_char_at (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t arg) /**< routine's argument */
+{
+ return ecma_builtin_string_prototype_char_at_helper (this_arg, arg, false);
} /* ecma_builtin_string_prototype_object_char_at */
/**
ecma_builtin_string_prototype_object_char_code_at (ecma_value_t this_arg, /**< this argument */
ecma_value_t arg) /**< routine's argument */
{
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
-
- /* 1 */
- ECMA_TRY_CATCH (check_coercible_val,
- ecma_op_check_object_coercible (this_arg),
- ret_value);
-
- /* 2 */
- ECMA_TRY_CATCH (to_string_val,
- ecma_op_to_string (this_arg),
- ret_value);
-
- /* 3 */
- ECMA_OP_TO_NUMBER_TRY_CATCH (index_num,
- arg,
- ret_value);
-
- /* 4 */
- ecma_string_t *original_string_p = ecma_get_string_from_value (to_string_val);
- const ecma_length_t len = ecma_string_get_length (original_string_p);
-
- /* 5 */
- // When index_num is NaN, then the first two comparisons are false
- if (index_num < 0 || index_num >= len || (ecma_number_is_nan (index_num) && !len))
- {
- ret_value = ecma_make_nan_value ();
- }
- else
- {
- /* 6 */
- /*
- * String length is currently uit32_t, but index_num may be bigger,
- * ToInteger performs floor, while ToUInt32 performs modulo 2^32,
- * hence after the check 0 <= index_num < len we assume to_uint32 can be used.
- * We assume to_uint32 (NaN) is 0.
- */
- JERRY_ASSERT (ecma_number_is_nan (index_num) || ecma_number_to_uint32 (index_num) == ecma_number_trunc (index_num));
-
- ecma_char_t new_ecma_char = ecma_string_get_char_at_pos (original_string_p, ecma_number_to_uint32 (index_num));
- ret_value = ecma_make_uint32_value (new_ecma_char);
- }
-
- ECMA_OP_TO_NUMBER_FINALIZE (index_num);
-
- ECMA_FINALIZE (to_string_val);
- ECMA_FINALIZE (check_coercible_val);
-
- return ret_value;
+ return ecma_builtin_string_prototype_char_at_helper (this_arg, arg, true);
} /* ecma_builtin_string_prototype_object_char_code_at */
/**
#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
/**
- * The String.prototype object's 'match' routine
+ * The common preparation code for 'search' and 'match' functions
+ * of the String prototype.
*
- * See also:
- * ECMA-262 v5, 15.5.4.10
- *
- * @return ecma value
+ * @return empty value on success, error value otherwise
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
-ecma_builtin_string_prototype_object_match (ecma_value_t this_arg, /**< this argument */
- ecma_value_t arg) /**< routine's argument */
+ecma_builtin_string_prepare_search (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t *this_to_string_value_ptr, /**< [out] ptr to store as string */
+ ecma_value_t regexp_arg, /**< regex argument */
+ ecma_value_t *regexp_value) /**< [out] ptr to store the regexp object */
{
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
ecma_op_to_string (this_arg),
ret_value);
- ecma_value_t regexp_value = ECMA_VALUE_EMPTY;
+ *this_to_string_value_ptr = ecma_copy_value (this_to_string_value);
+
/* 3. */
- if (ecma_is_value_object (arg)
- && ecma_object_class_is (ecma_get_object_from_value (arg), LIT_MAGIC_STRING_REGEXP_UL))
+ if (ecma_is_value_object (regexp_arg)
+ && ecma_object_class_is (ecma_get_object_from_value (regexp_arg), LIT_MAGIC_STRING_REGEXP_UL))
{
- regexp_value = ecma_copy_value (arg);
+ *regexp_value = ecma_copy_value (regexp_arg);
}
else
{
/* 4. */
- ecma_value_t regexp_arguments[1] = { arg };
+ ecma_value_t regexp_arguments[1] = { regexp_arg };
ECMA_TRY_CATCH (new_regexp_value,
ecma_builtin_regexp_dispatch_construct (regexp_arguments, 1),
ret_value);
- regexp_value = ecma_copy_value (new_regexp_value);
+ *regexp_value = ecma_copy_value (new_regexp_value);
ECMA_FINALIZE (new_regexp_value);
}
+ ECMA_FINALIZE (this_to_string_value);
+ ECMA_FINALIZE (this_check_coercible_value);
+
+ return ret_value;
+} /* ecma_builtin_string_prepare_search */
+
+/**
+ * The String.prototype object's 'match' routine
+ *
+ * See also:
+ * ECMA-262 v5, 15.5.4.10
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_string_prototype_object_match (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t regexp_arg) /**< routine's argument */
+{
+ ecma_value_t this_to_string_value = ECMA_VALUE_EMPTY;
+ ecma_value_t regexp_value = ECMA_VALUE_EMPTY;
+
+ ecma_value_t ret_value = ecma_builtin_string_prepare_search (this_arg, &this_to_string_value,
+ regexp_arg, ®exp_value);
+
if (ecma_is_value_empty (ret_value))
{
JERRY_ASSERT (!ecma_is_value_empty (regexp_value));
ecma_value_t completion = ecma_builtin_helper_def_prop (new_array_obj_p,
current_index_str_p,
match_string_value,
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (completion));
ecma_free_value (regexp_value);
}
- ECMA_FINALIZE (this_to_string_value);
-
- ECMA_FINALIZE (this_check_coercible_value);
+ ecma_free_value (this_to_string_value);
return ret_value;
} /* ecma_builtin_string_prototype_object_match */
ecma_length_t match_end; /**< end position of the match */
/* Replace value callable part. */
- ecma_object_t *replace_function_p;
+ ecma_object_t *replace_function_p; /**< replace function */
/* Replace value string part. */
ecma_string_t *replace_string_p; /**< replace string */
ecma_builtin_string_prototype_object_search (ecma_value_t this_arg, /**< this argument */
ecma_value_t regexp_arg) /**< routine's argument */
{
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
-
- /* 1. */
- ECMA_TRY_CATCH (check_coercible_value,
- ecma_op_check_object_coercible (this_arg),
- ret_value);
-
- /* 2. */
- ECMA_TRY_CATCH (to_string_value,
- ecma_op_to_string (this_arg),
- ret_value);
-
+ ecma_value_t to_string_value = ECMA_VALUE_EMPTY;
ecma_value_t regexp_value = ECMA_VALUE_EMPTY;
- /* 3. */
- if (ecma_is_value_object (regexp_arg)
- && ecma_object_class_is (ecma_get_object_from_value (regexp_arg), LIT_MAGIC_STRING_REGEXP_UL))
- {
- regexp_value = ecma_copy_value (regexp_arg);
- }
- else
- {
- /* 4. */
- ecma_value_t regexp_arguments[1] = { regexp_arg };
-
- ECMA_TRY_CATCH (new_regexp_value,
- ecma_builtin_regexp_dispatch_construct (regexp_arguments, 1),
- ret_value);
-
- regexp_value = ecma_copy_value (new_regexp_value);
-
- ECMA_FINALIZE (new_regexp_value);
- }
+ ecma_value_t ret_value = ecma_builtin_string_prepare_search (this_arg, &to_string_value,
+ regexp_arg, ®exp_value);
/* 5. */
if (ecma_is_value_empty (ret_value))
ecma_free_value (regexp_value);
}
- ECMA_FINALIZE (to_string_value);
- ECMA_FINALIZE (check_coercible_value);
+ ecma_free_value (to_string_value);
/* 6. */
return ret_value;
ecma_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p,
zero_str_p,
this_to_string_val,
- true,
- true,
- true,
- false);
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (put_comp));
ecma_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p,
zero_str_p,
this_to_string_val,
- true,
- true,
- true,
- false);
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (put_comp));
ecma_deref_ecma_string (zero_str_p);
ecma_value_t put_comp = ecma_builtin_helper_def_prop (match_obj_p,
zero_str_p,
ecma_make_string_value (separator_str_p),
- true,
- true,
- true,
- true);
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ true); /* Failure handling */
+
JERRY_ASSERT (ecma_is_value_true (put_comp));
index_prop_value_p = ecma_create_named_data_property (match_obj_p,
ecma_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p,
array_length_str_p,
ecma_make_string_value (substr_str_p),
- true,
- true,
- true,
- false);
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (put_comp));
put_comp = ecma_builtin_helper_def_prop (new_array_p,
new_array_idx_str_p,
match_comp_value,
- true,
- true,
- true,
- false);
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (put_comp));
ecma_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p,
array_length_string_p,
ecma_make_string_value (substr_str_p),
- true,
- true,
- true,
- false);
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ false); /* Failure handling */
JERRY_ASSERT (ecma_is_value_true (put_comp));
*/
typedef const ecma_builtin_property_descriptor_t *ecma_builtin_property_list_reference_t;
+/**
+ * Definition of built-in dispatch routine function pointer.
+ */
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);
+/**
+ * Definition of built-in dispatch call function pointer.
+ */
typedef ecma_value_t (*ecma_builtin_dispatch_call_t)(const ecma_value_t arguments_list[],
ecma_length_t arguments_number);
-
+/**
+ * List of the built-in routines.
+ */
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
+/** @cond doxygen_suppress */
+#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
+/** @endcond */
};
+/**
+ * List of the built-in call functions.
+ */
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
+/** @cond doxygen_suppress */
+#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
+/** @endcond */
};
+/**
+ * List of the built-in construct functions.
+ */
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
+/** @cond doxygen_suppress */
+#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
+/** @endcond */
};
/**
*/
static const ecma_builtin_property_list_reference_t ecma_builtin_property_list_references[] =
{
+/** @cond doxygen_suppress */
#define BUILTIN(a, b, c, d, e)
#define BUILTIN_ROUTINE(builtin_id, \
object_type, \
#include "ecma-builtins.inc.h"
#undef BUILTIN_ROUTINE
#undef BUILTIN
+/** @endcond */
};
/**
* @return the number of properties
*/
static size_t
-ecma_builtin_get_property_count (ecma_builtin_id_t builtin_id)
+ecma_builtin_get_property_count (ecma_builtin_id_t builtin_id) /**< built-in ID */
{
+ JERRY_ASSERT (builtin_id < ECMA_BUILTIN_ID__COUNT);
const ecma_builtin_property_descriptor_t *property_list_p = ecma_builtin_property_list_references[builtin_id];
const ecma_builtin_property_descriptor_t *curr_property_p = property_list_p;
/**
* Check if passed object is the instance of specified built-in.
+ *
+ * @return true - if the object is instance of the specified built-in
+ * false - otherwise
*/
bool
ecma_builtin_is (ecma_object_t *obj_p, /**< pointer to an object */
JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p));
JERRY_ASSERT (builtin_id < ECMA_BUILTIN_ID__COUNT);
- if (JERRY_CONTEXT (ecma_builtin_objects)[builtin_id] == NULL)
- {
- /* If a built-in object is not instantiated,
- * the specified object cannot be the built-in object */
- return false;
- }
- else
- {
- return (obj_p == JERRY_CONTEXT (ecma_builtin_objects)[builtin_id]);
- }
+ /* If a built-in object is not instantiated, its value is NULL,
+ hence it cannot be equal to a valid object. */
+ return (obj_p == JERRY_CONTEXT (ecma_builtin_objects)[builtin_id]);
} /* ecma_builtin_is */
/**
* Get reference to specified built-in object
*
+ * Note:
+ * Does not increase the reference counter.
+ *
* @return pointer to the object's instance
*/
ecma_object_t *
{
JERRY_ASSERT (builtin_id < ECMA_BUILTIN_ID__COUNT);
- if (unlikely (JERRY_CONTEXT (ecma_builtin_objects)[builtin_id] == NULL))
+ if (JERRY_UNLIKELY (JERRY_CONTEXT (ecma_builtin_objects)[builtin_id] == NULL))
{
ecma_instantiate_builtin (builtin_id);
}
- ecma_ref_object (JERRY_CONTEXT (ecma_builtin_objects)[builtin_id]);
-
return JERRY_CONTEXT (ecma_builtin_objects)[builtin_id];
} /* ecma_builtin_get */
+/**
+ * Get reference to the global object
+ *
+ * Note:
+ * Does not increase the reference counter.
+ *
+ * @return pointer to the global object
+ */
+inline ecma_object_t * JERRY_ATTR_ALWAYS_INLINE
+ecma_builtin_get_global (void)
+{
+ JERRY_ASSERT (JERRY_CONTEXT (ecma_builtin_objects)[ECMA_BUILTIN_ID_GLOBAL] != NULL);
+
+ return JERRY_CONTEXT (ecma_builtin_objects)[ECMA_BUILTIN_ID_GLOBAL];
+} /* ecma_builtin_get_global */
+
/**
* Checks whether the given function is a built-in routine
*
* @return true - if the function object is a built-in routine
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_builtin_function_is_routine (ecma_object_t *func_obj_p) /**< function object */
{
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION);
ecma_object_t *obj_p = ecma_create_object (prototype_obj_p, ext_object_size, obj_type);
- if (unlikely (!is_extensible))
+ if (JERRY_UNLIKELY (!is_extensible))
{
ecma_set_object_extensible (obj_p, false);
}
built_in_props_p = &((ecma_extended_object_t *) obj_p)->u.built_in;
}
- built_in_props_p->id = obj_builtin_id;
- built_in_props_p->routine_id = obj_builtin_id;
+ built_in_props_p->id = (uint8_t) obj_builtin_id;
+ built_in_props_p->routine_id = (uint16_t) obj_builtin_id;
built_in_props_p->instantiated_bitset[0] = 0;
if (property_count > 32)
static void
ecma_instantiate_builtin (ecma_builtin_id_t id) /**< built-in id */
{
+ JERRY_ASSERT (id < ECMA_BUILTIN_ID__COUNT);
switch (id)
{
+/** @cond doxygen_suppress */
#define BUILTIN(builtin_id, \
object_type, \
object_prototype_builtin_id, \
#include "ecma-builtins.inc.h"
#undef BUILTIN
#undef BUILTIN_ROUTINE
+/** @endcond */
default:
{
- JERRY_ASSERT (id < ECMA_BUILTIN_ID__COUNT);
-
JERRY_UNREACHABLE (); /* The built-in is not implemented. */
}
}
ext_object_size,
ECMA_OBJECT_TYPE_FUNCTION);
- ecma_deref_object (prototype_obj_p);
-
ecma_set_object_is_builtin (func_obj_p);
JERRY_ASSERT (routine_id >= ECMA_BUILTIN_ID__COUNT);
ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p;
- ext_func_obj_p->u.built_in.id = builtin_id;
+ ext_func_obj_p->u.built_in.id = (uint8_t) builtin_id;
ext_func_obj_p->u.built_in.routine_id = routine_id;
ext_func_obj_p->u.built_in.instantiated_bitset[0] = 0;
{
switch (curr_property_p->value)
{
- case ECMA_BUILTIN_NUMBER_NAN:
- {
- num = ecma_number_make_nan ();
- break;
- }
case ECMA_BUILTIN_NUMBER_POSITIVE_INFINITY:
{
num = ecma_number_make_infinity (false);
}
default:
{
- JERRY_UNREACHABLE ();
+ JERRY_ASSERT (curr_property_p->value == ECMA_BUILTIN_NUMBER_NAN);
+
+ num = ecma_number_make_nan ();
break;
}
}
}
case ECMA_BUILTIN_PROPERTY_STRING:
{
- value = ecma_make_magic_string_value (curr_property_p->value);
+ value = ecma_make_magic_string_value ((lit_magic_string_id_t) curr_property_p->value);
break;
}
case ECMA_BUILTIN_PROPERTY_OBJECT:
{
- value = ecma_make_object_value (ecma_builtin_get (curr_property_p->value));
+ ecma_object_t *builtin_object_p = ecma_builtin_get ((ecma_builtin_id_t) curr_property_p->value);
+ ecma_ref_object (builtin_object_p);
+ value = ecma_make_object_value (builtin_object_p);
break;
}
case ECMA_BUILTIN_PROPERTY_ROUTINE:
setter_p = ecma_builtin_make_function_object_for_setter_accessor (builtin_id, setter_id);
break;
}
- case ECMA_BUILTIN_PROPERTY_ACCESSOR_READ_ONLY:
+ default:
{
+ JERRY_ASSERT (curr_property_p->type == ECMA_BUILTIN_PROPERTY_ACCESSOR_READ_ONLY);
+
is_accessor = true;
getter_p = ecma_builtin_make_function_object_for_getter_accessor (builtin_id,
curr_property_p->value);
break;
}
- default:
- {
- JERRY_UNREACHABLE ();
- return NULL;
- }
}
ecma_property_t *prop_p;
index = 0;
}
- ecma_string_t *name_p = ecma_get_magic_string (curr_property_p->magic_string_id);
+ ecma_string_t *name_p = ecma_get_magic_string ((lit_magic_string_id_t) curr_property_p->magic_string_id);
uint32_t bit_for_index = (uint32_t) 1u << index;
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_magic_string_value (curr_property_p->magic_string_id),
- 0);
+ ecma_value_t name = ecma_make_magic_string_value ((lit_magic_string_id_t) curr_property_p->magic_string_id);
+
+ ecma_append_to_values_collection (for_non_enumerable_p, name, 0);
}
ecma_deref_ecma_string (name_p);
*/
typedef enum
{
+/** @cond doxygen_suppress */
#define BUILTIN(a, b, c, d, e)
#define BUILTIN_ROUTINE(builtin_id, \
object_type, \
#include "ecma-builtins.inc.h"
#undef BUILTIN
#undef BUILTIN_ROUTINE
+/** @endcond */
ECMA_BUILTIN_ID__COUNT /**< number of built-in objects */
} ecma_builtin_id_t;
ecma_builtin_is (ecma_object_t *obj_p, ecma_builtin_id_t builtin_id);
ecma_object_t *
ecma_builtin_get (ecma_builtin_id_t builtin_id);
+ecma_object_t *
+ecma_builtin_get_global (void);
bool
ecma_builtin_function_is_routine (ecma_object_t *func_obj_p);
#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+
+/* The Map prototype object (23.1.3) */
+BUILTIN (ECMA_BUILTIN_ID_MAP_PROTOTYPE,
+ ECMA_OBJECT_TYPE_GENERAL,
+ ECMA_BUILTIN_ID_OBJECT_PROTOTYPE,
+ true,
+ map_prototype)
+
+/* The Map routine (ECMA-262 v6, 23.1.1.1) */
+BUILTIN_ROUTINE (ECMA_BUILTIN_ID_MAP,
+ ECMA_OBJECT_TYPE_FUNCTION,
+ ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE,
+ true,
+ map)
+
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
+
/* The Global object (15.1) */
BUILTIN (ECMA_BUILTIN_ID_GLOBAL,
ECMA_OBJECT_TYPE_GENERAL,
* Float32Array prototype description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.3.4 */
-OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
- ECMA_BUILTIN_ID_FLOAT32ARRAY,
- ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
-
-/* ES2015 22.2.6.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 4,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 4
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_FLOAT32ARRAY
+#include "ecma-builtin-typedarray-prototype-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
#define BUILTIN_UNDERSCORED_ID float32array
#include "ecma-builtin-internal-routines-template.inc.h"
+#include "ecma-builtin-typedarray-helpers.h"
+
/** \addtogroup ecma ECMA
* @{
*
ecma_builtin_float32array_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< number of arguments */
{
- JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
-
- ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FLOAT32ARRAY_PROTOTYPE);
- ecma_value_t val = ecma_op_create_typedarray (arguments_list_p,
- arguments_list_len,
- prototype_obj_p,
- 2,
- LIT_MAGIC_STRING_FLOAT32_ARRAY_UL);
-
- ecma_deref_object (prototype_obj_p);
-
- return val;
+ return ecma_typedarray_helper_dispatch_construct (arguments_list_p, arguments_list_len,
+ ECMA_BUILTIN_ID_FLOAT32ARRAY);
} /* ecma_builtin_float32array_dispatch_construct */
/**
* Float32Array description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 4,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-STRING_VALUE (LIT_MAGIC_STRING_NAME,
- LIT_MAGIC_STRING_FLOAT32_ARRAY_UL,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.2 */
-OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
- ECMA_BUILTIN_ID_FLOAT32ARRAY_PROTOTYPE,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 4
+#define TYPEDARRAY_MAGIC_STRING_ID LIT_MAGIC_STRING_FLOAT32_ARRAY_UL
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_FLOAT32ARRAY_PROTOTYPE
+#include "ecma-builtin-typedarray-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
* @}
* @}
*/
+
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
* Float64Array prototype description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
-/* ES2015 22.2.3.4 */
-OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
- ECMA_BUILTIN_ID_FLOAT64ARRAY,
- ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
-
-/* ES2015 22.2.6.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 8,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 8
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_FLOAT64ARRAY
+#include "ecma-builtin-typedarray-prototype-template.inc.h"
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
#define BUILTIN_UNDERSCORED_ID float64array
#include "ecma-builtin-internal-routines-template.inc.h"
+#include "ecma-builtin-typedarray-helpers.h"
+
/** \addtogroup ecma ECMA
* @{
*
ecma_builtin_float64array_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< number of arguments */
{
- JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
-
- ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FLOAT64ARRAY_PROTOTYPE);
- ecma_value_t val = ecma_op_create_typedarray (arguments_list_p,
- arguments_list_len,
- prototype_obj_p,
- 3,
- LIT_MAGIC_STRING_FLOAT64_ARRAY_UL);
-
- ecma_deref_object (prototype_obj_p);
-
- return val;
+ return ecma_typedarray_helper_dispatch_construct (arguments_list_p, arguments_list_len,
+ ECMA_BUILTIN_ID_FLOAT64ARRAY);
} /* ecma_builtin_float64array_dispatch_construct */
/**
* Float64Array description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 8,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-STRING_VALUE (LIT_MAGIC_STRING_NAME,
- LIT_MAGIC_STRING_FLOAT64_ARRAY_UL,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.2 */
-OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
- ECMA_BUILTIN_ID_FLOAT64ARRAY_PROTOTYPE,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 8
+#define TYPEDARRAY_MAGIC_STRING_ID LIT_MAGIC_STRING_FLOAT64_ARRAY_UL
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_FLOAT64ARRAY_PROTOTYPE
+#include "ecma-builtin-typedarray-template.inc.h"
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
* Int16Array prototype description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.3.4 */
-OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
- ECMA_BUILTIN_ID_INT16ARRAY,
- ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
-
-/* ES2015 22.2.6.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 2,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 2
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_INT16ARRAY
+#include "ecma-builtin-typedarray-prototype-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
#define BUILTIN_UNDERSCORED_ID int16array
#include "ecma-builtin-internal-routines-template.inc.h"
+#include "ecma-builtin-typedarray-helpers.h"
+
/** \addtogroup ecma ECMA
* @{
*
ecma_builtin_int16array_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< number of arguments */
{
- JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
-
- ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_INT16ARRAY_PROTOTYPE);
- ecma_value_t val = ecma_op_create_typedarray (arguments_list_p,
- arguments_list_len,
- prototype_obj_p,
- 1,
- LIT_MAGIC_STRING_INT16_ARRAY_UL);
-
- ecma_deref_object (prototype_obj_p);
-
- return val;
+ return ecma_typedarray_helper_dispatch_construct (arguments_list_p, arguments_list_len,
+ ECMA_BUILTIN_ID_INT16ARRAY);
} /* ecma_builtin_int16array_dispatch_construct */
/**
* Int16Array description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 2,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-STRING_VALUE (LIT_MAGIC_STRING_NAME,
- LIT_MAGIC_STRING_INT16_ARRAY_UL,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.2 */
-OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
- ECMA_BUILTIN_ID_INT16ARRAY_PROTOTYPE,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 2
+#define TYPEDARRAY_MAGIC_STRING_ID LIT_MAGIC_STRING_INT16_ARRAY_UL
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_INT16ARRAY_PROTOTYPE
+#include "ecma-builtin-typedarray-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
* Int32Array prototype description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.3.4 */
-OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
- ECMA_BUILTIN_ID_INT32ARRAY,
- ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
-
-/* ES2015 22.2.6.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 4,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 4
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_INT32ARRAY
+#include "ecma-builtin-typedarray-prototype-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
#define BUILTIN_UNDERSCORED_ID int32array
#include "ecma-builtin-internal-routines-template.inc.h"
+#include "ecma-builtin-typedarray-helpers.h"
+
/** \addtogroup ecma ECMA
* @{
*
ecma_builtin_int32array_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< number of arguments */
{
- JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
-
- ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_INT32ARRAY_PROTOTYPE);
- ecma_value_t val = ecma_op_create_typedarray (arguments_list_p,
- arguments_list_len,
- prototype_obj_p,
- 2,
- LIT_MAGIC_STRING_INT32_ARRAY_UL);
-
- ecma_deref_object (prototype_obj_p);
-
- return val;
+ return ecma_typedarray_helper_dispatch_construct (arguments_list_p, arguments_list_len,
+ ECMA_BUILTIN_ID_INT32ARRAY);
} /* ecma_builtin_int32array_dispatch_construct */
/**
* Int32Array description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 4,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-STRING_VALUE (LIT_MAGIC_STRING_NAME,
- LIT_MAGIC_STRING_INT32_ARRAY_UL,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.2 */
-OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
- ECMA_BUILTIN_ID_INT32ARRAY_PROTOTYPE,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 4
+#define TYPEDARRAY_MAGIC_STRING_ID LIT_MAGIC_STRING_INT32_ARRAY_UL
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_INT32ARRAY_PROTOTYPE
+#include "ecma-builtin-typedarray-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
* Int8Array prototype description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.3.4 */
-OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
- ECMA_BUILTIN_ID_INT8ARRAY,
- ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
-
-/* ES2015 22.2.6.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 1,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 1
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_INT8ARRAY
+#include "ecma-builtin-typedarray-prototype-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
#define BUILTIN_UNDERSCORED_ID int8array
#include "ecma-builtin-internal-routines-template.inc.h"
+#include "ecma-builtin-typedarray-helpers.h"
+
/** \addtogroup ecma ECMA
* @{
*
ecma_builtin_int8array_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< number of arguments */
{
- JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
-
- ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_INT8ARRAY_PROTOTYPE);
- ecma_value_t val = ecma_op_create_typedarray (arguments_list_p,
- arguments_list_len,
- prototype_obj_p,
- 0,
- LIT_MAGIC_STRING_INT8_ARRAY_UL);
-
- ecma_deref_object (prototype_obj_p);
-
- return val;
+ return ecma_typedarray_helper_dispatch_construct (arguments_list_p, arguments_list_len,
+ ECMA_BUILTIN_ID_INT8ARRAY);
} /* ecma_builtin_int8array_dispatch_construct */
/**
* Int8Array description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 1,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-STRING_VALUE (LIT_MAGIC_STRING_NAME,
- LIT_MAGIC_STRING_INT8_ARRAY_UL,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.2 */
-OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
- ECMA_BUILTIN_ID_INT8ARRAY_PROTOTYPE,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 1
+#define TYPEDARRAY_MAGIC_STRING_ID LIT_MAGIC_STRING_INT8_ARRAY_UL
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_INT8ARRAY_PROTOTYPE
+#include "ecma-builtin-typedarray-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
--- /dev/null
+/* 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-builtin-typedarray-helpers.h"
+
+#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
+
+#include "ecma-builtins.h"
+#include "ecma-gc.h"
+#include "ecma-objects.h"
+#include "ecma-typedarray-object.h"
+
+#define ECMA_BUILTINS_INTERNAL
+#include "ecma-builtins-internal.h"
+
+/**
+ * Returns true if the builtin is a TypedArray type.
+ *
+ * @return bool
+ */
+bool
+ecma_typedarray_helper_is_typedarray (uint8_t builtin_id) /**< the builtin id of a type **/
+{
+ switch (builtin_id)
+ {
+ case ECMA_BUILTIN_ID_INT8ARRAY:
+ case ECMA_BUILTIN_ID_UINT8ARRAY:
+ case ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY:
+ case ECMA_BUILTIN_ID_INT16ARRAY:
+ case ECMA_BUILTIN_ID_UINT16ARRAY:
+ case ECMA_BUILTIN_ID_INT32ARRAY:
+ case ECMA_BUILTIN_ID_UINT32ARRAY:
+ case ECMA_BUILTIN_ID_FLOAT32ARRAY:
+#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
+ case ECMA_BUILTIN_ID_FLOAT64ARRAY:
+#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+} /* ecma_typedarray_helper_is_typedarray */
+
+/**
+ * Get the element shift size of a TypedArray type.
+ *
+ * @return uint8_t
+ */
+uint8_t
+ecma_typedarray_helper_get_shift_size (uint8_t builtin_id) /**< the builtin id of the typedarray **/
+{
+ switch (builtin_id)
+ {
+ case ECMA_BUILTIN_ID_INT8ARRAY:
+ case ECMA_BUILTIN_ID_UINT8ARRAY:
+ case ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY:
+ {
+ return 0;
+ }
+ case ECMA_BUILTIN_ID_INT16ARRAY:
+ case ECMA_BUILTIN_ID_UINT16ARRAY:
+ {
+ return 1;
+ }
+ case ECMA_BUILTIN_ID_INT32ARRAY:
+ case ECMA_BUILTIN_ID_UINT32ARRAY:
+ case ECMA_BUILTIN_ID_FLOAT32ARRAY:
+ {
+ return 2;
+ }
+#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
+ case ECMA_BUILTIN_ID_FLOAT64ARRAY:
+ {
+ return 3;
+ }
+#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
+ default:
+ {
+ JERRY_UNREACHABLE ();
+ }
+ }
+} /* ecma_typedarray_helper_get_shift_size */
+
+/**
+ * Get the built-in TypedArray type from a magic string.
+ *
+ * @return uint8_t
+ */
+uint8_t
+ecma_typedarray_helper_get_builtin_id (ecma_object_t *obj_p) /**< typedarray object **/
+{
+#define TYPEDARRAY_ID_CASE(magic_id, builtin_id) \
+ case magic_id: \
+ { \
+ return builtin_id; \
+ }
+
+ switch (ecma_object_get_class_name (obj_p))
+ {
+ TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_INT8_ARRAY_UL, ECMA_BUILTIN_ID_INT8ARRAY)
+ TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_UINT8_ARRAY_UL, ECMA_BUILTIN_ID_UINT8ARRAY)
+ TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL, ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY)
+ TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_INT16_ARRAY_UL, ECMA_BUILTIN_ID_INT16ARRAY)
+ TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_UINT16_ARRAY_UL, ECMA_BUILTIN_ID_UINT16ARRAY)
+ TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_INT32_ARRAY_UL, ECMA_BUILTIN_ID_INT32ARRAY)
+ TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_UINT32_ARRAY_UL, ECMA_BUILTIN_ID_UINT32ARRAY)
+ TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_FLOAT32_ARRAY_UL, ECMA_BUILTIN_ID_FLOAT32ARRAY)
+#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
+ TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_FLOAT64_ARRAY_UL, ECMA_BUILTIN_ID_FLOAT64ARRAY)
+#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
+ default:
+ {
+ JERRY_UNREACHABLE ();
+ }
+ }
+#undef TYPEDARRAY_ID_CASE
+} /* ecma_typedarray_helper_get_builtin_id */
+
+/**
+ * Get the magic string of a TypedArray type.
+ *
+ * @return uint8_t
+ */
+uint8_t
+ecma_typedarray_helper_get_magic_string (uint8_t builtin_id) /**< the builtin id of the typedarray **/
+{
+#define TYPEDARRAY_ID_CASE(builtin_id, magic_id) \
+ case builtin_id: \
+ { \
+ return magic_id; \
+ }
+
+ switch (builtin_id)
+ {
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_INT8ARRAY, LIT_MAGIC_STRING_INT8_ARRAY_UL)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_UINT8ARRAY, LIT_MAGIC_STRING_UINT8_ARRAY_UL)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY, LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_INT16ARRAY, LIT_MAGIC_STRING_INT16_ARRAY_UL)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_UINT16ARRAY, LIT_MAGIC_STRING_UINT16_ARRAY_UL)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_INT32ARRAY, LIT_MAGIC_STRING_INT32_ARRAY_UL)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_UINT32ARRAY, LIT_MAGIC_STRING_UINT32_ARRAY_UL)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_FLOAT32ARRAY, LIT_MAGIC_STRING_FLOAT32_ARRAY_UL)
+#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_FLOAT64ARRAY, LIT_MAGIC_STRING_FLOAT64_ARRAY_UL)
+#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
+ default:
+ {
+ JERRY_UNREACHABLE ();
+ }
+ }
+#undef TYPEDARRAY_ID_CASE
+} /* ecma_typedarray_helper_get_magic_string */
+
+/**
+ * Get the prototype ID of a TypedArray type.
+ *
+ * @return uint8_t
+ */
+uint8_t
+ecma_typedarray_helper_get_prototype_id (uint8_t builtin_id) /**< the builtin id of the typedarray **/
+{
+#define TYPEDARRAY_ID_CASE(builtin_id) \
+ case builtin_id: \
+ { \
+ return builtin_id ## _PROTOTYPE; \
+ }
+
+ switch (builtin_id)
+ {
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_INT8ARRAY)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_UINT8ARRAY)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_INT16ARRAY)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_UINT16ARRAY)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_INT32ARRAY)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_UINT32ARRAY)
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_FLOAT32ARRAY)
+#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
+ TYPEDARRAY_ID_CASE (ECMA_BUILTIN_ID_FLOAT64ARRAY)
+#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
+ default:
+ {
+ JERRY_UNREACHABLE ();
+ }
+ }
+#undef TYPEDARRAY_ID_CASE
+} /* ecma_typedarray_helper_get_prototype_id */
+
+/**
+ * Common implementation of the [[Construct]] call of TypedArrays.
+ *
+ * @return ecma value of the new TypedArray object
+ * Returned value must be freed with ecma_free_value
+ */
+ecma_value_t
+ecma_typedarray_helper_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
+ ecma_length_t arguments_list_len, /**< number of arguments */
+ uint8_t builtin_id) /**< the builtin id of the typedarray */
+{
+ JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
+ JERRY_ASSERT (ecma_typedarray_helper_is_typedarray (builtin_id));
+
+ ecma_object_t *prototype_obj_p = ecma_builtin_get (ecma_typedarray_helper_get_prototype_id (builtin_id));
+ ecma_value_t val = ecma_op_create_typedarray (arguments_list_p,
+ arguments_list_len,
+ prototype_obj_p,
+ ecma_typedarray_helper_get_shift_size (builtin_id),
+ ecma_typedarray_helper_get_magic_string (builtin_id));
+
+ return val;
+} /* ecma_typedarray_helper_dispatch_construct */
+
+#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ECMA_TYPEDARRAY_HELPERS_H
+#define ECMA_TYPEDARRAY_HELPERS_H
+#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
+
+#include "ecma-globals.h"
+
+/** \addtogroup ecma ECMA
+ * @{
+ *
+ * \addtogroup ecmabuiltinhelpers ECMA builtin helper operations
+ * @{
+ */
+
+bool ecma_typedarray_helper_is_typedarray (uint8_t builtin_id);
+uint8_t ecma_typedarray_helper_get_shift_size (uint8_t builtin_id);
+uint8_t ecma_typedarray_helper_get_builtin_id (ecma_object_t *obj_p);
+uint8_t ecma_typedarray_helper_get_magic_string (uint8_t builtin_id);
+uint8_t ecma_typedarray_helper_get_prototype_id (uint8_t builtin_id);
+
+ecma_value_t
+ecma_typedarray_helper_dispatch_construct (const ecma_value_t *arguments_list_p,
+ ecma_length_t arguments_list_len,
+ uint8_t builtin_id);
+
+/**
+ * @}
+ * @}
+ */
+
+#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
+#endif /* !ECMA_TYPEDARRAY_HELPERS_H */
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
+
+#ifndef TYPEDARRAY_BYTES_PER_ELEMENT
+# error "Please define TYPEDARRAY_BYTES_PER_ELEMENT"
+#endif /* !TYPEDARRAY_BYTES_PER_ELEMENT */
+
+#ifndef TYPEDARRAY_BUILTIN_ID
+# error "Please define TYPEDARRAY_BUILTIN_ID"
+#endif /* !TYPEDARRAY_BUILTIN_ID */
+
+#include "ecma-builtin-helpers-macro-defines.inc.h"
+
+/* ES2015 22.2.3.4 */
+OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
+ TYPEDARRAY_BUILTIN_ID,
+ ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
+
+/* ES2015 22.2.6.1 */
+NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
+ TYPEDARRAY_BYTES_PER_ELEMENT,
+ ECMA_PROPERTY_FIXED)
+
+#include "ecma-builtin-helpers-macro-undefs.inc.h"
+
+#undef TYPEDARRAY_BUILTIN_ID
+#undef TYPEDARRAY_BYTES_PER_ELEMENT
+
+#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
*/
#include "ecma-builtin-helpers.h"
+#include "ecma-builtin-typedarray-helpers.h"
#include "ecma-builtins.h"
#include "ecma-exceptions.h"
#include "ecma-globals.h"
ret_value = ECMA_VALUE_FALSE;
}
}
- else if (mode == TYPEDARRAY_ROUTINE_SOME)
+ else if (mode == TYPEDARRAY_ROUTINE_SOME
+ && ecma_op_to_boolean (call_value))
{
- if (ecma_op_to_boolean (call_value))
- {
- ret_value = ECMA_VALUE_TRUE;
- }
+ ret_value = ECMA_VALUE_TRUE;
}
ECMA_FINALIZE (call_value);
ecma_object_t *func_object_p = ecma_get_object_from_value (cb_func_val);
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+ if (len == 0)
+ {
+ return ecma_op_create_typedarray_with_type_and_length (obj_p, 0);
+ }
+
JMEM_DEFINE_LOCAL_ARRAY (pass_value_list_p, len * element_size, lit_utf8_byte_t);
lit_utf8_byte_t *pass_value_p = pass_value_list_p;
ret_value = ecma_op_create_typedarray_with_type_and_length (obj_p, pass_num);
-
if (!ECMA_IS_VALUE_ERROR (ret_value))
{
obj_p = ecma_get_object_from_value (ret_value);
return ecma_copy_value (this_arg);
} /* ecma_builtin_typedarray_prototype_reverse */
+/**
+ * The %TypedArray%.prototype object's 'set' routine for a typedArray source
+ *
+ * See also:
+ * ES2015, 22.2.3.22, 22.2.3.22.2
+ *
+ * @return ecma value of undefined if success, error otherwise.
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_op_typedarray_set_with_typedarray (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t arr_val, /**< typedarray object */
+ ecma_value_t offset_val) /**< offset value */
+{
+ /* 6.~ 8. targetOffset */
+ ecma_number_t target_offset_num;
+ if (!ecma_is_value_empty (ecma_get_number (offset_val, &target_offset_num)))
+ {
+ return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid offset"));
+ }
+
+ if (ecma_number_is_nan (target_offset_num))
+ {
+ target_offset_num = 0;
+ }
+
+ if (target_offset_num <= -1.0 || target_offset_num >= (ecma_number_t) UINT32_MAX + 0.5)
+ {
+ return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid offset"));
+ }
+
+ ecma_object_t *target_typedarray_p = ecma_get_object_from_value (this_arg);
+ ecma_object_t *src_typedarray_p = ecma_get_object_from_value (arr_val);
+
+ /* 9. targetBuffer */
+ ecma_object_t *target_arraybuffer_p = ecma_typedarray_get_arraybuffer (target_typedarray_p);
+ lit_utf8_byte_t *target_buffer_p = ecma_typedarray_get_buffer (target_typedarray_p);
+
+ /* 11. targetLength */
+ ecma_length_t target_length = ecma_typedarray_get_length (target_typedarray_p);
+
+ /* 12. srcBuffer */
+ ecma_object_t *src_arraybuffer_p = ecma_typedarray_get_arraybuffer (src_typedarray_p);
+ lit_utf8_byte_t *src_buffer_p = ecma_typedarray_get_buffer (src_typedarray_p);
+
+ /* 15. targetType */
+ lit_magic_string_id_t target_class_id = ecma_object_get_class_name (target_typedarray_p);
+
+ /* 16. targetElementSize */
+ uint8_t target_shift = ecma_typedarray_get_element_size_shift (target_typedarray_p);
+ uint8_t target_element_size = (uint8_t) (1 << target_shift);
+
+ /* 17. targetByteOffset */
+ ecma_length_t target_byte_offset = ecma_typedarray_get_offset (target_typedarray_p);
+
+ /* 19. srcType */
+ lit_magic_string_id_t src_class_id = ecma_object_get_class_name (src_typedarray_p);
+
+ /* 20. srcElementSize */
+ uint8_t src_shift = ecma_typedarray_get_element_size_shift (src_typedarray_p);
+ uint8_t src_element_size = (uint8_t) (1 << src_shift);
+
+ /* 21. srcLength */
+ ecma_length_t src_length = ecma_typedarray_get_length (src_typedarray_p);
+ uint32_t src_length_uint32 = ecma_number_to_uint32 (src_length);
+
+ if ((ecma_number_t) src_length_uint32 != src_length)
+ {
+ return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid source length"));
+ }
+
+ /* 22. srcByteOffset */
+ ecma_length_t src_byte_offset = ecma_typedarray_get_offset (src_typedarray_p);
+
+ /* 23. */
+ uint32_t target_offset_uint32 = ecma_number_to_uint32 (target_offset_num);
+
+ if ((int64_t) src_length_uint32 + target_offset_uint32 > target_length)
+ {
+ return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid range of index"));
+ }
+
+ /* 24.d, 25. srcByteIndex */
+ ecma_length_t src_byte_index = 0;
+
+ if (src_arraybuffer_p != target_arraybuffer_p)
+ {
+ src_byte_index = src_byte_offset;
+ }
+
+ /* 26. targetByteIndex */
+ uint32_t target_byte_index = target_offset_uint32 * target_element_size + target_byte_offset;
+
+ /* 27. limit */
+ uint32_t limit = target_byte_index + target_element_size * src_length_uint32;
+
+ if (src_class_id == target_class_id)
+ {
+ memmove (target_buffer_p + target_byte_index, src_buffer_p + src_byte_index,
+ target_element_size * src_length_uint32);
+ }
+ else
+ {
+ while (target_byte_index < limit)
+ {
+ ecma_number_t elem_num = ecma_get_typedarray_element (src_buffer_p + src_byte_index, src_class_id);
+ ecma_set_typedarray_element (target_buffer_p + target_byte_index, elem_num, target_class_id);
+ src_byte_index += src_element_size;
+ target_byte_index += target_element_size;
+ }
+ }
+
+ return ECMA_VALUE_UNDEFINED;
+} /* ecma_op_typedarray_set_with_typedarray */
+
/**
* The %TypedArray%.prototype object's 'set' routine
*
* See also:
* ES2015, 22.2.3.22, 22.2.3.22.1
*
- * @return ecma value of undefined.
+ * @return ecma value of undefined if success, error otherwise.
+ * Returned value must be freed with ecma_free_value.
*/
ecma_value_t
ecma_builtin_typedarray_prototype_set (ecma_value_t this_arg, /**< this argument */
ecma_value_t arr_val, /**< array object */
ecma_value_t offset_val) /**< offset value */
{
- /* 1. */
- if (ecma_is_typedarray (arr_val))
- {
- /* 22.2.3.22.2 %TypedArray%.prototype(typedArray [, offset ]) is not supported */
- return ecma_raise_type_error (ECMA_ERR_MSG ("TypedArray.set(typedArray [,offset]) is not supported."));
- }
-
/* 2.~ 4. */
if (!ecma_is_typedarray (this_arg))
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
}
+ /* 1. */
+ if (ecma_is_typedarray (arr_val))
+ {
+ /* 22.2.3.22.2 */
+ return ecma_op_typedarray_set_with_typedarray (this_arg, arr_val, offset_val);
+ }
+
/* 6.~ 8. targetOffset */
ecma_value_t ret_val = ECMA_VALUE_EMPTY;
ECMA_OP_TO_NUMBER_TRY_CATCH (target_offset_num, offset_val, ret_val);
{
target_offset_num = 0;
}
- if (target_offset_num <= -1.0 || target_offset_num >= (double) UINT32_MAX + 0.5)
+ if (target_offset_num <= -1.0 || target_offset_num >= (ecma_number_t) UINT32_MAX + 0.5)
{
return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid offset"));
}
return ret_val;
} /* ecma_builtin_typedarray_prototype_set */
+/**
+ * TypedArray.prototype's 'toString' single element operation routine based
+ * on the Array.prototype's 'toString' single element operation routine
+ *
+ * See also:
+ * ECMA-262 v5.1, 15.4.4.2
+ *
+ * @return ecma_value_t value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_op_typedarray_get_to_string_at_index (ecma_object_t *obj_p, /**< this object */
+ uint32_t index) /**< array index */
+{
+ ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+ ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
+ ecma_value_t index_value = ecma_op_object_get (obj_p, index_string_p);
+ ecma_deref_ecma_string (index_string_p);
+
+ if (ECMA_IS_VALUE_ERROR (index_value))
+ {
+ return index_value;
+ }
+
+ if (ecma_is_value_undefined (index_value)
+ || ecma_is_value_null (index_value))
+ {
+ ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
+ }
+ else
+ {
+ ret_value = ecma_op_to_string (index_value);
+ }
+
+ ecma_free_value (index_value);
+ return ret_value;
+} /* ecma_op_typedarray_get_to_string_at_index */
+
+/**
+ * The TypedArray.prototype.toString's separator creation routine based on
+ * the Array.prototype.toString's separator routine
+ *
+ * See also:
+ * ECMA-262 v5.1, 15.4.4.2 4th step
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_op_typedarray_get_separator_string (ecma_value_t separator) /**< possible separator */
+{
+ if (ecma_is_value_undefined (separator))
+ {
+ return ecma_make_magic_string_value (LIT_MAGIC_STRING_COMMA_CHAR);
+ }
+
+ return ecma_op_to_string (separator);
+} /* ecma_op_typedarray_get_separator_string */
+
+/**
+ * The TypedArray.prototype object's 'join' routine basen on
+ * the Array.porottype object's 'join'
+ *
+ * See also:
+ * ECMA-262 v5, 15.4.4.5
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_typedarray_prototype_join (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t separator_arg) /**< separator argument */
+{
+ /* 1. */
+ ecma_value_t obj_value = ecma_op_to_object (this_arg);
+
+ if (ECMA_IS_VALUE_ERROR (obj_value))
+ {
+ return obj_value;
+ }
+ ecma_object_t *obj_p = ecma_get_object_from_value (obj_value);
+
+ /* 2. */
+ 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_free_value (obj_value);
+ return length_value;
+ }
+
+ ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+
+ ECMA_OP_TO_NUMBER_TRY_CATCH (length_number,
+ length_value,
+ ret_value);
+
+ /* 3. */
+ uint32_t length = ecma_number_to_uint32 (length_number);
+ /* 4-5. */
+ ecma_value_t separator_value = ecma_op_typedarray_get_separator_string (separator_arg);
+ if (ECMA_IS_VALUE_ERROR (separator_value))
+ {
+ ecma_free_value (length_value);
+ ecma_free_value (obj_value);
+ return separator_value;
+ }
+
+ if (length == 0)
+ {
+ /* 6. */
+ ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
+ }
+ else
+ {
+ ecma_string_t *separator_string_p = ecma_get_string_from_value (separator_value);
+
+ /* 7-8. */
+ ecma_value_t first_value = ecma_op_typedarray_get_to_string_at_index (obj_p, 0);
+ if (ECMA_IS_VALUE_ERROR (first_value))
+ {
+ ecma_free_value (separator_value);
+ ecma_free_value (length_value);
+ ecma_free_value (obj_value);
+ return first_value;
+ }
+
+ ecma_string_t *return_string_p = ecma_get_string_from_value (first_value);
+ ecma_ref_ecma_string (return_string_p);
+ if (ecma_is_value_empty (ret_value))
+ {
+ /* 9-10. */
+ for (uint32_t k = 1; k < length; k++)
+ {
+ /* 10.a */
+ return_string_p = ecma_concat_ecma_strings (return_string_p, separator_string_p);
+
+ /* 10.b, 10.c */
+ ecma_value_t next_string_value = ecma_op_typedarray_get_to_string_at_index (obj_p, k);
+ if (ECMA_IS_VALUE_ERROR (next_string_value))
+ {
+ ecma_free_value (first_value);
+ ecma_free_value (separator_value);
+ ecma_free_value (length_value);
+ ecma_free_value (obj_value);
+ return next_string_value;
+ }
+
+ /* 10.d */
+ ecma_string_t *next_string_p = ecma_get_string_from_value (next_string_value);
+ return_string_p = ecma_concat_ecma_strings (return_string_p, next_string_p);
+
+ ecma_free_value (next_string_value);
+ }
+ ret_value = ecma_make_string_value (return_string_p);
+ }
+ else
+ {
+ ecma_deref_ecma_string (return_string_p);
+ }
+
+ ecma_free_value (first_value);
+ }
+ ecma_free_value (separator_value);
+
+ ecma_free_value (length_value);
+ ecma_free_value (obj_value);
+ ECMA_OP_TO_NUMBER_FINALIZE (length_number);
+ return ret_value;
+} /* ecma_builtin_typedarray_prototype_join */
+
+/**
+ * The TypedArray.prototype object's 'toString' routine basen on
+ * the Array.porottype object's 'toString'
+ *
+ * See also:
+ * ECMA-262 v5, 15.4.4.2
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_typedarray_prototype_object_to_string (ecma_value_t this_arg) /**< this argument */
+{
+ ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+
+ /* 1. */
+ ecma_value_t obj_this_value = ecma_op_to_object (this_arg);
+ if (ECMA_IS_VALUE_ERROR (obj_this_value))
+ {
+ return obj_this_value;
+ }
+ ecma_object_t *obj_p = ecma_get_object_from_value (obj_this_value);
+
+ /* 2. */
+ ecma_value_t join_value = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_JOIN);
+ if (ECMA_IS_VALUE_ERROR (join_value))
+ {
+ ecma_free_value (obj_this_value);
+ return join_value;
+ }
+
+ if (!ecma_op_is_callable (join_value))
+ {
+ /* 3. */
+ ret_value = ecma_builtin_helper_object_to_string (this_arg);
+ }
+ else
+ {
+ /* 4. */
+ ecma_object_t *join_func_obj_p = ecma_get_object_from_value (join_value);
+
+ ret_value = ecma_op_function_call (join_func_obj_p, this_arg, NULL, 0);
+ }
+
+ ecma_free_value (join_value);
+ ecma_free_value (obj_this_value);
+
+ return ret_value;
+} /* ecma_builtin_typedarray_prototype_object_to_string */
+
+/**
+ * The %TypedArray%.prototype object's 'subarray' routine.
+ *
+ * See also:
+ * ES2015, 22.2.3.26
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_typedarray_prototype_subarray (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t begin, /**< begin */
+ ecma_value_t end) /**< end */
+{
+ ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+
+ /* 2.~ 4. */
+ if (!ecma_is_typedarray (this_arg))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
+ }
+
+ ecma_object_t *src_typedarray_p = ecma_get_object_from_value (this_arg);
+
+ /* 5. buffer */
+ ecma_object_t *src_typedarray_arraybuffer_p = ecma_typedarray_get_arraybuffer (src_typedarray_p);
+
+ /* 6. srcLength */
+ ecma_length_t src_length = ecma_typedarray_get_length (src_typedarray_p);
+
+ /* 9. beginIndex, 12. endIndex */
+ uint32_t begin_index_uint32 = 0, end_index_uint32 = 0;
+
+ /* 7. relativeBegin */
+ ECMA_OP_TO_NUMBER_TRY_CATCH (relative_begin, begin, ret_value);
+ begin_index_uint32 = ecma_builtin_helper_array_index_normalize (relative_begin, src_length);
+
+ if (ecma_is_value_undefined (end))
+ {
+ end_index_uint32 = (uint32_t) src_length;
+ }
+ else
+ {
+ /* 10. relativeEnd */
+ ECMA_OP_TO_NUMBER_TRY_CATCH (relative_end, end, ret_value);
+
+ end_index_uint32 = ecma_builtin_helper_array_index_normalize (relative_end, src_length);
+
+ ECMA_OP_TO_NUMBER_FINALIZE (relative_end);
+ }
+
+ ECMA_OP_TO_NUMBER_FINALIZE (relative_begin);
+
+ if (!ecma_is_value_empty (ret_value))
+ {
+ return ret_value;
+ }
+
+ /* 13. newLength */
+ ecma_length_t subarray_length = 0;
+
+ if (end_index_uint32 > begin_index_uint32)
+ {
+ subarray_length = end_index_uint32 - begin_index_uint32;
+ }
+
+ /* 15. elementSize */
+ uint8_t shift = ecma_typedarray_get_element_size_shift (src_typedarray_p);
+ uint8_t element_size = (uint8_t) (1 << shift);
+
+ /* 16. srcByteOffset */
+ ecma_length_t src_byte_offset = ecma_typedarray_get_offset (src_typedarray_p);
+
+ /* 17. beginByteOffset */
+ ecma_length_t begin_byte_offset = src_byte_offset + begin_index_uint32 * element_size;
+
+ uint8_t src_builtin_id = ecma_typedarray_helper_get_builtin_id (src_typedarray_p);
+ ecma_value_t arguments_p[3] =
+ {
+ ecma_make_object_value (src_typedarray_arraybuffer_p),
+ ecma_make_uint32_value (begin_byte_offset),
+ ecma_make_uint32_value (subarray_length)
+ };
+
+ ret_value = ecma_typedarray_helper_dispatch_construct (arguments_p, 3, src_builtin_id);
+
+ ecma_free_value (arguments_p[1]);
+ ecma_free_value (arguments_p[2]);
+ return ret_value;
+} /* ecma_builtin_typedarray_prototype_subarray */
+
+/**
+ * The %TypedArray%.prototype object's 'fill' routine.
+ *
+ * See also:
+ * ES2015, 22.2.3.8, 22.1.3.6
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_typedarray_prototype_fill (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t value, /**< value */
+ ecma_value_t begin, /**< begin */
+ ecma_value_t end) /**< end */
+{
+ if (!ecma_is_typedarray (this_arg))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
+ }
+
+ ecma_number_t value_num;
+ ecma_value_t ret_value = ecma_get_number (value, &value_num);
+
+ if (!ecma_is_value_empty (ret_value))
+ {
+ return ret_value;
+ }
+
+ ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg);
+ ecma_object_t *typedarray_arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p);
+ lit_utf8_byte_t *buffer_p = ecma_arraybuffer_get_buffer (typedarray_arraybuffer_p);
+ ecma_length_t length = ecma_typedarray_get_length (typedarray_p);
+
+ uint32_t begin_index_uint32 = 0, end_index_uint32 = 0;
+
+ ECMA_OP_TO_NUMBER_TRY_CATCH (relative_begin, begin, ret_value);
+ begin_index_uint32 = ecma_builtin_helper_array_index_normalize (relative_begin, length);
+
+ if (ecma_is_value_undefined (end))
+ {
+ end_index_uint32 = (uint32_t) length;
+ }
+ else
+ {
+ ECMA_OP_TO_NUMBER_TRY_CATCH (relative_end, end, ret_value);
+
+ end_index_uint32 = ecma_builtin_helper_array_index_normalize (relative_end, length);
+
+ ECMA_OP_TO_NUMBER_FINALIZE (relative_end);
+ }
+
+ ECMA_OP_TO_NUMBER_FINALIZE (relative_begin);
+
+ if (!ecma_is_value_empty (ret_value))
+ {
+ return ret_value;
+ }
+
+ ecma_length_t subarray_length = 0;
+
+ if (end_index_uint32 > begin_index_uint32)
+ {
+ subarray_length = end_index_uint32 - begin_index_uint32;
+ }
+
+ uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p);
+ ecma_length_t byte_offset = ecma_typedarray_get_offset (typedarray_p);
+ lit_magic_string_id_t class_id = ecma_object_get_class_name (typedarray_p);
+
+ uint8_t element_size = (uint8_t) (1 << shift);
+ uint32_t byte_index = byte_offset + begin_index_uint32 * element_size;
+ uint32_t limit = byte_index + subarray_length * element_size;
+
+ while (byte_index < limit)
+ {
+ ecma_set_typedarray_element (buffer_p + byte_index, value_num, class_id);
+ byte_index += element_size;
+ }
+
+ return ecma_copy_value (this_arg);
+} /* ecma_builtin_typedarray_prototype_fill */
+
+/**
+ * SortCompare abstract method
+ *
+ * See also:
+ * ECMA-262 v5, 15.4.4.11
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_typedarray_prototype_sort_compare_helper (ecma_value_t lhs, /**< left value */
+ ecma_value_t rhs, /**< right value */
+ ecma_value_t compare_func) /**< compare function */
+{
+ ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+ ecma_number_t result = ECMA_NUMBER_ZERO;
+
+ if (ecma_is_value_undefined (compare_func))
+ {
+ /* Default comparison when no comparefn is passed. */
+ double lhs_value = (double) ecma_get_number_from_value (lhs);
+ double rhs_value = (double) ecma_get_number_from_value (rhs);
+
+ if (ecma_number_is_nan (lhs_value))
+ {
+ // Keep NaNs at the end of the array.
+ result = ECMA_NUMBER_ONE;
+ }
+ else if (ecma_number_is_nan (rhs_value))
+ {
+ // Keep NaNs at the end of the array.
+ result = ECMA_NUMBER_MINUS_ONE;
+ }
+ else if (lhs_value < rhs_value)
+ {
+ result = ECMA_NUMBER_MINUS_ONE;
+ }
+ else if (lhs_value > rhs_value)
+ {
+ result = ECMA_NUMBER_ONE;
+ }
+ else
+ {
+ result = ECMA_NUMBER_ZERO;
+ }
+
+ return ecma_make_number_value (result);
+ }
+
+ /*
+ * compare_func, if not undefined, will always contain a callable function object.
+ * We checked this previously, before this function was called.
+ */
+ JERRY_ASSERT (ecma_op_is_callable (compare_func));
+ ecma_object_t *comparefn_obj_p = ecma_get_object_from_value (compare_func);
+
+ ecma_value_t compare_args[] = { lhs, rhs };
+
+ ECMA_TRY_CATCH (call_value,
+ ecma_op_function_call (comparefn_obj_p,
+ ECMA_VALUE_UNDEFINED,
+ compare_args,
+ 2),
+ ret_value);
+
+ if (!ecma_is_value_number (call_value))
+ {
+ ECMA_OP_TO_NUMBER_TRY_CATCH (ret_num, call_value, ret_value);
+ result = ret_num;
+ ECMA_OP_TO_NUMBER_FINALIZE (ret_num);
+
+ // If the coerced value can't be represented as a Number, compare them as equals.
+ if (ecma_number_is_nan (result))
+ {
+ result = ECMA_NUMBER_ZERO;
+ }
+ }
+ else
+ {
+ result = ecma_get_number_from_value (call_value);
+ }
+
+ ECMA_FINALIZE (call_value);
+
+ if (ecma_is_value_empty (ret_value))
+ {
+ ret_value = ecma_make_number_value (result);
+ }
+
+ return ret_value;
+} /* ecma_builtin_typedarray_prototype_sort_compare_helper */
+
+/**
+ * The %TypedArray%.prototype object's 'sort' routine.
+ *
+ * See also:
+ * ES2015, 22.2.3.25, 22.1.3.24
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_typedarray_prototype_sort (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t compare_func) /**< comparator fn */
+{
+ if (!ecma_is_typedarray (this_arg))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
+ }
+
+ if (!ecma_is_value_undefined (compare_func) && !ecma_op_is_callable (compare_func))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Compare function is not callable."));
+ }
+
+ ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg);
+ ecma_length_t typedarray_length = ecma_typedarray_get_length (typedarray_p);
+
+ if (!typedarray_length)
+ {
+ return ecma_copy_value (this_arg);
+ }
+
+ ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+
+ JMEM_DEFINE_LOCAL_ARRAY (values_buffer, typedarray_length, ecma_value_t);
+
+ lit_magic_string_id_t class_id = ecma_object_get_class_name (typedarray_p);
+ lit_utf8_byte_t *typedarray_buffer_p = ecma_typedarray_get_buffer (typedarray_p);
+ uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p);
+ uint8_t element_size = (uint8_t) (1 << shift);
+
+ uint32_t byte_index = 0, buffer_index = 0;
+ uint32_t limit = typedarray_length * element_size;
+
+ /* Copy unsorted array into a native c array. */
+ while (byte_index < limit)
+ {
+ JERRY_ASSERT (buffer_index < typedarray_length);
+ ecma_number_t element_num = ecma_get_typedarray_element (typedarray_buffer_p + byte_index,
+ class_id);
+ ecma_value_t element_value = ecma_make_number_value (element_num);
+ values_buffer[buffer_index++] = element_value;
+ byte_index += element_size;
+ }
+
+ JERRY_ASSERT (buffer_index == typedarray_length);
+
+ const ecma_builtin_helper_sort_compare_fn_t sort_cb = &ecma_builtin_typedarray_prototype_sort_compare_helper;
+ ECMA_TRY_CATCH (sort_value,
+ ecma_builtin_helper_array_heap_sort_helper (values_buffer,
+ (uint32_t) (typedarray_length - 1),
+ compare_func,
+ sort_cb),
+ ret_value);
+ ECMA_FINALIZE (sort_value);
+
+ if (ecma_is_value_empty (ret_value))
+ {
+ byte_index = 0;
+ buffer_index = 0;
+ limit = typedarray_length * element_size;
+ /* Put sorted values from the native array back into the typedarray buffer. */
+ while (byte_index < limit)
+ {
+ JERRY_ASSERT (buffer_index < typedarray_length);
+ ecma_value_t element_value = values_buffer[buffer_index++];
+ ecma_number_t element_num = ecma_get_number_from_value (element_value);
+ ecma_set_typedarray_element (typedarray_buffer_p + byte_index, element_num, class_id);
+ byte_index += element_size;
+ }
+
+ JERRY_ASSERT (buffer_index == typedarray_length);
+ }
+
+ /* Free values that were copied to the local array. */
+ for (uint32_t index = 0; index < typedarray_length; index++)
+ {
+ ecma_free_value (values_buffer[index]);
+ }
+
+ JMEM_FINALIZE_LOCAL_ARRAY (values_buffer);
+
+ if (ecma_is_value_empty (ret_value))
+ {
+ ret_value = ecma_copy_value (this_arg);
+ }
+
+ return ret_value;
+} /* ecma_builtin_typedarray_prototype_sort */
+
+/**
+ * The %TypedArray%.prototype object's 'find' routine
+ *
+ * See also:
+ * ECMA-262 v6, 22.2.3.10
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_typedarray_prototype_find (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t predicate, /**< callback function */
+ ecma_value_t predicate_this_arg) /**< this argument for
+ * invoke predicate */
+{
+ if (!ecma_is_typedarray (this_arg))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
+ }
+
+ if (!ecma_op_is_callable (predicate))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Callback function is not callable."));
+ }
+
+ JERRY_ASSERT (ecma_is_value_object (predicate));
+ ecma_object_t *func_object_p = ecma_get_object_from_value (predicate);
+
+ ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg);
+ uint32_t typedarray_length = ecma_typedarray_get_length (typedarray_p);
+ lit_magic_string_id_t class_id = ecma_object_get_class_name (typedarray_p);
+ lit_utf8_byte_t *typedarray_buffer_p = ecma_typedarray_get_buffer (typedarray_p);
+ uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p);
+ uint8_t element_size = (uint8_t) (1 << shift);
+
+ uint32_t buffer_index = 0;
+ uint32_t limit = typedarray_length * element_size;
+
+ for (uint32_t byte_index = 0; byte_index < limit; byte_index += element_size)
+ {
+ JERRY_ASSERT (buffer_index < typedarray_length);
+ ecma_number_t element_num = ecma_get_typedarray_element (typedarray_buffer_p + byte_index, class_id);
+ ecma_value_t element_value = ecma_make_number_value (element_num);
+
+ ecma_value_t call_args[] = { element_value, ecma_make_uint32_value (buffer_index++), this_arg };
+
+ ecma_value_t call_value = ecma_op_function_call (func_object_p, predicate_this_arg, call_args, 3);
+
+ if (ECMA_IS_VALUE_ERROR (call_value))
+ {
+ ecma_free_value (element_value);
+ return call_value;
+ }
+
+ bool call_result = ecma_op_to_boolean (call_value);
+ ecma_free_value (call_value);
+
+ if (call_result)
+ {
+ return element_value;
+ }
+
+ ecma_free_value (element_value);
+ }
+
+ return ECMA_VALUE_UNDEFINED;
+} /* ecma_builtin_typedarray_prototype_find */
+
/**
* @}
* @}
ecma_builtin_typedarray_prototype_length_getter,
ECMA_PROPERTY_FIXED)
+/* Routine properties:
+ * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
+ROUTINE (LIT_MAGIC_STRING_TO_STRING_UL, ecma_builtin_typedarray_prototype_object_to_string, 0, 0)
+ROUTINE (LIT_MAGIC_STRING_JOIN, ecma_builtin_typedarray_prototype_join, 1, 1)
ROUTINE (LIT_MAGIC_STRING_EVERY, ecma_builtin_typedarray_prototype_every, 2, 1)
ROUTINE (LIT_MAGIC_STRING_SOME, ecma_builtin_typedarray_prototype_some, 2, 1)
ROUTINE (LIT_MAGIC_STRING_FOR_EACH_UL, ecma_builtin_typedarray_prototype_for_each, 2, 1)
ROUTINE (LIT_MAGIC_STRING_FILTER, ecma_builtin_typedarray_prototype_filter, 2, 1)
ROUTINE (LIT_MAGIC_STRING_REVERSE, ecma_builtin_typedarray_prototype_reverse, 0, 0)
ROUTINE (LIT_MAGIC_STRING_SET, ecma_builtin_typedarray_prototype_set, 2, 1)
+ROUTINE (LIT_MAGIC_STRING_SUBARRAY, ecma_builtin_typedarray_prototype_subarray, 2, 2)
+ROUTINE (LIT_MAGIC_STRING_FILL, ecma_builtin_typedarray_prototype_fill, 3, 1)
+ROUTINE (LIT_MAGIC_STRING_SORT, ecma_builtin_typedarray_prototype_sort, 1, 1)
+ROUTINE (LIT_MAGIC_STRING_FIND, ecma_builtin_typedarray_prototype_find, 2, 1)
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
+
+#ifndef TYPEDARRAY_BYTES_PER_ELEMENT
+# error "Please define TYPEDARRAY_BYTES_PER_ELEMENT"
+#endif /* !TYPEDARRAY_BYTES_PER_ELEMENT */
+
+#ifndef TYPEDARRAY_MAGIC_STRING_ID
+# error "Please define TYPEDARRAY_MAGIC_STRING_ID"
+#endif /* !TYPEDARRAY_MAGIC_STRING_ID */
+
+#ifndef TYPEDARRAY_BUILTIN_ID
+# error "Please define TYPEDARRAY_BUILTIN_ID"
+#endif /* !TYPEDARRAY_BUILTIN_ID */
+
+#include "ecma-builtin-helpers-macro-defines.inc.h"
+
+/* ES2015 22.2.5 */
+NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
+ 3,
+ ECMA_PROPERTY_FIXED)
+
+/* ES2015 22.2.5.1 */
+NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
+ TYPEDARRAY_BYTES_PER_ELEMENT,
+ ECMA_PROPERTY_FIXED)
+
+/* ES2015 22.2.5 */
+NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
+ 3,
+ ECMA_PROPERTY_FIXED)
+
+/* ES2015 22.2.5 */
+STRING_VALUE (LIT_MAGIC_STRING_NAME,
+ TYPEDARRAY_MAGIC_STRING_ID,
+ ECMA_PROPERTY_FIXED)
+
+/* ES2015 22.2.5.2 */
+OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
+ TYPEDARRAY_BUILTIN_ID,
+ ECMA_PROPERTY_FIXED)
+
+#include "ecma-builtin-helpers-macro-undefs.inc.h"
+
+#undef TYPEDARRAY_BUILTIN_ID
+#undef TYPEDARRAY_MAGIC_STRING_ID
+#undef TYPEDARRAY_BYTES_PER_ELEMENT
+
+#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
#define BUILTIN_UNDERSCORED_ID typedarray
#include "ecma-builtin-internal-routines-template.inc.h"
+#include "ecma-builtin-typedarray-helpers.h"
+
/** \addtogroup ecma ECMA
* @{
*
ecma_object_t *obj_p = ecma_get_object_from_value (this_arg);
- uint8_t builtin_id = ecma_get_object_builtin_id (obj_p);
- ecma_object_t *proto_p;
- uint8_t element_size_shift;
- lit_magic_string_id_t class_id;
-
- switch (builtin_id)
+ const uint8_t builtin_id = ecma_get_object_builtin_id (obj_p);
+ if (!ecma_typedarray_helper_is_typedarray (builtin_id))
{
- case ECMA_BUILTIN_ID_INT8ARRAY:
- {
- proto_p = ecma_builtin_get (ECMA_BUILTIN_ID_INT8ARRAY_PROTOTYPE);
- element_size_shift = 0;
- class_id = LIT_MAGIC_STRING_INT8_ARRAY_UL;
- break;
- }
- case ECMA_BUILTIN_ID_UINT8ARRAY:
- {
- proto_p = ecma_builtin_get (ECMA_BUILTIN_ID_UINT8ARRAY_PROTOTYPE);
- element_size_shift = 0;
- class_id = LIT_MAGIC_STRING_UINT8_ARRAY_UL;
- break;
- }
- case ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY:
- {
- proto_p = ecma_builtin_get (ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY_PROTOTYPE);
- element_size_shift = 0;
- class_id = LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL;
- break;
- }
- case ECMA_BUILTIN_ID_INT16ARRAY:
- {
- proto_p = ecma_builtin_get (ECMA_BUILTIN_ID_INT16ARRAY_PROTOTYPE);
- element_size_shift = 1;
- class_id = LIT_MAGIC_STRING_INT16_ARRAY_UL;
- break;
- }
- case ECMA_BUILTIN_ID_UINT16ARRAY:
- {
- proto_p = ecma_builtin_get (ECMA_BUILTIN_ID_UINT16ARRAY_PROTOTYPE);
- element_size_shift = 1;
- class_id = LIT_MAGIC_STRING_UINT16_ARRAY_UL;
- break;
- }
- case ECMA_BUILTIN_ID_INT32ARRAY:
- {
- proto_p = ecma_builtin_get (ECMA_BUILTIN_ID_INT32ARRAY_PROTOTYPE);
- element_size_shift = 2;
- class_id = LIT_MAGIC_STRING_INT32_ARRAY_UL;
- break;
- }
- case ECMA_BUILTIN_ID_UINT32ARRAY:
- {
- proto_p = ecma_builtin_get (ECMA_BUILTIN_ID_UINT32ARRAY_PROTOTYPE);
- element_size_shift = 2;
- class_id = LIT_MAGIC_STRING_UINT32_ARRAY_UL;
- break;
- }
- case ECMA_BUILTIN_ID_FLOAT32ARRAY:
- {
- proto_p = ecma_builtin_get (ECMA_BUILTIN_ID_FLOAT32ARRAY_PROTOTYPE);
- element_size_shift = 2;
- class_id = LIT_MAGIC_STRING_FLOAT32_ARRAY_UL;
- break;
- }
-#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
- case ECMA_BUILTIN_ID_FLOAT64ARRAY:
- {
- proto_p = ecma_builtin_get (ECMA_BUILTIN_ID_FLOAT64ARRAY_PROTOTYPE);
- element_size_shift = 3;
- class_id = LIT_MAGIC_STRING_FLOAT64_ARRAY_UL;
- break;
- }
-#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
- default:
- {
- return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a typedarray constructor"));
- }
+ return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a typedarray constructor"));
}
- ecma_deref_object (proto_p);
+ ecma_object_t *proto_p = ecma_builtin_get (ecma_typedarray_helper_get_prototype_id (builtin_id));
+ const uint8_t element_size_shift = ecma_typedarray_helper_get_shift_size (builtin_id);
+ const lit_magic_string_id_t class_id = ecma_typedarray_helper_get_magic_string (builtin_id);
+
return ecma_op_typedarray_from (source,
map_fn,
* Uint16Array prototype description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.3.4 */
-OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
- ECMA_BUILTIN_ID_UINT16ARRAY,
- ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
-
-/* ES2015 22.2.6.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 2,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 2
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_UINT16ARRAY
+#include "ecma-builtin-typedarray-prototype-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
#define BUILTIN_UNDERSCORED_ID uint16array
#include "ecma-builtin-internal-routines-template.inc.h"
+#include "ecma-builtin-typedarray-helpers.h"
+
/** \addtogroup ecma ECMA
* @{
*
ecma_builtin_uint16array_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< number of arguments */
{
- JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
-
- ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_UINT16ARRAY_PROTOTYPE);
- ecma_value_t val = ecma_op_create_typedarray (arguments_list_p,
- arguments_list_len,
- prototype_obj_p,
- 1,
- LIT_MAGIC_STRING_UINT16_ARRAY_UL);
-
- ecma_deref_object (prototype_obj_p);
-
- return val;
+ return ecma_typedarray_helper_dispatch_construct (arguments_list_p, arguments_list_len,
+ ECMA_BUILTIN_ID_UINT16ARRAY);
} /* ecma_builtin_uint16array_dispatch_construct */
/**
* Uint16Array description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 2,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-STRING_VALUE (LIT_MAGIC_STRING_NAME,
- LIT_MAGIC_STRING_UINT16_ARRAY_UL,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.2 */
-OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
- ECMA_BUILTIN_ID_UINT16ARRAY_PROTOTYPE,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 2
+#define TYPEDARRAY_MAGIC_STRING_ID LIT_MAGIC_STRING_UINT16_ARRAY_UL
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_UINT16ARRAY_PROTOTYPE
+#include "ecma-builtin-typedarray-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
* Uint32Array prototype description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.3.4 */
-OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
- ECMA_BUILTIN_ID_UINT32ARRAY,
- ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
-
-/* ES2015 22.2.6.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 4,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 4
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_UINT32ARRAY
+#include "ecma-builtin-typedarray-prototype-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
2,
LIT_MAGIC_STRING_UINT32_ARRAY_UL);
- ecma_deref_object (prototype_obj_p);
-
return val;
} /* ecma_builtin_uint32array_dispatch_construct */
* Uint32Array description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 4,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-STRING_VALUE (LIT_MAGIC_STRING_NAME,
- LIT_MAGIC_STRING_UINT32_ARRAY_UL,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.2 */
-OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
- ECMA_BUILTIN_ID_UINT32ARRAY_PROTOTYPE,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 4
+#define TYPEDARRAY_MAGIC_STRING_ID LIT_MAGIC_STRING_UINT32_ARRAY_UL
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_UINT32ARRAY_PROTOTYPE
+#include "ecma-builtin-typedarray-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
* Uint8Array prototype description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.3.4 */
-OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
- ECMA_BUILTIN_ID_UINT8ARRAY,
- ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
-
-/* ES2015 22.2.6.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 1,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 1
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_UINT8ARRAY
+#include "ecma-builtin-typedarray-prototype-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
#define BUILTIN_UNDERSCORED_ID uint8array
#include "ecma-builtin-internal-routines-template.inc.h"
+#include "ecma-builtin-typedarray-helpers.h"
+
/** \addtogroup ecma ECMA
* @{
*
ecma_builtin_uint8array_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< number of arguments */
{
- JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
-
- ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_UINT8ARRAY_PROTOTYPE);
- ecma_value_t val = ecma_op_create_typedarray (arguments_list_p,
- arguments_list_len,
- prototype_obj_p,
- 0,
- LIT_MAGIC_STRING_UINT8_ARRAY_UL);
-
- ecma_deref_object (prototype_obj_p);
-
- return val;
+ return ecma_typedarray_helper_dispatch_construct (arguments_list_p, arguments_list_len,
+ ECMA_BUILTIN_ID_UINT8ARRAY);
} /* ecma_builtin_uint8array_dispatch_construct */
/**
* Uint8Array description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 1,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-STRING_VALUE (LIT_MAGIC_STRING_NAME,
- LIT_MAGIC_STRING_UINT8_ARRAY_UL,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.2 */
-OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
- ECMA_BUILTIN_ID_UINT8ARRAY_PROTOTYPE,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 1
+#define TYPEDARRAY_MAGIC_STRING_ID LIT_MAGIC_STRING_UINT8_ARRAY_UL
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_UINT8ARRAY_PROTOTYPE
+#include "ecma-builtin-typedarray-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
* Uint8ClampedArray prototype description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.3.4 */
-OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
- ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY,
- ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
-
-/* ES2015 22.2.6.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 1,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 1
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY
+#include "ecma-builtin-typedarray-prototype-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
0,
LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL);
- ecma_deref_object (prototype_obj_p);
return val;
} /* ecma_builtin_uint8clampedarray_dispatch_construct */
* Uint8ClampedArray description
*/
-#include "ecma-builtin-helpers-macro-defines.inc.h"
-
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.1 */
-NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U,
- 1,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
- 3,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5 */
-STRING_VALUE (LIT_MAGIC_STRING_NAME,
- LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL,
- ECMA_PROPERTY_FIXED)
-
-/* ES2015 22.2.5.2 */
-OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
- ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY_PROTOTYPE,
- ECMA_PROPERTY_FIXED)
+#define TYPEDARRAY_BYTES_PER_ELEMENT 1
+#define TYPEDARRAY_MAGIC_STRING_ID LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL
+#define TYPEDARRAY_BUILTIN_ID ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY_PROTOTYPE
+#include "ecma-builtin-typedarray-template.inc.h"
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
-
-#include "ecma-builtin-helpers-macro-undefs.inc.h"
#include "ecma-number-arithmetic.h"
#include "ecma-objects.h"
#include "ecma-objects-general.h"
+#include "ecma-function-object.h"
/** \addtogroup ecma ECMA
* @{
*/
ecma_value_t
ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of arguments that
- are passed to Array constructor */
+ * are passed to Array constructor */
ecma_length_t arguments_list_len, /**< length of the arguments' list */
bool is_treat_single_arg_as_length) /**< if the value is true,
- arguments_list_len is 1
- and single argument is Number,
- then treat the single argument
- as new Array's length rather
- than as single item of the Array */
+ * arguments_list_len is 1
+ * and single argument is Number,
+ * then treat the single argument
+ * as new Array's length rather
+ * than as single item of the Array */
{
JERRY_ASSERT (arguments_list_len == 0
|| arguments_list_p != NULL);
sizeof (ecma_extended_object_t),
ECMA_OBJECT_TYPE_ARRAY);
- ecma_deref_object (array_prototype_object_p);
-
/*
* [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_ARRAY type.
*
ecma_builtin_helper_def_prop (object_p,
item_name_string_p,
array_items_p[index],
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
false); /* Failure handling */
ecma_deref_ecma_string (item_name_string_p);
return ecma_make_object_value (object_p);
} /* ecma_op_create_array_object */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+/**
+ * Array object creation with custom prototype.
+ *
+ * See also: ECMA-262 v6, 9.4.2.3
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value
+ */
+ecma_value_t
+ecma_op_create_array_object_by_constructor (const ecma_value_t *arguments_list_p, /**< list of arguments that
+ * are passed to
+ * Array constructor */
+ ecma_length_t arguments_list_len, /**< length of the arguments' list */
+ bool is_treat_single_arg_as_length, /**< if the value is true,
+ * arguments_list_len is 1
+ * and single argument is Number,
+ * then treat the single argument
+ * as new Array's length rather
+ * than as single item of the
+ * Array */
+ ecma_object_t *object_p) /**< The object from whom the new array object
+ * is being created */
+{
+ /* TODO: Use @@species after Symbol has been implemented */
+ JERRY_UNUSED (object_p);
+
+ return ecma_op_create_array_object (arguments_list_p,
+ arguments_list_len,
+ is_treat_single_arg_as_length);
+} /* ecma_op_create_array_object_by_constructor */
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
/**
* Update the length of an array to a new length
*
ecma_op_create_array_object (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len,
bool is_treat_single_arg_as_length);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ecma_value_t
+ecma_op_create_array_object_by_constructor (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len,
+ bool is_treat_single_arg_as_length, ecma_object_t *object_p);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
ecma_value_t
ecma_op_array_object_set_length (ecma_object_t *object_p, ecma_value_t new_value, uint32_t flags);
ecma_object_t *object_p = ecma_create_object (prototype_obj_p,
sizeof (ecma_extended_object_t) + length,
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;
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;
const uint32_t maximum_size_in_byte = UINT32_MAX - sizeof (ecma_extended_object_t) - JMEM_ALIGNMENT + 1;
- if (length_num <= -1.0 || length_num > (double) maximum_size_in_byte + 0.5)
+ if (length_num <= -1.0 || length_num > (ecma_number_t) maximum_size_in_byte + 0.5)
{
return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid ArrayBuffer length."));
}
*
* @return ecma_length_t, the length of the arraybuffer
*/
-ecma_length_t __attr_pure___
+ecma_length_t JERRY_ATTR_PURE
ecma_arraybuffer_get_length (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */
{
JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL));
*
* @return pointer to the data buffer
*/
-inline lit_utf8_byte_t * __attr_pure___ __attr_always_inline___
+inline lit_utf8_byte_t * JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
ecma_arraybuffer_get_buffer (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */
{
JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL));
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
-ecma_arraybuffer_get_length (ecma_object_t *obj_p) __attr_pure___;
+lit_utf8_byte_t * JERRY_ATTR_PURE
+ecma_arraybuffer_get_buffer (ecma_object_t *obj_p);
+ecma_length_t JERRY_ATTR_PURE
+ecma_arraybuffer_get_length (ecma_object_t *obj_p);
bool
ecma_is_arraybuffer (ecma_value_t val);
sizeof (ecma_extended_object_t),
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.class_id = LIT_MAGIC_STRING_BOOLEAN_UL;
ext_object_p->u.class_prop.u.value = ecma_make_boolean_value (boolean_value);
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
-ecma_get_number (ecma_value_t value, ecma_number_t *number_p)
+ecma_get_number (ecma_value_t value, /**< ecma value*/
+ ecma_number_t *number_p) /**< [out] ecma number */
{
if (ecma_is_value_integer_number (value))
{
{
ecma_check_value_type_is_spec_defined (value);
- if (unlikely (ecma_is_value_object (value)))
+ if (JERRY_UNLIKELY (ecma_is_value_object (value)))
{
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
JERRY_ASSERT (ecma_is_value_empty (ret_value));
/* 9. */
- if (prop_desc.is_get_defined
- || prop_desc.is_set_defined)
+ if ((prop_desc.is_get_defined || prop_desc.is_set_defined)
+ && (prop_desc.is_value_defined || prop_desc.is_writable_defined))
{
- if (prop_desc.is_value_defined
- || prop_desc.is_writable_defined)
- {
- ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Accessors cannot be writable."));
- }
+ ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Accessors cannot be writable."));
}
}
#include "ecma-lex-env.h"
#include "js-parser.h"
#include "vm.h"
-
-#ifdef JERRY_ENABLE_LINE_INFO
#include "jcontext.h"
-#endif /* JERRY_ENABLE_LINE_INFO */
/** \addtogroup ecma ECMA
* @{
*/
ecma_value_t
ecma_op_eval (ecma_string_t *code_p, /**< code string */
- bool is_direct, /**< is eval called directly (ECMA-262 v5, 15.1.2.1.1) */
- bool is_called_from_strict_mode_code) /**< is eval is called from strict mode code */
+ uint32_t parse_opts) /**< ecma_parse_opts_t option bits */
{
ecma_value_t ret_value;
ret_value = ecma_op_eval_chars_buffer (code_utf8_buffer_p,
chars_num,
- is_direct,
- is_called_from_strict_mode_code);
+ parse_opts);
ECMA_FINALIZE_UTF8_STRING (code_utf8_buffer_p, code_utf8_buffer_size);
}
ecma_value_t
ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, /**< code characters buffer */
size_t code_buffer_size, /**< size of the buffer */
- bool is_direct, /**< is eval called directly (ECMA-262 v5, 15.1.2.1.1) */
- bool is_called_from_strict_mode_code) /**< is eval is called from strict mode code */
+ uint32_t parse_opts) /**< ecma_parse_opts_t option bits */
{
#ifndef JERRY_DISABLE_JS_PARSER
JERRY_ASSERT (code_p != NULL);
ecma_compiled_code_t *bytecode_data_p;
- bool is_strict_call = (is_direct && is_called_from_strict_mode_code);
+ uint32_t is_strict_call = ECMA_PARSE_STRICT_MODE | ECMA_PARSE_DIRECT_EVAL;
+
+ if ((parse_opts & is_strict_call) != is_strict_call)
+ {
+ parse_opts &= (uint32_t) ~ECMA_PARSE_STRICT_MODE;
+ }
#ifdef JERRY_ENABLE_LINE_INFO
JERRY_CONTEXT (resource_name) = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
#endif /* JERRY_ENABLE_LINE_INFO */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ parse_opts |= ECMA_GET_SUPER_EVAL_PARSER_OPTS ();
+
+ ECMA_CLEAR_SUPER_EVAL_PARSER_OPTS ();
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
ecma_value_t parse_status = parser_parse_script (NULL,
0,
code_p,
code_buffer_size,
- is_strict_call,
+ parse_opts,
&bytecode_data_p);
if (ECMA_IS_VALUE_ERROR (parse_status))
return parse_status;
}
- return vm_run_eval (bytecode_data_p, is_direct);
+ return vm_run_eval (bytecode_data_p, parse_opts);
#else /* JERRY_DISABLE_JS_PARSER */
JERRY_UNUSED (code_p);
JERRY_UNUSED (code_buffer_size);
- JERRY_UNUSED (is_direct);
- JERRY_UNUSED (is_called_from_strict_mode_code);
+ JERRY_UNUSED (parse_opts);
return ecma_raise_syntax_error (ECMA_ERR_MSG ("The parser has been disabled."));
#endif /* !JERRY_DISABLE_JS_PARSER */
*/
ecma_value_t
-ecma_op_eval (ecma_string_t *code_p, bool is_direct, bool is_called_from_strict_mode_code);
+ecma_op_eval (ecma_string_t *code_p, uint32_t parse_opts);
ecma_value_t
-ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, size_t code_buffer_size, bool is_direct,
- bool is_called_from_strict_mode_code);
+ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, size_t code_buffer_size, uint32_t parse_opts);
/**
* @}
* \addtogroup exceptions Exceptions
* @{
*/
+
+/**
+ * Map error type to error prototype.
+ */
typedef struct
{
- ecma_standard_error_t error_type;
- ecma_builtin_id_t error_prototype_id;
+ ecma_standard_error_t error_type; /**< Native error type */
+ ecma_builtin_id_t error_prototype_id; /**< ID of the error prototype */
} ecma_error_mapping_t;
+/**
+ * List of error type mappings
+ */
const ecma_error_mapping_t ecma_error_mappings[] =
{
#define ERROR_ELEMENT(TYPE, ID) { TYPE, ID }
switch (error_type)
{
- case ECMA_ERROR_COMMON:
- {
- prototype_id = ECMA_BUILTIN_ID_ERROR_PROTOTYPE;
- break;
- }
-
case ECMA_ERROR_EVAL:
{
prototype_id = ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE;
break;
}
- case ECMA_ERROR_NONE:
+ default:
{
- JERRY_UNREACHABLE ();
+ JERRY_ASSERT (error_type == ECMA_ERROR_COMMON);
+
+ prototype_id = ECMA_BUILTIN_ID_ERROR_PROTOTYPE;
break;
}
}
sizeof (ecma_extended_object_t),
ECMA_OBJECT_TYPE_CLASS);
- ecma_deref_object (prototype_obj_p);
-
((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";
+ const char * const 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);
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
-ecma_value_t
+static ecma_value_t
ecma_raise_standard_error (ecma_standard_error_t error_type, /**< error type */
const lit_utf8_byte_t *msg_p) /**< error message */
{
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)))
+ if (JERRY_UNLIKELY (ecma_is_value_object (arg_val)))
{
ecma_object_t *arg_object_p = ecma_get_object_from_value (arg_val);
lit_magic_string_id_t class_name = ecma_object_get_class_name (arg_object_p);
return ecma_raise_standard_error (ECMA_ERROR_COMMON, (const lit_utf8_byte_t *) msg_p);
} /* ecma_raise_common_error */
-/**
- * Raise an EvalError with the given message.
- *
- * See also: ECMA-262 v5, 15.11.6.1
- *
- * @return ecma value
- * Returned value must be freed with ecma_free_value
- */
-ecma_value_t
-ecma_raise_eval_error (const char *msg_p) /**< error message */
-{
- return ecma_raise_standard_error (ECMA_ERROR_EVAL, (const lit_utf8_byte_t *) msg_p);
-} /* ecma_raise_eval_error */
-
/**
* Raise a RangeError with the given message.
*
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);
#ifdef JERRY_ENABLE_ERROR_MESSAGES
ecma_value_t ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, const char *msg_p, ...);
#endif /* JERRY_ENABLE_ERROR_MESSAGES */
ecma_value_t ecma_raise_common_error (const char *msg_p);
-ecma_value_t ecma_raise_eval_error (const char *msg_p);
ecma_value_t ecma_raise_range_error (const char *msg_p);
ecma_value_t ecma_raise_reference_error (const char *msg_p);
ecma_value_t ecma_raise_syntax_error (const char *msg_p);
* @return true - if the type is a normal or arrow function;
* false - otherwise
*/
-inline bool __attr_always_inline___
-ecma_is_normal_or_arrow_function (ecma_object_type_t type)
+inline bool JERRY_ATTR_ALWAYS_INLINE
+ecma_is_normal_or_arrow_function (ecma_object_type_t type) /**< object type */
{
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
return (type == ECMA_OBJECT_TYPE_FUNCTION || type == ECMA_OBJECT_TYPE_ARROW_FUNCTION);
ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */
const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */
{
+ JERRY_ASSERT (ecma_is_lexical_environment (scope_p));
+
/* 1., 4., 13. */
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
function_object_size,
ECMA_OBJECT_TYPE_FUNCTION);
- ecma_deref_object (prototype_obj_p);
-
/* 2., 6., 7., 8. */
/*
* We don't setup [[Get]], [[Call]], [[Construct]], [[HasInstance]] for each function object.
arrow_function_object_size,
ECMA_OBJECT_TYPE_ARROW_FUNCTION);
- ecma_deref_object (prototype_obj_p);
-
-
ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_p;
ECMA_SET_NON_NULL_POINTER (arrow_func_p->scope_cp, scope_p);
sizeof (ecma_extended_object_t),
ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
- ecma_deref_object (prototype_obj_p);
-
/*
* [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION type.
*
*
* @return compiled code
*/
-inline const ecma_compiled_code_t * __attr_always_inline___
+inline const ecma_compiled_code_t * JERRY_ATTR_ALWAYS_INLINE
ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p) /**< function pointer */
{
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
*
* @return compiled code
*/
-inline const ecma_compiled_code_t * __attr_always_inline___
+inline const ecma_compiled_code_t * JERRY_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
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
/**
- * [[Call]] implementation for Function objects,
- * created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION)
- * or 15.3.4.5 (ECMA_OBJECT_TYPE_BOUND_FUNCTION),
- * and for built-in Function objects
- * from section 15 (ECMA_OBJECT_TYPE_FUNCTION).
+ * 15.3.5.3 implementation of [[HasInstance]] for Function objects
*
* @return ecma value
* Returned value must be freed with ecma_free_value
JERRY_ASSERT (func_obj_p != NULL
&& !ecma_is_lexical_environment (func_obj_p));
- if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
+ while (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
{
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
- /* 1. */
+ /* 1. 3. */
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p;
- ecma_object_t *target_func_obj_p;
- target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
- ext_function_p->u.bound_function.target_function);
-
- /* 3. */
- return ecma_op_object_has_instance (target_func_obj_p, value);
+ func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
+ ext_function_p->u.bound_function.target_function);
}
JERRY_ASSERT (ecma_is_normal_or_arrow_function (ecma_get_object_type (func_obj_p))
ecma_object_t *prototype_obj_p = ecma_get_object_from_value (prototype_obj_value);
JERRY_ASSERT (prototype_obj_p != NULL);
- bool result = false;
+ ecma_value_t result = ECMA_VALUE_FALSE;
while (true)
{
if (v_obj_p == prototype_obj_p)
{
- result = true;
+ result = ECMA_VALUE_TRUE;
break;
}
}
ecma_deref_object (prototype_obj_p);
- return ecma_make_boolean_value (result);
+ return result;
} /* ecma_op_function_has_instance */
+
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+/**
+ * Indicates whether the class has been invoked with 'new'.
+ */
+#define ECMA_CLASS_CONSTRUCT_FLAG ((uintptr_t) 0x01u)
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
+/**
+ * Sets the construct flag in the arguments list pointer.
+ *
+ * @return arguments list pointer with the construct flag
+ */
+static inline const ecma_value_t * JERRY_ATTR_ALWAYS_INLINE
+ecma_op_function_set_construct_flag (const ecma_value_t *arguments_list_p) /**< original arguments list pointer */
+{
+ /* Any ecma value list must be aligned to 4 byte. */
+ JERRY_ASSERT ((((uintptr_t) arguments_list_p) & 0x3) == 0);
+
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ arguments_list_p = (const ecma_value_t *)(((uintptr_t) arguments_list_p) | ECMA_CLASS_CONSTRUCT_FLAG);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
+ return arguments_list_p;
+} /* ecma_op_function_set_construct_flag */
+
+/**
+ * Clears the construct flag in the arguments list pointer.
+ *
+ * @return arguments list pointer without the construct flag
+ */
+static inline const ecma_value_t * JERRY_ATTR_ALWAYS_INLINE
+ecma_op_function_clear_construct_flag (const ecma_value_t *arguments_list_p) /**< modified arguments list pointer */
+{
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ arguments_list_p = (const ecma_value_t *)(((uintptr_t) arguments_list_p) & ~ECMA_CLASS_CONSTRUCT_FLAG);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
+ return arguments_list_p;
+} /* ecma_op_function_clear_construct_flag */
+
+/**
+ * Returns true if the construct flag is set.
+ *
+ * @return true, if construct flag is set, false otherwise
+ */
+static inline bool JERRY_ATTR_ALWAYS_INLINE
+ecma_op_function_has_construct_flag (const ecma_value_t *arguments_list_p) /**< modified arguments list pointer */
+{
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ return (((uintptr_t) arguments_list_p) & ECMA_CLASS_CONSTRUCT_FLAG);
+#else /* CONFIG_DISABLE_ES2015_CLASS */
+ JERRY_UNUSED (arguments_list_p);
+ return false;
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+} /* ecma_op_function_has_construct_flag */
+
+#ifndef CONFIG_DISABLE_ES2015
+/**
+ * Returns the closest declarative lexical enviroment to the super object bound lexical enviroment.
+ *
+ * @return the found lexical enviroment
+ */
+static ecma_object_t *
+ecma_op_find_super_declerative_lex_env (ecma_object_t *lex_env_p) /**< starting lexical enviroment */
+{
+ JERRY_ASSERT (lex_env_p);
+ JERRY_ASSERT (ecma_op_resolve_super_reference_value (lex_env_p));
+ JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) != ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
+
+ while (true)
+ {
+ ecma_object_t *lex_env_outer_p = ecma_get_lex_env_outer_reference (lex_env_p);
+
+ JERRY_ASSERT (lex_env_outer_p);
+
+ if (ecma_get_lex_env_type (lex_env_outer_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND)
+ {
+ JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
+ return lex_env_p;
+ }
+
+ lex_env_p = lex_env_outer_p;
+ }
+} /* ecma_op_find_super_declerative_lex_env */
+
+/**
+ * Returns with the current class this_binding property
+ *
+ * @return NULL - if the property was not found
+ * the found property - otherwise
+ */
+static ecma_property_t *
+ecma_op_get_class_this_binding_property (ecma_object_t *lex_env_p) /**< starting lexical enviroment */
+{
+ JERRY_ASSERT (lex_env_p);
+ JERRY_ASSERT (ecma_is_lexical_environment (lex_env_p));
+
+ lex_env_p = ecma_op_find_super_declerative_lex_env (lex_env_p);
+ ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING);
+ return ecma_find_named_property (lex_env_p, name_p);
+} /* ecma_op_get_class_this_binding_property */
+
+/**
+ * Checks whether the 'super(...)' has been called.
+ *
+ * @return true - if the 'super (...)' has been called
+ * false - otherwise
+ */
+inline bool JERRY_ATTR_PURE
+ecma_op_is_super_called (ecma_object_t *lex_env_p) /**< starting lexical enviroment */
+{
+ ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p);
+
+ JERRY_ASSERT (property_p);
+ return (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);
+} /* ecma_op_is_super_called */
+
+/**
+ * Sets the value of 'super(...)' has been called.
+ */
+inline void
+ecma_op_set_super_called (ecma_object_t *lex_env_p) /**< starting lexical enviroment */
+{
+ ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p);
+
+ JERRY_ASSERT (property_p);
+
+ JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL);
+ ECMA_CONVERT_INTERNAL_PROPERTY_TO_DATA_PROPERTY (property_p);
+} /* ecma_op_set_super_called */
+
+/**
+ * Sets the class context this_binding value.
+ */
+void
+ecma_op_set_class_this_binding (ecma_object_t *lex_env_p, /**< starting lexical enviroment */
+ ecma_value_t this_binding) /**< 'this' argument's value */
+{
+ JERRY_ASSERT (ecma_is_value_object (this_binding));
+ ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p);
+
+ ecma_property_value_t *value_p;
+
+ if (property_p)
+ {
+ JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);
+ value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
+ }
+ else
+ {
+ ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING);
+ value_p = ecma_create_named_data_property (lex_env_p, name_p, ECMA_PROPERTY_FLAG_WRITABLE, &property_p);
+ ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p);
+ }
+
+ value_p->value = this_binding;
+} /* ecma_op_set_class_this_binding */
+
+/**
+ * Gets the class context this binding value.
+ *
+ * @return the class context this binding value
+ */
+ecma_value_t
+ecma_op_get_class_this_binding (ecma_object_t *lex_env_p) /**< starting lexical enviroment */
+{
+ ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p);
+
+ JERRY_ASSERT (property_p);
+
+ ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
+
+ JERRY_ASSERT (ecma_is_value_object (value_p->value));
+ return value_p->value;
+} /* ecma_op_get_class_this_binding */
+
+/**
+ * Dummy external function for implicit constructor call.
+ *
+ * @return ECMA_VALUE_ERROR - TypeError
+ */
+ecma_value_t
+ecma_op_function_implicit_constructor_handler_cb (const ecma_value_t function_obj, /**< the function itself */
+ const ecma_value_t this_val, /**< this_arg of the function */
+ const ecma_value_t args_p[], /**< argument list */
+ const ecma_length_t args_count) /**< argument number */
+{
+ JERRY_UNUSED_4 (function_obj, this_val, args_p, args_count);
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'."));
+} /* ecma_op_function_implicit_constructor_handler_cb */
+
+/**
+ * Sets the completion value [[Prototype]] based on the this_arg value
+ */
+void
+ecma_op_set_class_prototype (ecma_value_t completion_value, /**< completion_value */
+ ecma_value_t this_arg) /**< this argument*/
+{
+ JERRY_ASSERT (ecma_is_value_object (completion_value));
+ JERRY_ASSERT (ecma_is_value_object (this_arg));
+
+ ecma_object_t *completion_obj_p = ecma_get_object_from_value (completion_value);
+ ecma_object_t *prototype_obj_p = ecma_get_object_prototype (ecma_get_object_from_value (this_arg));
+
+ JERRY_ASSERT (prototype_obj_p);
+ ECMA_SET_POINTER (completion_obj_p->prototype_or_outer_reference_cp, prototype_obj_p);
+} /* ecma_op_set_class_prototype */
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
/**
* [[Call]] implementation for Function objects,
* created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION)
&& !ecma_is_lexical_environment (func_obj_p));
JERRY_ASSERT (ecma_op_is_callable (ecma_make_object_value (func_obj_p)));
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
-
- if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION)
+ while (true)
{
- if (unlikely (ecma_get_object_is_builtin (func_obj_p)))
- {
- ret_value = ecma_builtin_dispatch_call (func_obj_p,
- this_arg_value,
- arguments_list_p,
- arguments_list_len);
- }
- else
+ ecma_object_type_t func_type = ecma_get_object_type (func_obj_p);
+
+ JERRY_ASSERT (func_type == ECMA_OBJECT_TYPE_FUNCTION
+ || func_type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION
+ || func_type == ECMA_OBJECT_TYPE_BOUND_FUNCTION
+ || !ecma_op_function_has_construct_flag (arguments_list_p));
+
+ if (func_type == ECMA_OBJECT_TYPE_FUNCTION)
{
+ if (JERRY_UNLIKELY (ecma_get_object_is_builtin (func_obj_p)))
+ {
+ JERRY_ASSERT (!ecma_op_function_has_construct_flag (arguments_list_p));
+
+ return ecma_builtin_dispatch_call (func_obj_p,
+ this_arg_value,
+ arguments_list_p,
+ arguments_list_len);
+ }
+
/* Entering Function Code (ECMA-262 v5, 10.4.3) */
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_obj_p;
ext_func_p->u.function.scope_cp);
/* 8. */
- ecma_value_t this_binding;
- bool is_strict;
- bool is_no_lex_env;
+ ecma_value_t this_binding = this_arg_value;
+ bool free_this_binding = false;
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;
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ bool is_class_constructor = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_CONSTRUCTOR) != 0;
- /* 1. */
- if (is_strict)
- {
- this_binding = ecma_copy_value (this_arg_value);
- }
- else if (ecma_is_value_undefined (this_arg_value)
- || ecma_is_value_null (this_arg_value))
+ if (is_class_constructor && !ecma_op_function_has_construct_flag (arguments_list_p))
{
- /* 2. */
- this_binding = ecma_make_object_value (ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL));
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'."));
}
- else
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
+ bool is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0;
+ bool is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) != 0;
+
+ /* 1. */
+ if (!is_strict)
{
- /* 3., 4. */
- this_binding = ecma_op_to_object (this_arg_value);
+ if (ecma_is_value_undefined (this_binding)
+ || ecma_is_value_null (this_binding))
+ {
+ /* 2. */
+ this_binding = ecma_make_object_value (ecma_builtin_get_global ());
+ }
+ else if (!ecma_is_value_object (this_binding))
+ {
+ /* 3., 4. */
+ this_binding = ecma_op_to_object (this_binding);
+ free_this_binding = true;
- JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (this_binding));
+ JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (this_binding));
+ }
}
+ arguments_list_p = ecma_op_function_clear_construct_flag (arguments_list_p);
+
/* 5. */
ecma_object_t *local_env_p;
if (is_no_lex_env)
arguments_list_len,
bytecode_data_p);
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (JERRY_UNLIKELY (is_class_constructor))
+ {
+ ecma_op_set_class_this_binding (local_env_p, this_binding);
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
}
- ret_value = vm_run (bytecode_data_p,
- this_binding,
- local_env_p,
- false,
- arguments_list_p,
- arguments_list_len);
+ ecma_value_t ret_value = vm_run (bytecode_data_p,
+ this_binding,
+ local_env_p,
+ ECMA_PARSE_NO_OPTS,
+ arguments_list_p,
+ arguments_list_len);
if (!is_no_lex_env)
{
ecma_deref_object (local_env_p);
}
- ecma_free_value (this_binding);
+ if (JERRY_UNLIKELY (free_this_binding))
+ {
+ ecma_free_value (this_binding);
+ }
+
+ return ret_value;
+ }
+ else if (func_type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)
+ {
+ ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p;
+
+ ecma_value_t ret_value = ext_func_obj_p->u.external_handler_cb (ecma_make_object_value (func_obj_p),
+ this_arg_value,
+ arguments_list_p,
+ arguments_list_len);
+
+ if (JERRY_UNLIKELY (ecma_is_value_error_reference (ret_value)))
+ {
+ JERRY_CONTEXT (error_value) = ecma_clear_error_reference (ret_value, true);
+ return ECMA_VALUE_ERROR;
+ }
+
+#ifdef JERRY_DEBUGGER
+ JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
+#endif /* JERRY_DEBUGGER */
+ return ret_value;
}
- }
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
- else if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_ARROW_FUNCTION)
- {
- /* Entering Function Code (ES2015, 9.2.1) */
- ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_obj_p;
+ else if (func_type == ECMA_OBJECT_TYPE_ARROW_FUNCTION)
+ {
+ /* Entering Function Code (ES2015, 9.2.1) */
+ ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_obj_p;
- ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t,
- arrow_func_p->scope_cp);
+ ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t,
+ arrow_func_p->scope_cp);
- bool is_no_lex_env;
+ bool is_no_lex_env;
- const ecma_compiled_code_t *bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p);
+ 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;
+ is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) != 0;
- ecma_object_t *local_env_p;
- if (is_no_lex_env)
- {
- local_env_p = scope_p;
- }
- else
- {
- local_env_p = ecma_create_decl_lex_env (scope_p);
+ ecma_object_t *local_env_p = scope_p;
- JERRY_ASSERT (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED));
- }
+ if (!is_no_lex_env)
+ {
+ local_env_p = ecma_create_decl_lex_env (scope_p);
- ret_value = vm_run (bytecode_data_p,
- arrow_func_p->this_binding,
- local_env_p,
- false,
- arguments_list_p,
- arguments_list_len);
+ JERRY_ASSERT (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED));
+ }
- if (!is_no_lex_env)
- {
- ecma_deref_object (local_env_p);
- }
- }
-#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
- else if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)
- {
- ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p;
+ ecma_value_t ret_value = vm_run (bytecode_data_p,
+ arrow_func_p->this_binding,
+ local_env_p,
+ ECMA_PARSE_NO_OPTS,
+ arguments_list_p,
+ arguments_list_len);
- ret_value = ext_func_obj_p->u.external_handler_cb (ecma_make_object_value (func_obj_p),
- this_arg_value,
- arguments_list_p,
- arguments_list_len);
+ if (!is_no_lex_env)
+ {
+ ecma_deref_object (local_env_p);
+ }
- if (unlikely (ecma_is_value_error_reference (ret_value)))
- {
- JERRY_CONTEXT (error_value) = ecma_clear_error_reference (ret_value, true);
- ret_value = ECMA_VALUE_ERROR;
+ return ret_value;
}
- else
- {
-#ifdef JERRY_DEBUGGER
- JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
-#endif /* JERRY_DEBUGGER */
- }
- }
- else
- {
+#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
+
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL;
/* 4. */
ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this;
- ecma_value_t bound_this_value;
ecma_length_t args_length;
if (!ecma_is_value_integer_number (args_len_or_this))
{
- bound_this_value = args_len_or_this;
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (JERRY_UNLIKELY (args_len_or_this == ECMA_VALUE_IMPLICIT_CONSTRUCTOR))
+ {
+ if (!ecma_op_function_has_construct_flag (arguments_list_p))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'."));
+ }
+ if (ecma_get_object_is_builtin (target_func_obj_p))
+ {
+ arguments_list_p = ecma_op_function_clear_construct_flag (arguments_list_p);
+ }
+ }
+ else
+ {
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+ this_arg_value = args_len_or_this;
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
args_length = 1;
}
else
{
- bound_this_value = *(ecma_value_t *) (ext_function_p + 1);
+ this_arg_value = *(ecma_value_t *) (ext_function_p + 1);
args_length = (ecma_length_t) ecma_get_integer_from_value (args_len_or_this);
}
JERRY_ASSERT (args_length > 0);
- if (args_length > 1)
+ if (args_length == 1)
{
- args_length--;
- ecma_length_t merged_args_list_len = args_length + arguments_list_len;
-
- JMEM_DEFINE_LOCAL_ARRAY (merged_args_list_p, merged_args_list_len, ecma_value_t);
-
- ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
-
- memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t));
- memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t));
-
- /* 5. */
- ret_value = ecma_op_function_call (target_func_obj_p,
- bound_this_value,
- merged_args_list_p,
- merged_args_list_len);
-
- JMEM_FINALIZE_LOCAL_ARRAY (merged_args_list_p);
- }
- else
- {
- /* 5. */
- ret_value = ecma_op_function_call (target_func_obj_p,
- bound_this_value,
- arguments_list_p,
- arguments_list_len);
+ func_obj_p = target_func_obj_p;
+ continue;
}
- }
- JERRY_ASSERT (!ecma_is_value_empty (ret_value));
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ arguments_list_p = ecma_op_function_clear_construct_flag (arguments_list_p);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
- return ret_value;
-} /* ecma_op_function_call */
+ JERRY_ASSERT (!ecma_op_function_has_construct_flag (arguments_list_p));
+ args_length--;
-/**
- * [[Construct]] implementation for Function objects (13.2.2),
- * created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) and
- * externally defined (host) functions (ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION).
- *
- * @return ecma value
- * Returned value must be freed with ecma_free_value
- */
-static ecma_value_t
-ecma_op_function_construct_simple_or_external (ecma_object_t *func_obj_p, /**< Function object */
- const ecma_value_t *arguments_list_p, /**< arguments list */
- ecma_length_t arguments_list_len) /**< length of arguments list */
-{
- JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION
- || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
+ ecma_length_t merged_args_list_len = args_length + arguments_list_len;
+ ecma_value_t ret_value;
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+ JMEM_DEFINE_LOCAL_ARRAY (merged_args_list_p, merged_args_list_len, ecma_value_t);
- /* 5. */
- ECMA_TRY_CATCH (func_obj_prototype_prop_value,
- ecma_op_object_get_by_magic_id (func_obj_p,
- LIT_MAGIC_STRING_PROTOTYPE),
- ret_value);
+ ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
- /* 1., 2., 4. */
- ecma_object_t *obj_p;
- if (ecma_is_value_object (func_obj_prototype_prop_value))
- {
- /* 6. */
- obj_p = ecma_create_object (ecma_get_object_from_value (func_obj_prototype_prop_value),
- 0,
- ECMA_OBJECT_TYPE_GENERAL);
- }
- else
- {
- /* 7. */
- ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
+ memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t));
+ memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t));
- obj_p = ecma_create_object (prototype_p, 0, ECMA_OBJECT_TYPE_GENERAL);
+ /* 5. */
+ ret_value = ecma_op_function_call (target_func_obj_p,
+ this_arg_value,
+ merged_args_list_p,
+ merged_args_list_len);
- ecma_deref_object (prototype_p);
- }
+ JMEM_FINALIZE_LOCAL_ARRAY (merged_args_list_p);
- /* 3. */
- /*
- * [[Class]] property of ECMA_OBJECT_TYPE_GENERAL type objects
- * without ECMA_INTERNAL_PROPERTY_CLASS internal property
- * is "Object".
- *
- * See also: ecma_object_get_class_name.
- */
-
- /* 8. */
- ECMA_TRY_CATCH (call_completion,
- ecma_op_function_call (func_obj_p,
- ecma_make_object_value (obj_p),
- arguments_list_p,
- arguments_list_len),
- ret_value);
-
- /* 9. */
- if (ecma_is_value_object (call_completion))
- {
- ret_value = ecma_copy_value (call_completion);
+ return ret_value;
}
- else
- {
- /* 10. */
- ecma_ref_object (obj_p);
- ret_value = ecma_make_object_value (obj_p);
- }
-
- ECMA_FINALIZE (call_completion);
-
- ecma_deref_object (obj_p);
-
- ECMA_FINALIZE (func_obj_prototype_prop_value);
-
- return ret_value;
-} /* ecma_op_function_construct_simple_or_external */
+} /* ecma_op_function_call */
/**
* [[Construct]] implementation:
*/
ecma_value_t
ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
+ ecma_value_t this_arg_value, /**< optional 'this' object value
+ * or ECMA_VALUE_UNDEFINED */
const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< length of arguments list */
{
JERRY_ASSERT (func_obj_p != NULL
&& !ecma_is_lexical_environment (func_obj_p));
- JERRY_ASSERT (ecma_is_constructor (ecma_make_object_value (func_obj_p)));
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+ JERRY_ASSERT (ecma_is_value_object (this_arg_value)
+ || this_arg_value == ECMA_VALUE_UNDEFINED);
- if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION)
+ ecma_object_t *target_func_obj_p = NULL;
+
+ while (JERRY_UNLIKELY (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION))
{
- if (unlikely (ecma_get_object_is_builtin (func_obj_p)
- && !ecma_builtin_function_is_routine (func_obj_p)))
+ /* 1-3. */
+ ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p;
+
+ target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
+ ext_function_p->u.bound_function.target_function);
+
+ /* 4. */
+ ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this;
+
+ ecma_length_t args_length = 1;
+
+ if (ecma_is_value_integer_number (args_len_or_this))
{
- ret_value = ecma_builtin_dispatch_construct (func_obj_p,
- arguments_list_p,
- arguments_list_len);
+ args_length = (ecma_length_t) ecma_get_integer_from_value (args_len_or_this);
}
- else
+
+ JERRY_ASSERT (args_length > 0);
+
+ /* 5. */
+ if (args_length == 1)
{
- ret_value = ecma_op_function_construct_simple_or_external (func_obj_p,
- arguments_list_p,
- arguments_list_len);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (args_len_or_this == ECMA_VALUE_IMPLICIT_CONSTRUCTOR && ecma_is_value_undefined (this_arg_value))
+ {
+ break;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+ func_obj_p = target_func_obj_p;
+ continue;
}
+
+ ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
+ ecma_value_t ret_value;
+
+ args_length--;
+ ecma_length_t merged_args_list_len = args_length + arguments_list_len;
+
+ JMEM_DEFINE_LOCAL_ARRAY (merged_args_list_p, merged_args_list_len, ecma_value_t);
+
+ memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t));
+ memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t));
+
+ /* 5. */
+ ret_value = ecma_op_function_construct (target_func_obj_p,
+ this_arg_value,
+ merged_args_list_p,
+ merged_args_list_len);
+
+ JMEM_FINALIZE_LOCAL_ARRAY (merged_args_list_p);
+
+ return ret_value;
}
- else if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)
+
+ ecma_object_type_t type = ecma_get_object_type (func_obj_p);
+
+#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
+ if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_ARROW_FUNCTION))
{
- ret_value = ecma_op_function_construct_simple_or_external (func_obj_p,
- arguments_list_p,
- arguments_list_len);
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Arrow functions have no constructor."));
}
- else
+#endif /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
+
+ if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_FUNCTION && ecma_get_object_is_builtin (func_obj_p)))
{
- JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
+ if (ecma_builtin_function_is_routine (func_obj_p))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Built-in routines have no constructor."));
+ }
- /* 1. */
- ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p;
+ ecma_value_t ret_value = ecma_builtin_dispatch_construct (func_obj_p,
+ arguments_list_p,
+ arguments_list_len);
- ecma_object_t *target_func_obj_p;
- target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
- ext_function_p->u.bound_function.target_function);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (!ecma_is_value_undefined (this_arg_value) && !ECMA_IS_VALUE_ERROR (ret_value))
+ {
+ ecma_op_set_class_prototype (ret_value, this_arg_value);
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
+ return ret_value;
+ }
+
+ ecma_object_t *new_this_obj_p = NULL;
+
+ if (JERRY_LIKELY (this_arg_value == ECMA_VALUE_UNDEFINED))
+ {
+ /* 5. */
+ ecma_value_t prototype_prop_value = ecma_op_object_get_by_magic_id (func_obj_p,
+ LIT_MAGIC_STRING_PROTOTYPE);
- /* 2. */
- if (!ecma_is_constructor (ecma_make_object_value (target_func_obj_p)))
+ if (ECMA_IS_VALUE_ERROR (prototype_prop_value))
{
- ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Expected a constructor."));
+ return prototype_prop_value;
+ }
+
+ /* 1., 2., 4. */
+ if (ecma_is_value_object (prototype_prop_value))
+ {
+ /* 6. */
+ new_this_obj_p = ecma_create_object (ecma_get_object_from_value (prototype_prop_value),
+ 0,
+ ECMA_OBJECT_TYPE_GENERAL);
}
else
{
- /* 4. */
- ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this;
+ /* 7. */
+ ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
- ecma_length_t args_length = 1;
+ new_this_obj_p = ecma_create_object (prototype_p, 0, ECMA_OBJECT_TYPE_GENERAL);
+ }
- if (ecma_is_value_integer_number (args_len_or_this))
- {
- args_length = (ecma_length_t) ecma_get_integer_from_value (args_len_or_this);
- }
+ ecma_free_value (prototype_prop_value);
- JERRY_ASSERT (args_length > 0);
+ this_arg_value = ecma_make_object_value (new_this_obj_p);
+ }
- if (args_length > 1)
- {
- ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
+ /* 8. */
+ ecma_value_t ret_value;
- args_length--;
- ecma_length_t merged_args_list_len = args_length + arguments_list_len;
+ switch (type)
+ {
+ case ECMA_OBJECT_TYPE_FUNCTION:
+ {
+ arguments_list_p = ecma_op_function_set_construct_flag (arguments_list_p);
- JMEM_DEFINE_LOCAL_ARRAY (merged_args_list_p, merged_args_list_len, ecma_value_t);
+ ret_value = ecma_op_function_call (func_obj_p,
+ this_arg_value,
+ arguments_list_p,
+ arguments_list_len);
+ break;
+ }
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
+ {
+ JERRY_ASSERT (!ecma_op_function_has_construct_flag (arguments_list_p));
+ JERRY_ASSERT (target_func_obj_p != NULL);
- memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t));
- memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t));
+ ret_value = ecma_op_function_construct (target_func_obj_p,
+ this_arg_value,
+ arguments_list_p,
+ arguments_list_len);
+ break;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+ default:
+ {
+ JERRY_ASSERT (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
- /* 5. */
- ret_value = ecma_op_function_construct (target_func_obj_p,
- merged_args_list_p,
- merged_args_list_len);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p;
- JMEM_FINALIZE_LOCAL_ARRAY (merged_args_list_p);
- }
- else
+ if (ext_func_obj_p->u.external_handler_cb == ecma_op_function_implicit_constructor_handler_cb)
{
- /* 5. */
- ret_value = ecma_op_function_construct (target_func_obj_p,
- arguments_list_p,
- arguments_list_len);
+ ret_value = ECMA_VALUE_UNDEFINED;
+ break;
}
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
+ ret_value = ecma_op_function_call (func_obj_p,
+ this_arg_value,
+ arguments_list_p,
+ arguments_list_len);
+ break;
}
}
- return ret_value;
+ /* 9. */
+ if (ECMA_IS_VALUE_ERROR (ret_value) || ecma_is_value_object (ret_value))
+ {
+ if (new_this_obj_p != NULL)
+ {
+ ecma_deref_object (new_this_obj_p);
+ }
+ return ret_value;
+ }
+
+ ecma_fast_free_value (ret_value);
+
+ if (JERRY_UNLIKELY (new_this_obj_p == NULL))
+ {
+ ecma_ref_object (ecma_get_object_from_value (this_arg_value));
+ }
+
+ return this_arg_value;
} /* ecma_op_function_construct */
/**
thrower_p,
ECMA_PROPERTY_FIXED,
&caller_prop_p);
-
- ecma_deref_object (thrower_p);
return caller_prop_p;
}
}
thrower_p,
ECMA_PROPERTY_FIXED,
&caller_prop_p);
-
- ecma_deref_object (thrower_p);
return caller_prop_p;
}
0);
const ecma_compiled_code_t *bytecode_data_p;
+
+#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
+ if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARROW_FUNCTION)
+ {
+ bytecode_data_p = ecma_op_arrow_function_get_compiled_code ((ecma_arrow_function_t *) object_p);
+ }
+ else
+ {
+ bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p);
+ }
+#else /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p);
+#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE)
{
const ecma_compiled_code_t *
ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+void
+ecma_op_set_super_called (ecma_object_t *lex_env_p);
+
+bool
+ecma_op_is_super_called (ecma_object_t *lex_env_p);
+
+void
+ecma_op_set_class_this_binding (ecma_object_t *lex_env_p, ecma_value_t this_binding);
+
+ecma_value_t
+ecma_op_get_class_this_binding (ecma_object_t *lex_env_p);
+
+ecma_value_t
+ecma_op_function_implicit_constructor_handler_cb (const ecma_value_t function_obj,
+ const ecma_value_t this_val,
+ const ecma_value_t args_p[],
+ const ecma_length_t args_count);
+
+void
+ecma_op_set_class_prototype (ecma_value_t completion_value, ecma_value_t this_arg);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
#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);
const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len);
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_op_function_construct (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);
ecma_property_t *
ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p);
const bool is_unresolvable_reference = (ref_base_lex_env_p == NULL);
/* 3. */
- if (unlikely (is_unresolvable_reference))
+ if (JERRY_UNLIKELY (is_unresolvable_reference))
{
#ifdef JERRY_ENABLE_ERROR_MESSAGES
ecma_value_t var_name_val = ecma_make_string_value (var_name_string_p);
const bool is_unresolvable_reference = (ref_base_lex_env_p == NULL);
/* 3. */
- if (unlikely (is_unresolvable_reference))
+ if (JERRY_UNLIKELY (is_unresolvable_reference))
{
/* 3.a. */
if (is_strict)
else
{
/* 3.b. */
- ecma_object_t *global_object_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL);
+ ecma_object_t *global_object_p = ecma_builtin_get_global ();
ecma_value_t completion = ecma_op_object_put (global_object_p,
var_name_string_p,
value,
false);
- ecma_deref_object (global_object_p);
-
JERRY_ASSERT (ecma_is_value_boolean (completion));
return ECMA_VALUE_EMPTY;
{
ecma_value_t promise; /**< promise to be resolved */
ecma_value_t thenable; /**< thenbale object */
- ecma_value_t then; /** 'then' function */
+ ecma_value_t then; /**< 'then' function */
} ecma_job_promise_resolve_thenable_t;
/**
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 *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);
+ ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
+ ecma_string_t *handler_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_HANDLER);
+ ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
+ ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
/* 2. */
ecma_value_t capability = ecma_op_object_get (reaction_p, capability_str_p);
void
ecma_init_global_lex_env (void)
{
-#ifdef CONFIG_ECMA_GLOBAL_ENVIRONMENT_DECLARATIVE
- JERRY_CONTEXT (ecma_global_lex_env_p) = ecma_create_decl_lex_env (NULL);
-#else /* !CONFIG_ECMA_GLOBAL_ENVIRONMENT_DECLARATIVE */
ecma_object_t *glob_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL);
- JERRY_CONTEXT (ecma_global_lex_env_p) = ecma_create_object_lex_env (NULL, glob_obj_p, false);
-
- ecma_deref_object (glob_obj_p);
-#endif /* CONFIG_ECMA_GLOBAL_ENVIRONMENT_DECLARATIVE */
+ JERRY_CONTEXT (ecma_global_lex_env_p) = ecma_create_object_lex_env (NULL,
+ glob_obj_p,
+ ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
} /* ecma_init_global_lex_env */
/**
JERRY_ASSERT (lex_env_p != NULL
&& ecma_is_lexical_environment (lex_env_p));
- if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
+ ecma_lexical_environment_type_t lex_env_type = ecma_get_lex_env_type (lex_env_p);
+
+ if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
}
else
{
- JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND
- || ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND
+ || lex_env_type == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
+#else /* CONFIG_DISABLE_ES2015_CLASS */
+ JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
}
else
{
- JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND
- || ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+ JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
completion = ecma_builtin_helper_def_prop (binding_obj_p,
name_p,
ECMA_VALUE_UNDEFINED,
- true, /* Writable */
- true, /* Enumerable */
- is_deletable, /* Configurable */
+ is_deletable ? ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE
+ : ECMA_PROPERTY_ENUMERABLE_WRITABLE,
true); /* Failure handling */
if (ECMA_IS_VALUE_ERROR (completion))
}
else
{
- JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND
- || ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+ JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
{
return completion;
}
- else
- {
- JERRY_ASSERT (ecma_is_value_boolean (completion));
- }
+
+ JERRY_ASSERT (ecma_is_value_boolean (completion));
}
return ECMA_VALUE_EMPTY;
}
else
{
- JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND
- || ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+ JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
}
else
{
- JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND
- || ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+ JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
}
else
{
- JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND
- || ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+ JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
- if (ecma_get_lex_env_provide_this (lex_env_p))
- {
- ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
- ecma_ref_object (binding_obj_p);
+ ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
+ ecma_ref_object (binding_obj_p);
- return ecma_make_object_value (binding_obj_p);
- }
- else
- {
- return ECMA_VALUE_UNDEFINED;
- }
+ return ecma_make_object_value (binding_obj_p);
}
} /* ecma_op_implicit_this_value */
/* ECMA-262 v5, Table 18. Additional methods of Declarative Environment Records */
void ecma_op_create_immutable_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, ecma_value_t value);
-ecma_object_t *ecma_op_create_global_environment (ecma_object_t *);
-
/**
* @}
* @}
--- /dev/null
+/* 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-builtins.h"
+#include "ecma-exceptions.h"
+#include "ecma-gc.h"
+#include "ecma-helpers.h"
+#include "ecma-map-object.h"
+#include "ecma-objects.h"
+
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+
+/** \addtogroup ecma ECMA
+ * @{
+ *
+ * \addtogroup \addtogroup ecmamaphelpers ECMA builtin map helper functions
+ * @{
+ */
+
+JERRY_STATIC_ASSERT (ECMA_MAP_OBJECT_ITEM_COUNT == 3,
+ ecma_map_object_item_count_must_be_3);
+
+/**
+ * Handle calling [[Construct]] of built-in map like objects
+ *
+ * @return ecma value
+ */
+ecma_value_t
+ecma_op_map_create (const ecma_value_t *arguments_list_p, /**< arguments list */
+ ecma_length_t arguments_list_len) /**< number of arguments */
+{
+ JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
+
+ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_MAP_PROTOTYPE);
+ ecma_object_t *object_p = ecma_create_object (prototype_obj_p,
+ sizeof (ecma_map_object_t),
+ ECMA_OBJECT_TYPE_CLASS);
+
+ ecma_map_object_t *map_object_p = (ecma_map_object_t *) object_p;
+ map_object_p->header.u.class_prop.class_id = LIT_MAGIC_STRING_MAP_UL;
+ map_object_p->header.u.class_prop.extra_info = 0;
+ map_object_p->header.u.class_prop.u.length = 0;
+ map_object_p->first_chunk_cp = ECMA_NULL_POINTER;
+ map_object_p->last_chunk_cp = ECMA_NULL_POINTER;
+
+ return ecma_make_object_value (object_p);
+} /* ecma_op_map_create */
+
+/**
+ * Get map object pointer
+ *
+ * Note:
+ * If the function returns with NULL, the error object has
+ * already set, and the caller must return with ECMA_VALUE_ERROR
+ *
+ * @return pointer to the map if this_arg is a valid map object
+ * NULL otherwise
+ */
+static ecma_map_object_t *
+ecma_op_map_get_object (ecma_value_t this_arg) /**< this argument */
+{
+ if (ecma_is_value_object (this_arg))
+ {
+ ecma_map_object_t *map_object_p = (ecma_map_object_t *) ecma_get_object_from_value (this_arg);
+
+ if (ecma_get_object_type (&map_object_p->header.object) == ECMA_OBJECT_TYPE_CLASS
+ && map_object_p->header.u.class_prop.class_id == LIT_MAGIC_STRING_MAP_UL)
+ {
+ return map_object_p;
+ }
+ }
+
+ ecma_raise_type_error (ECMA_ERR_MSG ("Expected a Map object."));
+ return NULL;
+} /* ecma_op_map_get_object */
+
+/**
+ * Returns with the size of the map object.
+ *
+ * @return size of the map object as ecma-value.
+ */
+ecma_value_t
+ecma_op_map_size (ecma_value_t this_arg) /**< this argument */
+{
+ ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg);
+ if (map_object_p == NULL)
+ {
+ return ECMA_VALUE_ERROR;
+ }
+
+ return ecma_make_uint32_value (map_object_p->header.u.class_prop.u.length);
+} /* ecma_op_map_size */
+
+/**
+ * Linear search for the value in the map storage
+ *
+ * @return pointer to value if key is found
+ * NULL otherwise
+ */
+static ecma_value_t *
+ecma_builtin_map_search (jmem_cpointer_t first_chunk_cp, /**< first chunk */
+ ecma_value_t key) /**< key to search */
+{
+ if (JERRY_UNLIKELY (first_chunk_cp == ECMA_NULL_POINTER))
+ {
+ return NULL;
+ }
+
+ ecma_map_object_chunk_t *chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_map_object_chunk_t,
+ first_chunk_cp);
+
+ bool is_direct = true;
+ const ecma_string_t *key_str_p = NULL;
+ ecma_number_t key_float = 0;
+
+ if (ecma_is_value_non_direct_string (key))
+ {
+ key_str_p = ecma_get_string_from_value (key);
+ is_direct = false;
+ }
+ else if (ecma_is_value_float_number (key))
+ {
+ key_float = ecma_get_float_from_value (key);
+ is_direct = false;
+ }
+
+ ecma_value_t *item_p = chunk_p->items;
+ ecma_value_t last_key = ECMA_VALUE_ARRAY_HOLE;
+
+ while (true)
+ {
+ ecma_value_t item = *item_p++;
+
+ if (JERRY_UNLIKELY (item == ECMA_VALUE_ARRAY_HOLE))
+ {
+ JERRY_ASSERT (last_key == ECMA_VALUE_ARRAY_HOLE);
+ continue;
+ }
+
+ if (JERRY_UNLIKELY (ecma_is_value_pointer (item)))
+ {
+ item_p = (ecma_value_t *) ecma_get_pointer_from_value (item);
+
+ if (item_p == NULL)
+ {
+ JERRY_ASSERT (last_key == ECMA_VALUE_ARRAY_HOLE);
+ return NULL;
+ }
+
+ JERRY_ASSERT (!ecma_is_value_pointer (*item_p));
+ continue;
+ }
+
+ if (last_key == ECMA_VALUE_ARRAY_HOLE)
+ {
+ last_key = item;
+ }
+ else
+ {
+ if (JERRY_LIKELY (is_direct))
+ {
+ if (key == last_key)
+ {
+ return item_p - 1;
+ }
+ }
+ else if (key_str_p != NULL)
+ {
+ if (ecma_is_value_non_direct_string (last_key)
+ && ecma_compare_ecma_non_direct_strings (key_str_p, ecma_get_string_from_value (last_key)))
+ {
+ return item_p - 1;
+ }
+ }
+ else if (ecma_is_value_float_number (last_key)
+ && ecma_get_float_from_value (last_key) == key_float)
+ {
+ return item_p - 1;
+ }
+
+ last_key = ECMA_VALUE_ARRAY_HOLE;
+ }
+ }
+} /* ecma_builtin_map_search */
+
+/**
+ * The generic map prototype object's 'get' routine
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_op_map_get (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t key_arg) /**< key argument */
+{
+ ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg);
+ if (map_object_p == NULL)
+ {
+ return ECMA_VALUE_ERROR;
+ }
+
+ ecma_value_t *value_p = ecma_builtin_map_search (map_object_p->first_chunk_cp, key_arg);
+
+ if (value_p == NULL)
+ {
+ return ECMA_VALUE_UNDEFINED;
+ }
+
+ return ecma_copy_value (*value_p);
+} /* ecma_op_map_get */
+
+/**
+ * The generic map prototype object's 'has' routine
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_op_map_has (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t key_arg) /**< key argument */
+{
+ ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg);
+ if (map_object_p == NULL)
+ {
+ return ECMA_VALUE_ERROR;
+ }
+
+ return ecma_make_boolean_value (ecma_builtin_map_search (map_object_p->first_chunk_cp, key_arg) != NULL);
+} /* ecma_op_map_has */
+
+/**
+ * The generic map prototype object's 'set' routine
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_op_map_set (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t key_arg, /**< key argument */
+ ecma_value_t value_arg) /**< value argument */
+{
+ ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg);
+ if (map_object_p == NULL)
+ {
+ return ECMA_VALUE_ERROR;
+ }
+
+ ecma_value_t *value_p = ecma_builtin_map_search (map_object_p->first_chunk_cp, key_arg);
+
+ if (value_p == NULL)
+ {
+ ecma_value_t *key_p = NULL;
+ ecma_map_object_chunk_t *last_chunk_p = ECMA_GET_POINTER (ecma_map_object_chunk_t,
+ map_object_p->last_chunk_cp);
+
+ if (last_chunk_p != NULL)
+ {
+ if (last_chunk_p->items[2] == ECMA_VALUE_ARRAY_HOLE)
+ {
+ key_p = last_chunk_p->items + 2;
+
+ if (last_chunk_p->items[1] == ECMA_VALUE_ARRAY_HOLE)
+ {
+ key_p = last_chunk_p->items + 1;
+ value_p = last_chunk_p->items + 2;
+ }
+ }
+ }
+
+ if (key_p == NULL || value_p == NULL)
+ {
+ size_t size = sizeof (ecma_map_object_chunk_t);
+ ecma_map_object_chunk_t *new_chunk_p = (ecma_map_object_chunk_t *) jmem_heap_alloc_block (size);
+
+ new_chunk_p->items[ECMA_MAP_OBJECT_ITEM_COUNT] = ecma_make_pointer_value (NULL);
+
+ for (int i = 0; i < ECMA_MAP_OBJECT_ITEM_COUNT; i++)
+ {
+ new_chunk_p->items[i] = ECMA_VALUE_ARRAY_HOLE;
+ }
+
+ ECMA_SET_NON_NULL_POINTER (map_object_p->last_chunk_cp, new_chunk_p);
+
+ if (last_chunk_p == NULL)
+ {
+ map_object_p->first_chunk_cp = map_object_p->last_chunk_cp;
+ }
+ else
+ {
+ last_chunk_p->items[ECMA_MAP_OBJECT_ITEM_COUNT] = ecma_make_pointer_value (new_chunk_p);
+ }
+
+ if (key_p == NULL)
+ {
+ JERRY_ASSERT (value_p == NULL);
+ key_p = new_chunk_p->items + 0;
+ value_p = new_chunk_p->items + 1;
+ }
+ else
+ {
+ value_p = new_chunk_p->items + 0;
+ }
+ }
+
+ *key_p = ecma_copy_value_if_not_object (key_arg);
+ map_object_p->header.u.class_prop.u.length++;
+ }
+ else
+ {
+ ecma_free_value_if_not_object (*value_p);
+ }
+
+ *value_p = ecma_copy_value_if_not_object (value_arg);
+
+ ecma_ref_object (&map_object_p->header.object);
+ return this_arg;
+} /* ecma_op_map_set */
+
+/**
+ * Low-level function to clear all items from a map
+ */
+void
+ecma_op_map_clear_map (ecma_map_object_t *map_object_p) /**< map object */
+{
+ JERRY_ASSERT (ecma_get_object_type (&map_object_p->header.object) == ECMA_OBJECT_TYPE_CLASS
+ && (map_object_p->header.u.class_prop.class_id == LIT_MAGIC_STRING_MAP_UL));
+
+ jmem_cpointer_t first_chunk_cp = map_object_p->first_chunk_cp;
+
+ if (JERRY_UNLIKELY (first_chunk_cp == ECMA_NULL_POINTER))
+ {
+ return;
+ }
+
+ ecma_map_object_chunk_t *chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_map_object_chunk_t,
+ first_chunk_cp);
+
+ do
+ {
+ ecma_value_t *current_p = chunk_p->items;
+ ecma_value_t *last_p = current_p + ECMA_MAP_OBJECT_ITEM_COUNT;
+
+ do
+ {
+ ecma_free_value_if_not_object (*current_p++);
+ }
+ while (current_p < last_p);
+
+ ecma_value_t next = *current_p;
+
+ jmem_heap_free_block (chunk_p, sizeof (ecma_map_object_chunk_t));
+
+ chunk_p = (ecma_map_object_chunk_t *) ecma_get_pointer_from_value (next);
+ }
+ while (chunk_p != NULL);
+
+ map_object_p->header.u.class_prop.u.length = 0;
+ map_object_p->first_chunk_cp = ECMA_NULL_POINTER;
+ map_object_p->last_chunk_cp = ECMA_NULL_POINTER;
+} /* ecma_op_map_clear_map */
+
+/**
+ * The Map prototype object's 'clear' routine
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_op_map_clear (ecma_value_t this_arg) /**< this argument */
+{
+ /* WeakMap does not have a clear method. */
+ ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg);
+ if (map_object_p == NULL)
+ {
+ return ECMA_VALUE_ERROR;
+ }
+
+ ecma_op_map_clear_map (map_object_p);
+ return ECMA_VALUE_UNDEFINED;
+} /* ecma_op_map_clear */
+
+/**
+ * Deletes the current chunk if it is filled with ECMA_VALUE_ARRAY_HOLE.
+ *
+ * @return next chunk if the chunk is deleted, NULL otherwise
+ */
+static ecma_map_object_chunk_t *
+ecma_op_map_delete_chunk (ecma_map_object_t *map_object_p, /**< map object */
+ ecma_map_object_chunk_t *chunk_p, /**< current chunk */
+ ecma_map_object_chunk_t *prev_chunk_p) /**< previous chunk */
+{
+ for (int i = 0; i < ECMA_MAP_OBJECT_ITEM_COUNT; i++)
+ {
+ JERRY_ASSERT (!ecma_is_value_pointer (chunk_p->items[i]));
+
+ if (chunk_p->items[i] != ECMA_VALUE_ARRAY_HOLE)
+ {
+ return NULL;
+ }
+ }
+
+ ecma_value_t next_chunk = chunk_p->items[ECMA_MAP_OBJECT_ITEM_COUNT];
+ ecma_map_object_chunk_t *next_chunk_p = (ecma_map_object_chunk_t *) ecma_get_pointer_from_value (next_chunk);
+
+ jmem_heap_free_block (chunk_p, sizeof (ecma_map_object_chunk_t));
+
+ if (prev_chunk_p != NULL)
+ {
+ prev_chunk_p->items[ECMA_MAP_OBJECT_ITEM_COUNT] = ecma_make_pointer_value (next_chunk_p);
+
+ if (next_chunk_p == NULL)
+ {
+ JERRY_ASSERT (map_object_p->first_chunk_cp != map_object_p->last_chunk_cp);
+ JERRY_ASSERT (ECMA_GET_NON_NULL_POINTER (ecma_map_object_chunk_t, map_object_p->last_chunk_cp) == chunk_p);
+
+ ECMA_SET_POINTER (map_object_p->last_chunk_cp, prev_chunk_p);
+ }
+ return next_chunk_p;
+ }
+
+ if (next_chunk_p == NULL)
+ {
+ JERRY_ASSERT (map_object_p->first_chunk_cp == map_object_p->last_chunk_cp);
+ JERRY_ASSERT (ECMA_GET_NON_NULL_POINTER (ecma_map_object_chunk_t, map_object_p->last_chunk_cp) == chunk_p);
+
+ map_object_p->first_chunk_cp = ECMA_NULL_POINTER;
+ map_object_p->last_chunk_cp = ECMA_NULL_POINTER;
+ return next_chunk_p;
+ }
+
+ ECMA_SET_POINTER (map_object_p->first_chunk_cp, next_chunk_p);
+ return next_chunk_p;
+} /* ecma_op_map_delete_chunk */
+
+/**
+ * The generic map prototype object's 'delete' routine
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_op_map_delete (ecma_value_t this_arg, /**< this argument */
+ ecma_value_t key_arg) /**< key argument */
+{
+ ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg);
+ if (map_object_p == NULL)
+ {
+ return ECMA_VALUE_ERROR;
+ }
+
+ if (JERRY_UNLIKELY (map_object_p->first_chunk_cp == ECMA_NULL_POINTER))
+ {
+ return ECMA_VALUE_FALSE;
+ }
+
+ ecma_map_object_chunk_t *chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_map_object_chunk_t,
+ map_object_p->first_chunk_cp);
+
+ bool is_direct = true;
+ const ecma_string_t *key_str_p = NULL;
+ ecma_number_t key_float = 0;
+
+ if (ecma_is_value_non_direct_string (key_arg))
+ {
+ key_str_p = ecma_get_string_from_value (key_arg);
+ is_direct = false;
+ }
+ else if (ecma_is_value_float_number (key_arg))
+ {
+ key_float = ecma_get_float_from_value (key_arg);
+ is_direct = false;
+ }
+
+ ecma_map_object_chunk_t *prev_chunk_p = NULL;
+ ecma_value_t *item_p = chunk_p->items;
+ bool is_key = true;
+
+ while (true)
+ {
+ ecma_value_t item = *item_p++;
+
+ if (JERRY_UNLIKELY (item == ECMA_VALUE_ARRAY_HOLE))
+ {
+ JERRY_ASSERT (is_key);
+ continue;
+ }
+
+ if (JERRY_UNLIKELY (ecma_is_value_pointer (item)))
+ {
+ prev_chunk_p = chunk_p;
+ chunk_p = (ecma_map_object_chunk_t *) ecma_get_pointer_from_value (item);
+
+ if (chunk_p == NULL)
+ {
+ JERRY_ASSERT (is_key);
+ return ECMA_VALUE_FALSE;
+ }
+
+ item_p = chunk_p->items;
+
+ JERRY_ASSERT (!ecma_is_value_pointer (*item_p));
+ continue;
+ }
+
+ if (is_key)
+ {
+ if (JERRY_LIKELY (is_direct))
+ {
+ if (key_arg == item)
+ {
+ break;
+ }
+ }
+ else if (key_str_p != NULL)
+ {
+ if (ecma_is_value_non_direct_string (item)
+ && ecma_compare_ecma_non_direct_strings (key_str_p, ecma_get_string_from_value (item)))
+ {
+ break;
+ }
+ }
+ else if (ecma_is_value_float_number (item)
+ && ecma_get_float_from_value (item) == key_float)
+ {
+ break;
+ }
+ }
+
+ is_key = !is_key;
+ }
+
+ map_object_p->header.u.class_prop.u.length--;
+
+ item_p -= 1;
+ ecma_free_value_if_not_object (item_p[0]);
+ item_p[0] = ECMA_VALUE_ARRAY_HOLE;
+
+ if ((item_p - chunk_p->items) < ECMA_MAP_OBJECT_ITEM_COUNT - 1)
+ {
+ JERRY_ASSERT (!ecma_is_value_pointer (item_p[1]));
+
+ ecma_free_value_if_not_object (item_p[1]);
+ item_p[1] = ECMA_VALUE_ARRAY_HOLE;
+
+ ecma_op_map_delete_chunk (map_object_p, chunk_p, prev_chunk_p);
+ return ECMA_VALUE_TRUE;
+ }
+
+ ecma_map_object_chunk_t *next_chunk_p = ecma_op_map_delete_chunk (map_object_p, chunk_p, prev_chunk_p);
+
+ if (next_chunk_p == NULL)
+ {
+ prev_chunk_p = chunk_p;
+
+ ecma_value_t next_chunk = chunk_p->items[ECMA_MAP_OBJECT_ITEM_COUNT];
+ next_chunk_p = (ecma_map_object_chunk_t *) ecma_get_pointer_from_value (next_chunk);
+ }
+
+ ecma_free_value_if_not_object (next_chunk_p->items[0]);
+ next_chunk_p->items[0] = ECMA_VALUE_ARRAY_HOLE;
+
+ ecma_op_map_delete_chunk (map_object_p, next_chunk_p, prev_chunk_p);
+
+ return ECMA_VALUE_TRUE;
+} /* ecma_op_map_delete */
+
+/**
+ * @}
+ * @}
+ */
+
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ECMA_MAP_OBJECT_H
+#define ECMA_MAP_OBJECT_H
+
+#include "ecma-globals.h"
+
+#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN
+
+/** \addtogroup ecma ECMA
+ * @{
+ *
+ * \addtogroup ecmamaphelpers ECMA builtin map helper functions
+ * @{
+ */
+
+ecma_value_t ecma_op_map_create (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len);
+ecma_value_t ecma_op_map_size (ecma_value_t this_arg);
+ecma_value_t ecma_op_map_get (ecma_value_t this_arg, ecma_value_t key_arg);
+ecma_value_t ecma_op_map_has (ecma_value_t this_arg, ecma_value_t key_arg);
+ecma_value_t ecma_op_map_set (ecma_value_t this_arg, ecma_value_t key_arg, ecma_value_t value_arg);
+void ecma_op_map_clear_map (ecma_map_object_t *map_object_p);
+ecma_value_t ecma_op_map_clear (ecma_value_t this_arg);
+ecma_value_t ecma_op_map_delete (ecma_value_t this_arg, ecma_value_t key_arg);
+
+/**
+ * @}
+ * @}
+ */
+
+#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */
+
+#endif /* !ECMA_MAP_OBJECT_H */
sizeof (ecma_extended_object_t),
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.class_id = LIT_MAGIC_STRING_NUMBER_UL;
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
-#include "ecma-lcache.h"
#include "ecma-lex-env.h"
#include "ecma-objects.h"
#include "ecma-objects-arguments.h"
ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_ARGUMENTS_UL;
}
- ecma_deref_object (prototype_p);
-
ecma_property_value_t *prop_value_p;
/* 11.a, 11.b */
&prop_desc,
false);
JERRY_ASSERT (ecma_is_value_true (completion));
-
- ecma_deref_object (thrower_p);
}
ecma_string_t *arguments_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
ecma_object_t *object_prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
/* 3., 4., 6., 7. */
- ecma_object_t *obj_p = ecma_op_create_object_object_noarg_and_set_prototype (object_prototype_p);
-
- ecma_deref_object (object_prototype_p);
-
- return obj_p;
+ return ecma_op_create_object_object_noarg_and_set_prototype (object_prototype_p);
} /* ecma_op_create_object_object_noarg */
/**
/* b. */
return ECMA_VALUE_TRUE;
}
- else if (is_throw)
+
+ /* 4. */
+ if (is_throw)
{
- /* 4. */
return ecma_raise_type_error (ECMA_ERR_MSG ("Expected a configurable property."));
}
- else
- {
- /* 5. */
- return ECMA_VALUE_FALSE;
- }
- JERRY_UNREACHABLE ();
+ /* 5. */
+ return ECMA_VALUE_FALSE;
} /* ecma_op_general_object_delete */
/**
{
/* No action required. */
}
- else if (likely (property_desc_type == current_property_type))
+ else if (JERRY_LIKELY (property_desc_type == current_property_type))
{
/* If property is configurable, there is no need for checks. */
- if (unlikely (!is_current_configurable))
+ if (JERRY_UNLIKELY (!is_current_configurable))
{
if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDDATA)
{
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-function-object.h"
-#include "ecma-lcache.h"
#include "ecma-lex-env.h"
#include "ecma-string-object.h"
#include "ecma-objects-arguments.h"
{
uint32_t index = ecma_string_get_array_index (property_name_p);
- if (index != ECMA_STRING_NOT_ARRAY_INDEX)
+ if (index != ECMA_STRING_NOT_ARRAY_INDEX
+ && index < ext_object_p->u.pseudo_array.u1.length)
{
- if (index < ext_object_p->u.pseudo_array.u1.length)
- {
- ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1);
+ ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1);
- if (arg_Literal_p[index] != ECMA_VALUE_EMPTY)
- {
- ecma_string_t *arg_name_p = ecma_get_string_from_value (arg_Literal_p[index]);
+ if (arg_Literal_p[index] != ECMA_VALUE_EMPTY)
+ {
+ 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);
+ ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
+ ext_object_p->u.pseudo_array.u2.lex_env_cp);
- JERRY_ASSERT (lex_env_p != NULL
- && ecma_is_lexical_environment (lex_env_p));
+ JERRY_ASSERT (lex_env_p != NULL
+ && ecma_is_lexical_environment (lex_env_p));
- ecma_value_t binding_value = ecma_op_get_binding_value (lex_env_p, arg_name_p, true);
+ ecma_value_t binding_value = ecma_op_get_binding_value (lex_env_p, arg_name_p, true);
- ecma_named_data_property_assign_value (object_p,
- ECMA_PROPERTY_VALUE_PTR (property_p),
- binding_value);
- ecma_free_value (binding_value);
- }
+ ecma_named_data_property_assign_value (object_p,
+ ECMA_PROPERTY_VALUE_PTR (property_p),
+ binding_value);
+ ecma_free_value (binding_value);
}
}
}
* @return pointer to a property - if it exists,
* NULL (i.e. ecma-undefined) - otherwise.
*/
-ecma_property_t
+static ecma_property_t
ecma_op_object_get_property (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p, /**< property name */
ecma_property_ref_t *property_ref_p, /**< property reference */
* @return true - if property is found
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_op_object_has_own_property (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p) /**< property name */
{
* @return true - if property is found
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_op_object_has_property (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p) /**< property name */
{
{
uint32_t index = ecma_string_get_array_index (property_name_p);
- if (index != ECMA_STRING_NOT_ARRAY_INDEX)
+ if (index != ECMA_STRING_NOT_ARRAY_INDEX
+ && index < ext_object_p->u.pseudo_array.u1.length)
{
- if (index < ext_object_p->u.pseudo_array.u1.length)
- {
- ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1);
+ ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1);
- if (arg_Literal_p[index] != ECMA_VALUE_EMPTY)
- {
- ecma_string_t *arg_name_p = ecma_get_string_from_value (arg_Literal_p[index]);
+ if (arg_Literal_p[index] != ECMA_VALUE_EMPTY)
+ {
+ 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);
+ ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
+ ext_object_p->u.pseudo_array.u2.lex_env_cp);
- JERRY_ASSERT (lex_env_p != NULL
- && ecma_is_lexical_environment (lex_env_p));
+ JERRY_ASSERT (lex_env_p != NULL
+ && ecma_is_lexical_environment (lex_env_p));
- return ecma_op_get_binding_value (lex_env_p, arg_name_p, true);
- }
+ return ecma_op_get_binding_value (lex_env_p, arg_name_p, true);
}
}
}
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
-inline ecma_value_t __attr_always_inline___
+inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_op_object_get_own_data_prop (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p) /**< property name */
{
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
-inline ecma_value_t __attr_always_inline___
+inline ecma_value_t JERRY_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 */
{
{
uint32_t index = ecma_string_get_array_index (property_name_p);
- if (index != ECMA_STRING_NOT_ARRAY_INDEX)
+ if (index != ECMA_STRING_NOT_ARRAY_INDEX
+ && index < ext_object_p->u.pseudo_array.u1.length)
{
- if (index < ext_object_p->u.pseudo_array.u1.length)
- {
- ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1);
+ ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1);
- if (arg_Literal_p[index] != ECMA_VALUE_EMPTY)
- {
- ecma_string_t *arg_name_p = ecma_get_string_from_value (arg_Literal_p[index]);
+ if (arg_Literal_p[index] != ECMA_VALUE_EMPTY)
+ {
+ 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);
+ ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
+ ext_object_p->u.pseudo_array.u2.lex_env_cp);
- JERRY_ASSERT (lex_env_p != NULL
- && ecma_is_lexical_environment (lex_env_p));
+ JERRY_ASSERT (lex_env_p != NULL
+ && ecma_is_lexical_environment (lex_env_p));
- ecma_op_set_mutable_binding (lex_env_p, arg_name_p, value, true);
- return ECMA_VALUE_TRUE;
- }
+ ecma_op_set_mutable_binding (lex_env_p, arg_name_p, value, true);
+ return ECMA_VALUE_TRUE;
}
}
}
return ecma_builtin_helper_def_prop (object_p,
property_name_p,
value,
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
- is_throw); /* Failure handling */
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
+ true); /* Failure handling */
}
}
is_throw);
}
- case ECMA_OBJECT_TYPE_PSEUDO_ARRAY:
+ default:
{
+ JERRY_ASSERT (type == ECMA_OBJECT_TYPE_PSEUDO_ARRAY);
+
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
+#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
if (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS)
{
+#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
+ JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS);
+#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
return ecma_op_arguments_object_define_own_property (obj_p,
property_name_p,
property_desc_p,
is_throw);
- }
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
+ }
/* ES2015 9.4.5.3 */
if (ecma_is_typedarray (ecma_make_object_value (obj_p)))
{
property_name_p,
property_desc_p,
is_throw);
-
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
break;
}
- default:
- {
- JERRY_ASSERT (false);
- }
}
-
- JERRY_UNREACHABLE ();
-
- return ecma_reject (is_throw);
} /* ecma_op_object_define_own_property */
/**
*
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 9
+ *
+ * @return ecma value containing a boolean value or an error
+ * Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_object_has_instance (ecma_object_t *obj_p, /**< the object */
*/
ecma_collection_header_t *
ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */
- bool is_array_indices_only, /**< true - exclude properties with names
- * that are not indices */
- bool is_enumerable_only, /**< true - exclude non-enumerable properties */
- bool is_with_prototype_chain) /**< true - list properties from prototype chain,
- * false - list only own properties */
+ uint32_t opts) /**< any combination of ecma_list_properties_options_t values */
{
JERRY_ASSERT (obj_p != NULL
&& !ecma_is_lexical_environment (obj_p));
const ecma_object_type_t type = ecma_get_object_type (obj_p);
const bool obj_is_builtin = ecma_get_object_is_builtin (obj_p);
+ const bool is_enumerable_only = (const bool) (opts & ECMA_LIST_ENUMERABLE);
+ const bool is_array_indices_only = (const bool) (opts & ECMA_LIST_ARRAY_INDICES);
+ const bool is_with_prototype_chain = (const bool) (opts & ECMA_LIST_PROTOTYPE);
const size_t bitmap_row_size = sizeof (uint32_t) * JERRY_BITSINBYTE;
- uint32_t names_hashes_bitmap[ECMA_OBJECT_HASH_BITMAP_SIZE / bitmap_row_size];
+ const size_t names_hashes_bitmap_size = ECMA_OBJECT_HASH_BITMAP_SIZE / bitmap_row_size;
+ JERRY_VLA (uint32_t, names_hashes_bitmap, names_hashes_bitmap_size);
- memset (names_hashes_bitmap, 0, sizeof (names_hashes_bitmap));
+ memset (names_hashes_bitmap, 0, names_hashes_bitmap_size * sizeof (names_hashes_bitmap[0]));
for (ecma_object_t *prototype_chain_iter_p = obj_p;
prototype_chain_iter_p != NULL;
{
switch (type)
{
- case ECMA_OBJECT_TYPE_GENERAL:
- {
- break;
- }
case ECMA_OBJECT_TYPE_PSEUDO_ARRAY:
{
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
}
default:
{
- JERRY_UNREACHABLE ();
+ JERRY_ASSERT (type == ECMA_OBJECT_TYPE_GENERAL);
+
break;
}
}
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));
+ const size_t own_names_hashes_bitmap_size = ECMA_OBJECT_HASH_BITMAP_SIZE / bitmap_row_size;
+ JERRY_VLA (uint32_t, own_names_hashes_bitmap, own_names_hashes_bitmap_size);
+ memset (own_names_hashes_bitmap, 0, own_names_hashes_bitmap_size * sizeof (own_names_hashes_bitmap[0]));
while (ecma_value_p != NULL)
{
/**
* The function is used in the assert of ecma_object_get_class_name
+ *
+ * @return true - if class name is an object
+ * false - otherwise
*/
inline static bool
ecma_object_check_class_name_is_object (ecma_object_t *obj_p) /**< object */
case ECMA_OBJECT_TYPE_CLASS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
- return ext_object_p->u.class_prop.class_id;
+ return (lit_magic_string_id_t) ext_object_p->u.class_prop.class_id;
}
case ECMA_OBJECT_TYPE_PSEUDO_ARRAY:
{
switch (ext_obj_p->u.pseudo_array.type)
{
- case ECMA_PSEUDO_ARRAY_ARGUMENTS:
- {
- return LIT_MAGIC_STRING_ARGUMENTS_UL;
- }
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
case ECMA_PSEUDO_ARRAY_TYPEDARRAY:
case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO:
{
- return ext_obj_p->u.pseudo_array.u1.class_id;
+ return (lit_magic_string_id_t) ext_obj_p->u.pseudo_array.u1.class_id;
}
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
default:
{
- JERRY_UNREACHABLE ();
+ JERRY_ASSERT (ext_obj_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS);
+
+ return LIT_MAGIC_STRING_ARGUMENTS_UL;
}
}
- JERRY_UNREACHABLE ();
break;
}
case ECMA_OBJECT_TYPE_FUNCTION:
* @return value of the object if the class matches
* ECMA_VALUE_NOT_FOUND otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_object_class_is (ecma_object_t *object_p, /**< object */
uint32_t class_id) /**< class id */
{
ecma_property_t ecma_op_object_get_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p,
ecma_property_ref_t *property_ref_p, uint32_t options);
-ecma_property_t ecma_op_object_get_property (ecma_object_t *object_p, ecma_string_t *property_name_p,
- ecma_property_ref_t *property_ref_p, uint32_t options);
bool ecma_op_object_has_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p);
bool ecma_op_object_has_property (ecma_object_t *object_p, ecma_string_t *property_name_p);
ecma_value_t ecma_op_object_find_own (ecma_value_t base_value, ecma_object_t *object_p, ecma_string_t *property_name_p);
ecma_property_descriptor_t *prop_desc_p);
ecma_value_t ecma_op_object_has_instance (ecma_object_t *obj_p, ecma_value_t value);
bool ecma_op_object_is_prototype_of (ecma_object_t *base_p, ecma_object_t *target_p);
-ecma_collection_header_t * ecma_op_object_get_property_names (ecma_object_t *obj_p, bool is_array_indices_only,
- bool is_enumerable_only, bool is_with_prototype_chain);
+ecma_collection_header_t * ecma_op_object_get_property_names (ecma_object_t *obj_p, uint32_t opts);
lit_magic_string_id_t ecma_object_get_class_name (ecma_object_t *obj_p);
bool ecma_object_class_is (ecma_object_t *object_p, uint32_t class_id);
* @return true - if the object is a promise.
* false - otherwise.
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_is_promise (ecma_object_t *obj_p) /**< points to object */
{
return ecma_object_class_is (obj_p, LIT_MAGIC_STRING_PROMISE_UL);
* @return ecma value of the promise result.
* Returned value must be freed with ecma_free_value
*/
-inline ecma_value_t
+static inline ecma_value_t
ecma_promise_get_result (ecma_object_t *obj_p) /**< points to promise object */
{
JERRY_ASSERT (ecma_is_promise (obj_p));
/**
* Set the PromiseResult of promise.
*/
-inline void __attr_always_inline___
+static inline void JERRY_ATTR_ALWAYS_INLINE
ecma_promise_set_result (ecma_object_t *obj_p, /**< points to promise object */
ecma_value_t result) /**< the result value */
{
*
* @return the state's enum value
*/
-inline uint8_t __attr_always_inline___
+static inline uint8_t JERRY_ATTR_ALWAYS_INLINE
ecma_promise_get_state (ecma_object_t *obj_p) /**< points to promise object */
{
JERRY_ASSERT (ecma_is_promise (obj_p));
/**
* Set the PromiseState of promise.
*/
-inline void __attr_always_inline___
+static inline void JERRY_ATTR_ALWAYS_INLINE
ecma_promise_set_state (ecma_object_t *obj_p, /**< points to promise object */
uint8_t state) /**< the state */
{
JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL);
- return ext_object_p->u.class_prop.u.value == ecma_make_boolean_value (true);
+ return ext_object_p->u.class_prop.u.value == ECMA_VALUE_TRUE;
} /* ecma_get_already_resolved_bool_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, ECMA_COLLECTION_NO_REF_OBJECTS);
} /* ecma_promise_trigger_reactions */
/**
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;
+
+ /* Fulfill reactions will never be triggered. */
+ ecma_promise_trigger_reactions (reject_reactions, reason);
+
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 (reject_reactions, ECMA_COLLECTION_NO_REF_OBJECTS);
ecma_free_values_collection (fulfill_reactions, ECMA_COLLECTION_NO_REF_OBJECTS);
- ecma_promise_trigger_reactions (reject_reactions, reason);
} /* ecma_reject_promise */
/**
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;
+
+ /* Reject reactions will never be triggered. */
+ ecma_promise_trigger_reactions (fulfill_reactions, value);
+
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_free_values_collection (fulfill_reactions, ECMA_COLLECTION_NO_REF_OBJECTS);
} /* ecma_fulfill_promise */
/**
ecma_value_t resolve_func, /**< the resolve function */
ecma_value_t reject_func) /**< the reject function */
{
- 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);
+ ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
+ ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
+ ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
/* 2. */
ecma_value_t capability = ecma_op_object_get (executor_p, capability_str_p);
ecma_promise_create_resolving_functions (ecma_object_t *object_p) /**< the promise object */
{
/* 1. */
- ecma_value_t already_resolved = ecma_op_create_boolean_object (ecma_make_boolean_value (false));
+ ecma_value_t already_resolved = ecma_op_create_boolean_object (ECMA_VALUE_FALSE);
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 *object_p = ecma_create_object (prototype_obj_p,
sizeof (ecma_promise_object_t),
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.class_id = LIT_MAGIC_STRING_PROMISE_UL;
ext_object_p->u.class_prop.u.value = ECMA_VALUE_UNDEFINED;
/* 3. */
ecma_object_t *capability_p = ecma_op_create_object_object_noarg ();
- 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);
+ ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
+ ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
/* 4. */
ecma_object_t *executor_p;
executor_p = ecma_op_create_object_object_noarg ();
ecma_free_value (promise);
/* 8. */
- ecma_string_t *resolve_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE);
+ ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
ecma_value_t resolve = ecma_op_object_get (capability_p, resolve_str_p);
if (!ecma_op_is_callable (resolve))
ecma_free_value (resolve);
/* 9. */
- ecma_string_t *reject_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT);
+ ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
ecma_value_t reject = ecma_op_object_get (capability_p, reject_str_p);
if (!ecma_op_is_callable (reject))
ecma_value_t on_rejected, /**< on_rejected function */
ecma_value_t result_capability) /**< promise capability */
{
- 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);
+ ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
+ ecma_string_t *handler_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_HANDLER);
+ ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
/* 3. boolean true indicates "indentity" */
if (!ecma_op_is_callable (on_fulfilled))
{
- on_fulfilled = ecma_make_boolean_value (true);
+ on_fulfilled = ECMA_VALUE_TRUE;
}
/* 4. boolean false indicates "thrower" */
if (!ecma_op_is_callable (on_rejected))
{
- on_rejected = ecma_make_boolean_value (false);
+ on_rejected = ECMA_VALUE_FALSE;
}
/* 5-6. */
ecma_collection_header_t *reject_reactions; /**< list of PromiseRejectReactions */
} ecma_promise_object_t;
-/**
- * Use symbolic constant to represent the internal property name of
- * promise related structures.
- */
-typedef enum
-{
- ECMA_PROMISE_PROPERTY_PROMISE, /**< [[Promise]] property */
- ECMA_PROMISE_PROPERTY_RESOLVE, /**< [[Resolve]] property */
- ECMA_PROMISE_PROPERTY_REJECT, /**< [[Reject]] property */
- ECMA_PROMISE_PROPERTY_CAPABILITY, /**< [[Capability]] property */
- ECMA_PROMISE_PROPERTY_HANDLER, /**< [[Handler]] property */
- ECMA_PROMISE_PROPERTY_ALREADY_CALLED, /**< [[AlreadyCalled]] property */
- ECMA_PROMISE_PROPERTY_INDEX, /**< [[Index]] property */
- ECMA_PROMISE_PROPERTY_VALUE, /**< [[Values]] property */
- ECMA_PROMISE_PROPERTY_REMAINING_ELEMENT /**< [[RemainingElement]] property */
-} ecma_promise_property_symbolic_constant_t;
-
bool ecma_is_promise (ecma_object_t *obj_p);
-ecma_value_t ecma_promise_get_result (ecma_object_t *obj_p);
-void ecma_promise_set_result (ecma_object_t *obj_p, ecma_value_t result);
-uint8_t ecma_promise_get_state (ecma_object_t *obj_p);
-void ecma_promise_set_state (ecma_object_t *obj_p, uint8_t state);
ecma_value_t
ecma_op_create_promise_object (ecma_value_t executor, ecma_promise_executor_type_t type);
ecma_value_t ecma_promise_new_capability (void);
return NULL;
} /* ecma_op_resolve_reference_base */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+/**
+ * Resolve super reference.
+ *
+ * @return value of the reference
+ */
+ecma_object_t *
+ecma_op_resolve_super_reference_value (ecma_object_t *lex_env_p) /**< starting lexical environment */
+{
+ while (true)
+ {
+ JERRY_ASSERT (lex_env_p != NULL);
+
+ if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND)
+ {
+ return ecma_get_lex_env_binding_object (lex_env_p);
+ }
+
+ lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
+ }
+} /* ecma_op_resolve_super_reference_value */
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
/**
* Resolve value corresponding to reference.
*
while (lex_env_p != NULL)
{
- if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
+ ecma_lexical_environment_type_t lex_env_type = ecma_get_lex_env_type (lex_env_p);
+
+ if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
return ecma_fast_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
}
}
- else
+ else if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND)
{
- JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND
- || ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
-
ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
+#ifndef CONFIG_ECMA_LCACHE_DISABLE
ecma_property_t *property_p = ecma_lcache_lookup (binding_obj_p, name_p);
if (property_p != NULL)
ecma_value_t base_value = ecma_make_object_value (binding_obj_p);
return ecma_op_function_call (getter_p, base_value, NULL, 0);
}
+#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
ecma_value_t prop_value = ecma_op_object_find (binding_obj_p, name_p);
return prop_value;
}
}
+ else
+ {
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
+#else /* CONFIG_DISABLE_ES2015_CLASS */
+ JERRY_UNREACHABLE ();
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+ }
lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
}
ecma_object_t *ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, ecma_string_t *name_p);
ecma_value_t ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, ecma_string_t *name_p);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ecma_object_t *ecma_op_resolve_super_reference_value (ecma_object_t *lex_env_p);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/**
* @}
* [n+1] n/2 th group end
*/
#define RE_GLOBAL_START_IDX 0
+
+/**
+ * @copydoc RE_GLOBAL_START_IDX
+ */
#define RE_GLOBAL_END_IDX 1
/**
sizeof (ecma_extended_object_t),
ECMA_OBJECT_TYPE_CLASS);
- ecma_deref_object (re_prototype_obj_p);
-
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
/* Set the internal [[Class]] property */
*/
ecma_value_t
ecma_op_create_regexp_object (ecma_string_t *pattern_p, /**< input pattern */
- ecma_string_t *flags_str_p) /**< flags */
+ uint16_t flags) /**< flags */
{
JERRY_ASSERT (pattern_p != NULL);
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
- uint16_t flags = 0;
-
- if (flags_str_p != NULL)
- {
- ECMA_TRY_CATCH (empty, re_parse_regexp_flags (flags_str_p, &flags), ret_value);
- ECMA_FINALIZE (empty);
-
- if (!ecma_is_value_empty (ret_value))
- {
- return ret_value;
- }
- }
ecma_object_t *re_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE);
ecma_object_t *object_p = ecma_create_object (re_prototype_obj_p,
sizeof (ecma_extended_object_t),
ECMA_OBJECT_TYPE_CLASS);
-
- ecma_deref_object (re_prototype_obj_p);
-
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_UNDEFINED;
*
* @return ecma_char_t canonicalized character
*/
-inline ecma_char_t __attr_always_inline___
+inline ecma_char_t JERRY_ATTR_ALWAYS_INLINE
re_canonicalize (ecma_char_t ch, /**< character */
bool is_ignorecase) /**< IgnoreCase flag */
{
const lit_utf8_byte_t *str_p, /**< input string pointer */
const lit_utf8_byte_t **out_str_p) /**< [out] matching substring iterator */
{
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
- re_opcode_t op;
-
const lit_utf8_byte_t *str_curr_p = str_p;
- while ((op = re_get_opcode (&bc_p)))
+ while (true)
{
+ re_opcode_t op = re_get_opcode (&bc_p);
+
switch (op)
{
case RE_OP_MATCH:
{
JERRY_TRACE_MSG ("Execute RE_OP_MATCH: match\n");
*out_str_p = str_curr_p;
- ret_value = ECMA_VALUE_TRUE;
- return ret_value; /* match */
+ return ECMA_VALUE_TRUE; /* match */
}
case RE_OP_CHAR:
{
}
return ECMA_VALUE_FALSE; /* fail */
}
- case RE_OP_GREEDY_ITERATOR:
+ default:
{
+ JERRY_ASSERT (op == RE_OP_GREEDY_ITERATOR);
+
uint32_t min, max, offset, num_of_iter;
const lit_utf8_byte_t *sub_str_p = NULL;
}
return ECMA_VALUE_FALSE; /* fail */
}
- default:
- {
- JERRY_TRACE_MSG ("UNKNOWN opcode (%u)!\n", (unsigned int) op);
- return ecma_raise_common_error (ECMA_ERR_MSG ("Unknown RegExp opcode."));
- }
}
}
-
- JERRY_UNREACHABLE ();
- return ECMA_VALUE_FALSE; /* fail */
} /* re_match_regexp */
/**
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 */
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
true); /* Failure handling */
/* Set input property of the result array */
ecma_builtin_helper_def_prop (array_obj_p,
ecma_get_magic_string (LIT_MAGIC_STRING_INPUT),
ecma_make_string_value (input_str_p),
- true, /* Writable */
- true, /* Enumerable */
- true, /* Configurable */
+ ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
true); /* Failure handling */
/* Set length property of the result array */
return ret_value;
} /* ecma_regexp_exec_helper */
+/**
+ * Helper function for converting a RegExp pattern parameter to string.
+ *
+ * See also:
+ * RegExp.compile
+ * RegExp dispatch call
+ *
+ * @return empty value if success, error value otherwise
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_regexp_read_pattern_str_helper (ecma_value_t pattern_arg, /**< the RegExp pattern */
+ ecma_string_t **pattern_string_p) /**< [out] ptr to the pattern string ptr */
+{
+ if (!ecma_is_value_undefined (pattern_arg))
+ {
+ ecma_value_t regexp_str_value = ecma_op_to_string (pattern_arg);
+ if (ECMA_IS_VALUE_ERROR (regexp_str_value))
+ {
+ return regexp_str_value;
+ }
+
+ *pattern_string_p = ecma_get_string_from_value (regexp_str_value);
+ if (!ecma_string_is_empty (*pattern_string_p))
+ {
+ ecma_ref_ecma_string (*pattern_string_p);
+ }
+
+ ecma_free_value (regexp_str_value); // must be freed *after* ecma_ref_ecma_string
+ }
+
+ if (!*pattern_string_p || ecma_string_is_empty (*pattern_string_p))
+ {
+ *pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
+ }
+ return ECMA_VALUE_EMPTY;
+} /* ecma_regexp_read_pattern_str_helper */
+
/**
* @}
* @}
/**
* RegExp flags
+ * Note:
+ * This enum has to be kept in sync with jerry_regexp_flags_t.
*/
typedef enum
{
} re_matcher_ctx_t;
ecma_value_t ecma_op_create_regexp_object_from_bytecode (re_compiled_code_t *bytecode_p);
-ecma_value_t ecma_op_create_regexp_object (ecma_string_t *pattern_p, ecma_string_t *flags_str_p);
+ecma_value_t ecma_op_create_regexp_object (ecma_string_t *pattern_p, uint16_t flags);
ecma_value_t ecma_regexp_exec_helper (ecma_value_t regexp_value, ecma_value_t input_string, bool ignore_global);
+ecma_value_t ecma_regexp_read_pattern_str_helper (ecma_value_t pattern_arg, ecma_string_t **pattern_string_p);
ecma_char_t re_canonicalize (ecma_char_t ch, bool is_ignorecase);
void re_set_result_array_properties (ecma_object_t *array_obj_p, ecma_string_t *input_str_p, uint32_t num_of_elements,
int32_t index);
sizeof (ecma_extended_object_t),
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.class_id = LIT_MAGIC_STRING_STRING_UL;
ext_object_p->u.class_prop.u.value = prim_value;
ecma_number_t num_var; \
return_value = ecma_get_number (value, &num_var); \
\
- if (likely (ecma_is_value_empty (return_value))) \
+ if (JERRY_LIKELY (ecma_is_value_empty (return_value))) \
{
/**
default:
{
JERRY_UNREACHABLE ();
- return 0;
}
}
} /* ecma_get_typedarray_element */
ECMA_OBJECT_TYPE_PSEUDO_ARRAY);
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
- ext_object_p->u.pseudo_array.u1.class_id = class_id;
+ ext_object_p->u.pseudo_array.u1.class_id = (uint16_t) class_id;
ext_object_p->u.pseudo_array.type = ECMA_PSEUDO_ARRAY_TYPEDARRAY;
ext_object_p->u.pseudo_array.extra_info = element_size_shift;
ext_object_p->u.pseudo_array.u2.arraybuffer = new_arraybuffer_p;
ecma_free_value (new_arraybuffer_p);
return ecma_make_object_value (object_p);
-} /* !ecma_typedarray_create_object_with_length */
+} /* ecma_typedarray_create_object_with_length */
/**
* Create a TypedArray object by given buffer, offset, and array_length
ecma_object_t *object_p = ecma_create_object (proto_p, object_size, ECMA_OBJECT_TYPE_PSEUDO_ARRAY);
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
- ext_object_p->u.pseudo_array.u1.class_id = class_id;
+ ext_object_p->u.pseudo_array.u1.class_id = (uint16_t) class_id;
ext_object_p->u.pseudo_array.type = ECMA_PSEUDO_ARRAY_TYPEDARRAY;
ext_object_p->u.pseudo_array.extra_info = element_size_shift;
ext_object_p->u.pseudo_array.u2.arraybuffer = ecma_make_object_value (arraybuffer_p);
*
* @return the pointer to the internal arraybuffer
*/
-inline ecma_object_t * __attr_always_inline___
+inline ecma_object_t * JERRY_ATTR_ALWAYS_INLINE
ecma_typedarray_get_arraybuffer (ecma_object_t *typedarray_p) /**< the pointer to the typedarray object */
{
JERRY_ASSERT (ecma_is_typedarray (ecma_make_object_value (typedarray_p)));
JERRY_ASSERT (ecma_is_typedarray (ecma_make_object_value (obj_p)));
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
- lit_magic_string_id_t class_id = ext_object_p->u.pseudo_array.u1.class_id;
+ lit_magic_string_id_t class_id = (lit_magic_string_id_t) ext_object_p->u.pseudo_array.u1.class_id;
ecma_object_t *proto_p;
uint8_t element_size_shift = 0;
}
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ ecma_value_t constructor_value = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_CONSTRUCTOR);
+
+ if (ECMA_IS_VALUE_ERROR (constructor_value)
+ || !ecma_is_value_object (constructor_value)
+ || !ecma_is_constructor (constructor_value))
+ {
+ ecma_free_value (constructor_value);
+ return ecma_raise_type_error (ECMA_ERR_MSG ("object.constructor is not a constructor."));
+ }
+
+ ecma_object_t *constructor_object_p = ecma_get_object_from_value (constructor_value);
+ ecma_value_t constructor_prototype = ecma_op_object_get_by_magic_id (constructor_object_p,
+ LIT_MAGIC_STRING_PROTOTYPE);
+
+ ecma_deref_object (constructor_object_p);
+
+ if (ECMA_IS_VALUE_ERROR (constructor_prototype))
+ {
+ return constructor_prototype;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
ecma_value_t new_obj = ecma_typedarray_create_object_with_length (array_length,
proto_p,
element_size_shift,
class_id);
- ecma_deref_object (proto_p);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ ecma_object_t *constructor_prototype_object_p = ecma_get_object_from_value (constructor_prototype);
+ ecma_object_t *new_obj_p = ecma_get_object_from_value (new_obj);
+ ECMA_SET_POINTER (new_obj_p->prototype_or_outer_reference_cp, constructor_prototype_object_p);
+
+ ecma_deref_object (constructor_prototype_object_p);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
return new_obj;
} /* ecma_op_create_typedarray_with_type_and_length */
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JERRY_API_H
-#define JERRY_API_H
-
-#pragma message ("using jerry-api.h directly is deprecated, please use jerryscript.h")
-
-#include "jerryscript.h"
-
-#endif /* !JERRY_API_H */
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JERRY_PORT_H
-#define JERRY_PORT_H
-
-#pragma message ("using jerry-port.h directly is deprecated, please use jerryscript-port.h")
-
-#include "jerryscript-port.h"
-
-#endif /* !JERRY_PORT_H */
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef JERRYSCRIPT_COMPILER_H
+#define JERRYSCRIPT_COMPILER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/** \addtogroup jerry-compiler Jerry compiler compatibility components
+ * @{
+ */
+
+#ifdef __GNUC__
+
+/*
+ * Compiler-specific macros relevant for GCC.
+ */
+#define JERRY_ATTR_ALIGNED(ALIGNMENT) __attribute__((aligned(ALIGNMENT)))
+#define JERRY_ATTR_ALWAYS_INLINE __attribute__((always_inline))
+#define JERRY_ATTR_CONST __attribute__((const))
+#define JERRY_ATTR_DEPRECATED __attribute__((deprecated))
+#define JERRY_ATTR_FORMAT(...) __attribute__((format(__VA_ARGS__)))
+#define JERRY_ATTR_HOT __attribute__((hot))
+#define JERRY_ATTR_NOINLINE __attribute__((noinline))
+#define JERRY_ATTR_NORETURN __attribute__((noreturn))
+#define JERRY_ATTR_PURE __attribute__((pure))
+#define JERRY_ATTR_SECTION(SECTION) __attribute__((section(SECTION)))
+#define JERRY_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+
+#define JERRY_LIKELY(x) __builtin_expect(!!(x), 1)
+#define JERRY_UNLIKELY(x) __builtin_expect(!!(x), 0)
+
+#endif /* __GNUC__ */
+
+#ifdef _MSC_VER
+
+/*
+ * Compiler-specific macros relevant for Microsoft Visual C/C++ Compiler.
+ */
+#define JERRY_ATTR_DEPRECATED __declspec(deprecated)
+#define JERRY_ATTR_NOINLINE __declspec(noinline)
+#define JERRY_ATTR_NORETURN __declspec(noreturn)
+
+/*
+ * Microsoft Visual C/C++ Compiler doesn't support for VLA, using _alloca
+ * instead.
+ */
+void * __cdecl _alloca (size_t _Size);
+#define JERRY_VLA(type, name, size) type *name = (type *) (_alloca (sizeof (type) * size))
+
+#endif /* _MSC_VER */
+
+/*
+ * Default empty definitions for all compiler-specific macros. Define any of
+ * these in a guarded block above (e.g., as for GCC) to fine tune compilation
+ * for your own compiler. */
+
+/**
+ * Function attribute to align function to given number of bytes.
+ */
+#ifndef JERRY_ATTR_ALIGNED
+#define JERRY_ATTR_ALIGNED(ALIGNMENT)
+#endif /* !JERRY_ATTR_ALIGNED */
+
+/**
+ * Function attribute to inline function to all call sites.
+ */
+#ifndef JERRY_ATTR_ALWAYS_INLINE
+#define JERRY_ATTR_ALWAYS_INLINE
+#endif /* !JERRY_ATTR_ALWAYS_INLINE */
+
+/**
+ * Function attribute to declare that function has no effect except the return
+ * value and it only depends on parameters.
+ */
+#ifndef JERRY_ATTR_CONST
+#define JERRY_ATTR_CONST
+#endif /* !JERRY_ATTR_CONST */
+
+/**
+ * Function attribute to trigger warning if deprecated function is called.
+ */
+#ifndef JERRY_ATTR_DEPRECATED
+#define JERRY_ATTR_DEPRECATED
+#endif /* !JERRY_ATTR_DEPRECATED */
+
+/**
+ * Function attribute to declare that function is variadic and takes a format
+ * string and some arguments as parameters.
+ */
+#ifndef JERRY_ATTR_FORMAT
+#define JERRY_ATTR_FORMAT(...)
+#endif /* !JERRY_ATTR_FORMAT */
+
+/**
+ * Function attribute to predict that function is a hot spot, and therefore
+ * should be optimized aggressively.
+ */
+#ifndef JERRY_ATTR_HOT
+#define JERRY_ATTR_HOT
+#endif /* !JERRY_ATTR_HOT */
+
+/**
+ * Function attribute not to inline function ever.
+ */
+#ifndef JERRY_ATTR_NOINLINE
+#define JERRY_ATTR_NOINLINE
+#endif /* !JERRY_ATTR_NOINLINE */
+
+/**
+ * Function attribute to declare that function never returns.
+ */
+#ifndef JERRY_ATTR_NORETURN
+#define JERRY_ATTR_NORETURN
+#endif /* !JERRY_ATTR_NORETURN */
+
+/**
+ * Function attribute to declare that function has no effect except the return
+ * value and it only depends on parameters and global variables.
+ */
+#ifndef JERRY_ATTR_PURE
+#define JERRY_ATTR_PURE
+#endif /* !JERRY_ATTR_PURE */
+
+/**
+ * Function attribute to place function in given section.
+ */
+#ifndef JERRY_ATTR_SECTION
+#define JERRY_ATTR_SECTION(SECTION)
+#endif /* !JERRY_ATTR_SECTION */
+
+/**
+ * Function attribute to trigger warning if function's caller doesn't use (e.g.,
+ * check) the return value.
+ */
+#ifndef JERRY_ATTR_WARN_UNUSED_RESULT
+#define JERRY_ATTR_WARN_UNUSED_RESULT
+#endif /* !JERRY_ATTR_WARN_UNUSED_RESULT */
+
+/**
+ * Helper to predict that a condition is likely.
+ */
+#ifndef JERRY_LIKELY
+#define JERRY_LIKELY(x) (x)
+#endif /* !JERRY_LIKELY */
+
+/**
+ * Helper to predict that a condition is unlikely.
+ */
+#ifndef JERRY_UNLIKELY
+#define JERRY_UNLIKELY(x) (x)
+#endif /* !JERRY_UNLIKELY */
+
+/**
+ * Helper to declare (or mimic) a C99 variable-length array.
+ */
+#ifndef JERRY_VLA
+#define JERRY_VLA(type, name, size) type name[size]
+#endif /* !JERRY_VLA */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* !JERRYSCRIPT_COMPILER_H */
#include <stddef.h>
#include <stdint.h>
+#include "jerryscript-compiler.h"
+
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
-#ifdef __GNUC__
-#define JERRY_DEPRECATED_API __attribute__((deprecated))
-#else /* !__GNUC__ */
-/* TODO: for other compilers */
-#define JERRY_DEPRECATED_API
-#endif /* __GNUC__ */
-
/** \addtogroup jerry Jerry engine interface
* @{
*/
JERRY_FEATURE_DATE, /**< Date support */
JERRY_FEATURE_REGEXP, /**< Regexp support */
JERRY_FEATURE_LINE_INFO, /**< line info available */
+ JERRY_FEATURE_LOGGING, /**< logging */
JERRY_FEATURE__COUNT /**< number of features. NOTE: must be at the end of the list */
} jerry_feature_t;
typedef enum
{
JERRY_PARSE_NO_OPTS = 0, /**< no options passed */
- JERRY_PARSE_STRICT_MODE = (1 << 0), /**< enable strict mode */
+ JERRY_PARSE_STRICT_MODE = (1 << 0) /**< enable strict mode */
} jerry_parse_opts_t;
/**
- * Character type of JerryScript.
+ * GC operational modes.
*/
-typedef uint8_t jerry_char_t;
+typedef enum
+{
+ JERRY_GC_SEVERITY_LOW, /**< free unused objects, but keep memory
+ * allocated for performance improvements
+ * such as property hash tables for large objects */
+ JERRY_GC_SEVERITY_HIGH /**< free as much memory as possible */
+} jerry_gc_mode_t;
+
+/**
+ * Jerry regexp flags.
+ */
+typedef enum
+{
+ JERRY_REGEXP_FLAG_GLOBAL = (1u << 1), /**< Globally scan string */
+ JERRY_REGEXP_FLAG_IGNORE_CASE = (1u << 2), /**< Ignore case */
+ JERRY_REGEXP_FLAG_MULTILINE = (1u << 3) /**< Multiline string scan */
+} jerry_regexp_flags_t;
/**
- * Pointer to an array of character values.
+ * Character type of JerryScript.
*/
-typedef jerry_char_t *jerry_char_ptr_t;
+typedef uint8_t jerry_char_t;
/**
* Size type of JerryScript.
const jerry_value_t args_p[],
const jerry_length_t args_count);
-/**
- * Native free callback of an object (deprecated).
- */
-typedef void (*jerry_object_free_callback_t) (const uintptr_t native_p);
-
/**
* Native free callback of an object.
*/
} jerry_context_data_manager_t;
/**
- * Function type for allocating buffer for JerryScript instance.
+ * Function type for allocating buffer for JerryScript context.
*/
-typedef void *(*jerry_instance_alloc_t) (size_t size, void *cb_data_p);
+typedef void *(*jerry_context_alloc_t) (size_t size, void *cb_data_p);
/**
* Type information of a native pointer.
} jerry_object_native_info_t;
/**
- * A forward declaration of the JerryScript instance structure.
+ * An opaque declaration of the JerryScript context structure.
*/
-typedef struct jerry_instance_t jerry_instance_t;
+typedef struct jerry_context_t jerry_context_t;
/**
* General engine functions.
*/
void jerry_init (jerry_init_flag_t flags);
void jerry_cleanup (void);
-void jerry_register_magic_strings (const jerry_char_ptr_t *ex_str_items_p, uint32_t count,
+void jerry_register_magic_strings (const jerry_char_t * const *ex_str_items_p,
+ uint32_t count,
const jerry_length_t *str_lengths_p);
-void jerry_get_memory_limits (size_t *out_data_bss_brk_limit_p, size_t *out_stack_limit_p);
-void jerry_gc (void);
+void jerry_gc (jerry_gc_mode_t mode);
void *jerry_get_context_data (const jerry_context_data_manager_t *manager_p);
bool jerry_get_memory_stats (jerry_heap_stats_t *out_stats_p);
const jerry_char_t *arg_list_p, size_t arg_list_size,
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);
+jerry_value_t jerry_eval (const jerry_char_t *source_p, size_t source_size, uint32_t parse_opts);
jerry_value_t jerry_run_all_enqueued_jobs (void);
/**
* Checker functions of 'jerry_value_t'.
*/
+bool jerry_value_is_abort (const jerry_value_t value);
bool jerry_value_is_array (const jerry_value_t value);
bool jerry_value_is_boolean (const jerry_value_t value);
bool jerry_value_is_constructor (const jerry_value_t value);
+bool jerry_value_is_error (const jerry_value_t value);
bool jerry_value_is_function (const jerry_value_t value);
bool jerry_value_is_number (const jerry_value_t value);
bool jerry_value_is_null (const jerry_value_t value);
JERRY_TYPE_STRING, /**< string type */
JERRY_TYPE_OBJECT, /**< object type */
JERRY_TYPE_FUNCTION, /**< function type */
+ JERRY_TYPE_ERROR, /**< error/abort type */
} jerry_type_t;
jerry_type_t jerry_value_get_type (const jerry_value_t value);
bool jerry_is_feature_enabled (const jerry_feature_t feature);
/**
- * Error flag manipulation functions.
+ * Error 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);
+jerry_value_t jerry_create_abort_from_value (jerry_value_t value, bool release);
+jerry_value_t jerry_create_error_from_value (jerry_value_t value, bool release);
+jerry_value_t jerry_get_value_from_error (jerry_value_t value, bool release);
/**
* Error object function(s).
*/
-jerry_error_t jerry_get_error_type (const jerry_value_t value);
+jerry_error_t jerry_get_error_type (jerry_value_t value);
/**
* Getter functions of 'jerry_value_t'.
jerry_value_t jerry_create_null (void);
jerry_value_t jerry_create_object (void);
jerry_value_t jerry_create_promise (void);
+jerry_value_t jerry_create_regexp (const jerry_char_t *pattern, jerry_regexp_flags_t flags);
+jerry_value_t jerry_create_regexp_sz (const jerry_char_t *pattern, jerry_size_t pattern_size,
+ jerry_regexp_flags_t flags);
jerry_value_t jerry_create_string_from_utf8 (const jerry_char_t *str_p);
jerry_value_t jerry_create_string_sz_from_utf8 (const jerry_char_t *str_p, jerry_size_t str_size);
jerry_value_t jerry_create_string (const jerry_char_t *str_p);
jerry_value_t jerry_get_prototype (const jerry_value_t obj_val);
jerry_value_t jerry_set_prototype (const jerry_value_t obj_val, const jerry_value_t proto_obj_val);
-JERRY_DEPRECATED_API
-bool jerry_get_object_native_handle (const jerry_value_t obj_val, uintptr_t *out_handle_p);
-JERRY_DEPRECATED_API
-void jerry_set_object_native_handle (const jerry_value_t obj_val, uintptr_t handle_p,
- jerry_object_free_callback_t freecb_p);
-
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);
+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);
+
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);
bool jerry_foreach_object_property (const jerry_value_t obj_val, jerry_object_property_foreach_t foreach_p,
void *user_data_p);
bool jerry_is_valid_utf8_string (const jerry_char_t *utf8_buf_p, jerry_size_t buf_size);
bool jerry_is_valid_cesu8_string (const jerry_char_t *cesu8_buf_p, jerry_size_t buf_size);
+/*
+ * Dynamic memory management functions.
+ */
+void *jerry_heap_alloc (size_t size);
+void jerry_heap_free (void *mem_p, size_t size);
+
/*
* External context functions.
*/
-jerry_instance_t *jerry_create_instance (uint32_t heap_size, jerry_instance_alloc_t alloc, void *cb_data_p);
+jerry_context_t *jerry_create_context (uint32_t heap_size, jerry_context_alloc_t alloc, void *cb_data_p);
/**
* Miscellaneous functions.
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);
+jerry_value_t jerry_json_stringify (const jerry_value_t object_to_stringify);
/**
* @}
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef JERRYSCRIPT_DEBUGGER_TRANSPORT_H
+#define JERRYSCRIPT_DEBUGGER_TRANSPORT_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/** \addtogroup jerry-debugger-transport Jerry engine debugger interface - transport control
+ * @{
+ */
+
+/**
+ * Maximum number of bytes transmitted or received.
+ */
+#define JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE 128
+
+/**
+ * Receive message context.
+ */
+typedef struct
+{
+ uint8_t *buffer_p; /**< buffer for storing the received data */
+ size_t received_length; /**< number of currently received bytes */
+ uint8_t *message_p; /**< start of the received message */
+ size_t message_length; /**< length of the received message */
+ size_t message_total_length; /**< total length for datagram protocols,
+ * 0 for stream protocols */
+} jerry_debugger_transport_receive_context_t;
+
+/**
+ * Forward definition of jerry_debugger_transport_header_t.
+ */
+struct jerry_debugger_transport_interface_t;
+
+/**
+ * Close connection callback.
+ */
+typedef void (*jerry_debugger_transport_close_t) (struct jerry_debugger_transport_interface_t *header_p);
+
+/**
+ * Send data callback.
+ */
+typedef bool (*jerry_debugger_transport_send_t) (struct jerry_debugger_transport_interface_t *header_p,
+ uint8_t *message_p, size_t message_length);
+
+/**
+ * Receive data callback.
+ */
+typedef bool (*jerry_debugger_transport_receive_t) (struct jerry_debugger_transport_interface_t *header_p,
+ jerry_debugger_transport_receive_context_t *context_p);
+
+/**
+ * Transport layer header.
+ */
+typedef struct jerry_debugger_transport_interface_t
+{
+ /* The following fields must be filled before calling jerry_debugger_transport_add(). */
+ jerry_debugger_transport_close_t close; /**< close connection callback */
+ jerry_debugger_transport_send_t send; /**< send data callback */
+ jerry_debugger_transport_receive_t receive; /**< receive data callback */
+
+ /* The following fields are filled by jerry_debugger_transport_add(). */
+ struct jerry_debugger_transport_interface_t *next_p; /**< next transport layer */
+} jerry_debugger_transport_header_t;
+
+void jerry_debugger_transport_add (jerry_debugger_transport_header_t *header_p,
+ size_t send_message_header_size, size_t max_send_message_size,
+ size_t receive_message_header_size, size_t max_receive_message_size);
+void jerry_debugger_transport_start (void);
+
+bool jerry_debugger_transport_is_connected (void);
+void jerry_debugger_transport_close (void);
+
+bool jerry_debugger_transport_send (const uint8_t *message_p, size_t message_length);
+bool jerry_debugger_transport_receive (jerry_debugger_transport_receive_context_t *context_p);
+void jerry_debugger_transport_receive_completed (jerry_debugger_transport_receive_context_t *context_p);
+
+void jerry_debugger_transport_sleep (void);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* !JERRYSCRIPT_DEBUGGER_TRANSPORT_H */
#ifndef JERRYSCRIPT_DEBUGGER_H
#define JERRYSCRIPT_DEBUGGER_H
-#include <stdbool.h>
+#include "jerryscript-core.h"
+#include "jerryscript-port.h"
#ifdef __cplusplus
extern "C"
* @{
*/
+/**
+ * JerryScript debugger protocol version.
+ */
+#define JERRY_DEBUGGER_VERSION (8)
+
/**
* Types for the client source wait and run method.
*/
/**
* Engine debugger functions.
*/
-void jerry_debugger_init (uint16_t port);
bool jerry_debugger_is_connected (void);
void jerry_debugger_stop (void);
void jerry_debugger_continue (void);
jerry_debugger_wait_for_source_status_t
jerry_debugger_wait_for_client_source (jerry_debugger_wait_for_source_callback_t callback_p,
void *user_p, jerry_value_t *return_value);
-void jerry_debugger_send_output (jerry_char_t buffer[], jerry_size_t str_size, uint8_t type);
+void jerry_debugger_send_output (const jerry_char_t *buffer, jerry_size_t str_size);
+void jerry_debugger_send_log (jerry_log_level_t level, const jerry_char_t *buffer, jerry_size_t str_size);
/**
* @}
#include <stdint.h>
#include <stdio.h>
+#include "jerryscript-compiler.h"
+
#ifdef __cplusplus
extern "C"
{
ERR_OUT_OF_MEMORY = 10,
ERR_SYSCALL = 11,
ERR_REF_COUNT_LIMIT = 12,
+ ERR_DISABLED_BYTE_CODE = 13,
ERR_FAILED_INTERNAL_ASSERTION = 120
} jerry_fatal_code_t;
*
* Example: a libc-based port may implement this with exit() or abort(), or both.
*/
-void jerry_port_fatal (jerry_fatal_code_t code) __attribute__((noreturn));
+void JERRY_ATTR_NORETURN jerry_port_fatal (jerry_fatal_code_t code);
/*
* I/O Port API
*
* Example: a libc-based port may implement this with vfprintf(stderr) or
* vfprintf(logfile), or both, depending on log level.
+ *
+ * Note:
+ * This port function is called by jerry-core when JERRY_ENABLE_LOGGING is
+ * defined. It is also common practice though to use this function in
+ * application code.
*/
-void jerry_port_log (jerry_log_level_t level, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+void JERRY_ATTR_FORMAT (printf, 2, 3) jerry_port_log (jerry_log_level_t level, const char *format, ...);
/*
* Date Port API
*/
/**
- * Jerry time zone structure
- */
-typedef struct
-{
- int offset; /**< minutes from west */
- int daylight_saving_time; /**< daylight saving time (1 - DST applies, 0 - not on DST) */
-} jerry_time_zone_t;
-
-/**
- * Get timezone and daylight saving data
+ * Get local time zone adjustment, in milliseconds, for the given timestamp.
+ * The timestamp can be specified in either UTC or local time, depending on
+ * the value of is_utc. Adding the value returned from this function to
+ * a timestamp in UTC time should result in local time for the current time
+ * zone, and subtracting it from a timestamp in local time should result in
+ * UTC time.
+ *
+ * Ideally, this function should satisfy the stipulations applied to LocalTZA
+ * in section 20.3.1.7 of the ECMAScript version 9.0 spec.
+ *
+ * See Also:
+ * ECMA-262 v9, 20.3.1.7
*
- * @return true - if success
- * false - otherwise
+ * Note:
+ * This port function is called by jerry-core when
+ * CONFIG_DISABLE_DATE_BUILTIN is _not_ defined. Otherwise this function is
+ * not used.
+ *
+ * @param unix_ms The unix timestamp we want an offset for, given in
+ * millisecond precision (could be now, in the future,
+ * or in the past). As with all unix timestamps, 0 refers to
+ * 1970-01-01, a day is exactly 86 400 000 milliseconds, and
+ * leap seconds cause the same second to occur twice.
+ * @param is_utc Is the given timestamp in UTC time? If false, it is in local
+ * time.
+ *
+ * @return milliseconds between local time and UTC for the given timestamp,
+ * if available
+ *. 0 if not available / we are in UTC.
*/
-bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p);
+double jerry_port_get_local_time_zone_adjustment (double unix_ms, bool is_utc);
/**
* Get system time
*
+ * Note:
+ * This port function is called by jerry-core when
+ * CONFIG_DISABLE_DATE_BUILTIN is _not_ defined. It is also common practice
+ * in application code to use this function for the initialization of the
+ * random number generator.
+ *
* @return milliseconds since Unix epoch
*/
double jerry_port_get_current_time (void);
/**
- * Get the current instance which contains the current context, heap and other
- * structures. Each port should provide its own implementation of this interface.
+ * Get the current context of the engine. Each port should provide its own
+ * implementation of this interface.
*
- *Note:
- * This port function is called by jerry-core when JERRY_ENABLE_EXTERNAL_CONTEXT
- * is defined. Otherwise this function is not used.
+ * Note:
+ * This port function is called by jerry-core when
+ * JERRY_ENABLE_EXTERNAL_CONTEXT is defined. Otherwise this function is not
+ * used.
*
- * @return the pointer to the jerry instance.
+ * @return the pointer to the engine context.
*/
-struct jerry_instance_t *jerry_port_get_current_instance (void);
+struct jerry_context_t *jerry_port_get_current_context (void);
/**
* Makes the process sleep for a given time.
+ *
+ * Note:
+ * This port function is called by jerry-core when JERRY_DEBUGGER is
+ * defined. Otherwise this function is not used.
+ *
+ * @param sleep_time milliseconds to sleep.
*/
-#ifdef JERRY_DEBUGGER
void jerry_port_sleep (uint32_t sleep_time);
-#endif /* JERRY_DEBUGGER */
/**
* @}
* @{
*/
+/**
+ * Jerry snapshot format version.
+ */
+#define JERRY_SNAPSHOT_VERSION (20u)
+
/**
* Flags for jerry_generate_snapshot and jerry_generate_function_snapshot.
*/
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_get_literals_from_snapshot (const uint32_t *snapshot_p, size_t snapshot_size,
+ jerry_char_t *lit_buf_p, size_t lit_buf_size, bool is_c_format);
/**
* @}
*/
*/
#ifndef JERRY_ENABLE_EXTERNAL_CONTEXT
+
/**
* Global context.
*/
jerry_context_t jerry_global_context;
+#ifndef JERRY_SYSTEM_ALLOCATOR
+
+/**
+ * Check size of heap is corresponding to configuration
+ */
+JERRY_STATIC_ASSERT (sizeof (jmem_heap_t) <= JMEM_HEAP_SIZE,
+ size_of_mem_heap_must_be_less_than_or_equal_to_JMEM_HEAP_SIZE);
+
/**
* Jerry global heap section attribute.
*/
#ifndef JERRY_HEAP_SECTION_ATTR
#define JERRY_GLOBAL_HEAP_SECTION
#else /* JERRY_HEAP_SECTION_ATTR */
-#define JERRY_GLOBAL_HEAP_SECTION __attribute__ ((section (JERRY_HEAP_SECTION_ATTR)))
+#define JERRY_GLOBAL_HEAP_SECTION JERRY_ATTR_SECTION (JERRY_HEAP_SECTION_ATTR)
#endif /* !JERRY_HEAP_SECTION_ATTR */
-#ifndef JERRY_SYSTEM_ALLOCATOR
/**
* Global heap.
*/
-jmem_heap_t jerry_global_heap __attribute__ ((aligned (JMEM_ALIGNMENT))) JERRY_GLOBAL_HEAP_SECTION;
-#endif /* !JERRY_SYSTEM_ALLOCATOR */
-
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
+jmem_heap_t jerry_global_heap JERRY_ATTR_ALIGNED (JMEM_ALIGNMENT) JERRY_GLOBAL_HEAP_SECTION;
-/**
- * Global hash table.
- */
-jerry_hash_table_t jerry_global_hash_table;
+#endif /* !JERRY_SYSTEM_ALLOCATOR */
-#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
#endif /* !JERRY_ENABLE_EXTERNAL_CONTEXT */
/**
* limitations under the License.
*/
-/**
- * Memory context for JerryScript
+/*
+ * Engine context for JerryScript
*/
#ifndef JCONTEXT_H
#define JCONTEXT_H
#include "re-bytecode.h"
#include "vm-defines.h"
#include "jerryscript.h"
+#include "jerryscript-debugger-transport.h"
/** \addtogroup context Context
* @{
*/
+#ifndef JERRY_SYSTEM_ALLOCATOR
/**
- * First member of the jerry context
+ * Heap structure
+ *
+ * Memory blocks returned by the allocator must not start from the
+ * beginning of the heap area because offset 0 is reserved for
+ * JMEM_CP_NULL. This special constant is used in several places,
+ * e.g. it marks the end of the property chain list, so it cannot
+ * be eliminated from the project. Although the allocator cannot
+ * use the first 8 bytes of the heap, nothing prevents to use it
+ * for other purposes. Currently the free region start is stored
+ * there.
*/
-#define JERRY_CONTEXT_FIRST_MEMBER ecma_builtin_objects
+typedef struct jmem_heap_t jmem_heap_t;
+#endif /* !JERRY_SYSTEM_ALLOCATOR */
/**
* User context item
#define JERRY_CONTEXT_DATA_HEADER_USER_DATA(item_p) \
((uint8_t *) (item_p + 1))
+/**
+ * First non-external member of the jerry context
+ */
+#define JERRY_CONTEXT_FIRST_MEMBER ecma_builtin_objects
+
/**
* JerryScript context
*
* The purpose of this header is storing
* all global variables for Jerry
*/
-typedef struct
+struct jerry_context_t
{
- /* Update JERRY_CONTEXT_FIRST_MEMBER if the first member changes */
+ /* The value of external context members must be preserved across initializations and cleanups. */
+#ifdef JERRY_ENABLE_EXTERNAL_CONTEXT
+#ifndef JERRY_SYSTEM_ALLOCATOR
+ jmem_heap_t *heap_p; /**< point to the heap aligned to JMEM_ALIGNMENT. */
+ uint32_t heap_size; /**< size of the heap */
+#endif /* !JERRY_SYSTEM_ALLOCATOR */
+#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
+
+ /* Update JERRY_CONTEXT_FIRST_MEMBER if the first non-external member changes */
ecma_object_t *ecma_builtin_objects[ECMA_BUILTIN_ID__COUNT]; /**< pointer to instances of built-in objects */
#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
const re_compiled_code_t *re_cache[RE_CACHE_SIZE]; /**< regex cache */
jmem_pools_chunk_t *jmem_free_16_byte_chunk_p; /**< list of free sixteen byte pool chunks */
#endif /* JERRY_CPOINTER_32_BIT */
jmem_free_unused_memory_callback_t jmem_free_unused_memory_callback; /**< Callback for freeing up memory. */
- const lit_utf8_byte_t **lit_magic_string_ex_array; /**< array of external magic strings */
+ const lit_utf8_byte_t * const *lit_magic_string_ex_array; /**< array of external magic strings */
const lit_utf8_size_t *lit_magic_string_ex_sizes; /**< external magic string lengths */
ecma_lit_storage_item_t *string_list_first_p; /**< first item of the literal string list */
ecma_lit_storage_item_t *number_list_first_p; /**< first item of the literal number list */
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 */
- uint32_t status_flags; /**< run-time flags */
+ uint32_t status_flags; /**< run-time flags (the top 8 bits are used for passing class parsing options) */
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
uint8_t ecma_prop_hashmap_alloc_state; /**< property hashmap allocation state: 0-4,
#endif /* JERRY_VM_EXEC_STOP */
#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[JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE]; /**< buffer for sending messages */
+ uint8_t debugger_receive_buffer[JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE]; /**< buffer for receiving messages */
+ jerry_debugger_transport_header_t *debugger_transport_header_p; /**< head of transport protocol chain */
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 */
+ uint8_t *debugger_exception_byte_code_p; /**< Location of the currently executed byte code if an
+ * error occours while the vm_loop is suspended */
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 */
uint32_t debugger_flags; /**< debugger flags */
- uint16_t debugger_receive_buffer_offset; /**< receive buffer offset */
- uint16_t debugger_port; /**< debugger socket communication port */
+ uint16_t debugger_received_length; /**< length of currently received bytes */
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_send_size; /**< maximum amount of data that can be sent */
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
jmem_heap_stats_t jmem_heap_stats; /**< heap's memory usage statistics */
#endif /* JMEM_STATS */
-#ifdef JERRY_VALGRIND_FREYA
- uint8_t valgrind_freya_mempool_request; /**< Tells whether a pool manager
- * allocator request is in progress */
-#endif /* JERRY_VALGRIND_FREYA */
-} jerry_context_t;
-
+ /* This must be at the end of the context for performance reasons */
#ifndef CONFIG_ECMA_LCACHE_DISABLE
-/**
- * Hash table for caching the last access of properties.
- */
-typedef struct
-{
- ecma_lcache_hash_entry_t table[ECMA_LCACHE_HASH_ROWS_COUNT][ECMA_LCACHE_HASH_ROW_LENGTH];
-} jerry_hash_table_t;
+ /** hash table for caching the last access of properties */
+ ecma_lcache_hash_entry_t lcache[ECMA_LCACHE_HASH_ROWS_COUNT][ECMA_LCACHE_HASH_ROW_LENGTH];
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
+};
-#ifdef JERRY_ENABLE_EXTERNAL_CONTEXT
-#ifndef JERRY_GET_CURRENT_INSTANCE
+#ifdef JERRY_ENABLE_EXTERNAL_CONTEXT
-/**
- * Default function if JERRY_GET_CURRENT_INSTANCE is not defined.
+/*
+ * This part is for JerryScript which uses external context.
*/
-#define JERRY_GET_CURRENT_INSTANCE() (jerry_port_get_current_instance ())
-
-#endif /* !JERRY_GET_CURRENT_INSTANCE */
-/**
- * This part is for Jerry which enable external context.
- */
-typedef struct
-{
- jmem_heap_free_t first; /**< first node in free region list */
- uint8_t area[]; /**< heap area */
-} jmem_heap_t;
+#define JERRY_CONTEXT(field) (jerry_port_get_current_context ()->field)
-/**
- * Description of jerry instance which is the header of the context space.
- */
-struct jerry_instance_t
-{
- jerry_context_t context; /**< the context of the instance */
#ifndef JERRY_SYSTEM_ALLOCATOR
- jmem_heap_t *heap_p; /**< point to the heap aligned to JMEM_ALIGNMENT. */
- uint32_t heap_size; /**< size of the heap */
-#endif /* !JERRY_SYSTEM_ALLOCATOR */
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
- uint8_t *lcache_p; /**< point to the entrance of the lcache in buffer */
-#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
-};
-#define JERRY_CONTEXT(field) (JERRY_GET_CURRENT_INSTANCE ()->context.field)
+#define JMEM_HEAP_SIZE (JERRY_CONTEXT (heap_size))
-#ifndef JERRY_SYSTEM_ALLOCATOR
+#define JMEM_HEAP_AREA_SIZE (JMEM_HEAP_SIZE - JMEM_ALIGNMENT)
-static inline jmem_heap_t * __attr_always_inline___
-jerry_context_get_current_heap (void)
+struct jmem_heap_t
{
- return JERRY_GET_CURRENT_INSTANCE ()->heap_p;
-} /* jerry_context_get_current_heap */
-
-#define JERRY_HEAP_CONTEXT(field) (jerry_context_get_current_heap ()->field)
-
-#ifdef JMEM_HEAP_SIZE
-#error "JMEM_HEAP_SIZE must not be defined if JERRY_ENABLE_EXTERNAL_CONTEXT is defined"
-#endif /* JMEM_HEAP_SIZE */
-
-#define JMEM_HEAP_SIZE (JERRY_GET_CURRENT_INSTANCE ()->heap_size)
+ jmem_heap_free_t first; /**< first node in free region list */
+ uint8_t area[]; /**< heap area */
+};
-#define JMEM_HEAP_AREA_SIZE (JERRY_GET_CURRENT_INSTANCE ()->heap_size - JMEM_ALIGNMENT)
+#define JERRY_HEAP_CONTEXT(field) (JERRY_CONTEXT (heap_p)->field)
#endif /* !JERRY_SYSTEM_ALLOCATOR */
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
+#else /* !JERRY_ENABLE_EXTERNAL_CONTEXT */
-static inline jerry_hash_table_t * __attr_always_inline___
-jerry_context_get_current_lcache (void)
-{
- return (jerry_hash_table_t *) (JERRY_GET_CURRENT_INSTANCE ()->lcache_p);
-} /* jerry_context_get_current_lcache */
+/*
+ * This part is for JerryScript which uses default context.
+ */
-#define JERRY_HASH_TABLE_CONTEXT(field) (jerry_context_get_current_lcache ()->field)
+/**
+ * Global context.
+ */
+extern jerry_context_t jerry_global_context;
-#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
+/**
+ * Provides a reference to a field in the current context.
+ */
+#define JERRY_CONTEXT(field) (jerry_global_context.field)
-#else /* !JERRY_ENABLE_EXTERNAL_CONTEXT */
+#ifndef JERRY_SYSTEM_ALLOCATOR
/**
- * This part is for Jerry which use default context.
- */
+* Size of heap
+*/
+#define JMEM_HEAP_SIZE ((size_t) (CONFIG_MEM_HEAP_AREA_SIZE))
/**
* Calculate heap area size, leaving space for a pointer to the free list
*/
#define JMEM_HEAP_AREA_SIZE (JMEM_HEAP_SIZE - JMEM_ALIGNMENT)
-/**
- * Heap structure
- *
- * Memory blocks returned by the allocator must not start from the
- * beginning of the heap area because offset 0 is reserved for
- * JMEM_CP_NULL. This special constant is used in several places,
- * e.g. it marks the end of the property chain list, so it cannot
- * be eliminated from the project. Although the allocator cannot
- * use the first 8 bytes of the heap, nothing prevents to use it
- * for other purposes. Currently the free region start is stored
- * there.
- */
-typedef struct
+struct jmem_heap_t
{
jmem_heap_free_t first; /**< first node in free region list */
uint8_t area[JMEM_HEAP_AREA_SIZE]; /**< heap area */
-} jmem_heap_t;
-
-/**
- * Global context.
- */
-extern jerry_context_t jerry_global_context;
+};
-#ifndef JERRY_SYSTEM_ALLOCATOR
/**
* Global heap.
*/
extern jmem_heap_t jerry_global_heap;
-#endif /* !JERRY_SYSTEM_ALLOCATOR */
-
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
-
-/**
- * Global hash table.
- */
-extern jerry_hash_table_t jerry_global_hash_table;
-
-#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
/**
- * Provides a reference to a field in the current context.
- */
-#define JERRY_CONTEXT(field) (jerry_global_context.field)
-
-#ifndef JERRY_SYSTEM_ALLOCATOR
-/**
- * Provides a reference to the area field of the heap.
+ * Provides a reference to a field of the heap.
*/
#define JERRY_HEAP_CONTEXT(field) (jerry_global_heap.field)
#endif /* !JERRY_SYSTEM_ALLOCATOR */
-#ifndef CONFIG_ECMA_LCACHE_DISABLE
-
-/**
- * Provides a reference to the global hash table.
- */
-#define JERRY_HASH_TABLE_CONTEXT(field) (jerry_global_hash_table.field)
-
-#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
-
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
/**
* @{
*/
+/**
+ * @{
+ * Valgrind-related options and headers
+ */
+#ifdef JERRY_VALGRIND
+# include "memcheck.h"
+
+# define JMEM_VALGRIND_NOACCESS_SPACE(p, s) VALGRIND_MAKE_MEM_NOACCESS((p), (s))
+# define JMEM_VALGRIND_UNDEFINED_SPACE(p, s) VALGRIND_MAKE_MEM_UNDEFINED((p), (s))
+# define JMEM_VALGRIND_DEFINED_SPACE(p, s) VALGRIND_MAKE_MEM_DEFINED((p), (s))
+# define JMEM_VALGRIND_MALLOCLIKE_SPACE(p, s) VALGRIND_MALLOCLIKE_BLOCK((p), (s), 0, 0)
+# define JMEM_VALGRIND_FREELIKE_SPACE(p) VALGRIND_FREELIKE_BLOCK((p), 0)
+#else /* !JERRY_VALGRIND */
+# define JMEM_VALGRIND_NOACCESS_SPACE(p, s)
+# define JMEM_VALGRIND_UNDEFINED_SPACE(p, s)
+# define JMEM_VALGRIND_DEFINED_SPACE(p, s)
+# define JMEM_VALGRIND_MALLOCLIKE_SPACE(p, s)
+# define JMEM_VALGRIND_FREELIKE_SPACE(p)
+#endif /* JERRY_VALGRIND */
+/** @} */
+
#ifdef JMEM_STATS
void jmem_heap_stats_reset_peak (void);
void jmem_heap_stats_print (void);
* \addtogroup poolman Memory pool manager
* @{
*/
-#ifdef JMEM_STATS
-void jmem_pools_stats_print (void);
-#endif /* JMEM_STATS */
void jmem_pools_finalize (void);
void jmem_pools_collect_empty (void);
#define JMEM_ALLOCATOR_INTERNAL
#include "jmem-allocator-internal.h"
+#ifdef JMEM_STATS
+/**
+ * Register byte code allocation.
+ */
+void
+jmem_stats_allocate_byte_code_bytes (size_t byte_code_size)
+{
+ jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
+
+ heap_stats->byte_code_bytes += byte_code_size;
+
+ if (heap_stats->byte_code_bytes >= heap_stats->peak_byte_code_bytes)
+ {
+ heap_stats->peak_byte_code_bytes = heap_stats->byte_code_bytes;
+ }
+} /* jmem_stats_allocate_byte_code_bytes */
+
+/**
+ * Register byte code free.
+ */
+void
+jmem_stats_free_byte_code_bytes (size_t byte_code_size)
+{
+ jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
+
+ JERRY_ASSERT (heap_stats->byte_code_bytes >= byte_code_size);
+
+ heap_stats->byte_code_bytes -= byte_code_size;
+} /* jmem_stats_free_byte_code_bytes */
+
+/**
+ * Register string allocation.
+ */
+void
+jmem_stats_allocate_string_bytes (size_t string_size)
+{
+ jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
+
+ heap_stats->string_bytes += string_size;
+
+ if (heap_stats->string_bytes >= heap_stats->peak_string_bytes)
+ {
+ heap_stats->peak_string_bytes = heap_stats->string_bytes;
+ }
+} /* jmem_stats_allocate_string_bytes */
+
+/**
+ * Register string free.
+ */
+void
+jmem_stats_free_string_bytes (size_t string_size)
+{
+ jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
+
+ JERRY_ASSERT (heap_stats->string_bytes >= string_size);
+
+ heap_stats->string_bytes -= string_size;
+} /* jmem_stats_free_string_bytes */
+
+/**
+ * Register object allocation.
+ */
+void
+jmem_stats_allocate_object_bytes (size_t object_size)
+{
+ jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
+
+ heap_stats->object_bytes += object_size;
+
+ if (heap_stats->object_bytes >= heap_stats->peak_object_bytes)
+ {
+ heap_stats->peak_object_bytes = heap_stats->object_bytes;
+ }
+} /* jmem_stats_allocate_object_bytes */
+
+/**
+ * Register object free.
+ */
+void
+jmem_stats_free_object_bytes (size_t object_size)
+{
+ jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
+
+ JERRY_ASSERT (heap_stats->object_bytes >= object_size);
+
+ heap_stats->object_bytes -= object_size;
+} /* jmem_stats_free_object_bytes */
+
+/**
+ * Register property allocation.
+ */
+void
+jmem_stats_allocate_property_bytes (size_t property_size)
+{
+ jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
+
+ heap_stats->property_bytes += property_size;
+
+ if (heap_stats->property_bytes >= heap_stats->peak_property_bytes)
+ {
+ heap_stats->peak_property_bytes = heap_stats->property_bytes;
+ }
+} /* jmem_stats_allocate_property_bytes */
+
+/**
+ * Register property free.
+ */
+void
+jmem_stats_free_property_bytes (size_t property_size)
+{
+ jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
+
+ JERRY_ASSERT (heap_stats->property_bytes >= property_size);
+
+ heap_stats->property_bytes -= property_size;
+} /* jmem_stats_free_property_bytes */
+
+#endif /* JMEM_STATS */
+
/**
* Initialize memory allocators.
*/
#ifdef JMEM_STATS
if (JERRY_CONTEXT (jerry_init_flags) & ECMA_INIT_MEM_STATS)
{
- jmem_stats_print ();
+ jmem_heap_stats_print ();
}
#endif /* JMEM_STATS */
*
* @return packed pointer
*/
-inline jmem_cpointer_t __attr_pure___ __attr_always_inline___
+inline jmem_cpointer_t JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
jmem_compress_pointer (const void *pointer_p) /**< pointer to compress */
{
JERRY_ASSERT (pointer_p != NULL);
*
* @return unpacked pointer
*/
-inline void * __attr_pure___ __attr_always_inline___
+inline void * JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
jmem_decompress_pointer (uintptr_t compressed_pointer) /**< pointer to decompress */
{
JERRY_ASSERT (compressed_pointer != JMEM_CP_NULL);
jmem_pools_collect_empty ();
} /* jmem_run_free_unused_memory_callbacks */
-
-#ifdef JMEM_STATS
-/**
- * Print memory usage statistics
- */
-void
-jmem_stats_print (void)
-{
- jmem_heap_stats_print ();
-} /* jmem_stats_print */
-
-/**
- * Register byte code allocation.
- */
-void
-jmem_stats_allocate_byte_code_bytes (size_t byte_code_size)
-{
- jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
-
- heap_stats->byte_code_bytes += byte_code_size;
-
- if (heap_stats->byte_code_bytes >= heap_stats->peak_byte_code_bytes)
- {
- heap_stats->peak_byte_code_bytes = heap_stats->byte_code_bytes;
- }
-} /* jmem_stats_allocate_byte_code_bytes */
-
-/**
- * Register byte code free.
- */
-void
-jmem_stats_free_byte_code_bytes (size_t byte_code_size)
-{
- jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
-
- JERRY_ASSERT (heap_stats->byte_code_bytes >= byte_code_size);
-
- heap_stats->byte_code_bytes -= byte_code_size;
-} /* jmem_stats_free_byte_code_bytes */
-
-/**
- * Register string allocation.
- */
-void
-jmem_stats_allocate_string_bytes (size_t string_size)
-{
- jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
-
- heap_stats->string_bytes += string_size;
-
- if (heap_stats->string_bytes >= heap_stats->peak_string_bytes)
- {
- heap_stats->peak_string_bytes = heap_stats->string_bytes;
- }
-} /* jmem_stats_allocate_string_bytes */
-
-/**
- * Register string free.
- */
-void
-jmem_stats_free_string_bytes (size_t string_size)
-{
- jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
-
- JERRY_ASSERT (heap_stats->string_bytes >= string_size);
-
- heap_stats->string_bytes -= string_size;
-} /* jmem_stats_free_string_bytes */
-
-/**
- * Register object allocation.
- */
-void
-jmem_stats_allocate_object_bytes (size_t object_size)
-{
- jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
-
- heap_stats->object_bytes += object_size;
-
- if (heap_stats->object_bytes >= heap_stats->peak_object_bytes)
- {
- heap_stats->peak_object_bytes = heap_stats->object_bytes;
- }
-} /* jmem_stats_allocate_object_bytes */
-
-/**
- * Register object free.
- */
-void
-jmem_stats_free_object_bytes (size_t object_size)
-{
- jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
-
- JERRY_ASSERT (heap_stats->object_bytes >= object_size);
-
- heap_stats->object_bytes -= object_size;
-} /* jmem_stats_free_object_bytes */
-
-/**
- * Register property allocation.
- */
-void
-jmem_stats_allocate_property_bytes (size_t property_size)
-{
- jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
-
- heap_stats->property_bytes += property_size;
-
- if (heap_stats->property_bytes >= heap_stats->peak_property_bytes)
- {
- heap_stats->peak_property_bytes = heap_stats->property_bytes;
- }
-} /* jmem_stats_allocate_property_bytes */
-
-/**
- * Register property free.
- */
-void
-jmem_stats_free_property_bytes (size_t property_size)
-{
- jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
-
- JERRY_ASSERT (heap_stats->property_bytes >= property_size);
-
- heap_stats->property_bytes -= property_size;
-} /* jmem_stats_free_property_bytes */
-
-#endif /* JMEM_STATS */
* @{
*/
-/*
- * Valgrind-related options and headers
- */
-#ifdef JERRY_VALGRIND
-# include "memcheck.h"
-
-# define VALGRIND_NOACCESS_SPACE(p, s) VALGRIND_MAKE_MEM_NOACCESS((p), (s))
-# define VALGRIND_UNDEFINED_SPACE(p, s) VALGRIND_MAKE_MEM_UNDEFINED((p), (s))
-# define VALGRIND_DEFINED_SPACE(p, s) VALGRIND_MAKE_MEM_DEFINED((p), (s))
-
-#else /* !JERRY_VALGRIND */
-# define VALGRIND_NOACCESS_SPACE(p, s)
-# define VALGRIND_UNDEFINED_SPACE(p, s)
-# define VALGRIND_DEFINED_SPACE(p, s)
-#endif /* JERRY_VALGRIND */
-
-#ifdef JERRY_VALGRIND_FREYA
-
-#ifdef JERRY_VALGRIND
-#error Valgrind and valgrind-freya modes are not compatible.
-#endif /* JERRY_VALGRIND */
-
-#include "memcheck.h"
-
-# define VALGRIND_FREYA_CHECK_MEMPOOL_REQUEST \
- bool mempool_request = JERRY_CONTEXT (valgrind_freya_mempool_request); \
- JERRY_CONTEXT (valgrind_freya_mempool_request) = false
-
-# define VALGRIND_FREYA_MALLOCLIKE_SPACE(p, s) \
- if (!mempool_request) \
- { \
- VALGRIND_MALLOCLIKE_BLOCK((p), (s), 0, 0); \
- }
-
-# define VALGRIND_FREYA_FREELIKE_SPACE(p) \
- if (!mempool_request) \
- { \
- VALGRIND_FREELIKE_BLOCK((p), 0); \
- }
-
-#else /* !JERRY_VALGRIND_FREYA */
-# define VALGRIND_FREYA_CHECK_MEMPOOL_REQUEST
-# define VALGRIND_FREYA_MALLOCLIKE_SPACE(p, s)
-# define VALGRIND_FREYA_FREELIKE_SPACE(p)
-#endif /* JERRY_VALGRIND_FREYA */
-
+#ifndef JERRY_SYSTEM_ALLOCATOR
/**
* End of list marker.
*/
#define JMEM_HEAP_END_OF_LIST ((uint32_t) 0xffffffff)
+/**
+ * @{
+ */
#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY
/* In this case we simply store the pointer, since it fits anyway. */
#define JMEM_HEAP_GET_OFFSET_FROM_ADDR(p) ((uint32_t) (p))
#define JMEM_HEAP_GET_OFFSET_FROM_ADDR(p) ((uint32_t) ((uint8_t *) (p) - JERRY_HEAP_CONTEXT (area)))
#define JMEM_HEAP_GET_ADDR_FROM_OFFSET(u) ((jmem_heap_free_t *) (JERRY_HEAP_CONTEXT (area) + (u)))
#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
+/**
+ * @}
+ */
-#ifndef JERRY_SYSTEM_ALLOCATOR
/**
* Get end of region
+ *
+ * @return pointer to the end of the region
*/
-static inline jmem_heap_free_t * __attr_always_inline___ __attr_pure___
+static inline jmem_heap_free_t * JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_PURE
jmem_heap_get_region_end (jmem_heap_free_t *curr_p) /**< current region */
{
return (jmem_heap_free_t *)((uint8_t *) curr_p + curr_p->size);
} /* jmem_heap_get_region_end */
#endif /* !JERRY_SYSTEM_ALLOCATOR */
-#ifndef JERRY_ENABLE_EXTERNAL_CONTEXT
/**
- * Check size of heap is corresponding to configuration
+ * @{
+ * JMEM_HEAP_STAT_xxx definitions
*/
-JERRY_STATIC_ASSERT (sizeof (jmem_heap_t) <= JMEM_HEAP_SIZE,
- size_of_mem_heap_must_be_less_than_or_equal_to_MEM_HEAP_SIZE);
-#endif /* !JERRY_ENABLE_EXTERNAL_CONTEXT */
-
#ifdef JMEM_STATS
static void jmem_heap_stat_init (void);
static void jmem_heap_stat_alloc (size_t num);
static void jmem_heap_stat_free (size_t num);
+#define JMEM_HEAP_STAT_INIT() jmem_heap_stat_init ()
+#define JMEM_HEAP_STAT_ALLOC(v1) jmem_heap_stat_alloc (v1)
+#define JMEM_HEAP_STAT_FREE(v1) jmem_heap_stat_free (v1)
+
#ifndef JERRY_SYSTEM_ALLOCATOR
static void jmem_heap_stat_skip (void);
static void jmem_heap_stat_nonskip (void);
static void jmem_heap_stat_alloc_iter (void);
static void jmem_heap_stat_free_iter (void);
-#endif /* !JERRY_SYSTEM_ALLOCATOR */
-# define JMEM_HEAP_STAT_INIT() jmem_heap_stat_init ()
-# define JMEM_HEAP_STAT_ALLOC(v1) jmem_heap_stat_alloc (v1)
-# define JMEM_HEAP_STAT_FREE(v1) jmem_heap_stat_free (v1)
-# define JMEM_HEAP_STAT_SKIP() jmem_heap_stat_skip ()
-# define JMEM_HEAP_STAT_NONSKIP() jmem_heap_stat_nonskip ()
-# define JMEM_HEAP_STAT_ALLOC_ITER() jmem_heap_stat_alloc_iter ()
-# define JMEM_HEAP_STAT_FREE_ITER() jmem_heap_stat_free_iter ()
+#define JMEM_HEAP_STAT_SKIP() jmem_heap_stat_skip ()
+#define JMEM_HEAP_STAT_NONSKIP() jmem_heap_stat_nonskip ()
+#define JMEM_HEAP_STAT_ALLOC_ITER() jmem_heap_stat_alloc_iter ()
+#define JMEM_HEAP_STAT_FREE_ITER() jmem_heap_stat_free_iter ()
+#endif /* !JERRY_SYSTEM_ALLOCATOR */
#else /* !JMEM_STATS */
-# define JMEM_HEAP_STAT_INIT()
-# define JMEM_HEAP_STAT_ALLOC(v1)
-# define JMEM_HEAP_STAT_FREE(v1)
-# define JMEM_HEAP_STAT_SKIP()
-# define JMEM_HEAP_STAT_NONSKIP()
-# define JMEM_HEAP_STAT_ALLOC_ITER()
-# define JMEM_HEAP_STAT_FREE_ITER()
+#define JMEM_HEAP_STAT_INIT()
+#define JMEM_HEAP_STAT_ALLOC(v1) JERRY_UNUSED (v1)
+#define JMEM_HEAP_STAT_FREE(v1) JERRY_UNUSED (v1)
+
+#ifndef JERRY_SYSTEM_ALLOCATOR
+#define JMEM_HEAP_STAT_SKIP()
+#define JMEM_HEAP_STAT_NONSKIP()
+#define JMEM_HEAP_STAT_ALLOC_ITER()
+#define JMEM_HEAP_STAT_FREE_ITER()
+#endif /* !JERRY_SYSTEM_ALLOCATOR */
#endif /* JMEM_STATS */
+/** @} */
/**
* Startup initialization of heap
void
jmem_heap_init (void)
{
+#ifndef JERRY_SYSTEM_ALLOCATOR
#ifndef JERRY_CPOINTER_32_BIT
/* the maximum heap size for 16bit compressed pointers should be 512K */
JERRY_ASSERT (((UINT16_MAX + 1) << JMEM_ALIGNMENT_LOG) >= JMEM_HEAP_SIZE);
#endif /* !JERRY_CPOINTER_32_BIT */
-
-#ifndef JERRY_SYSTEM_ALLOCATOR
JERRY_ASSERT ((uintptr_t) JERRY_HEAP_CONTEXT (area) % JMEM_ALIGNMENT == 0);
JERRY_CONTEXT (jmem_heap_limit) = CONFIG_MEM_HEAP_DESIRED_LIMIT;
JERRY_CONTEXT (jmem_heap_list_skip_p) = &JERRY_HEAP_CONTEXT (first);
- VALGRIND_NOACCESS_SPACE (JERRY_HEAP_CONTEXT (area), JMEM_HEAP_AREA_SIZE);
+ JMEM_VALGRIND_NOACCESS_SPACE (JERRY_HEAP_CONTEXT (area), JMEM_HEAP_AREA_SIZE);
#endif /* !JERRY_SYSTEM_ALLOCATOR */
JMEM_HEAP_STAT_INIT ();
{
JERRY_ASSERT (JERRY_CONTEXT (jmem_heap_allocated_size) == 0);
#ifndef JERRY_SYSTEM_ALLOCATOR
- VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), JMEM_HEAP_SIZE);
+ JMEM_VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), JMEM_HEAP_SIZE);
#endif /* !JERRY_SYSTEM_ALLOCATOR */
} /* jmem_heap_finalize */
* @return pointer to allocated memory block - if allocation is successful,
* NULL - if there is not enough memory.
*/
-static __attr_hot___ void *
-jmem_heap_alloc_block_internal (const size_t size)
+static void * JERRY_ATTR_HOT
+jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block */
{
#ifndef JERRY_SYSTEM_ALLOCATOR
/* Align size. */
const size_t required_size = ((size + JMEM_ALIGNMENT - 1) / JMEM_ALIGNMENT) * JMEM_ALIGNMENT;
jmem_heap_free_t *data_space_p = NULL;
- VALGRIND_DEFINED_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t));
/* Fast path for 8 byte chunks, first region is guaranteed to be sufficient. */
if (required_size == JMEM_ALIGNMENT
- && likely (JERRY_HEAP_CONTEXT (first).next_offset != JMEM_HEAP_END_OF_LIST))
+ && JERRY_LIKELY (JERRY_HEAP_CONTEXT (first).next_offset != JMEM_HEAP_END_OF_LIST))
{
data_space_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (JERRY_HEAP_CONTEXT (first).next_offset);
JERRY_ASSERT (jmem_is_heap_pointer (data_space_p));
- VALGRIND_DEFINED_SPACE (data_space_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (data_space_p, sizeof (jmem_heap_free_t));
JERRY_CONTEXT (jmem_heap_allocated_size) += JMEM_ALIGNMENT;
JMEM_HEAP_STAT_ALLOC_ITER ();
jmem_heap_free_t *remaining_p;
remaining_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (JERRY_HEAP_CONTEXT (first).next_offset) + 1;
- VALGRIND_DEFINED_SPACE (remaining_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (remaining_p, sizeof (jmem_heap_free_t));
remaining_p->size = data_space_p->size - JMEM_ALIGNMENT;
remaining_p->next_offset = data_space_p->next_offset;
- VALGRIND_NOACCESS_SPACE (remaining_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (remaining_p, sizeof (jmem_heap_free_t));
JERRY_HEAP_CONTEXT (first).next_offset = JMEM_HEAP_GET_OFFSET_FROM_ADDR (remaining_p);
}
- VALGRIND_UNDEFINED_SPACE (data_space_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_UNDEFINED_SPACE (data_space_p, sizeof (jmem_heap_free_t));
- if (unlikely (data_space_p == JERRY_CONTEXT (jmem_heap_list_skip_p)))
+ if (JERRY_UNLIKELY (data_space_p == JERRY_CONTEXT (jmem_heap_list_skip_p)))
{
JERRY_CONTEXT (jmem_heap_list_skip_p) = JMEM_HEAP_GET_ADDR_FROM_OFFSET (JERRY_HEAP_CONTEXT (first).next_offset);
}
{
jmem_heap_free_t *current_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (current_offset);
JERRY_ASSERT (jmem_is_heap_pointer (current_p));
- VALGRIND_DEFINED_SPACE (current_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (current_p, sizeof (jmem_heap_free_t));
JMEM_HEAP_STAT_ALLOC_ITER ();
const uint32_t next_offset = current_p->next_offset;
jmem_heap_free_t *const remaining_p = (jmem_heap_free_t *) ((uint8_t *) current_p + required_size);
/* Update metadata. */
- VALGRIND_DEFINED_SPACE (remaining_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (remaining_p, sizeof (jmem_heap_free_t));
remaining_p->size = current_p->size - (uint32_t) required_size;
remaining_p->next_offset = next_offset;
- VALGRIND_NOACCESS_SPACE (remaining_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (remaining_p, sizeof (jmem_heap_free_t));
/* Update list. */
- VALGRIND_DEFINED_SPACE (prev_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (prev_p, sizeof (jmem_heap_free_t));
prev_p->next_offset = JMEM_HEAP_GET_OFFSET_FROM_ADDR (remaining_p);
- VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
}
/* Block is an exact fit. */
else
{
/* Remove the region from the list. */
- VALGRIND_DEFINED_SPACE (prev_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (prev_p, sizeof (jmem_heap_free_t));
prev_p->next_offset = next_offset;
- VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
}
JERRY_CONTEXT (jmem_heap_list_skip_p) = prev_p;
break;
}
- VALGRIND_NOACCESS_SPACE (current_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (current_p, sizeof (jmem_heap_free_t));
/* Next in list. */
prev_p = current_p;
current_offset = next_offset;
JERRY_CONTEXT (jmem_heap_limit) += CONFIG_MEM_HEAP_DESIRED_LIMIT;
}
- VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t));
- if (unlikely (!data_space_p))
+ if (JERRY_UNLIKELY (!data_space_p))
{
return NULL;
}
JERRY_ASSERT ((uintptr_t) data_space_p % JMEM_ALIGNMENT == 0);
- VALGRIND_UNDEFINED_SPACE (data_space_p, size);
+ JMEM_VALGRIND_UNDEFINED_SPACE (data_space_p, size);
JMEM_HEAP_STAT_ALLOC (size);
return (void *) data_space_p;
bool ret_null_on_error) /**< indicates whether return null or terminate
with ERR_OUT_OF_MEMORY on out of memory */
{
- if (unlikely (size == 0))
+ if (JERRY_UNLIKELY (size == 0))
{
return NULL;
}
- VALGRIND_FREYA_CHECK_MEMPOOL_REQUEST;
-
#ifdef JMEM_GC_BEFORE_EACH_ALLOC
jmem_run_free_unused_memory_callbacks (JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH);
#endif /* JMEM_GC_BEFORE_EACH_ALLOC */
void *data_space_p = jmem_heap_alloc_block_internal (size);
- if (likely (data_space_p != NULL))
+ if (JERRY_LIKELY (data_space_p != NULL))
{
- VALGRIND_FREYA_MALLOCLIKE_SPACE (data_space_p, size);
+ JMEM_VALGRIND_MALLOCLIKE_SPACE (data_space_p, size);
return data_space_p;
}
data_space_p = jmem_heap_alloc_block_internal (size);
- if (likely (data_space_p != NULL))
+ if (JERRY_LIKELY (data_space_p != NULL))
{
- VALGRIND_FREYA_MALLOCLIKE_SPACE (data_space_p, size);
+ JMEM_VALGRIND_MALLOCLIKE_SPACE (data_space_p, size);
return data_space_p;
}
}
* @return NULL, if the required memory is 0
* pointer to allocated memory block, otherwise
*/
-inline void * __attr_hot___ __attr_always_inline___
+inline void * JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE
jmem_heap_alloc_block (const size_t size) /**< required memory size */
{
return jmem_heap_gc_and_alloc_block (size, false);
* also NULL, if the allocation has failed
* pointer to the allocated memory block, otherwise
*/
-inline void * __attr_hot___ __attr_always_inline___
+inline void * JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE
jmem_heap_alloc_block_null_on_error (const size_t size) /**< required memory size */
{
return jmem_heap_gc_and_alloc_block (size, true);
/**
* Free the memory block.
*/
-void __attr_hot___
+void JERRY_ATTR_HOT
jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the block */
const size_t size) /**< size of allocated region */
{
#ifndef JERRY_SYSTEM_ALLOCATOR
- VALGRIND_FREYA_CHECK_MEMPOOL_REQUEST;
-
/* checking that ptr points to the heap */
JERRY_ASSERT (jmem_is_heap_pointer (ptr));
JERRY_ASSERT (size > 0);
JERRY_ASSERT (JERRY_CONTEXT (jmem_heap_limit) >= JERRY_CONTEXT (jmem_heap_allocated_size));
- VALGRIND_FREYA_FREELIKE_SPACE (ptr);
- VALGRIND_NOACCESS_SPACE (ptr, size);
+ JMEM_VALGRIND_FREELIKE_SPACE (ptr);
+ JMEM_VALGRIND_NOACCESS_SPACE (ptr, size);
JMEM_HEAP_STAT_FREE_ITER ();
jmem_heap_free_t *block_p = (jmem_heap_free_t *) ptr;
jmem_heap_free_t *prev_p;
jmem_heap_free_t *next_p;
- VALGRIND_DEFINED_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t));
if (block_p > JERRY_CONTEXT (jmem_heap_list_skip_p))
{
JERRY_ASSERT (jmem_is_heap_pointer (block_p));
const uint32_t block_offset = JMEM_HEAP_GET_OFFSET_FROM_ADDR (block_p);
- VALGRIND_DEFINED_SPACE (prev_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (prev_p, sizeof (jmem_heap_free_t));
/* Find position of region in the list. */
while (prev_p->next_offset < block_offset)
{
next_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (prev_p->next_offset);
JERRY_ASSERT (jmem_is_heap_pointer (next_p));
- VALGRIND_DEFINED_SPACE (next_p, sizeof (jmem_heap_free_t));
- VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (next_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
prev_p = next_p;
JMEM_HEAP_STAT_FREE_ITER ();
}
next_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (prev_p->next_offset);
- VALGRIND_DEFINED_SPACE (next_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (next_p, sizeof (jmem_heap_free_t));
/* Realign size */
const size_t aligned_size = (size + JMEM_ALIGNMENT - 1) / JMEM_ALIGNMENT * JMEM_ALIGNMENT;
- VALGRIND_DEFINED_SPACE (block_p, sizeof (jmem_heap_free_t));
- VALGRIND_DEFINED_SPACE (prev_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (block_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (prev_p, sizeof (jmem_heap_free_t));
/* Update prev. */
if (jmem_heap_get_region_end (prev_p) == block_p)
{
/* Can be merged. */
prev_p->size += (uint32_t) aligned_size;
- VALGRIND_NOACCESS_SPACE (block_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (block_p, sizeof (jmem_heap_free_t));
block_p = prev_p;
}
else
prev_p->next_offset = block_offset;
}
- VALGRIND_DEFINED_SPACE (next_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_DEFINED_SPACE (next_p, sizeof (jmem_heap_free_t));
/* Update next. */
if (jmem_heap_get_region_end (block_p) == next_p)
{
JERRY_CONTEXT (jmem_heap_list_skip_p) = prev_p;
- VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
- VALGRIND_NOACCESS_SPACE (block_p, size);
- VALGRIND_NOACCESS_SPACE (next_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (block_p, size);
+ JMEM_VALGRIND_NOACCESS_SPACE (next_p, sizeof (jmem_heap_free_t));
JERRY_ASSERT (JERRY_CONTEXT (jmem_heap_allocated_size) > 0);
JERRY_CONTEXT (jmem_heap_allocated_size) -= aligned_size;
JERRY_CONTEXT (jmem_heap_limit) -= CONFIG_MEM_HEAP_DESIRED_LIMIT;
}
- VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t));
JERRY_ASSERT (JERRY_CONTEXT (jmem_heap_limit) >= JERRY_CONTEXT (jmem_heap_allocated_size));
JMEM_HEAP_STAT_FREE (size);
#else /* JERRY_SYSTEM_ALLOCATOR */
-#ifdef JMEM_STATS
JMEM_HEAP_STAT_FREE (size);
-#else /* !JMEM_STATS */
- JERRY_UNUSED (size);
-#endif /* JMEM_STATS */
free (ptr);
#endif /* !JERRY_SYSTEM_ALLOCATOR */
} /* jmem_heap_free_block */
{
jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
- JERRY_DEBUG_MSG ("Heap stats:\n"
- " Heap size = %zu bytes\n"
- " Allocated = %zu bytes\n"
+ JERRY_DEBUG_MSG ("Heap stats:\n");
+#ifndef JERRY_SYSTEM_ALLOCATOR
+ JERRY_DEBUG_MSG (" Heap size = %zu bytes\n",
+ heap_stats->size);
+#endif /* !JERRY_SYSTEM_ALLOCATOR */
+ JERRY_DEBUG_MSG (" Allocated = %zu bytes\n"
" Peak allocated = %zu bytes\n"
" Waste = %zu bytes\n"
" Peak waste = %zu bytes\n"
" Peak allocated object data = %zu bytes\n"
" Allocated property data = %zu bytes\n"
" Peak allocated property data = %zu bytes\n",
- heap_stats->size,
heap_stats->allocated_bytes,
heap_stats->peak_allocated_bytes,
heap_stats->waste_bytes,
static void
jmem_heap_stat_init (void)
{
+#ifndef JERRY_SYSTEM_ALLOCATOR
JERRY_CONTEXT (jmem_heap_stats).size = JMEM_HEAP_AREA_SIZE;
+#endif /* !JERRY_SYSTEM_ALLOCATOR */
} /* jmem_heap_stat_init */
/**
#endif /* !JERRY_SYSTEM_ALLOCATOR */
#endif /* JMEM_STATS */
-#undef VALGRIND_NOACCESS_SPACE
-#undef VALGRIND_UNDEFINED_SPACE
-#undef VALGRIND_DEFINED_SPACE
-#undef VALGRIND_FREYA_CHECK_MEMPOOL_REQUEST
-#undef VALGRIND_FREYA_MALLOCLIKE_SPACE
-#undef VALGRIND_FREYA_FREELIKE_SPACE
-
/**
* @}
* @}
* @{
*/
-/*
- * Valgrind-related options and headers
- */
-#ifdef JERRY_VALGRIND
-# include "memcheck.h"
-
-# define VALGRIND_NOACCESS_SPACE(p, s) VALGRIND_MAKE_MEM_NOACCESS((p), (s))
-# define VALGRIND_UNDEFINED_SPACE(p, s) VALGRIND_MAKE_MEM_UNDEFINED((p), (s))
-# define VALGRIND_DEFINED_SPACE(p, s) VALGRIND_MAKE_MEM_DEFINED((p), (s))
-#else /* !JERRY_VALGRIND */
-# define VALGRIND_NOACCESS_SPACE(p, s)
-# define VALGRIND_UNDEFINED_SPACE(p, s)
-# define VALGRIND_DEFINED_SPACE(p, s)
-#endif /* JERRY_VALGRIND */
-
-#ifdef JERRY_VALGRIND_FREYA
-# include "memcheck.h"
-
-# define VALGRIND_FREYA_MALLOCLIKE_SPACE(p, s) VALGRIND_MALLOCLIKE_BLOCK((p), (s), 0, 0)
-# define VALGRIND_FREYA_FREELIKE_SPACE(p) VALGRIND_FREELIKE_BLOCK((p), 0)
-#else /* !JERRY_VALGRIND_FREYA */
-# define VALGRIND_FREYA_MALLOCLIKE_SPACE(p, s)
-# define VALGRIND_FREYA_FREELIKE_SPACE(p)
-#endif /* JERRY_VALGRIND_FREYA */
-
/**
* Finalize pool manager
*/
* @return pointer to allocated chunk, if allocation was successful,
* or NULL - if not enough memory.
*/
-inline void * __attr_hot___ __attr_always_inline___
+inline void * JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE
jmem_pools_alloc (size_t size) /**< size of the chunk */
{
#ifdef JMEM_GC_BEFORE_EACH_ALLOC
jmem_run_free_unused_memory_callbacks (JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH);
#endif /* JMEM_GC_BEFORE_EACH_ALLOC */
+#ifdef JERRY_CPOINTER_32_BIT
if (size <= 8)
{
+#else /* !JERRY_CPOINTER_32_BIT */
+ JERRY_ASSERT (size <= 8);
+#endif /* JERRY_CPOINTER_32_BIT */
+
if (JERRY_CONTEXT (jmem_free_8_byte_chunk_p) != NULL)
{
const jmem_pools_chunk_t *const chunk_p = JERRY_CONTEXT (jmem_free_8_byte_chunk_p);
- VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
+ JMEM_VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
JERRY_CONTEXT (jmem_free_8_byte_chunk_p) = chunk_p->next_p;
- VALGRIND_UNDEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
+ JMEM_VALGRIND_UNDEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
return (void *) chunk_p;
}
{
return (void *) jmem_heap_alloc_block (8);
}
- }
#ifdef JERRY_CPOINTER_32_BIT
+ }
+
JERRY_ASSERT (size <= 16);
if (JERRY_CONTEXT (jmem_free_16_byte_chunk_p) != NULL)
{
const jmem_pools_chunk_t *const chunk_p = JERRY_CONTEXT (jmem_free_16_byte_chunk_p);
- VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
+ JMEM_VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
JERRY_CONTEXT (jmem_free_16_byte_chunk_p) = chunk_p->next_p;
- VALGRIND_UNDEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
+ JMEM_VALGRIND_UNDEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
return (void *) chunk_p;
}
{
return (void *) jmem_heap_alloc_block (16);
}
-#else /* !JERRY_CPOINTER_32_BIT */
- JERRY_UNREACHABLE ();
- return NULL;
-#endif
+#endif /* JERRY_CPOINTER_32_BIT */
} /* jmem_pools_alloc */
/**
* Free the chunk
*/
-inline void __attr_hot___ __attr_always_inline___
+inline void JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE
jmem_pools_free (void *chunk_p, /**< pointer to the chunk */
size_t size) /**< size of the chunk */
{
jmem_pools_chunk_t *const chunk_to_free_p = (jmem_pools_chunk_t *) chunk_p;
- VALGRIND_DEFINED_SPACE (chunk_to_free_p, size);
+ JMEM_VALGRIND_DEFINED_SPACE (chunk_to_free_p, size);
+#ifdef JERRY_CPOINTER_32_BIT
if (size <= 8)
{
+#else /* !JERRY_CPOINTER_32_BIT */
+ JERRY_ASSERT (size <= 8);
+#endif /* JERRY_CPOINTER_32_BIT */
+
chunk_to_free_p->next_p = JERRY_CONTEXT (jmem_free_8_byte_chunk_p);
JERRY_CONTEXT (jmem_free_8_byte_chunk_p) = chunk_to_free_p;
+
+#ifdef JERRY_CPOINTER_32_BIT
}
else
{
-#ifdef JERRY_CPOINTER_32_BIT
JERRY_ASSERT (size <= 16);
chunk_to_free_p->next_p = JERRY_CONTEXT (jmem_free_16_byte_chunk_p);
JERRY_CONTEXT (jmem_free_16_byte_chunk_p) = chunk_to_free_p;
-#else /* !JERRY_CPOINTER_32_BIT */
- JERRY_UNREACHABLE ();
-#endif /* JERRY_CPOINTER_32_BIT */
}
+#endif /* JERRY_CPOINTER_32_BIT */
- VALGRIND_NOACCESS_SPACE (chunk_to_free_p, size);
+ JMEM_VALGRIND_NOACCESS_SPACE (chunk_to_free_p, size);
} /* jmem_pools_free */
/**
while (chunk_p)
{
- VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
+ JMEM_VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
jmem_pools_chunk_t *const next_p = chunk_p->next_p;
- VALGRIND_NOACCESS_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
jmem_heap_free_block (chunk_p, 8);
chunk_p = next_p;
while (chunk_p)
{
- VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
+ JMEM_VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
jmem_pools_chunk_t *const next_p = chunk_p->next_p;
- VALGRIND_NOACCESS_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
+ JMEM_VALGRIND_NOACCESS_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
jmem_heap_free_block (chunk_p, 16);
chunk_p = next_p;
#endif /* JERRY_CPOINTER_32_BIT */
} /* jmem_pools_collect_empty */
-#undef VALGRIND_NOACCESS_SPACE
-#undef VALGRIND_UNDEFINED_SPACE
-#undef VALGRIND_DEFINED_SPACE
-#undef VALGRIND_FREYA_MALLOCLIKE_SPACE
-#undef VALGRIND_FREYA_FREELIKE_SPACE
-
/**
* @}
* @}
* @{
*/
-#ifndef JERRY_ENABLE_EXTERNAL_CONTEXT
-/**
- * Size of heap
- */
-#define JMEM_HEAP_SIZE ((size_t) (CONFIG_MEM_HEAP_AREA_SIZE))
-#endif /* !JERRY_ENABLE_EXTERNAL_CONTEXT */
-
/**
* Logarithm of required alignment for allocated units/blocks
*/
size_t free_iter_count; /**< Number of iterations required for inserting free blocks */
} jmem_heap_stats_t;
-void jmem_stats_print (void);
void jmem_stats_allocate_byte_code_bytes (size_t property_size);
void jmem_stats_free_byte_code_bytes (size_t property_size);
void jmem_stats_allocate_string_bytes (size_t string_size);
void jmem_heap_get_stats (jmem_heap_stats_t *);
#endif /* JMEM_STATS */
-jmem_cpointer_t jmem_compress_pointer (const void *pointer_p) __attr_pure___;
-void *jmem_decompress_pointer (uintptr_t compressed_pointer) __attr_pure___;
+jmem_cpointer_t JERRY_ATTR_PURE jmem_compress_pointer (const void *pointer_p);
+void * JERRY_ATTR_PURE jmem_decompress_pointer (uintptr_t compressed_pointer);
/**
* A free memory callback routine type.
* Get value of pointer from specified compressed pointer value
*/
#define JMEM_CP_GET_POINTER(type, cp_value) \
- (((unlikely ((cp_value) == JMEM_CP_NULL)) ? NULL : JMEM_CP_GET_NON_NULL_POINTER (type, cp_value)))
+ (((JERRY_UNLIKELY ((cp_value) == JMEM_CP_NULL)) ? NULL : JMEM_CP_GET_NON_NULL_POINTER (type, cp_value)))
/**
* Set value of non-null compressed pointer so that it will correspond
{ \
void *ptr_value = (void *) non_compressed_pointer; \
\
- if (unlikely ((ptr_value) == NULL)) \
+ if (JERRY_UNLIKELY ((ptr_value) == NULL)) \
{ \
(cp_value) = JMEM_CP_NULL; \
} \
* If !JERRY_NDEBUG and code != 0, print status code with description
* and call assertion fail handler.
*/
-void __noreturn
+void JERRY_ATTR_NORETURN
jerry_fatal (jerry_fatal_code_t code) /**< status code */
{
#ifndef JERRY_NDEBUG
JERRY_ERROR_MSG ("Error: ERR_REF_COUNT_LIMIT\n");
break;
}
+ case ERR_DISABLED_BYTE_CODE:
+ {
+ JERRY_ERROR_MSG ("Error: ERR_DISABLED_BYTE_CODE\n");
+ break;
+ }
case ERR_FAILED_INTERNAL_ASSERTION:
{
JERRY_ERROR_MSG ("Error: ERR_FAILED_INTERNAL_ASSERTION\n");
/**
* Handle failed assertion
*/
-void __noreturn
+void JERRY_ATTR_NORETURN
jerry_assert_fail (const char *assertion, /**< assertion condition string */
const char *file, /**< file name */
const char *function, /**< function name */
/**
* Handle execution of control path that should be unreachable
*/
-void __noreturn
+void JERRY_ATTR_NORETURN
jerry_unreachable (const char *file, /**< file name */
const char *function, /**< function name */
const uint32_t line) /**< line */
#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 <stdio.h>
#include <string.h>
#include "jerryscript-port.h"
#include "jrt-types.h"
-/*
- * Attributes
- */
-#define __noreturn __attribute__((noreturn))
-#define __attr_noinline___ __attribute__((noinline))
-#define __attr_return_value_should_be_checked___ __attribute__((warn_unused_result))
-#define __attr_hot___ __attribute__((hot))
-#ifndef __attr_always_inline___
-#define __attr_always_inline___ __attribute__((always_inline))
-#endif /* !__attr_always_inline___ */
-#ifndef __attr_const___
-#define __attr_const___ __attribute__((const))
-#endif /* !__attr_const___ */
-#ifndef __attr_pure___
-#define __attr_pure___ __attribute__((pure))
-#endif /* !__attr_pure___ */
-
-/*
- * Conditions' likeliness, unlikeliness.
- */
-#ifdef __GNUC__
-#define likely(x) __builtin_expect(!!(x), 1)
-#define unlikely(x) __builtin_expect(!!(x), 0)
-#else /* !__GNUC__ */
-#define likely(x) (x)
-#define unlikely(x) (x)
-#endif /* __GNUC__ */
-
/*
* Normally compilers store const(ant)s in ROM. Thus saving RAM.
* But if your compiler does not support it then the directive below can force it.
*/
#define JERRY_UNUSED(x) ((void) (x))
+#define JERRY_UNUSED_1(_1) JERRY_UNUSED (_1)
+#define JERRY_UNUSED_2(_1, _2) JERRY_UNUSED (_1), JERRY_UNUSED_1 (_2)
+#define JERRY_UNUSED_3(_1, _2, _3) JERRY_UNUSED (_1), JERRY_UNUSED_2 (_2, _3)
+#define JERRY_UNUSED_4(_1, _2, _3, _4) JERRY_UNUSED (_1), JERRY_UNUSED_3 (_2, _3, _4)
+#define JERRY_UNUSED_5(_1, _2, _3, _4, _5) JERRY_UNUSED (_1), JERRY_UNUSED_4 (_2, _3, _4, _5)
+
+#define JERRY_VA_ARGS_NUM_IMPL(_1, _2, _3, _4, _5, N, ...) N
+#define JERRY_VA_ARGS_NUM(...) JERRY_VA_ARGS_NUM_IMPL (__VA_ARGS__, 5, 4, 3, 2, 1, 0)
+
+#define JERRY_UNUSED_ALL_IMPL_(nargs) JERRY_UNUSED_ ## nargs
+#define JERRY_UNUSED_ALL_IMPL(nargs) JERRY_UNUSED_ALL_IMPL_ (nargs)
+#define JERRY_UNUSED_ALL(...) JERRY_UNUSED_ALL_IMPL (JERRY_VA_ARGS_NUM (__VA_ARGS__)) (__VA_ARGS__)
+
/*
* Asserts
*
enum { JERRY_STATIC_ASSERT_GLUE (static_assertion_failed_, __LINE__, msg) = 1 / (!!(x)) }
#ifndef JERRY_NDEBUG
-void __noreturn jerry_assert_fail (const char *assertion, const char *file, const char *function, const uint32_t line);
-void __noreturn jerry_unreachable (const char *file, const char *function, const uint32_t line);
+void JERRY_ATTR_NORETURN
+jerry_assert_fail (const char *assertion, const char *file, const char *function, const uint32_t line);
+void JERRY_ATTR_NORETURN
+jerry_unreachable (const char *file, const char *function, const uint32_t line);
#define JERRY_ASSERT(x) \
do \
{ \
- if (unlikely (!(x))) \
+ if (JERRY_UNLIKELY (!(x))) \
{ \
jerry_assert_fail (#x, __FILE__, __func__, __LINE__); \
} \
#ifdef __GNUC__
#define JERRY_UNREACHABLE() __builtin_unreachable ()
-#else /* !__GNUC__ */
-#define JERRY_UNREACHABLE()
#endif /* __GNUC__ */
+
+#ifdef _MSC_VER
+#define JERRY_UNREACHABLE() _assume (0)
+#endif /* _MSC_VER */
+
+#ifndef JERRY_UNREACHABLE
+#define JERRY_UNREACHABLE()
+#endif /* !JERRY_UNREACHABLE */
+
#endif /* !JERRY_NDEBUG */
/**
* Exit on fatal error
*/
-void __noreturn jerry_fatal (jerry_fatal_code_t code);
+void JERRY_ATTR_NORETURN jerry_fatal (jerry_fatal_code_t code);
/*
* Logging
*/
+#ifdef JERRY_ENABLE_LOGGING
#define JERRY_ERROR_MSG(...) jerry_port_log (JERRY_LOG_LEVEL_ERROR, __VA_ARGS__)
#define JERRY_WARNING_MSG(...) jerry_port_log (JERRY_LOG_LEVEL_WARNING, __VA_ARGS__)
#define JERRY_DEBUG_MSG(...) jerry_port_log (JERRY_LOG_LEVEL_DEBUG, __VA_ARGS__)
#define JERRY_TRACE_MSG(...) jerry_port_log (JERRY_LOG_LEVEL_TRACE, __VA_ARGS__)
+#else /* !JERRY_ENABLE_LOGGING */
+#define JERRY_ERROR_MSG(...) do { if (false) { JERRY_UNUSED_ALL (__VA_ARGS__); } } while (0)
+#define JERRY_WARNING_MSG(...) do { if (false) { JERRY_UNUSED_ALL (__VA_ARGS__); } } while (0)
+#define JERRY_DEBUG_MSG(...) do { if (false) { JERRY_UNUSED_ALL (__VA_ARGS__); } } while (0)
+#define JERRY_TRACE_MSG(...) do { if (false) { JERRY_UNUSED_ALL (__VA_ARGS__); } } while (0)
+#endif /* JERRY_ENABLE_LOGGING */
/**
* Size of struct member
#define JERRY_MIN(v1, v2) (((v1) < (v2)) ? (v1) : (v2))
#define JERRY_MAX(v1, v2) (((v1) < (v2)) ? (v2) : (v1))
+/**
+ * Calculate the index of the first non-zero bit of a 32 bit integer value
+ */
+#define JERRY__LOG2_1(n) (((n) >= 2) ? 1 : 0)
+#define JERRY__LOG2_2(n) (((n) >= 1 << 2) ? (2 + JERRY__LOG2_1 ((n) >> 2)) : JERRY__LOG2_1 (n))
+#define JERRY__LOG2_4(n) (((n) >= 1 << 4) ? (4 + JERRY__LOG2_2 ((n) >> 4)) : JERRY__LOG2_2 (n))
+#define JERRY__LOG2_8(n) (((n) >= 1 << 8) ? (8 + JERRY__LOG2_4 ((n) >> 8)) : JERRY__LOG2_4 (n))
+#define JERRY_LOG2(n) (((n) >= 1 << 16) ? (16 + JERRY__LOG2_8 ((n) >> 16)) : JERRY__LOG2_8 (n))
+
#endif /* !JRT_H */
*/
#include "lit-char-helpers.h"
-#include "lit/lit-unicode-ranges.inc.h"
+#include "lit-unicode-ranges.inc.h"
#include "lit-strings.h"
#ifndef CONFIG_DISABLE_UNICODE_CASE_CONVERSION
return false;
} /* search_char_in_interval_array */
-/**
- * Check if specified character is one of the Format-Control characters
- *
- * @return true - if the character is one of characters, listed in ECMA-262 v5, Table 1,
- * false - otherwise
- */
-bool
-lit_char_is_format_control (ecma_char_t c) /**< code unit */
-{
- return (c == LIT_CHAR_ZWNJ
- || c == LIT_CHAR_ZWJ
- || c == LIT_CHAR_BOM);
-} /* lit_char_is_format_control */
-
/**
* Check if specified character is one of the Whitespace characters including those
* that fall into "Space, Separator" ("Zs") Unicode character category.
bool
lit_read_code_unit_from_hex (const lit_utf8_byte_t *buf_p, /**< buffer with characters */
lit_utf8_size_t number_of_characters, /**< number of characters to be read */
- ecma_char_ptr_t out_code_unit_p) /**< [out] decoded result */
+ ecma_char_t *out_code_unit_p) /**< [out] decoded result */
{
ecma_char_t code_unit = LIT_CHAR_NULL;
#define LIT_CHAR_ZWJ ((ecma_char_t) 0x200D) /* zero width joiner */
#define LIT_CHAR_BOM ((ecma_char_t) 0xFEFF) /* byte order mark */
-bool lit_char_is_format_control (ecma_char_t c);
-
/*
* Whitespace characters (ECMA-262 v5, Table 2)
*/
/* read a hex encoded code point from a zero terminated buffer */
bool lit_read_code_unit_from_hex (const lit_utf8_byte_t *buf_p, lit_utf8_size_t number_of_characters,
- ecma_char_ptr_t out_code_unit_p);
+ ecma_char_t *out_code_unit_p);
/**
* Null character
*/
typedef uint32_t ecma_length_t;
-/**
- * Description of an ecma-character pointer
- */
-typedef ecma_char_t *ecma_char_ptr_t;
-
/**
* Max bytes needed to represent a code unit (utf-16 char) via utf-8 encoding
*/
* @return number of the strings, if there were registered,
* zero - otherwise.
*/
-inline uint32_t __attr_always_inline___
+inline uint32_t JERRY_ATTR_ALWAYS_INLINE
lit_get_magic_string_ex_count (void)
{
return JERRY_CONTEXT (lit_magic_string_ex_count);
{
static const lit_utf8_byte_t * const lit_magic_strings[] JERRY_CONST_DATA =
{
+/** @cond doxygen_suppress */
#define LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE(size, id)
#define LIT_MAGIC_STRING_DEF(id, utf8_string) \
(const lit_utf8_byte_t *) utf8_string,
#include "lit-magic-strings.inc.h"
#undef LIT_MAGIC_STRING_DEF
#undef LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE
+/** @endcond */
};
JERRY_ASSERT (id < LIT_NON_INTERNAL_MAGIC_STRING__COUNT);
{
static const lit_magic_size_t lit_magic_string_sizes[] JERRY_CONST_DATA =
{
+/** @cond doxygen_suppress */
#define LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE(size, id)
#define LIT_MAGIC_STRING_DEF(id, utf8_string) \
sizeof(utf8_string) - 1,
#include "lit-magic-strings.inc.h"
#undef LIT_MAGIC_STRING_DEF
#undef LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE
+/** @endcond */
};
JERRY_ASSERT (id < LIT_NON_INTERNAL_MAGIC_STRING__COUNT);
*
* @return magic string id
*/
-lit_magic_string_id_t
+static lit_magic_string_id_t
lit_get_magic_string_size_block_start (lit_utf8_size_t size) /**< magic string size */
{
static const lit_magic_string_id_t lit_magic_string_size_block_starts[] JERRY_CONST_DATA =
{
+/** @cond doxygen_suppress */
#define LIT_MAGIC_STRING_DEF(id, utf8_string)
#define LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE(size, id) \
id,
LIT_NON_INTERNAL_MAGIC_STRING__COUNT
#undef LIT_MAGIC_STRING_DEF
#undef LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE
+/** @endcond */
};
JERRY_ASSERT (size <= (sizeof (lit_magic_string_size_block_starts) / sizeof (lit_magic_string_id_t)));
const lit_utf8_byte_t *
lit_get_magic_string_ex_utf8 (lit_magic_string_ex_id_t id) /**< extern magic string id */
{
- if (JERRY_CONTEXT (lit_magic_string_ex_array) && id < JERRY_CONTEXT (lit_magic_string_ex_count))
- {
- return JERRY_CONTEXT (lit_magic_string_ex_array)[id];
- }
+ JERRY_ASSERT (JERRY_CONTEXT (lit_magic_string_ex_array) && id < JERRY_CONTEXT (lit_magic_string_ex_count));
- JERRY_UNREACHABLE ();
+ return JERRY_CONTEXT (lit_magic_string_ex_array)[id];
} /* lit_get_magic_string_ex_utf8 */
/**
* Register external magic strings
*/
void
-lit_magic_strings_ex_set (const lit_utf8_byte_t **ex_str_items, /**< character arrays, representing
- * external magic strings' contents */
+lit_magic_strings_ex_set (const lit_utf8_byte_t * const *ex_str_items, /**< character arrays, representing
+ * external magic strings' contents */
uint32_t count, /**< number of the strings */
const lit_utf8_size_t *ex_str_sizes) /**< sizes of the strings */
{
id < JERRY_CONTEXT (lit_magic_string_ex_count);
id = (lit_magic_string_ex_id_t) (id + 1))
{
- lit_utf8_size_t string_size = lit_zt_utf8_string_size (lit_get_magic_string_ex_utf8 (id));
- JERRY_ASSERT (JERRY_CONTEXT (lit_magic_string_ex_sizes)[id] == string_size);
- JERRY_ASSERT (JERRY_CONTEXT (lit_magic_string_ex_sizes)[id] <= LIT_MAGIC_STRING_LENGTH_LIMIT);
+ lit_utf8_size_t string_size = JERRY_CONTEXT (lit_magic_string_ex_sizes)[id];
/**
* Check whether the strings are sorted by size and lexicographically,
{
const lit_magic_string_ex_id_t prev_id = id - 1;
const lit_utf8_size_t prev_string_size = lit_get_magic_string_ex_size (prev_id);
+ JERRY_ASSERT (lit_is_valid_cesu8_string (lit_get_magic_string_ex_utf8 (id),
+ string_size));
JERRY_ASSERT (prev_string_size <= string_size);
if (prev_string_size == string_size)
while (first < last)
{
lit_utf8_size_t middle = ((first + last) / 2); /**< mid point of search */
- int compare = memcmp (lit_get_magic_string_utf8 (middle), string_p, string_size);
+ int compare = memcmp (lit_get_magic_string_utf8 ((lit_magic_string_id_t) middle), string_p, string_size);
if (compare == 0)
{
while (first < last)
{
lit_utf8_size_t middle = ((first + last) / 2); /**< mid point of search */
- const lit_utf8_byte_t *middle_string_p = lit_get_magic_string_utf8 (middle);
+ const lit_utf8_byte_t *middle_string_p = lit_get_magic_string_utf8 ((lit_magic_string_id_t) middle);
int compare = memcmp (middle_string_p, string1_p, string1_size);
#include "lit-globals.h"
-/**
- * Limit for magic string length
- */
-#define LIT_MAGIC_STRING_LENGTH_LIMIT 32
-
/**
* Identifiers of ECMA and implementation-defined magic string constants
*/
typedef enum
{
+/** @cond doxygen_suppress */
#define LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE(size, id)
#define LIT_MAGIC_STRING_DEF(id, ascii_zt_string) \
id,
#include "lit-magic-strings.inc.h"
#undef LIT_MAGIC_STRING_DEF
#undef LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE
+/** @endcond */
LIT_NON_INTERNAL_MAGIC_STRING__COUNT, /**< number of non-internal magic strings */
LIT_INTERNAL_MAGIC_STRING_PROMISE = LIT_NON_INTERNAL_MAGIC_STRING__COUNT, /**< [[Promise]] of promise
* reject or resolve functions */
LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED, /**< [[AlreadyResolved]] of promise reject or resolve functions */
LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION, /**< the resolve funtion of the promise object */
LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION, /**< the reject function of the promise object */
- LIT_NEED_MARK_MAGIC_STRING__COUNT, /**< number of internal magic strings which will be used as properties' names,
- * and the properties need to be marked during gc. */
- LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE = LIT_NEED_MARK_MAGIC_STRING__COUNT, /**< native handle package
- * associated with an object */
- LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< native pointer package associated with an object */
+ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE, /**< [[Promise]] property */
+ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE, /**< [[Resolve]] property */
+ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT, /**< [[Reject]] property */
+ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY, /**< [[Capability]] property */
+ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_HANDLER, /**< [[Handler]] property */
+ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_ALREADY_CALLED, /**< [[AlreadyCalled]] property */
+ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_INDEX, /**< [[Index]] property */
+ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_VALUE, /**< [[Values]] property */
+ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REMAINING_ELEMENT, /**< [[RemainingElement]] property */
+ LIT_GC_MARK_REQUIRED_MAGIC_STRING__COUNT, /**< number of internal magic strings which will be used as
+ * property names, and their values need to be marked during gc. */
+ LIT_INTERNAL_MAGIC_STRING_DELETED = LIT_GC_MARK_REQUIRED_MAGIC_STRING__COUNT, /**< special value for
+ * deleted properties */
+
+ LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< native pointer info associated with an object */
+ LIT_FIRST_INTERNAL_MAGIC_STRING = LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< first index of internal
+ * magic strings */
+ LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING, /**< the this binding of the class constructor */
LIT_MAGIC_STRING__COUNT /**< number of magic strings */
} lit_magic_string_id_t;
const lit_utf8_byte_t *lit_get_magic_string_utf8 (lit_magic_string_id_t id);
lit_utf8_size_t lit_get_magic_string_size (lit_magic_string_id_t id);
-lit_magic_string_id_t lit_get_magic_string_size_block_start (lit_utf8_size_t size);
const lit_utf8_byte_t *lit_get_magic_string_ex_utf8 (lit_magic_string_ex_id_t id);
lit_utf8_size_t lit_get_magic_string_ex_size (lit_magic_string_ex_id_t id);
-void lit_magic_strings_ex_set (const lit_utf8_byte_t **ex_str_items, uint32_t count,
+void lit_magic_strings_ex_set (const lit_utf8_byte_t * const *ex_str_items,
+ uint32_t count,
const lit_utf8_size_t *ex_str_sizes);
lit_magic_string_id_t lit_is_utf8_string_magic (const lit_utf8_byte_t *string_p, lit_utf8_size_t string_size);
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING__EMPTY, "")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SPACE_CHAR, " ")
-#if !defined (CONFIG_DISABLE_JSON_BUILTIN)
-LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DOUBLE_QUOTE_CHAR, "\"")
-#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMMA_CHAR, ",")
#if !defined (CONFIG_DISABLE_REGEXP_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SLASH_CHAR, "/")
#if !defined (CONFIG_DISABLE_MATH_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LN2_U, "LN2")
#endif
+#if !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN)
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MAP_UL, "Map")
+#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NAN, "NaN")
#if !defined (CONFIG_DISABLE_DATE_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UTC_U, "UTC")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EXP, "exp")
#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET, "get")
+#if !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN)
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_HAS, "has")
+#endif
#if !defined (CONFIG_DISABLE_MATH_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LOG, "log")
#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EXEC, "exec")
#endif
#if !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN)
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FILL, "fill")
+#endif
+#if !defined (CONFIG_DISABLE_ARRAY_BUILTIN) && !defined (CONFIG_DISABLE_ES2015_BUILTIN) \
+|| !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN)
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FIND, "find")
+#endif
+#if !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FROM, "from")
#endif
-#if !defined (CONFIG_DISABLE_ARRAY_BUILTIN)
+#if !defined (CONFIG_DISABLE_ARRAY_BUILTIN) \
+|| !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_JOIN, "join")
#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_KEYS, "keys")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RACE, "race")
#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SEAL, "seal")
+#if !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN)
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SIZE, "size")
+#endif
#if !defined (CONFIG_DISABLE_ARRAY_BUILTIN) \
|| !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SOME, "some")
-#endif
-#if !defined (CONFIG_DISABLE_ARRAY_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SORT, "sort")
#endif
#if !defined (CONFIG_DISABLE_MATH_BUILTIN)
#if !defined (CONFIG_DISABLE_ES2015_PROMISE_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CATCH, "catch")
#endif
+#if !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN)
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CLEAR, "clear")
+#endif
#if !defined (CONFIG_DISABLE_ARRAY_BUILTIN) \
|| !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EVERY, "every")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CONCAT, "concat")
#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CREATE, "create")
+#if !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN)
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DELETE, "delete")
+#endif
#if !defined (CONFIG_DISABLE_ANNEXB_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ESCAPE, "escape")
#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_HOURS_UL, "setHours")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_MONTH_UL, "setMonth")
#endif
+#if !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN)
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SUBARRAY, "subarray")
+#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_STRING_UL, "toString")
#if !defined (CONFIG_DISABLE_ANNEXB_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UNESCAPE, "unescape")
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_OF)
#elif !defined (CONFIG_DISABLE_MATH_BUILTIN)
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_LN2_U)
+#elif !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN)
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_MAP_UL)
#else
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_NAN)
#endif
#if !defined (CONFIG_DISABLE_MATH_BUILTIN)
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (3, LIT_MAGIC_STRING_LN2_U)
+#elif !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN)
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (3, LIT_MAGIC_STRING_MAP_UL)
#else
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (3, LIT_MAGIC_STRING_NAN)
#endif
LIT_MAGIC_STRING__EMPTY = ""
LIT_MAGIC_STRING_SPACE_CHAR = " "
-LIT_MAGIC_STRING_DOUBLE_QUOTE_CHAR = "\""
LIT_MAGIC_STRING_COMMA_CHAR = ","
LIT_MAGIC_STRING_SLASH_CHAR = "/"
LIT_MAGIC_STRING_COLON_CHAR = ":"
LIT_MAGIC_STRING_PI_U = "PI"
LIT_MAGIC_STRING_OF = "of"
LIT_MAGIC_STRING_LN2_U = "LN2"
+LIT_MAGIC_STRING_MAP_UL = "Map"
LIT_MAGIC_STRING_NAN = "NaN"
LIT_MAGIC_STRING_UTC_U = "UTC"
LIT_MAGIC_STRING_ABS = "abs"
LIT_MAGIC_STRING_COS = "cos"
LIT_MAGIC_STRING_EXP = "exp"
LIT_MAGIC_STRING_GET = "get"
+LIT_MAGIC_STRING_HAS = "has"
LIT_MAGIC_STRING_LOG = "log"
LIT_MAGIC_STRING_MAP = "map"
LIT_MAGIC_STRING_MAX = "max"
LIT_MAGIC_STRING_CEIL = "ceil"
LIT_MAGIC_STRING_EVAL = "eval"
LIT_MAGIC_STRING_EXEC = "exec"
+LIT_MAGIC_STRING_FILL = "fill"
+LIT_MAGIC_STRING_FIND = "find"
LIT_MAGIC_STRING_FROM = "from"
LIT_MAGIC_STRING_JOIN = "join"
LIT_MAGIC_STRING_KEYS = "keys"
LIT_MAGIC_STRING_PUSH = "push"
LIT_MAGIC_STRING_RACE = "race"
LIT_MAGIC_STRING_SEAL = "seal"
+LIT_MAGIC_STRING_SIZE = "size"
LIT_MAGIC_STRING_SOME = "some"
LIT_MAGIC_STRING_SORT = "sort"
LIT_MAGIC_STRING_SQRT = "sqrt"
LIT_MAGIC_STRING_APPLY = "apply"
LIT_MAGIC_STRING_ATAN2 = "atan2"
LIT_MAGIC_STRING_CATCH = "catch"
+LIT_MAGIC_STRING_CLEAR = "clear"
LIT_MAGIC_STRING_EVERY = "every"
LIT_MAGIC_STRING_FALSE = "false"
LIT_MAGIC_STRING_FLOOR = "floor"
LIT_MAGIC_STRING_CHAR_AT_UL = "charAt"
LIT_MAGIC_STRING_CONCAT = "concat"
LIT_MAGIC_STRING_CREATE = "create"
+LIT_MAGIC_STRING_DELETE = "delete"
LIT_MAGIC_STRING_ESCAPE = "escape"
LIT_MAGIC_STRING_FILTER = "filter"
LIT_MAGIC_STRING_FREEZE = "freeze"
LIT_MAGIC_STRING_PARSE_INT = "parseInt"
LIT_MAGIC_STRING_SET_HOURS_UL = "setHours"
LIT_MAGIC_STRING_SET_MONTH_UL = "setMonth"
+LIT_MAGIC_STRING_SUBARRAY = "subarray"
LIT_MAGIC_STRING_TO_STRING_UL = "toString"
LIT_MAGIC_STRING_UNESCAPE = "unescape"
LIT_MAGIC_STRING_WRITABLE = "writable"
bytes_count = 3;
ret = ((lit_code_point_t) (c & LIT_UTF8_LAST_4_BITS_MASK));
}
- else if ((c & LIT_UTF8_4_BYTE_MASK) == LIT_UTF8_4_BYTE_MARKER)
+ else
{
+ JERRY_ASSERT ((c & LIT_UTF8_4_BYTE_MASK) == LIT_UTF8_4_BYTE_MARKER);
bytes_count = 4;
ret = ((lit_code_point_t) (c & LIT_UTF8_LAST_3_BITS_MASK));
}
- else
- {
- JERRY_ASSERT (false);
- }
JERRY_ASSERT (buf_size >= bytes_count);
*
* @return ecma-string's hash
*/
-inline lit_string_hash_t __attr_always_inline___
+inline lit_string_hash_t JERRY_ATTR_ALWAYS_INLINE
lit_utf8_string_hash_combine (lit_string_hash_t hash_basis, /**< hash to be combined with */
const lit_utf8_byte_t *utf8_buf_p, /**< characters buffer */
lit_utf8_size_t utf8_buf_size) /**< number of characters in the buffer */
*
* @return ecma-string's hash
*/
-inline lit_string_hash_t __attr_always_inline___
+inline lit_string_hash_t JERRY_ATTR_ALWAYS_INLINE
lit_utf8_string_calc_hash (const lit_utf8_byte_t *utf8_buf_p, /**< characters buffer */
lit_utf8_size_t utf8_buf_size) /**< number of characters in the buffer */
{
*
* @return number of bytes occupied in CESU-8
*/
-inline lit_utf8_size_t __attr_always_inline___
+inline lit_utf8_size_t JERRY_ATTR_ALWAYS_INLINE
lit_get_unicode_char_size_by_utf8_first_byte (const lit_utf8_byte_t first_byte) /**< buffer with characters */
{
if ((first_byte & LIT_UTF8_1_BYTE_MASK) == LIT_UTF8_1_BYTE_MARKER)
/* code unit access */
ecma_char_t lit_utf8_string_code_unit_at (const lit_utf8_byte_t *utf8_buf_p, lit_utf8_size_t utf8_buf_size,
ecma_length_t code_unit_offset);
-lit_utf8_size_t lit_get_unicode_char_size_by_utf8_first_byte (lit_utf8_byte_t first_byte);
+lit_utf8_size_t lit_get_unicode_char_size_by_utf8_first_byte (const lit_utf8_byte_t first_byte);
/* conversion */
lit_utf8_size_t lit_code_unit_to_utf8 (ecma_char_t code_unit, lit_utf8_byte_t *buf_p);
* @{
*/
+/**
+ * Compact bytecode definition
+ */
#define CBC_OPCODE(arg1, arg2, arg3, arg4) \
((arg2) | (((arg3) + CBC_STACK_ADJUST_BASE) << CBC_STACK_ADJUST_SHIFT)),
#define CBC_HAS_POP_STACK_BYTE_ARG (CBC_HAS_BYTE_ARG | CBC_POP_STACK_BYTE_ARG)
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+/**
+ * Checks whether the current opcode is a super constructor call
+ */
+#define CBC_SUPER_CALL_OPERATION(opcode) \
+ ((opcode) >= PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL) \
+ && (opcode) <= PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL_BLOCK))
+#else /* CONFIG_DISABLE_ES2015_CLASS */
+/**
+ * Checks whether the current opcode is a super constructor call
+ */
+#define CBC_SUPER_CALL_OPERATION(opcode) false
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
/* Debug macro. */
#define CBC_ARGS_EQ(op, types) \
((cbc_flags[op] & CBC_ARG_TYPES) == (types))
/* Debug macro. */
#define CBC_SAME_ARGS(op1, op2) \
- ((cbc_flags[op1] & CBC_ARG_TYPES) == (cbc_flags[op2] & CBC_ARG_TYPES))
+ (CBC_SUPER_CALL_OPERATION (op1) ? ((cbc_ext_flags[PARSER_GET_EXT_OPCODE (op1)] & CBC_ARG_TYPES) \
+ == (cbc_ext_flags[PARSER_GET_EXT_OPCODE (op2)] & CBC_ARG_TYPES)) \
+ : ((cbc_flags[op1] & CBC_ARG_TYPES) == (cbc_flags[op2] & CBC_ARG_TYPES)))
#define CBC_UNARY_OPERATION(name, group) \
CBC_OPCODE (name, CBC_NO_FLAG, 0, \
/**
* Several opcodes (mostly call and assignment opcodes) have
* two forms: one which does not push a return value onto
- * the stack, and another which does. The reasion is that
+ * the stack, and another which does. The reason is that
* the return value of these opcodes are often not used
* and the first form provides smaller byte code.
*
* Hence CBC_NO_RESULT_OPERATION (context_p->last_cbc_opcode)
* cannot be true for an opcode which has a result
*/
-
#define CBC_NO_RESULT_OPERATION(opcode) \
- ((opcode) >= CBC_PRE_INCR && (opcode) < CBC_END)
+ (((opcode) >= CBC_PRE_INCR && (opcode) < CBC_END) || CBC_SUPER_CALL_OPERATION ((opcode)))
#define CBC_NO_RESULT_BLOCK(opcode) \
- ((opcode) >= CBC_PRE_INCR && (opcode) < CBC_ASSIGN_ADD)
+ (((opcode) >= CBC_PRE_INCR && (opcode) < CBC_ASSIGN_ADD) || CBC_SUPER_CALL_OPERATION ((opcode)))
#define CBC_NO_RESULT_COMPOUND_ASSIGMENT(opcode) \
- ((opcode) >= CBC_ASSIGN_ADD && (opcode) < CBC_END)
+ ((opcode) >= CBC_ASSIGN_ADD && (opcode) < CBC_END && !CBC_SUPER_CALL_OPERATION ((opcode)))
/**
* Branch instructions are organized in group of 8 opcodes.
/* PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 4
/* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */
-#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 2
+#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 1
+/* PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION must be <= 4 */
+#define PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION 1
/* PARSER_TRY_CONTEXT_STACK_ALLOCATION must be <= 3 */
#define PARSER_TRY_CONTEXT_STACK_ALLOCATION 2
CBC_BACKWARD_BRANCH (CBC_BRANCH_IF_FALSE_BACKWARD, -1, \
VM_OC_BRANCH_IF_FALSE) \
CBC_OPCODE (CBC_SET_PROPERTY, CBC_HAS_LITERAL_ARG, -1, \
- VM_OC_SET_PROPERTY | VM_OC_GET_STACK_LITERAL) \
+ VM_OC_SET_PROPERTY | VM_OC_NON_STATIC_FLAG | VM_OC_GET_STACK_LITERAL) \
CBC_FORWARD_BRANCH (CBC_JUMP_FORWARD_EXIT_CONTEXT, 0, \
VM_OC_JUMP_AND_EXIT_CONTEXT) \
CBC_OPCODE (CBC_CREATE_ARRAY, CBC_NO_FLAG, 1, \
CBC_OPCODE (CBC_PUSH_THIS_LITERAL, CBC_HAS_LITERAL_ARG, 2, \
VM_OC_PUSH_TWO | VM_OC_GET_THIS_LITERAL) \
CBC_OPCODE (CBC_PUSH_NUMBER_0, CBC_NO_FLAG, 1, \
- VM_OC_PUSH_NUMBER_0 | VM_OC_PUT_STACK) \
+ VM_OC_PUSH_0 | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_NUMBER_POS_BYTE, CBC_HAS_BYTE_ARG, 1, \
- VM_OC_PUSH_NUMBER_POS_BYTE | VM_OC_PUT_STACK) \
+ VM_OC_PUSH_POS_BYTE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_NUMBER_NEG_BYTE, CBC_HAS_BYTE_ARG, 1, \
- VM_OC_PUSH_NUMBER_NEG_BYTE | VM_OC_PUT_STACK) \
+ VM_OC_PUSH_NEG_BYTE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP, CBC_NO_FLAG, -1, \
VM_OC_PROP_GET | VM_OC_GET_STACK_STACK | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_LITERAL, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_RET) \
CBC_OPCODE (CBC_RETURN_WITH_LITERAL, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_RET | VM_OC_GET_LITERAL) \
+ CBC_OPCODE (CBC_SET_LITERAL_PROPERTY, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
+ VM_OC_SET_PROPERTY | VM_OC_NON_STATIC_FLAG | VM_OC_GET_LITERAL_LITERAL) \
CBC_OPCODE (CBC_BREAKPOINT_ENABLED, CBC_NO_FLAG, 0, \
VM_OC_BREAKPOINT_ENABLED) \
CBC_OPCODE (CBC_BREAKPOINT_DISABLED, CBC_NO_FLAG, 0, \
CBC_FORWARD_BRANCH (CBC_EXT_FOR_IN_CREATE_CONTEXT, \
-1 + PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION, VM_OC_FOR_IN_CREATE_CONTEXT) \
CBC_OPCODE (CBC_EXT_SET_GETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
- VM_OC_SET_GETTER | VM_OC_GET_LITERAL_LITERAL) \
+ VM_OC_SET_GETTER | VM_OC_NON_STATIC_FLAG | VM_OC_GET_LITERAL_LITERAL) \
CBC_BACKWARD_BRANCH (CBC_EXT_BRANCH_IF_FOR_IN_HAS_NEXT, 0, \
VM_OC_FOR_IN_HAS_NEXT) \
CBC_OPCODE (CBC_EXT_SET_SETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
- VM_OC_SET_SETTER | VM_OC_GET_LITERAL_LITERAL) \
+ VM_OC_SET_SETTER | VM_OC_NON_STATIC_FLAG | VM_OC_GET_LITERAL_LITERAL) \
CBC_FORWARD_BRANCH (CBC_EXT_TRY_CREATE_CONTEXT, PARSER_TRY_CONTEXT_STACK_ALLOCATION, \
VM_OC_TRY) \
CBC_OPCODE (CBC_EXT_THROW_REFERENCE_ERROR, CBC_NO_FLAG, 1, \
VM_OC_PUSH_UNDEFINED_BASE | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_EXT_FINALLY, 0, \
VM_OC_FINALLY) \
+ CBC_OPCODE (CBC_EXT_CLASS_EXPR_CONTEXT_END, CBC_NO_FLAG, 0, \
+ VM_OC_CLASS_EXPR_CONTEXT_END) \
+ CBC_FORWARD_BRANCH (CBC_EXT_SUPER_CLASS_CREATE_CONTEXT, \
+ -1 + PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION, VM_OC_CLASS_HERITAGE) \
\
/* Basic opcodes. */ \
- CBC_OPCODE (CBC_EXT_DEBUGGER, CBC_NO_FLAG, 0, \
- VM_OC_NONE) \
+ CBC_OPCODE (CBC_EXT_PUSH_NAMED_FUNC_EXPRESSION, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \
+ VM_OC_PUSH_NAMED_FUNC_EXPR | VM_OC_GET_LITERAL_LITERAL) \
+ CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0, CBC_HAS_LITERAL_ARG, 2, \
+ VM_OC_PUSH_LIT_0 | VM_OC_GET_LITERAL) \
+ CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE, CBC_HAS_LITERAL_ARG | CBC_HAS_BYTE_ARG, 2, \
+ VM_OC_PUSH_LIT_POS_BYTE | VM_OC_GET_LITERAL) \
+ CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE, CBC_HAS_LITERAL_ARG | CBC_HAS_BYTE_ARG, 2, \
+ VM_OC_PUSH_LIT_NEG_BYTE | VM_OC_GET_LITERAL) \
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) \
+ CBC_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY, CBC_NO_FLAG, -2, \
+ VM_OC_SET_COMPUTED_PROPERTY | VM_OC_NON_STATIC_FLAG | VM_OC_GET_STACK_STACK) \
+ CBC_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL, CBC_HAS_LITERAL_ARG, -1, \
+ VM_OC_SET_COMPUTED_PROPERTY | VM_OC_NON_STATIC_FLAG | VM_OC_GET_STACK_LITERAL) \
+ CBC_OPCODE (CBC_EXT_SET_COMPUTED_GETTER, CBC_HAS_LITERAL_ARG, -1, \
+ VM_OC_SET_GETTER | VM_OC_NON_STATIC_FLAG | VM_OC_GET_STACK_LITERAL) \
+ CBC_OPCODE (CBC_EXT_SET_COMPUTED_SETTER, CBC_HAS_LITERAL_ARG, -1, \
+ VM_OC_SET_SETTER | VM_OC_NON_STATIC_FLAG | VM_OC_GET_STACK_LITERAL) \
+ CBC_OPCODE (CBC_EXT_SET_STATIC_PROPERTY_LITERAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
+ VM_OC_SET_PROPERTY | VM_OC_GET_LITERAL_LITERAL) \
+ CBC_OPCODE (CBC_EXT_SET_STATIC_COMPUTED_PROPERTY_LITERAL, CBC_HAS_LITERAL_ARG, -1, \
+ VM_OC_SET_COMPUTED_PROPERTY | VM_OC_GET_STACK_LITERAL) \
+ CBC_OPCODE (CBC_EXT_SET_STATIC_GETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
+ VM_OC_SET_GETTER | VM_OC_GET_LITERAL_LITERAL) \
+ CBC_OPCODE (CBC_EXT_SET_STATIC_SETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
+ VM_OC_SET_SETTER | VM_OC_GET_LITERAL_LITERAL) \
+ CBC_OPCODE (CBC_EXT_SET_STATIC_COMPUTED_GETTER, CBC_HAS_LITERAL_ARG, -1, \
+ VM_OC_SET_GETTER | VM_OC_GET_STACK_LITERAL) \
+ CBC_OPCODE (CBC_EXT_SET_STATIC_COMPUTED_SETTER, CBC_HAS_LITERAL_ARG, -1, \
+ VM_OC_SET_SETTER | VM_OC_GET_STACK_LITERAL) \
+ CBC_OPCODE (CBC_EXT_RESOLVE_BASE, CBC_NO_FLAG, 0, \
+ VM_OC_RESOLVE_BASE_FOR_CALL) \
+ \
+ /* Class opcodes */ \
+ CBC_OPCODE (CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR, CBC_NO_FLAG, 0, \
+ VM_OC_CLASS_INHERITANCE) \
+ CBC_OPCODE (CBC_EXT_PUSH_CLASS_CONSTRUCTOR, CBC_NO_FLAG, 1, \
+ VM_OC_PUSH_CLASS_CONSTRUCTOR | VM_OC_PUT_STACK) \
+ CBC_OPCODE (CBC_EXT_IMPLICIT_CONSTRUCTOR_CALL, CBC_NO_FLAG, 0, \
+ VM_OC_PUSH_IMPL_CONSTRUCTOR) \
+ CBC_OPCODE (CBC_EXT_SET_CLASS_LITERAL, CBC_HAS_LITERAL_ARG, 0, \
+ VM_OC_SET_CLASS_CONSTRUCTOR | VM_OC_GET_LITERAL) \
+ CBC_OPCODE (CBC_EXT_CLASS_EVAL, CBC_HAS_BYTE_ARG, 0, \
+ VM_OC_CLASS_EVAL) \
+ CBC_OPCODE (CBC_EXT_SUPER_CALL, CBC_HAS_POP_STACK_BYTE_ARG, -1, \
+ VM_OC_SUPER_CALL) \
+ CBC_OPCODE (CBC_EXT_SUPER_CALL_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, 0, \
+ VM_OC_SUPER_CALL | VM_OC_PUT_STACK) \
+ CBC_OPCODE (CBC_EXT_SUPER_CALL_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -1, \
+ VM_OC_SUPER_CALL | VM_OC_PUT_BLOCK) \
+ CBC_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_SUPER, CBC_NO_FLAG, 1, \
+ VM_OC_PUSH_CONSTRUCTOR_SUPER | VM_OC_PUT_STACK) \
+ CBC_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP, CBC_NO_FLAG, 1, \
+ VM_OC_PUSH_CONSTRUCTOR_SUPER | VM_OC_PUT_STACK) \
+ CBC_OPCODE (CBC_EXT_PUSH_SUPER, CBC_NO_FLAG, 1, \
+ VM_OC_PUSH_SUPER | VM_OC_PUT_STACK) \
+ CBC_OPCODE (CBC_EXT_PUSH_STATIC_SUPER, CBC_NO_FLAG, 1, \
+ VM_OC_PUSH_SUPER | VM_OC_PUT_STACK) \
+ CBC_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_THIS, CBC_NO_FLAG, 1, \
+ VM_OC_PUSH_CONSTRUCTOR_THIS | VM_OC_PUT_STACK) \
+ CBC_OPCODE (CBC_EXT_SUPER_PROP_CALL, CBC_NO_FLAG, 0, \
+ VM_OC_SUPER_PROP_REFERENCE) \
+ CBC_OPCODE (CBC_EXT_SUPER_PROP_ASSIGN, CBC_NO_FLAG, 0, \
+ VM_OC_SUPER_PROP_REFERENCE) \
+ CBC_OPCODE (CBC_EXT_CONSTRUCTOR_RETURN, CBC_NO_FLAG, -1, \
+ VM_OC_CONSTRUCTOR_RET | VM_OC_GET_STACK) \
+ CBC_OPCODE (CBC_EXT_ERROR, CBC_NO_FLAG, 0, \
+ VM_OC_ERROR) \
\
/* Binary compound assignment opcodes with pushing the result. */ \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_ADD, \
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_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_LEXICAL_ENV_NOT_NEEDED = (1u << 5), /**< no need to create a lexical environment */
+ CBC_CODE_FLAGS_ARROW_FUNCTION = (1u << 6), /**< this function is an arrow function */
+ CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 7), /**< this function is a static snapshot function */
+ CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 8), /**< this function should be ignored by debugger */
+ CBC_CODE_FLAGS_CONSTRUCTOR = (1u << 9), /**< this function is a constructor */
} cbc_code_flags;
+/**
+ * Non-strict arguments object must be constructed
+ */
+#define CBC_NON_STRICT_ARGUMENTS_NEEDED(compiled_code_p) \
+ (((compiled_code_p)->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED) \
+ && !((compiled_code_p)->status_flags & CBC_CODE_FLAGS_STRICT_MODE))
+
#define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1,
/**
used by the byte code generator. */
} lexer_literal_type_t;
-/* Flags for status_flags. */
-
-/* Local identifier (var, function arg). */
-#define LEXER_FLAG_VAR 0x01
-/* This local identifier cannot be stored in register. */
-#define LEXER_FLAG_NO_REG_STORE 0x02
-/* This local identifier is initialized with a value. */
-#define LEXER_FLAG_INITIALIZED 0x04
-/* This local identifier has a reference to the function itself. */
-#define LEXER_FLAG_FUNCTION_NAME 0x08
-/* This local identifier is a function argument. */
-#define LEXER_FLAG_FUNCTION_ARGUMENT 0x10
-/* This local identifier is not used in the current context. */
-#define LEXER_FLAG_UNUSED_IDENT 0x20
-/* No space is allocated for this character literal. */
-#define LEXER_FLAG_SOURCE_PTR 0x40
-/* Initialize this variable after the byte code is freed. */
-#define LEXER_FLAG_LATE_INIT 0x80
+/**
+ * Flag bits for status_flags member of lexer_literal_t.
+ */
+typedef enum
+{
+ LEXER_FLAG_VAR = (1 << 0), /**< local identifier (var, function arg) */
+ LEXER_FLAG_NO_REG_STORE = (1 << 1), /**< this local identifier cannot be stored in register */
+ LEXER_FLAG_INITIALIZED = (1 << 2), /**< this local identifier is initialized with a value */
+ LEXER_FLAG_FUNCTION_ARGUMENT = (1 << 3), /**< this local identifier is a function argument */
+ LEXER_FLAG_UNUSED_IDENT = (1 << 4), /**< this identifier is referenced by sub-functions,
+ * but not referenced by the currently parsed function */
+ LEXER_FLAG_SOURCE_PTR = (1 << 5), /**< the literal is directly referenced in the source code
+ * (no need to allocate memory) */
+ LEXER_FLAG_LATE_INIT = (1 << 6), /**< initialize this variable after the byte code is freed */
+} lexer_literal_status_flags_t;
/**
* Type of property length.
* @{
*/
+/**
+ * Check whether the UTF-8 intermediate is an octet or not
+ */
#define IS_UTF8_INTERMEDIATE_OCTET(byte) (((byte) & LIT_UTF8_EXTRA_BYTE_MASK) == LIT_UTF8_2_BYTE_CODE_POINT_MIN)
/**
}
} /* lexer_skip_spaces */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+/**
+ * Skip all the continuous empty statements.
+ */
+void
+lexer_skip_empty_statements (parser_context_t *context_p) /**< context */
+{
+ lexer_skip_spaces (context_p);
+
+ while (context_p->source_p < context_p->source_end_p
+ && *context_p->source_p == LIT_CHAR_SEMICOLON)
+ {
+ context_p->source_p++;
+ lexer_skip_spaces (context_p);
+ }
+} /* lexer_skip_empty_statements */
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
/**
* Keyword data.
*/
typedef struct
{
- const uint8_t *keyword_p; /**< keyword string */
- lexer_token_type_t type; /**< keyword token type */
+ const uint8_t *keyword_p; /**< keyword string */
+ lexer_token_type_t type; /**< keyword token type */
} keyword_string_t;
+/**
+ * @{
+ * Keyword defines
+ */
#define LEXER_KEYWORD(name, type) { (const uint8_t *) (name), (type) }
-#define LEXER_KEYWORD_END() { (const uint8_t *) NULL, LEXER_EOS }
+#define LEXER_KEYWORD_LIST_LENGTH(name) (const uint8_t) (sizeof ((name)) / sizeof ((name)[0]))
+/** @} */
/**
* Keywords with 2 characters.
*/
-static const keyword_string_t keyword_length_2[4] =
+static const keyword_string_t keywords_with_length_2[] =
{
LEXER_KEYWORD ("do", LEXER_KEYW_DO),
LEXER_KEYWORD ("if", LEXER_KEYW_IF),
LEXER_KEYWORD ("in", LEXER_KEYW_IN),
- LEXER_KEYWORD_END ()
};
/**
* Keywords with 3 characters.
*/
-static const keyword_string_t keyword_length_3[6] =
+static const keyword_string_t keywords_with_length_3[] =
{
LEXER_KEYWORD ("for", LEXER_KEYW_FOR),
LEXER_KEYWORD ("let", LEXER_KEYW_LET),
LEXER_KEYWORD ("new", LEXER_KEYW_NEW),
LEXER_KEYWORD ("try", LEXER_KEYW_TRY),
LEXER_KEYWORD ("var", LEXER_KEYW_VAR),
- LEXER_KEYWORD_END ()
};
/**
* Keywords with 4 characters.
*/
-static const keyword_string_t keyword_length_4[9] =
+static const keyword_string_t keywords_with_length_4[] =
{
LEXER_KEYWORD ("case", LEXER_KEYW_CASE),
LEXER_KEYWORD ("else", LEXER_KEYW_ELSE),
LEXER_KEYWORD ("true", LEXER_LIT_TRUE),
LEXER_KEYWORD ("void", LEXER_KEYW_VOID),
LEXER_KEYWORD ("with", LEXER_KEYW_WITH),
- LEXER_KEYWORD_END ()
};
/**
* Keywords with 5 characters.
*/
-static const keyword_string_t keyword_length_5[10] =
+static const keyword_string_t keywords_with_length_5[] =
{
+#ifndef CONFIG_DISABLE_ES2015
+ LEXER_KEYWORD ("await", LEXER_KEYW_AWAIT),
+#endif /* !CONFIG_DISABLE_ES2015 */
LEXER_KEYWORD ("break", LEXER_KEYW_BREAK),
LEXER_KEYWORD ("catch", LEXER_KEYW_CATCH),
LEXER_KEYWORD ("class", LEXER_KEYW_CLASS),
LEXER_KEYWORD ("throw", LEXER_KEYW_THROW),
LEXER_KEYWORD ("while", LEXER_KEYW_WHILE),
LEXER_KEYWORD ("yield", LEXER_KEYW_YIELD),
- LEXER_KEYWORD_END ()
};
/**
* Keywords with 6 characters.
*/
-static const keyword_string_t keyword_length_6[9] =
+static const keyword_string_t keywords_with_length_6[] =
{
LEXER_KEYWORD ("delete", LEXER_KEYW_DELETE),
LEXER_KEYWORD ("export", LEXER_KEYW_EXPORT),
LEXER_KEYWORD ("static", LEXER_KEYW_STATIC),
LEXER_KEYWORD ("switch", LEXER_KEYW_SWITCH),
LEXER_KEYWORD ("typeof", LEXER_KEYW_TYPEOF),
- LEXER_KEYWORD_END ()
};
/**
* Keywords with 7 characters.
*/
-static const keyword_string_t keyword_length_7[6] =
+static const keyword_string_t keywords_with_length_7[] =
{
LEXER_KEYWORD ("default", LEXER_KEYW_DEFAULT),
LEXER_KEYWORD ("extends", LEXER_KEYW_EXTENDS),
LEXER_KEYWORD ("finally", LEXER_KEYW_FINALLY),
LEXER_KEYWORD ("package", LEXER_KEYW_PACKAGE),
LEXER_KEYWORD ("private", LEXER_KEYW_PRIVATE),
- LEXER_KEYWORD_END ()
};
/**
* Keywords with 8 characters.
*/
-static const keyword_string_t keyword_length_8[4] =
+static const keyword_string_t keywords_with_length_8[] =
{
LEXER_KEYWORD ("continue", LEXER_KEYW_CONTINUE),
LEXER_KEYWORD ("debugger", LEXER_KEYW_DEBUGGER),
LEXER_KEYWORD ("function", LEXER_KEYW_FUNCTION),
- LEXER_KEYWORD_END ()
};
/**
* Keywords with 9 characters.
*/
-static const keyword_string_t keyword_length_9[3] =
+static const keyword_string_t keywords_with_length_9[] =
{
LEXER_KEYWORD ("interface", LEXER_KEYW_INTERFACE),
LEXER_KEYWORD ("protected", LEXER_KEYW_PROTECTED),
- LEXER_KEYWORD_END ()
};
/**
* Keywords with 10 characters.
*/
-static const keyword_string_t keyword_length_10[3] =
+static const keyword_string_t keywords_with_length_10[] =
{
LEXER_KEYWORD ("implements", LEXER_KEYW_IMPLEMENTS),
LEXER_KEYWORD ("instanceof", LEXER_KEYW_INSTANCEOF),
- LEXER_KEYWORD_END ()
};
/**
- * List to the keywords.
+ * List of the keyword groups.
+ */
+static const keyword_string_t * const keyword_strings_list[] =
+{
+ keywords_with_length_2,
+ keywords_with_length_3,
+ keywords_with_length_4,
+ keywords_with_length_5,
+ keywords_with_length_6,
+ keywords_with_length_7,
+ keywords_with_length_8,
+ keywords_with_length_9,
+ keywords_with_length_10
+};
+
+/**
+ * List of the keyword groups length.
*/
-static const keyword_string_t * const keyword_string_list[9] =
+static const uint8_t keyword_lengths_list[] =
{
- keyword_length_2,
- keyword_length_3,
- keyword_length_4,
- keyword_length_5,
- keyword_length_6,
- keyword_length_7,
- keyword_length_8,
- keyword_length_9,
- keyword_length_10
+ LEXER_KEYWORD_LIST_LENGTH (keywords_with_length_2),
+ LEXER_KEYWORD_LIST_LENGTH (keywords_with_length_3),
+ LEXER_KEYWORD_LIST_LENGTH (keywords_with_length_4),
+ LEXER_KEYWORD_LIST_LENGTH (keywords_with_length_5),
+ LEXER_KEYWORD_LIST_LENGTH (keywords_with_length_6),
+ LEXER_KEYWORD_LIST_LENGTH (keywords_with_length_7),
+ LEXER_KEYWORD_LIST_LENGTH (keywords_with_length_8),
+ LEXER_KEYWORD_LIST_LENGTH (keywords_with_length_9),
+ LEXER_KEYWORD_LIST_LENGTH (keywords_with_length_10)
};
#undef LEXER_KEYWORD
-#undef LEXER_KEYWORD_END
+#undef LEXER_KEYWORD_LIST_LENGTH
/**
* Parse identifier.
&& !context_p->token.lit_location.has_escape
&& (length >= 2 && length <= 10))
{
- const keyword_string_t *keyword_p = keyword_string_list[length - 2];
+ const keyword_string_t *keyword_list_p = keyword_strings_list[length - 2];
+
+ int start = 0;
+ int end = keyword_lengths_list[length - 2];
+ int middle = end / 2;
do
{
- if (ident_start_p[0] == keyword_p->keyword_p[0]
- && ident_start_p[1] == keyword_p->keyword_p[1]
- && memcmp (ident_start_p, keyword_p->keyword_p, length) == 0)
+ const keyword_string_t *keyword_p = keyword_list_p + middle;
+ int compare_result = ident_start_p[0] - keyword_p->keyword_p[0];
+
+ if (compare_result == 0)
{
- if (keyword_p->type >= LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD)
+ compare_result = memcmp (ident_start_p, keyword_p->keyword_p, length);
+
+ if (compare_result == 0)
{
- if (context_p->status_flags & PARSER_IS_STRICT)
+ if (JERRY_UNLIKELY (keyword_p->type >= LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD))
{
- parser_raise_error (context_p, PARSER_ERR_STRICT_IDENT_NOT_ALLOWED);
+ if (context_p->status_flags & PARSER_IS_STRICT)
+ {
+ parser_raise_error (context_p, PARSER_ERR_STRICT_IDENT_NOT_ALLOWED);
+ }
+
+ context_p->token.literal_is_reserved = true;
+ break;
}
- context_p->token.literal_is_reserved = true;
+ context_p->token.type = (uint8_t) keyword_p->type;
break;
}
+ }
- context_p->token.type = keyword_p->type;
- break;
+ if (compare_result > 0)
+ {
+ start = middle + 1;
}
- keyword_p++;
+ else
+ {
+ JERRY_ASSERT (compare_result < 0);
+ end = middle;
+ }
+
+ middle = (start + end) / 2;
}
- while (keyword_p->type != LEXER_EOS);
+ while (start < end);
}
if (context_p->token.type == LEXER_LITERAL)
}
else
{
- do
+ while (source_p < source_end_p
+ && source_p[0] >= LIT_CHAR_0
+ && source_p[0] <= LIT_CHAR_9)
{
source_p++;
}
- while (source_p < source_end_p
- && source_p[0] >= LIT_CHAR_0
- && source_p[0] <= LIT_CHAR_9);
can_be_float = true;
}
context_p->source_p = source_p;
} /* lexer_parse_number */
+/**
+ * One character long token (e.g. comma).
+ *
+ * @param char1 character
+ * @param type1 type
+ */
#define LEXER_TYPE_A_TOKEN(char1, type1) \
case (uint8_t) (char1) : \
{ \
break; \
}
+/**
+ * Token pair, where the first token is prefix of the second (e.g. % and %=).
+ *
+ * @param char1 first character
+ * @param type1 type of the first character
+ * @param char2 second character
+ * @param type2 type of the second character
+ */
#define LEXER_TYPE_B_TOKEN(char1, type1, char2, type2) \
case (uint8_t) (char1) : \
{ \
break; \
}
+/**
+ * Three tokens, where the first is the prefix of the other two (e.g. &, &&, &=).
+ *
+ * @param char1 first character
+ * @param type1 type of the first character
+ * @param char2 second character
+ * @param type2 type of the second character
+ * @param char3 third character
+ * @param type3 type of the third character
+ */
#define LEXER_TYPE_C_TOKEN(char1, type1, char2, type2, char3, type3) \
case (uint8_t) (char1) : \
{ \
#undef LEXER_TYPE_D_TOKEN
/**
- * Checks whether the next token is a colon.
+ * Checks whether the next token is the specified character.
*
- * @return true - if the next token is a colon
+ * @return true - if the next is the specified character
* false - otherwise
*/
bool
-lexer_check_colon (parser_context_t *context_p) /**< context */
+lexer_check_next_character (parser_context_t *context_p, /**< context */
+ lit_utf8_byte_t character) /**< specified character */
{
lexer_skip_spaces (context_p);
context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES);
return (context_p->source_p < context_p->source_end_p
- && context_p->source_p[0] == (uint8_t) LIT_CHAR_COLON);
-} /* lexer_check_colon */
+ && context_p->source_p[0] == (uint8_t) character);
+} /* lexer_check_next_character */
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
context_p->literal_count++;
} /* lexer_process_char_literal */
-/* Maximum buffer size for identifiers which contains escape sequences. */
+/**
+ * Maximum local buffer size for identifiers which contains escape sequences.
+ */
#define LEXER_MAX_LITERAL_LOCAL_BUFFER_SIZE 48
/**
context_p->lit_object.type = LEXER_LITERAL_OBJECT_ANY;
- if (literal_type == LEXER_IDENT_LITERAL)
+ if (literal_type == LEXER_IDENT_LITERAL
+ && (context_p->status_flags & PARSER_INSIDE_WITH)
+ && context_p->lit_object.literal_p->type == LEXER_IDENT_LITERAL)
{
- if ((context_p->status_flags & PARSER_INSIDE_WITH)
- && context_p->lit_object.literal_p->type == LEXER_IDENT_LITERAL)
- {
- context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
- }
+ context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
+ }
- if (literal_p->length == 4
- && source_p[0] == LIT_CHAR_LOWERCASE_E
- && source_p[3] == LIT_CHAR_LOWERCASE_L
- && source_p[1] == LIT_CHAR_LOWERCASE_V
- && source_p[2] == LIT_CHAR_LOWERCASE_A)
- {
- context_p->lit_object.type = LEXER_LITERAL_OBJECT_EVAL;
- }
+ if (literal_p->length == 4
+ && source_p[0] == LIT_CHAR_LOWERCASE_E
+ && source_p[3] == LIT_CHAR_LOWERCASE_L
+ && source_p[1] == LIT_CHAR_LOWERCASE_V
+ && source_p[2] == LIT_CHAR_LOWERCASE_A)
+ {
+ context_p->lit_object.type = LEXER_LITERAL_OBJECT_EVAL;
+ }
- if (literal_p->length == 9
- && source_p[0] == LIT_CHAR_LOWERCASE_A
- && source_p[8] == LIT_CHAR_LOWERCASE_S
- && memcmp (source_p + 1, "rgument", 7) == 0)
+ if (literal_p->length == 9
+ && source_p[0] == LIT_CHAR_LOWERCASE_A
+ && source_p[8] == LIT_CHAR_LOWERCASE_S
+ && memcmp (source_p + 1, "rgument", 7) == 0)
+ {
+ context_p->lit_object.type = LEXER_LITERAL_OBJECT_ARGUMENTS;
+ if (!(context_p->status_flags & PARSER_ARGUMENTS_NOT_NEEDED))
{
- context_p->lit_object.type = LEXER_LITERAL_OBJECT_ARGUMENTS;
- if (!(context_p->status_flags & PARSER_ARGUMENTS_NOT_NEEDED))
- {
- context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED;
- context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
- }
+ context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED;
+ context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
}
}
*/
bool
lexer_construct_number_object (parser_context_t *context_p, /**< context */
- bool push_number_allowed, /**< push number support is allowed */
+ bool is_expr, /**< expression is parsed */
bool is_negative_number) /**< sign is negative */
{
parser_list_iterator_t literal_iterator;
while (src_p < src_end_p);
}
- if (push_number_allowed)
+ if (is_expr)
{
int32_t int_num = (int32_t) num;
- if (int_num == num)
+ if (int_num == num
+ && int_num <= CBC_PUSH_NUMBER_BYTE_RANGE_END
+ && (int_num != 0 || !is_negative_number))
{
- if (int_num <= CBC_PUSH_NUMBER_BYTE_RANGE_END
- && (int_num != 0 || !is_negative_number))
- {
- context_p->lit_object.index = (uint16_t) int_num;
- return true;
- }
+ context_p->lit_object.index = (uint16_t) int_num;
+ return true;
}
}
}
literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
- literal_p->prop.length = context_p->token.lit_location.length;
- literal_p->type = LEXER_UNUSED_LITERAL;
- literal_p->status_flags = 0;
-
- context_p->literal_count++;
-
literal_p->u.value = lit_value;
+ literal_p->prop.length = 0; /* Unused. */
literal_p->type = LEXER_NUMBER_LITERAL;
+ literal_p->status_flags = 0;
context_p->lit_object.literal_p = literal_p;
context_p->lit_object.index = (uint16_t) literal_index;
context_p->lit_object.type = LEXER_LITERAL_OBJECT_ANY;
+ context_p->literal_count++;
return false;
} /* lexer_construct_number_object */
+/**
+ * Convert a push number opcode to push literal opcode
+ */
+void
+lexer_convert_push_number_to_push_literal (parser_context_t *context_p) /**< context */
+{
+ ecma_integer_value_t value;
+ bool two_literals = !PARSER_IS_BASIC_OPCODE (context_p->last_cbc_opcode);
+
+ if (context_p->last_cbc_opcode == CBC_PUSH_NUMBER_0
+ || context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0))
+ {
+ value = 0;
+ }
+ else if (context_p->last_cbc_opcode == CBC_PUSH_NUMBER_POS_BYTE
+ || context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE))
+ {
+ value = ((ecma_integer_value_t) context_p->last_cbc.value) + 1;
+ }
+ else
+ {
+ JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_NUMBER_NEG_BYTE
+ || context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE));
+ value = -((ecma_integer_value_t) context_p->last_cbc.value) - 1;
+ }
+
+ ecma_value_t lit_value = ecma_make_integer_value (value);
+
+ parser_list_iterator_t literal_iterator;
+ parser_list_iterator_init (&context_p->literal_pool, &literal_iterator);
+
+ context_p->last_cbc_opcode = two_literals ? CBC_PUSH_TWO_LITERALS : CBC_PUSH_LITERAL;
+
+ uint32_t literal_index = 0;
+ lexer_literal_t *literal_p;
+
+ 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_value)
+ {
+ if (two_literals)
+ {
+ context_p->last_cbc.value = (uint16_t) literal_index;
+ }
+ else
+ {
+ context_p->last_cbc.literal_index = (uint16_t) literal_index;
+ }
+ return;
+ }
+
+ literal_index++;
+ }
+
+ JERRY_ASSERT (literal_index == context_p->literal_count);
+
+ if (literal_index >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
+ {
+ parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
+ }
+
+ literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
+ literal_p->u.value = lit_value;
+ literal_p->prop.length = 0; /* Unused. */
+ literal_p->type = LEXER_NUMBER_LITERAL;
+ literal_p->status_flags = 0;
+
+ context_p->literal_count++;
+
+ if (two_literals)
+ {
+ context_p->last_cbc.value = (uint16_t) literal_index;
+ }
+ else
+ {
+ context_p->last_cbc.literal_index = (uint16_t) literal_index;
+ }
+} /* lexer_convert_push_number_to_push_literal */
+
/**
* Construct a function literal object.
*
current_flags);
ecma_deref_ecma_string (pattern_str_p);
- bool is_throw = ECMA_IS_VALUE_ERROR (completion_value) ? true : false;
+ bool is_throw = ECMA_IS_VALUE_ERROR (completion_value) != 0;
ecma_free_value (completion_value);
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
} /* lexer_expect_identifier */
-static const lexer_lit_location_t lexer_get_literal =
-{
- (const uint8_t *) "get", 3, LEXER_IDENT_LITERAL, false
-};
-
-static const lexer_lit_location_t lexer_set_literal =
-{
- (const uint8_t *) "set", 3, LEXER_IDENT_LITERAL, false
-};
-
/**
* Next token must be an identifier.
*/
void
lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
- bool must_be_identifier) /**< only identifiers are accepted */
+ uint32_t ident_opts) /**< lexer_obj_ident_opts_t option bits */
{
lexer_skip_spaces (context_p);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ int is_class_method = ((ident_opts & LEXER_OBJ_IDENT_CLASS_METHOD)
+ && !(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS)
+ && (context_p->token.type != LEXER_KEYW_STATIC));
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
context_p->token.line = context_p->line;
context_p->token.column = context_p->column;
{
lexer_parse_identifier (context_p, false);
- if (!must_be_identifier
+ if (!(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS)
&& context_p->token.lit_location.length == 3)
{
lexer_skip_spaces (context_p);
if (context_p->source_p < context_p->source_end_p
&& context_p->source_p[0] != LIT_CHAR_COLON)
{
- if (lexer_compare_identifier_to_current (context_p, &lexer_get_literal))
+ if (lexer_compare_raw_identifier_to_current (context_p, "get", 3))
{
context_p->token.type = LEXER_PROPERTY_GETTER;
return;
}
- else if (lexer_compare_identifier_to_current (context_p, &lexer_set_literal))
+ else if (lexer_compare_raw_identifier_to_current (context_p, "set", 3))
{
context_p->token.type = LEXER_PROPERTY_SETTER;
return;
}
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (is_class_method
+ && lexer_compare_raw_identifier_to_current (context_p, "static", 6))
+ {
+ context_p->token.type = LEXER_KEYW_STATIC;
+ return;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
create_literal_object = true;
}
else if (context_p->source_p[0] == LIT_CHAR_DOUBLE_QUOTE
lexer_parse_string (context_p);
create_literal_object = true;
}
- else if (!must_be_identifier && context_p->source_p[0] == LIT_CHAR_RIGHT_BRACE)
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ else if (context_p->source_p[0] == LIT_CHAR_LEFT_SQUARE)
+ {
+ context_p->source_p += 1;
+ context_p->column++;
+
+ lexer_next_token (context_p);
+ parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
+
+ if (context_p->token.type != LEXER_RIGHT_SQUARE)
+ {
+ parser_raise_error (context_p, PARSER_ERR_RIGHT_SQUARE_EXPECTED);
+ }
+ return;
+ }
+#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+ else if (!(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS) && context_p->source_p[0] == LIT_CHAR_RIGHT_BRACE)
{
context_p->token.type = LEXER_RIGHT_BRACE;
context_p->source_p += 1;
if (create_literal_object)
{
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (is_class_method
+ && lexer_compare_raw_identifier_to_current (context_p, "constructor", 11))
+ {
+ context_p->token.type = LEXER_CLASS_CONSTRUCTOR;
+ return;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
lexer_construct_literal_object (context_p,
&context_p->token.lit_location,
LEXER_STRING_LITERAL);
*/
void
lexer_scan_identifier (parser_context_t *context_p, /**< context */
- bool propety_name) /**< property name */
+ bool property_name) /**< property name */
{
lexer_skip_spaces (context_p);
context_p->token.line = context_p->line;
{
lexer_parse_identifier (context_p, false);
- if (propety_name && context_p->token.lit_location.length == 3)
+ if (property_name && context_p->token.lit_location.length == 3)
{
lexer_skip_spaces (context_p);
if (context_p->source_p < context_p->source_end_p
&& context_p->source_p[0] != LIT_CHAR_COLON)
{
- if (lexer_compare_identifier_to_current (context_p, &lexer_get_literal))
+ if (lexer_compare_raw_identifier_to_current (context_p, "get", 3))
{
context_p->token.type = LEXER_PROPERTY_GETTER;
}
- else if (lexer_compare_identifier_to_current (context_p, &lexer_set_literal))
+ else if (lexer_compare_raw_identifier_to_current (context_p, "set", 3))
{
context_p->token.type = LEXER_PROPERTY_SETTER;
}
return;
}
- if (propety_name)
+ if (property_name)
{
lexer_next_token (context_p);
if (context_p->token.type == LEXER_LITERAL
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ || context_p->token.type == LEXER_LEFT_SQUARE
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
|| context_p->token.type == LEXER_RIGHT_BRACE)
{
return;
} /* lexer_scan_identifier */
/**
- * Compares the given identifier to that which is the current token
- * in the parser context.
+ * Compares the current identifier in the context to the parameter identifier
+ *
+ * Note:
+ * Escape sequences are allowed.
*
* @return true if the input identifiers are the same
*/
bool
-lexer_compare_identifier_to_current (parser_context_t *context_p, /**< context */
- const lexer_lit_location_t *right) /**< identifier */
+lexer_compare_identifier_to_current (parser_context_t *context_p, /**< context */
+ const lexer_lit_location_t *right_ident_p) /**< identifier */
{
- lexer_lit_location_t *left = &context_p->token.lit_location;
+ lexer_lit_location_t *left_ident_p = &context_p->token.lit_location;
const uint8_t *left_p;
const uint8_t *right_p;
size_t count;
- JERRY_ASSERT (left->length > 0 && right->length > 0);
+ JERRY_ASSERT (left_ident_p->length > 0 && right_ident_p->length > 0);
- if (left->length != right->length)
+ if (left_ident_p->length != right_ident_p->length)
{
return 0;
}
- if (!left->has_escape && !right->has_escape)
+ if (!left_ident_p->has_escape && !right_ident_p->has_escape)
{
- return memcmp (left->char_p, right->char_p, left->length) == 0;
+ return memcmp (left_ident_p->char_p, right_ident_p->char_p, left_ident_p->length) == 0;
}
- left_p = left->char_p;
- right_p = right->char_p;
- count = left->length;
+ left_p = left_ident_p->char_p;
+ right_p = right_ident_p->char_p;
+ count = left_ident_p->length;
do
{
if (*left_p == LIT_CHAR_BACKSLASH && *right_p == LIT_CHAR_BACKSLASH)
{
- uint16_t left_chr = lexer_hex_to_character (context_p, left_p, 6);
+ uint16_t left_chr = lexer_hex_to_character (context_p, left_p + 2, 4);
- if (left_chr != lexer_hex_to_character (context_p, right_p, 6))
+ if (left_chr != lexer_hex_to_character (context_p, right_p + 2, 4))
{
return false;
}
right_p = swap_p;
}
- utf8_len = lit_char_to_utf8_bytes (utf8_buf, lexer_hex_to_character (context_p, left_p, 6));
+ utf8_len = lit_char_to_utf8_bytes (utf8_buf, lexer_hex_to_character (context_p, left_p + 2, 4));
JERRY_ASSERT (utf8_len > 0);
count -= utf8_len;
offset = 0;
return true;
} /* lexer_compare_identifier_to_current */
+/**
+ * Compares the current identifier in the context to the parameter identifier
+ *
+ * Note:
+ * Escape sequences are not allowed.
+ *
+ * @return true if the input identifiers are the same
+ */
+bool
+lexer_compare_raw_identifier_to_current (parser_context_t *context_p, /**< context */
+ const char *right_ident_p, /**< identifier */
+ size_t right_ident_length) /**< identifier length */
+{
+ lexer_lit_location_t *left_ident_p = &context_p->token.lit_location;
+
+ if (left_ident_p->length != right_ident_length || left_ident_p->has_escape)
+ {
+ return 0;
+ }
+
+ return memcmp (left_ident_p->char_p, right_ident_p, right_ident_length) == 0;
+} /* lexer_compare_raw_identifier_to_current */
+
/**
* @}
* @}
LEXER_PROPERTY_SETTER, /**< property setter function */
LEXER_COMMA_SEP_LIST, /**< comma separated bracketed expression list */
LEXER_SCAN_SWITCH, /**< special value for switch pre-scan */
+ LEXER_CLASS_CONSTRUCTOR, /**< special value for class constructor method */
+#ifdef CONFIG_DISABLE_ES2015
/* Future reserved words: these keywords
* must form a group after all other keywords. */
#define LEXER_FIRST_FUTURE_RESERVED_WORD LEXER_KEYW_CLASS
+#endif /* CONFIG_DISABLE_ES2015 */
LEXER_KEYW_CLASS, /**< class */
- LEXER_KEYW_ENUM, /**< enum */
LEXER_KEYW_EXTENDS, /**< extends */
LEXER_KEYW_SUPER, /**< super */
LEXER_KEYW_CONST, /**< const */
LEXER_KEYW_EXPORT, /**< export */
LEXER_KEYW_IMPORT, /**< import */
+#ifndef CONFIG_DISABLE_ES2015
+ /* Future reserved words: these keywords
+ * must form a group after all other keywords.
+ * Note:
+ * Tokens from LEXER_KEYW_CLASS to LEXER_KEYW_IMPORT
+ * are no longer future reserved words in ES2015. */
+#define LEXER_FIRST_FUTURE_RESERVED_WORD LEXER_KEYW_ENUM
+#endif /* !CONFIG_DISABLE_ES2015 */
+ LEXER_KEYW_ENUM, /**< enum */
+#ifndef CONFIG_DISABLE_ES2015
+ LEXER_KEYW_AWAIT, /**< await */
+#endif /* !CONFIG_DISABLE_ES2015 */
/* Future strict reserved words: these keywords
* must form a group after future reserved words. */
#define LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD LEXER_KEYW_IMPLEMENTS
LEXER_KEYW_IMPLEMENTS, /**< implements */
- LEXER_KEYW_LET, /**< let */
LEXER_KEYW_PRIVATE, /**< private */
LEXER_KEYW_PUBLIC, /**< public */
- LEXER_KEYW_YIELD, /**< yield */
LEXER_KEYW_INTERFACE, /**< interface */
LEXER_KEYW_PACKAGE, /**< package */
LEXER_KEYW_PROTECTED, /**< protected */
+
+#ifndef CONFIG_DISABLE_ES2015
+ /* Context dependent strict reserved words:
+ * See also: ECMA-262 v6, 11.6.2.1 */
+#define LEXER_FIRST_CONTEXT_DEPENDENT_RESERVED_WORD LEXER_KEYW_STATIC
LEXER_KEYW_STATIC, /**< static */
+#else /* CONFIG_DISABLE_ES2015 */
+ /* Context dependent strict reserved words:
+ * See also: ECMA-262 v6, 11.6.2.1 */
+#define LEXER_FIRST_CONTEXT_DEPENDENT_RESERVED_WORD
+#endif /* !CONFIG_DISABLE_ES2015 */
+
+ /* Context dependent future strict reserved words:
+ * See also: ECMA-262 v6, 11.6.2.1 */
+#define LEXER_FIRST_CONTEXT_DEPENDENT_FUTURE_RESERVED_WORD LEXER_KEYW_LET
+ LEXER_KEYW_LET, /**< let */
+ LEXER_KEYW_YIELD, /**< yield */
+#ifdef CONFIG_DISABLE_ES2015
+ LEXER_KEYW_STATIC, /**< static */
+#endif /* CONFIG_DISABLE_ES2015 */
} lexer_token_type_t;
#define LEXER_NEWLINE_LS_PS_BYTE_1 0xe2
LEXER_NO_SKIP_SPACES = (1u << 1) /**< ignore skip spaces */
} lexer_newline_flags_t;
+/**
+ * Lexer object identifier parse options.
+ */
+typedef enum
+{
+ LEXER_OBJ_IDENT_NO_OPTS = (1u << 0), /**< no options */
+ LEXER_OBJ_IDENT_ONLY_IDENTIFIERS = (1u << 1), /**< only identifiers are accepted */
+ LEXER_OBJ_IDENT_CLASS_METHOD = (1u << 2), /**< expect identifier inside a class body */
+} lexer_obj_ident_opts_t;
+
/**
* Lexer literal object types.
*/
#include "js-parser-internal.h"
-#ifndef CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS
-#include "lit-char-helpers.h"
-#endif /* !CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS */
-
#ifndef JERRY_DISABLE_JS_PARSER
+#include "jcontext.h"
+#include "lit-char-helpers.h"
/** \addtogroup parser Parser
* @{
{
JERRY_ASSERT (CBC_SAME_ARGS (context_p->last_cbc_opcode, context_p->last_cbc_opcode + 1));
- if (context_p->last_cbc_opcode == CBC_POST_INCR
- || context_p->last_cbc_opcode == CBC_POST_DECR)
+ if ((context_p->last_cbc_opcode == CBC_POST_INCR
+ || context_p->last_cbc_opcode == CBC_POST_DECR)
+ && context_p->stack_depth >= context_p->stack_limit)
{
- if (context_p->stack_depth >= context_p->stack_limit)
- {
- /* Stack limit is increased for CBC_POST_INCR_PUSH_RESULT
- * and CBC_POST_DECR_PUSH_RESULT opcodes. Needed by vm.c. */
- JERRY_ASSERT (context_p->stack_depth == context_p->stack_limit);
+ /* Stack limit is increased for CBC_POST_INCR_PUSH_RESULT
+ * and CBC_POST_DECR_PUSH_RESULT opcodes. Needed by vm.c. */
+ JERRY_ASSERT (context_p->stack_depth == context_p->stack_limit);
- context_p->stack_limit++;
+ context_p->stack_limit++;
- if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
- {
- parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
- }
+ if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
+ {
+ parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
}
}
break;
}
}
- parser_emit_cbc (context_p, opcode);
+ parser_emit_cbc (context_p, (uint16_t) opcode);
}
} /* parser_emit_unary_lvalue_opcode */
}
} /* parser_parse_array_literal */
+#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
/**
* Object literal item types.
*/
context_p->stack_top_uint8 = PARSER_OBJECT_PROPERTY_BOTH_ACCESSORS;
}
} /* parser_append_object_literal_item */
+#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+
+#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+#error "Class support requires ES2015 object literal support"
+#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
/**
- * Parse object literal.
+ * Parse class as an object literal.
*/
static void
-parser_parse_object_literal (parser_context_t *context_p) /**< context */
+parser_parse_class_literal (parser_context_t *context_p) /**< context */
{
JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE);
-
parser_emit_cbc (context_p, CBC_CREATE_OBJECT);
- parser_stack_push_uint8 (context_p, PARSER_OBJECT_PROPERTY_START);
+ bool super_called = false;
+ uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | (context_p->status_flags & PARSER_CLASS_HAS_SUPER);
while (true)
{
- lexer_expect_object_literal_id (context_p, false);
+ if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION))
+ {
+ lexer_skip_empty_statements (context_p);
+ }
+
+ lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_CLASS_METHOD);
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
break;
}
- if (context_p->token.type == LEXER_PROPERTY_GETTER
- || context_p->token.type == LEXER_PROPERTY_SETTER)
+ if (context_p->token.type == LEXER_PROPERTY_GETTER || context_p->token.type == LEXER_PROPERTY_SETTER)
{
- uint32_t status_flags;
- cbc_ext_opcode_t opcode;
uint16_t literal_index, function_literal_index;
- parser_object_literal_item_types_t item_type;
+ bool is_getter = (context_p->token.type == LEXER_PROPERTY_GETTER);
+
+ uint32_t accessor_status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE;
+ accessor_status_flags |= (is_getter ? PARSER_IS_PROPERTY_GETTER : PARSER_IS_PROPERTY_SETTER);
+
+ lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_CLASS_METHOD | LEXER_OBJ_IDENT_ONLY_IDENTIFIERS);
+ literal_index = context_p->lit_object.index;
- if (context_p->token.type == LEXER_PROPERTY_GETTER)
+ bool is_computed = false;
+
+ if (context_p->token.type == LEXER_RIGHT_SQUARE)
{
- status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_GETTER;
- opcode = CBC_EXT_SET_GETTER;
- item_type = PARSER_OBJECT_PROPERTY_GETTER;
+ is_computed = true;
}
- else
+ else if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION)
+ && lexer_compare_raw_identifier_to_current (context_p, "constructor", 11))
{
- status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_SETTER;
- opcode = CBC_EXT_SET_SETTER;
- item_type = PARSER_OBJECT_PROPERTY_SETTER;
+ parser_raise_error (context_p, PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR);
}
- lexer_expect_object_literal_id (context_p, true);
- literal_index = context_p->lit_object.index;
-
- parser_append_object_literal_item (context_p, literal_index, item_type);
-
parser_flush_cbc (context_p);
- function_literal_index = lexer_construct_function_object (context_p, status_flags);
+ function_literal_index = lexer_construct_function_object (context_p, accessor_status_flags);
parser_emit_cbc_literal (context_p,
CBC_PUSH_LITERAL,
literal_index);
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
+
+ cbc_ext_opcode_t opcode;
+ bool is_static = (status_flags & PARSER_CLASS_STATIC_FUNCTION) != 0;
+
+ if (is_computed)
+ {
+ context_p->last_cbc.literal_index = function_literal_index;
+
+ if (is_getter)
+ {
+ opcode = is_static ? CBC_EXT_SET_STATIC_COMPUTED_GETTER : CBC_EXT_SET_COMPUTED_GETTER;
+ }
+ else
+ {
+ opcode = is_static ? CBC_EXT_SET_STATIC_COMPUTED_SETTER : CBC_EXT_SET_COMPUTED_SETTER;
+ }
+ }
+ else
+ {
+ context_p->last_cbc.value = function_literal_index;
+
+ if (is_getter)
+ {
+ opcode = is_static ? CBC_EXT_SET_STATIC_GETTER : CBC_EXT_SET_GETTER;
+ }
+ else
+ {
+ opcode = is_static ? CBC_EXT_SET_STATIC_SETTER : CBC_EXT_SET_SETTER;
+ }
+ }
+
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (opcode);
- context_p->last_cbc.value = function_literal_index;
+ status_flags &= (uint32_t) ~PARSER_CLASS_STATIC_FUNCTION;
+ continue;
+ }
- lexer_next_token (context_p);
+ if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION) && context_p->token.type == LEXER_CLASS_CONSTRUCTOR)
+ {
+ if (super_called)
+ {
+ /* 14.5.1 */
+ parser_raise_error (context_p, PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS);
+ }
+ else
+ {
+ super_called = true;
+ }
+
+ parser_flush_cbc (context_p);
+ uint32_t constructor_status_flags = status_flags | PARSER_CLASS_CONSTRUCTOR;
+
+ if (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
+ {
+ constructor_status_flags |= PARSER_LEXICAL_ENV_NEEDED;
+ }
+
+ if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
+ {
+ parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
+ }
+
+ lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
+ literal_p->type = LEXER_UNUSED_LITERAL;
+ literal_p->status_flags = 0;
+ literal_p->u.bytecode_p = parser_parse_function (context_p, constructor_status_flags);
+ literal_p->type = LEXER_FUNCTION_LITERAL;
+ parser_emit_cbc_literal (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_SET_CLASS_LITERAL), context_p->literal_count);
+ context_p->literal_count++;
+ continue;
+ }
+
+ if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION) && context_p->token.type == LEXER_KEYW_STATIC)
+ {
+ status_flags |= PARSER_CLASS_STATIC_FUNCTION;
+ continue;
+ }
+
+ bool is_computed = false;
+
+ if (context_p->token.type == LEXER_RIGHT_SQUARE)
+ {
+ is_computed = true;
+ }
+ else if ((status_flags & PARSER_CLASS_STATIC_FUNCTION)
+ && lexer_compare_raw_identifier_to_current (context_p, "prototype", 9))
+ {
+ parser_raise_error (context_p, PARSER_ERR_CLASS_STATIC_PROTOTYPE);
+ }
+
+ parser_flush_cbc (context_p);
+
+ uint16_t literal_index = context_p->lit_object.index;
+ uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags);
+
+ parser_emit_cbc_literal (context_p,
+ CBC_PUSH_LITERAL,
+ function_literal_index);
+
+ JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
+
+ context_p->last_cbc.value = literal_index;
+
+ if ((status_flags & PARSER_CLASS_STATIC_FUNCTION))
+ {
+ context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (is_computed ? CBC_EXT_SET_STATIC_COMPUTED_PROPERTY_LITERAL
+ : CBC_EXT_SET_STATIC_PROPERTY_LITERAL);
+ status_flags &= (uint32_t) ~PARSER_CLASS_STATIC_FUNCTION;
}
else
{
- uint16_t literal_index = context_p->lit_object.index;
+ context_p->last_cbc_opcode = (is_computed ? PARSER_TO_EXT_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL)
+ : CBC_SET_LITERAL_PROPERTY);
+ }
+ }
+
+ if (!super_called && (context_p->status_flags & PARSER_CLASS_HAS_SUPER))
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_IMPLICIT_CONSTRUCTOR_CALL);
+ }
+
+ if (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR);
+ }
+} /* parser_parse_class_literal */
- parser_append_object_literal_item (context_p,
- literal_index,
- PARSER_OBJECT_PROPERTY_VALUE);
+/**
+ * Description of "prototype" literal string.
+ */
+static const lexer_lit_location_t lexer_prototype_literal =
+{
+ (const uint8_t *) "prototype", 9, LEXER_STRING_LITERAL, false
+};
+
+/**
+ * Parse class statement or expression.
+ */
+void
+parser_parse_class (parser_context_t *context_p, /**< context */
+ bool is_statement) /**< true - if class is parsed as a statement
+ * false - otherwise (as an expression) */
+{
+ JERRY_ASSERT (context_p->token.type == LEXER_KEYW_CLASS);
+ uint16_t class_ident_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS;
+
+ if (is_statement)
+ {
+ /* Class statement must contain an identifier. */
+ lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL);
+ JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
+ && context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
+
+ class_ident_index = context_p->lit_object.index;
+ context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR;
+ lexer_next_token (context_p);
+ }
+ else
+ {
+ lexer_next_token (context_p);
+
+ /* Class expression may contain an identifier. */
+ if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
+ {
+ /* NOTE: If 'Function.name' will be supported, the current literal object must be set to 'name' property. */
lexer_next_token (context_p);
- if (context_p->token.type != LEXER_COLON)
+ }
+ }
+
+ if (context_p->token.type == LEXER_KEYW_EXTENDS)
+ {
+ parser_parse_super_class_context_start (context_p);
+ }
+
+ if (context_p->token.type != LEXER_LEFT_BRACE)
+ {
+ parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
+ }
+
+ parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CLASS_CONSTRUCTOR);
+
+ bool is_strict = context_p->status_flags & PARSER_IS_STRICT;
+
+ /* 14.5. A ClassBody is always strict code. */
+ context_p->status_flags |= PARSER_IS_STRICT;
+
+ /* ClassDeclaration is parsed. Continue with class body. */
+ parser_parse_class_literal (context_p);
+
+ JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE);
+
+ lexer_construct_literal_object (context_p,
+ (lexer_lit_location_t *) &lexer_prototype_literal,
+ lexer_prototype_literal.type);
+
+ parser_emit_cbc_literal (context_p, CBC_SET_PROPERTY, context_p->lit_object.index);
+
+ if (is_statement)
+ {
+ parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, class_ident_index);
+ }
+
+ if (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
+ {
+ parser_parse_super_class_context_end (context_p, is_statement);
+ context_p->status_flags &= (uint32_t) ~PARSER_CLASS_HAS_SUPER;
+ }
+
+ parser_flush_cbc (context_p);
+
+ if (!is_strict)
+ {
+ /* Restore flag */
+ context_p->status_flags &= (uint32_t) ~PARSER_IS_STRICT;
+ }
+
+ lexer_next_token (context_p);
+} /* parser_parse_class */
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+/**
+ * Parse object initializer method definition.
+ *
+ * See also: ES2015 14.3
+ */
+static void
+parser_parse_object_method (parser_context_t *context_p) /**< context */
+{
+ parser_flush_cbc (context_p);
+
+ context_p->source_p--;
+ context_p->column--;
+ uint16_t function_literal_index = lexer_construct_function_object (context_p,
+ PARSER_IS_FUNCTION | PARSER_IS_CLOSURE);
+
+ parser_emit_cbc_literal (context_p,
+ CBC_PUSH_LITERAL,
+ function_literal_index);
+
+ lexer_next_token (context_p);
+} /* parser_parse_object_method */
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+
+/**
+ * Parse object literal.
+ */
+static void
+parser_parse_object_literal (parser_context_t *context_p) /**< context */
+{
+ JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE);
+
+ parser_emit_cbc (context_p, CBC_CREATE_OBJECT);
+
+#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ parser_stack_push_uint8 (context_p, PARSER_OBJECT_PROPERTY_START);
+#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+
+ while (true)
+ {
+ lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_NO_OPTS);
+
+ switch (context_p->token.type)
+ {
+ case LEXER_RIGHT_BRACE:
{
- parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
+ break;
}
+ case LEXER_PROPERTY_GETTER:
+ case LEXER_PROPERTY_SETTER:
+ {
+ uint32_t status_flags;
+ cbc_ext_opcode_t opcode;
+ uint16_t literal_index, function_literal_index;
+#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ parser_object_literal_item_types_t item_type;
+#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+
+ if (context_p->token.type == LEXER_PROPERTY_GETTER)
+ {
+ status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_GETTER;
+ opcode = CBC_EXT_SET_GETTER;
+#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ item_type = PARSER_OBJECT_PROPERTY_GETTER;
+#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+ }
+ else
+ {
+ status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_SETTER;
+ opcode = CBC_EXT_SET_SETTER;
+#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ item_type = PARSER_OBJECT_PROPERTY_SETTER;
+#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+ }
- lexer_next_token (context_p);
- parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
+ lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS);
+
+ /* This assignment is a nop for computed getters/setters. */
+ literal_index = context_p->lit_object.index;
+
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ if (context_p->token.type == LEXER_RIGHT_SQUARE)
+ {
+ opcode = ((opcode == CBC_EXT_SET_GETTER) ? CBC_EXT_SET_COMPUTED_GETTER
+ : CBC_EXT_SET_COMPUTED_SETTER);
+ }
+#else /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+ parser_append_object_literal_item (context_p, literal_index, item_type);
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+
+ parser_flush_cbc (context_p);
+ function_literal_index = lexer_construct_function_object (context_p, status_flags);
+
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ if (opcode >= CBC_EXT_SET_COMPUTED_GETTER)
+ {
+ literal_index = function_literal_index;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
- parser_emit_cbc_literal (context_p, CBC_SET_PROPERTY, literal_index);
+ parser_emit_cbc_literal (context_p,
+ CBC_PUSH_LITERAL,
+ literal_index);
+
+ JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
+ context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (opcode);
+ context_p->last_cbc.value = function_literal_index;
+
+ lexer_next_token (context_p);
+ break;
+ }
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ case LEXER_RIGHT_SQUARE:
+ {
+ lexer_next_token (context_p);
+
+ if (context_p->token.type == LEXER_LEFT_PAREN)
+ {
+ parser_parse_object_method (context_p);
+
+ JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
+ context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL);
+ break;
+ }
+
+ if (context_p->token.type != LEXER_COLON)
+ {
+ parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
+ }
+
+ lexer_next_token (context_p);
+ parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
+
+ if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
+ {
+ context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL);
+ }
+ else
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_SET_COMPUTED_PROPERTY);
+ }
+ break;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+ default:
+ {
+ uint16_t literal_index = context_p->lit_object.index;
+
+#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ parser_append_object_literal_item (context_p,
+ literal_index,
+ PARSER_OBJECT_PROPERTY_VALUE);
+#else /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+ parser_line_counter_t start_line = context_p->token.line;
+ parser_line_counter_t start_column = context_p->token.column;
+#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+
+ lexer_next_token (context_p);
+
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ if (context_p->token.type == LEXER_LEFT_PAREN)
+ {
+ parser_parse_object_method (context_p);
+
+ JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
+ context_p->last_cbc_opcode = CBC_SET_LITERAL_PROPERTY;
+ context_p->last_cbc.value = literal_index;
+ break;
+ }
+
+ if (context_p->token.type == LEXER_RIGHT_BRACE
+ || context_p->token.type == LEXER_COMMA)
+ {
+ /* Re-parse the literal as common identifier. */
+ context_p->source_p = context_p->token.lit_location.char_p;
+ context_p->line = start_line;
+ context_p->column = start_column;
+
+ lexer_next_token (context_p);
+
+ if (context_p->token.type != LEXER_LITERAL
+ || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
+ {
+ parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
+ }
+
+ lexer_construct_literal_object (context_p,
+ &context_p->token.lit_location,
+ context_p->token.lit_location.type);
+
+ parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
+
+ context_p->last_cbc_opcode = CBC_SET_LITERAL_PROPERTY;
+ context_p->last_cbc.value = literal_index;
+
+ lexer_next_token (context_p);
+ break;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+
+ if (context_p->token.type != LEXER_COLON)
+ {
+ parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
+ }
+
+ lexer_next_token (context_p);
+ parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
+
+ if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
+ {
+ context_p->last_cbc_opcode = CBC_SET_LITERAL_PROPERTY;
+ context_p->last_cbc.value = literal_index;
+ }
+ else
+ {
+ parser_emit_cbc_literal (context_p, CBC_SET_PROPERTY, literal_index);
+ }
+
+ break;
+ }
}
if (context_p->token.type == LEXER_RIGHT_BRACE)
}
}
+#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
while (context_p->stack_top_uint8 != PARSER_OBJECT_PROPERTY_START)
{
parser_stack_pop (context_p, NULL, 3);
}
parser_stack_pop_uint8 (context_p);
+#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
} /* parser_parse_object_literal */
/**
uint16_t literal1 = 0;
uint16_t literal2 = 0;
uint16_t function_literal_index;
+ int32_t function_name_index = -1;
+
+ if (status_flags & PARSER_IS_FUNC_EXPRESSION)
+ {
+#ifdef JERRY_DEBUGGER
+ parser_line_counter_t debugger_line = context_p->token.line;
+ parser_line_counter_t debugger_column = context_p->token.column;
+#endif /* JERRY_DEBUGGER */
+
+ if (!lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
+ {
+ lexer_next_token (context_p);
+
+ if (context_p->token.type != LEXER_LITERAL
+ || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
+ {
+ parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
+ }
+
+ parser_flush_cbc (context_p);
+
+ lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL);
+
+#ifdef JERRY_DEBUGGER
+ if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
+ {
+ jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME,
+ JERRY_DEBUGGER_NO_SUBTYPE,
+ context_p->lit_object.literal_p->u.char_p,
+ context_p->lit_object.literal_p->prop.length);
+
+ /* Reset token position for the function. */
+ context_p->token.line = debugger_line;
+ context_p->token.column = debugger_column;
+ }
+#endif /* JERRY_DEBUGGER */
+
+ if (context_p->token.literal_is_reserved
+ || context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY)
+ {
+ status_flags |= PARSER_HAS_NON_STRICT_ARG;
+ }
+
+ function_name_index = context_p->lit_object.index;
+ }
+ }
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
parser_emit_cbc_literal (context_p,
CBC_PUSH_LITERAL,
function_literal_index);
+
+ if (function_name_index != -1)
+ {
+ context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_NAMED_FUNC_EXPRESSION);
+ context_p->last_cbc.value = (uint16_t) function_name_index;
+ }
}
context_p->last_cbc.literal_type = LEXER_FUNCTION_LITERAL;
{
JERRY_ASSERT (context_p->lit_object.index <= CBC_PUSH_NUMBER_BYTE_RANGE_END);
- if (context_p->lit_object.index == 0)
- {
- parser_emit_cbc (context_p, CBC_PUSH_NUMBER_0);
- break;
- }
-
parser_emit_cbc_push_number (context_p, is_negative_number);
break;
}
}
}
- parser_emit_cbc_literal_from_token (context_p, opcode);
+ parser_emit_cbc_literal_from_token (context_p, (uint16_t) opcode);
break;
}
case LEXER_KEYW_FUNCTION:
}
case LEXER_KEYW_THIS:
{
- parser_emit_cbc (context_p, CBC_PUSH_THIS);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags))
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
+ }
+ else
+ {
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+ parser_emit_cbc (context_p, CBC_PUSH_THIS);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
break;
}
case LEXER_LIT_TRUE:
parser_emit_cbc (context_p, CBC_PUSH_NULL);
break;
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ case LEXER_KEYW_CLASS:
+ {
+ parser_parse_class (context_p, false);
+ return;
+ }
+ case LEXER_KEYW_SUPER:
+ {
+ if ((lexer_check_next_character (context_p, LIT_CHAR_DOT)
+ || lexer_check_next_character (context_p, LIT_CHAR_LEFT_SQUARE))
+ && context_p->status_flags & (PARSER_CLASS_HAS_SUPER | PARSER_IS_ARROW_FUNCTION))
+ {
+ if (!LEXER_IS_BINARY_OP_TOKEN (context_p->stack_top_uint8))
+ {
+ context_p->status_flags |= PARSER_CLASS_SUPER_PROP_REFERENCE;
+ }
+
+ if (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR)
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP);
+ break;
+ }
+
+ bool is_static = (context_p->status_flags & PARSER_CLASS_STATIC_FUNCTION) != 0;
+ parser_emit_cbc_ext (context_p, is_static ? CBC_EXT_PUSH_STATIC_SUPER : CBC_EXT_PUSH_SUPER);
+ break;
+ }
+
+ if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)
+ && (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
+ && (context_p->status_flags & (PARSER_IS_ARROW_FUNCTION | PARSER_CLASS_CONSTRUCTOR)))
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_SUPER);
+ break;
+ }
+
+ parser_raise_error (context_p, PARSER_ERR_UNEXPECTED_SUPER_REFERENCE);
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
case LEXER_RIGHT_PAREN:
{
context_p->last_cbc_opcode = CBC_PUSH_PROP_THIS_LITERAL_REFERENCE;
opcode = CBC_CALL_PROP;
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_SUPER))
+ {
+ opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL);
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
else if ((context_p->status_flags & (PARSER_INSIDE_WITH | PARSER_RESOLVE_BASE_FOR_CALLS))
&& PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode)
&& context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL)
CBC_PUSH_IDENT_REFERENCE,
context_p->last_cbc.third_literal_index);
}
+
+ parser_emit_cbc_ext (context_p, CBC_EXT_RESOLVE_BASE);
}
}
if (is_eval)
{
- parser_emit_cbc (context_p, CBC_EVAL);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
+ {
+ parser_flush_cbc (context_p);
+ context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_CLASS_EVAL);
+ context_p->last_cbc.value = PARSER_GET_CLASS_ECMA_PARSE_OPTS (context_p->status_flags);
+ }
+ else
+ {
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+ parser_emit_cbc (context_p, CBC_EVAL);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if ((context_p->status_flags & PARSER_CLASS_SUPER_PROP_REFERENCE) && opcode == CBC_CALL_PROP)
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_SUPER_PROP_CALL);
+ context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
if (call_arguments == 0)
{
if (opcode == CBC_CALL)
parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index);
parser_stack_push_uint8 (context_p, CBC_ASSIGN_PROP_LITERAL);
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (context_p->status_flags & PARSER_CLASS_SUPER_PROP_REFERENCE)
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_SUPER_PROP_ASSIGN);
+ parser_flush_cbc (context_p);
+ }
+ context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE;
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
}
else
{
opcode = (cbc_opcode_t) context_p->stack_top_uint8;
parser_stack_pop_uint8 (context_p);
- if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
+ if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL
+ && opcode == CBC_ASSIGN_SET_IDENT)
{
- if (opcode == CBC_ASSIGN_SET_IDENT)
- {
- JERRY_ASSERT (CBC_ARGS_EQ (CBC_ASSIGN_LITERAL_SET_IDENT,
- CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2));
- context_p->last_cbc.value = parser_stack_pop_uint16 (context_p);
- context_p->last_cbc_opcode = CBC_ASSIGN_LITERAL_SET_IDENT;
- continue;
- }
+ JERRY_ASSERT (CBC_ARGS_EQ (CBC_ASSIGN_LITERAL_SET_IDENT,
+ CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2));
+ context_p->last_cbc.value = parser_stack_pop_uint16 (context_p);
+ context_p->last_cbc_opcode = CBC_ASSIGN_LITERAL_SET_IDENT;
+ continue;
}
if (cbc_flags[opcode] & CBC_HAS_LITERAL_ARG)
{
uint16_t index = parser_stack_pop_uint16 (context_p);
- parser_emit_cbc_literal (context_p, opcode, index);
+ parser_emit_cbc_literal (context_p, (uint16_t) opcode, index);
if (opcode == CBC_ASSIGN_PROP_THIS_LITERAL
&& (context_p->stack_depth >= context_p->stack_limit))
{
opcode = LEXER_BINARY_OP_TOKEN_TO_OPCODE (token);
+ if (PARSER_IS_PUSH_NUMBER (context_p->last_cbc_opcode))
+ {
+ lexer_convert_push_number_to_push_literal (context_p);
+ }
+
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
JERRY_ASSERT (CBC_SAME_ARGS (context_p->last_cbc_opcode, opcode + CBC_BINARY_WITH_LITERAL));
continue;
}
}
- parser_emit_cbc (context_p, opcode);
+ parser_emit_cbc (context_p, (uint16_t) opcode);
}
} /* parser_process_binary_opcodes */
opcode = CBC_BRANCH_IF_TRUE_FORWARD;
}
- parser_emit_cbc_forward_branch (context_p, opcode, &cond_branch);
+ parser_emit_cbc_forward_branch (context_p, (uint16_t) opcode, &cond_branch);
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
PARSER_IS_FUNC_EXPRESSION = (1u << 3), /**< a function expression is parsed */
PARSER_IS_PROPERTY_GETTER = (1u << 4), /**< a property getter function is parsed */
PARSER_IS_PROPERTY_SETTER = (1u << 5), /**< a property setter function is parsed */
- PARSER_NAMED_FUNCTION_EXP = (1u << 6), /**< a function expression has a name binding */
PARSER_HAS_NON_STRICT_ARG = (1u << 7), /**< the function has arguments which
* are not supported in strict mode */
PARSER_ARGUMENTS_NEEDED = (1u << 8), /**< arguments object must be created */
PARSER_IS_ARROW_FUNCTION = (1u << 18), /**< an arrow function is parsed */
PARSER_ARROW_PARSE_ARGS = (1u << 19), /**< parse the argument list of an arrow function */
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ /* These three status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
+ PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed (this value must be kept in
+ * in sync with ECMA_PARSE_CLASS_CONSTRUCTOR) */
+ PARSER_CLASS_HAS_SUPER = (1u << 21), /**< class has super reference */
+ PARSER_CLASS_STATIC_FUNCTION = (1u << 22), /**< this function is a static class method */
+ PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 23), /**< super property call or assignment */
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
} parser_general_flags_t;
/**
* CBC_PUSH_LITERAL instruction */
} parser_expression_flags_t;
+/**
+ * Mask for strict mode code
+ */
+#define PARSER_STRICT_MODE_MASK 0x1
+
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+/**
+ * Offset between PARSER_CLASS_CONSTRUCTOR and ECMA_PARSE_CLASS_CONSTRUCTOR
+ */
+#define PARSER_CLASS_PARSE_OPTS_OFFSET \
+ (JERRY_LOG2 (PARSER_CLASS_CONSTRUCTOR) - JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR))
+
+/**
+ * Count of ecma_parse_opts_t class parsing options related bits
+ */
+#define PARSER_CLASS_PARSE_OPTS_COUNT \
+ (JERRY_LOG2 (ECMA_PARSE_HAS_STATIC_SUPER) - JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR))
+
+/**
+ * Mask for get class option bits from ecma_parse_opts_t
+ */
+#define PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK \
+ (((1 << PARSER_CLASS_PARSE_OPTS_COUNT) - 1) << JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR))
+
+/**
+ * Get class option bits from ecma_parse_opts_t
+ */
+#define PARSER_GET_CLASS_PARSER_OPTS(opts) \
+ (((opts) & PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK) << PARSER_CLASS_PARSE_OPTS_OFFSET)
+
+/**
+ * Get class option bits from parser_general_flags_t
+ */
+#define PARSER_GET_CLASS_ECMA_PARSE_OPTS(opts) \
+ ((uint16_t) (((opts) >> PARSER_CLASS_PARSE_OPTS_OFFSET) & PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK))
+
+/**
+ * Class constructor with heritage context representing bits
+ */
+#define PARSER_CLASS_CONSTRUCTOR_SUPER (PARSER_CLASS_CONSTRUCTOR | PARSER_CLASS_HAS_SUPER)
+
+/**
+ * Check the scope is a class constructor with heritage context
+ */
+#define PARSER_IS_CLASS_CONSTRUCTOR_SUPER(flag) \
+ (((flag) & PARSER_CLASS_CONSTRUCTOR_SUPER) == PARSER_CLASS_CONSTRUCTOR_SUPER)
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
/* The maximum of PARSER_CBC_STREAM_PAGE_SIZE is 127. */
#define PARSER_CBC_STREAM_PAGE_SIZE \
((uint32_t) (64 - sizeof (void *)))
((opcode) == CBC_PUSH_LITERAL \
|| (opcode) == CBC_PUSH_TWO_LITERALS \
|| (opcode) == CBC_PUSH_THREE_LITERALS)
+#define PARSER_IS_PUSH_NUMBER(opcode) \
+ ((opcode) == CBC_PUSH_NUMBER_0 \
+ || (opcode) == CBC_PUSH_NUMBER_POS_BYTE \
+ || (opcode) == CBC_PUSH_NUMBER_NEG_BYTE \
+ || (opcode) == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0) \
+ || (opcode) == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE) \
+ || (opcode) == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE))
#define PARSER_GET_LITERAL(literal_index) \
((lexer_literal_t *) parser_list_get (&context_p->literal_pool, (literal_index)))
{
uint32_t value; /**< line or offset of the breakpoint */
} parser_breakpoint_info_t;
+
+/**
+ * Maximum number of breakpoint info.
+ */
+#define PARSER_MAX_BREAKPOINT_INFO_COUNT \
+ (JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE / sizeof (parser_breakpoint_info_t))
+
#endif /* JERRY_DEBUGGER */
/**
#endif /* PARSER_DUMP_BYTE_CODE */
#ifdef JERRY_DEBUGGER
- /** extra data for each breakpoint */
- parser_breakpoint_info_t breakpoint_info[JERRY_DEBUGGER_MAX_BUFFER_SIZE / sizeof (parser_breakpoint_info_t)];
+ parser_breakpoint_info_t breakpoint_info[PARSER_MAX_BREAKPOINT_INFO_COUNT]; /**< breakpoint info list */
uint16_t breakpoint_info_count; /**< current breakpoint index */
parser_line_counter_t last_breakpoint_line; /**< last line where breakpoint has been inserted */
#endif /* JERRY_DEBUGGER */
/* Lexer functions */
void lexer_next_token (parser_context_t *context_p);
-bool lexer_check_colon (parser_context_t *context_p);
+bool lexer_check_next_character (parser_context_t *context_p, lit_utf8_byte_t character);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+void lexer_skip_empty_statements (parser_context_t *context_p);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
lexer_token_type_t lexer_check_arrow (parser_context_t *context_p);
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
void lexer_parse_string (parser_context_t *context_p);
void lexer_expect_identifier (parser_context_t *context_p, uint8_t literal_type);
-void lexer_scan_identifier (parser_context_t *context_p, bool propety_name);
+void lexer_scan_identifier (parser_context_t *context_p, bool property_name);
ecma_char_t lexer_hex_to_character (parser_context_t *context_p, const uint8_t *source_p, int length);
-void lexer_expect_object_literal_id (parser_context_t *context_p, bool must_be_identifier);
+void lexer_expect_object_literal_id (parser_context_t *context_p, uint32_t ident_opts);
void lexer_construct_literal_object (parser_context_t *context_p, lexer_lit_location_t *literal_p,
uint8_t literal_type);
-bool lexer_construct_number_object (parser_context_t *context_p, bool push_number_allowed, bool is_negative_number);
+bool lexer_construct_number_object (parser_context_t *context_p, bool is_expr, bool is_negative_number);
+void lexer_convert_push_number_to_push_literal (parser_context_t *context_p);
uint16_t lexer_construct_function_object (parser_context_t *context_p, uint32_t extra_status_flags);
void lexer_construct_regexp_object (parser_context_t *context_p, bool parse_only);
-bool lexer_compare_identifier_to_current (parser_context_t *context_p, const lexer_lit_location_t *right);
+bool lexer_compare_identifier_to_current (parser_context_t *context_p, const lexer_lit_location_t *right_ident_p);
+bool lexer_compare_raw_identifier_to_current (parser_context_t *context_p, const char *right_ident_p,
+ size_t right_ident_length);
/**
* @}
/* Parser functions. */
void parser_parse_expression (parser_context_t *context_p, int options);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+void parser_parse_class (parser_context_t *context_p, bool is_statement);
+void parser_parse_super_class_context_start (parser_context_t *context_p);
+void parser_parse_super_class_context_end (parser_context_t *context_p, bool is_statement);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/**
* @}
#ifdef JERRY_DEBUGGER
void parser_append_breakpoint_info (parser_context_t *context_p, jerry_debugger_header_type_t type, uint32_t value);
-void parser_send_breakpoints (parser_context_t *context_p, jerry_debugger_header_type_t type);
#endif /* JERRY_DEBUGGER */
* @{
*/
-/* Maximum identifier length accepted by the parser.
- * Limit: LEXER_MAX_STRING_LENGTH. */
+/**
+ * Maximum identifier length accepted by the parser.
+ * Limit: LEXER_MAX_STRING_LENGTH.
+ */
#ifndef PARSER_MAXIMUM_IDENT_LENGTH
#define PARSER_MAXIMUM_IDENT_LENGTH 255
#endif /* !PARSER_MAXIMUM_IDENT_LENGTH */
-/* Maximum string limit.
- * Limit: 2147483647 / 65535. */
+/**
+ * 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: PARSER_MAXIMUM_STRING_LIMIT. */
+/**
+ * Maximum string length.
+ * Limit: PARSER_MAXIMUM_STRING_LIMIT.
+ */
#ifndef PARSER_MAXIMUM_STRING_LENGTH
#define PARSER_MAXIMUM_STRING_LENGTH PARSER_MAXIMUM_STRING_LIMIT
#endif /* !PARSER_MAXIMUM_STRING_LENGTH */
-/* Maximum number of literals.
- * Limit: 32767. Recommended: 510, 32767 */
+/**
+ * Maximum number of literals.
+ * Limit: 32767. Recommended: 510, 32767
+ */
#ifndef PARSER_MAXIMUM_NUMBER_OF_LITERALS
#define PARSER_MAXIMUM_NUMBER_OF_LITERALS 32767
#endif /* !PARSER_MAXIMUM_NUMBER_OF_LITERALS */
-/* Maximum number of registers.
- * Limit: PARSER_MAXIMUM_NUMBER_OF_LITERALS */
+/**
+ * Maximum number of registers.
+ * Limit: PARSER_MAXIMUM_NUMBER_OF_LITERALS
+ */
#ifndef PARSER_MAXIMUM_NUMBER_OF_REGISTERS
#define PARSER_MAXIMUM_NUMBER_OF_REGISTERS 256
#endif /* !PARSER_MAXIMUM_NUMBER_OF_REGISTERS */
-/* Maximum code size.
- * Limit: 16777215. Recommended: 65535, 16777215. */
+/**
+ * Maximum code size.
+ * Limit: 16777215. Recommended: 65535, 16777215.
+ */
#ifndef PARSER_MAXIMUM_CODE_SIZE
#define PARSER_MAXIMUM_CODE_SIZE (65535 << (JMEM_ALIGNMENT_LOG))
#endif /* !PARSER_MAXIMUM_CODE_SIZE */
-/* Maximum number of values pushed onto the stack by a function.
- * Limit: 65500. Recommended: 1024. */
+/**
+ * Maximum number of values pushed onto the stack by a function.
+ * Limit: 65500. Recommended: 1024.
+ */
#ifndef PARSER_MAXIMUM_STACK_LIMIT
#define PARSER_MAXIMUM_STACK_LIMIT 1024
*/
#include "js-parser-internal.h"
-
-#ifndef CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS
#include "lit-char-helpers.h"
-#endif /* !CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS */
#ifndef JERRY_DISABLE_JS_PARSER
SCAN_MODE_STATEMENT, /**< scanning statement */
SCAN_MODE_FUNCTION_ARGUMENTS, /**< scanning function arguments */
SCAN_MODE_PROPERTY_NAME, /**< scanning property name */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ SCAN_MODE_CLASS_DECLARATION, /**< scanning class declaration */
+ SCAN_MODE_CLASS_METHOD, /**< scanning class method */
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
} scan_modes_t;
/**
{
SCAN_STACK_HEAD, /**< head */
SCAN_STACK_PAREN_EXPRESSION, /**< parent expression group */
- SCAN_STACK_PAREN_STATEMENT, /**< parent stetement group */
+ SCAN_STACK_PAREN_STATEMENT, /**< parent statement group */
SCAN_STACK_COLON_EXPRESSION, /**< colon expression group */
- SCAN_STACK_COLON_STATEMENT, /**< colon statement group*/
+ SCAN_STACK_COLON_STATEMENT, /**< colon statement group */
SCAN_STACK_SQUARE_BRACKETED_EXPRESSION, /**< square bracketed expression group */
SCAN_STACK_OBJECT_LITERAL, /**< object literal group */
SCAN_STACK_BLOCK_STATEMENT, /**< block statement group */
SCAN_STACK_BLOCK_EXPRESSION, /**< block expression group */
SCAN_STACK_BLOCK_PROPERTY, /**< block property group */
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ SCAN_STACK_COMPUTED_PROPERTY, /**< computed property name */
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
#ifndef CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS
SCAN_STACK_TEMPLATE_STRING, /**< template string */
#endif /* !CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ SCAN_STACK_CLASS, /**< class language element */
+ SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
+ SCAN_STACK_FUNCTION_PARAMETERS, /**< function parameter initializer */
+#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
} scan_stack_modes_t;
/**
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
break;
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ case LEXER_KEYW_CLASS:
+ {
+ parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_EXPRESSION);
+ *mode = SCAN_MODE_CLASS_DECLARATION;
+ break;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
case LEXER_RIGHT_SQUARE:
{
if (stack_top != SCAN_STACK_SQUARE_BRACKETED_EXPRESSION)
if ((type == LEXER_RIGHT_SQUARE && stack_top == SCAN_STACK_SQUARE_BRACKETED_EXPRESSION)
|| (type == LEXER_RIGHT_PAREN && stack_top == SCAN_STACK_PAREN_EXPRESSION)
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ || (type == LEXER_LEFT_BRACE && stack_top == SCAN_STACK_CLASS_EXTENDS)
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
|| (type == LEXER_RIGHT_BRACE && stack_top == SCAN_STACK_OBJECT_LITERAL))
{
parser_stack_pop_uint8 (context_p);
*mode = SCAN_MODE_ARROW_FUNCTION;
}
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (stack_top == SCAN_STACK_CLASS_EXTENDS)
+ {
+ *mode = SCAN_MODE_CLASS_METHOD;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
return false;
}
return false;
}
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ if (context_p->token.type == LEXER_RIGHT_SQUARE && stack_top == SCAN_STACK_COMPUTED_PROPERTY)
+ {
+ lexer_next_token (context_p);
+
+ parser_stack_pop_uint8 (context_p);
+ stack_top = (scan_stack_modes_t) context_p->stack_top_uint8;
+
+ if (stack_top == SCAN_STACK_BLOCK_PROPERTY)
+ {
+ if (context_p->token.type != LEXER_LEFT_PAREN)
+ {
+ parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED);
+ }
+
+ *mode = SCAN_MODE_FUNCTION_ARGUMENTS;
+ return true;
+ }
+
+ JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL);
+
+ if (context_p->token.type == LEXER_LEFT_PAREN)
+ {
+ parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY);
+ *mode = SCAN_MODE_FUNCTION_ARGUMENTS;
+ return true;
+ }
+
+ if (context_p->token.type != LEXER_COLON)
+ {
+ parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
+ }
+
+ *mode = SCAN_MODE_PRIMARY_EXPRESSION;
+ return false;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+
+#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
+ if (context_p->token.type == LEXER_RIGHT_PAREN && stack_top == SCAN_STACK_FUNCTION_PARAMETERS)
+ {
+ lexer_next_token (context_p);
+
+ parser_stack_pop_uint8 (context_p);
+
+ if (context_p->token.type != LEXER_LEFT_BRACE)
+ {
+ parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
+ }
+ *mode = SCAN_MODE_STATEMENT;
+ return false;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
+
/* Check whether we can enter to statement mode. */
if (stack_top != SCAN_STACK_BLOCK_STATEMENT
&& stack_top != SCAN_STACK_BLOCK_EXPRESSION
+ && stack_top != SCAN_STACK_BLOCK_PROPERTY
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ && stack_top != SCAN_STACK_CLASS
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
&& !(stack_top == SCAN_STACK_HEAD && end_type == LEXER_SCAN_SWITCH))
{
parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION);
{
lexer_next_token (context_p);
if (!(context_p->token.flags & LEXER_WAS_NEWLINE)
- && context_p->token.type != LEXER_SEMICOLON)
+ && context_p->token.type != LEXER_SEMICOLON
+ && context_p->token.type != LEXER_RIGHT_BRACE)
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
}
{
if (stack_top == SCAN_STACK_BLOCK_STATEMENT
|| stack_top == SCAN_STACK_BLOCK_EXPRESSION
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ || stack_top == SCAN_STACK_CLASS
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
|| stack_top == SCAN_STACK_BLOCK_PROPERTY)
{
parser_stack_pop_uint8 (context_p);
{
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ else if (stack_top == SCAN_STACK_CLASS)
+ {
+ *mode = SCAN_MODE_CLASS_METHOD;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
else if (stack_top == SCAN_STACK_BLOCK_PROPERTY)
{
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
*mode = SCAN_MODE_FUNCTION_ARGUMENTS;
return false;
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ case LEXER_KEYW_CLASS:
+ {
+ parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT);
+ *mode = SCAN_MODE_CLASS_DECLARATION;
+ return false;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
default:
{
break;
}
break;
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ case SCAN_MODE_CLASS_DECLARATION:
+ {
+ if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
+ {
+ lexer_next_token (context_p);
+ }
+
+ if (context_p->token.type == LEXER_KEYW_EXTENDS)
+ {
+ parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_EXTENDS);
+ mode = SCAN_MODE_PRIMARY_EXPRESSION;
+ break;
+ }
+ else if (context_p->token.type != LEXER_LEFT_BRACE)
+ {
+ parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
+ }
+
+ mode = SCAN_MODE_CLASS_METHOD;
+ break;
+ }
+ case SCAN_MODE_CLASS_METHOD:
+ {
+ if (type == LEXER_SEMICOLON)
+ {
+ break;
+ }
+
+ if (type == LEXER_RIGHT_BRACE
+ && (stack_top == SCAN_STACK_BLOCK_STATEMENT
+ || stack_top == SCAN_STACK_BLOCK_EXPRESSION))
+ {
+ mode = (stack_top == SCAN_STACK_BLOCK_EXPRESSION) ? SCAN_MODE_PRIMARY_EXPRESSION_END : SCAN_MODE_STATEMENT;
+ parser_stack_pop_uint8 (context_p);
+ break;
+ }
+
+ if (lexer_compare_raw_identifier_to_current (context_p, "static", 6))
+ {
+ lexer_next_token (context_p);
+ }
+
+ if (lexer_compare_raw_identifier_to_current (context_p, "get", 3)
+ || lexer_compare_raw_identifier_to_current (context_p, "set", 3))
+ {
+ lexer_next_token (context_p);
+ }
+
+ parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS);
+ mode = SCAN_MODE_FUNCTION_ARGUMENTS;
+ continue;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
case SCAN_MODE_ARROW_FUNCTION:
{
}
case SCAN_MODE_FUNCTION_ARGUMENTS:
{
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ JERRY_ASSERT (stack_top == SCAN_STACK_BLOCK_STATEMENT
+ || stack_top == SCAN_STACK_BLOCK_EXPRESSION
+ || stack_top == SCAN_STACK_CLASS
+ || stack_top == SCAN_STACK_BLOCK_PROPERTY);
+#else /* CONFIG_DISABLE_ES2015_CLASS */
JERRY_ASSERT (stack_top == SCAN_STACK_BLOCK_STATEMENT
|| stack_top == SCAN_STACK_BLOCK_EXPRESSION
|| stack_top == SCAN_STACK_BLOCK_PROPERTY);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
if (context_p->token.type == LEXER_LITERAL
&& (context_p->token.lit_location.type == LEXER_IDENT_LITERAL
+ || context_p->token.lit_location.type == LEXER_STRING_LITERAL
|| context_p->token.lit_location.type == LEXER_NUMBER_LITERAL))
{
lexer_next_token (context_p);
}
}
+#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
+ if (context_p->token.type == LEXER_ASSIGN)
+ {
+ parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS);
+ mode = SCAN_MODE_PRIMARY_EXPRESSION;
+ break;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
+
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
lexer_scan_identifier (context_p, true);
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ if (context_p->token.type == LEXER_LEFT_SQUARE)
+ {
+ parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY);
+ mode = SCAN_MODE_PRIMARY_EXPRESSION;
+ break;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
parser_stack_pop_uint8 (context_p);
if (context_p->token.type == LEXER_PROPERTY_GETTER
|| context_p->token.type == LEXER_PROPERTY_SETTER)
{
+ lexer_next_token (context_p);
+
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY);
+
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ if (context_p->token.type == LEXER_LEFT_SQUARE)
+ {
+ parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY);
+ mode = SCAN_MODE_PRIMARY_EXPRESSION;
+ break;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+
+ if (context_p->token.type != LEXER_LITERAL)
+ {
+ parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
+ }
+
mode = SCAN_MODE_FUNCTION_ARGUMENTS;
- break;
+ continue;
}
lexer_next_token (context_p);
+
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ if (context_p->token.type == LEXER_LEFT_PAREN)
+ {
+ parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY);
+ mode = SCAN_MODE_FUNCTION_ARGUMENTS;
+ continue;
+ }
+
+ if (context_p->token.type == LEXER_COMMA)
+ {
+ continue;
+ }
+
+ if (context_p->token.type == LEXER_RIGHT_BRACE)
+ {
+ parser_stack_pop_uint8 (context_p);
+ mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
+ break;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+
if (context_p->token.type != LEXER_COLON)
{
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
#include "js-parser-internal.h"
#ifndef JERRY_DISABLE_JS_PARSER
-
-#if defined (JERRY_DEBUGGER) || defined (JERRY_ENABLE_LINE_INFO)
#include "jcontext.h"
-#endif /* JERRY_DEBUGGER || JERRY_ENABLE_LINE_INFO */
+#include "lit-char-helpers.h"
/** \addtogroup parser Parser
* @{
* @{
*/
-/* Strict mode string literal in directive prologues */
+/**
+ * @{
+ * Strict mode string literal in directive prologues
+ */
#define PARSER_USE_STRICT_LITERAL "use strict"
#define PARSER_USE_STRICT_LENGTH 10
+/** @} */
/**
* Parser statement types.
/**
* Read the next byte from the stack.
+ *
+ * @return byte
*/
static inline uint8_t
parser_stack_iterator_read_uint8 (parser_stack_iterator_t *iterator) /**< iterator */
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR;
- parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
-
lexer_next_token (context_p);
if (context_p->token.type == LEXER_ASSIGN)
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
&& ident_line_counter != context_p->last_breakpoint_line)
{
- JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
-
- cbc_argument_t last_cbc = context_p->last_cbc;
- context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
-
parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED);
parser_flush_cbc (context_p);
parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, ident_line_counter);
- context_p->last_cbc_opcode = CBC_PUSH_LITERAL;
- context_p->last_cbc = last_cbc;
-
context_p->last_breakpoint_line = ident_line_counter;
}
#endif /* JERRY_DEBUGGER */
}
#endif /* JERRY_ENABLE_LINE_INFO */
+ parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
parser_parse_expression (context_p,
PARSE_EXPR_STATEMENT | PARSE_EXPR_NO_COMMA | PARSE_EXPR_HAS_LITERAL);
}
- else
- {
- JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL
- && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL);
- /* We don't need to assign anything to this variable. */
- context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
- }
if (context_p->token.type != LEXER_COMMA)
{
if (name_p->status_flags & LEXER_FLAG_INITIALIZED)
{
- if (!(name_p->status_flags & (LEXER_FLAG_FUNCTION_NAME | LEXER_FLAG_FUNCTION_ARGUMENT)))
+ if (!(name_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT))
{
/* Overwrite the previous initialization. */
ecma_compiled_code_t *compiled_code_p;
/**
* Parse if statement (ending part).
+ *
+ * @return true - if parsing an 'else' statement
+ * false - otherwise
*/
static bool
parser_parse_if_statement_end (parser_context_t *context_p) /**< context */
}
} /* parser_parse_with_statement_end */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+/**
+ * Parse super class context like a with statement (starting part).
+ */
+void
+parser_parse_super_class_context_start (parser_context_t *context_p) /**< context */
+{
+ JERRY_ASSERT (context_p->token.type == LEXER_KEYW_EXTENDS);
+
+ parser_with_statement_t with_statement;
+
+ lexer_next_token (context_p);
+
+ /* NOTE: Currently there is no proper way to check whether the currently parsed expression
+ is a valid lefthand-side expression or not, so we do not throw syntax error and parse
+ the class extending value as an expression. */
+ parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_NO_COMMA);
+
+#ifndef JERRY_NDEBUG
+ PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION);
+#endif /* !JERRY_NDEBUG */
+
+ context_p->status_flags |= PARSER_CLASS_HAS_SUPER;
+ parser_emit_cbc_ext_forward_branch (context_p,
+ CBC_EXT_SUPER_CLASS_CREATE_CONTEXT,
+ &with_statement.branch);
+
+ parser_stack_push (context_p, &with_statement, sizeof (parser_with_statement_t));
+ parser_stack_push_uint8 (context_p, PARSER_STATEMENT_WITH);
+} /* parser_parse_super_class_context_start */
+
+/**
+ * Parse super class context like a with statement (ending part).
+ */
+void
+parser_parse_super_class_context_end (parser_context_t *context_p, /**< context */
+ bool is_statement) /**< true - if class is parsed as a statement
+ * false - otherwise (as an expression) */
+{
+ parser_with_statement_t with_statement;
+ parser_stack_pop_uint8 (context_p);
+ parser_stack_pop (context_p, &with_statement, sizeof (parser_with_statement_t));
+
+ parser_flush_cbc (context_p);
+ PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION);
+#ifndef JERRY_NDEBUG
+ PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION);
+#endif /* !JERRY_NDEBUG */
+
+ if (is_statement)
+ {
+ parser_emit_cbc (context_p, CBC_CONTEXT_END);
+ }
+ else
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_CLASS_EXPR_CONTEXT_END);
+ }
+
+ parser_set_branch_to_current_position (context_p, &with_statement.branch);
+} /* parser_parse_super_class_context_end */
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
/**
* Parse do-while statement (ending part).
*/
parser_stack_iterator_skip (&iterator, sizeof (parser_loop_statement_t));
parser_stack_iterator_read (&iterator, &do_while_statement, sizeof (parser_do_while_statement_t));
- parser_emit_cbc_backward_branch (context_p, opcode, do_while_statement.start_offset);
+ parser_emit_cbc_backward_branch (context_p, (uint16_t) opcode, do_while_statement.start_offset);
}
else
{
/**
* Parse while statement (ending part).
*/
-static void __attr_noinline___
+static void JERRY_ATTR_NOINLINE
parser_parse_while_statement_end (parser_context_t *context_p) /**< context */
{
parser_while_statement_t while_statement;
parser_stack_pop (context_p, NULL, 1 + sizeof (parser_loop_statement_t) + sizeof (parser_while_statement_t));
parser_stack_iterator_init (context_p, &context_p->last_statement);
- parser_emit_cbc_backward_branch (context_p, opcode, while_statement.start_offset);
+ parser_emit_cbc_backward_branch (context_p, (uint16_t) opcode, while_statement.start_offset);
parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
parser_set_range (context_p, &range);
/**
* Parse for statement (ending part).
*/
-static void __attr_noinline___
+static void JERRY_ATTR_NOINLINE
parser_parse_for_statement_end (parser_context_t *context_p) /**< context */
{
parser_for_statement_t for_statement;
parser_stack_pop (context_p, NULL, 1 + sizeof (parser_loop_statement_t) + sizeof (parser_for_statement_t));
parser_stack_iterator_init (context_p, &context_p->last_statement);
- parser_emit_cbc_backward_branch (context_p, opcode, for_statement.start_offset);
+ parser_emit_cbc_backward_branch (context_p, (uint16_t) opcode, for_statement.start_offset);
parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
parser_set_range (context_p, &range);
/**
* Parse switch statement (starting part).
*/
-static void __attr_noinline___
+static void JERRY_ATTR_NOINLINE
parser_parse_switch_statement_start (parser_context_t *context_p) /**< context */
{
parser_switch_statement_t switch_statement;
try_statement.type = parser_finally_block;
}
}
- else if (try_statement.type == parser_try_block)
+ else if (try_statement.type == parser_try_block
+ && context_p->token.type != LEXER_KEYW_CATCH
+ && context_p->token.type != LEXER_KEYW_FINALLY)
{
- if (context_p->token.type != LEXER_KEYW_CATCH
- && context_p->token.type != LEXER_KEYW_FINALLY)
- {
- parser_raise_error (context_p, PARSER_ERR_CATCH_FINALLY_EXPECTED);
- }
+ parser_raise_error (context_p, PARSER_ERR_CATCH_FINALLY_EXPECTED);
}
}
if (lexer_compare_identifier_to_current (context_p, &label_statement.label_ident))
{
label_statement.break_list_p = parser_emit_cbc_forward_branch_item (context_p,
- opcode,
+ (uint16_t) opcode,
label_statement.break_list_p);
parser_stack_iterator_write (&iterator, &label_statement, sizeof (parser_label_statement_t));
lexer_next_token (context_p);
parser_stack_iterator_skip (&iterator, 1);
parser_stack_iterator_read (&iterator, &loop, sizeof (parser_loop_statement_t));
loop.branch_list_p = parser_emit_cbc_forward_branch_item (context_p,
- opcode,
+ (uint16_t) opcode,
loop.branch_list_p);
parser_stack_iterator_write (&iterator, &loop, sizeof (parser_loop_statement_t));
return;
parser_stack_iterator_skip (&loop_iterator, 1);
parser_stack_iterator_read (&loop_iterator, &loop, sizeof (parser_loop_statement_t));
loop.branch_list_p = parser_emit_cbc_forward_branch_item (context_p,
- opcode,
+ (uint16_t) opcode,
loop.branch_list_p);
loop.branch_list_p->branch.offset |= CBC_HIGHEST_BIT_MASK;
parser_stack_iterator_write (&loop_iterator, &loop, sizeof (parser_loop_statement_t));
parser_stack_iterator_skip (&iterator, 1);
parser_stack_iterator_read (&iterator, &loop, sizeof (parser_loop_statement_t));
loop.branch_list_p = parser_emit_cbc_forward_branch_item (context_p,
- opcode,
+ (uint16_t) opcode,
loop.branch_list_p);
loop.branch_list_p->branch.offset |= CBC_HIGHEST_BIT_MASK;
parser_stack_iterator_write (&iterator, &loop, sizeof (parser_loop_statement_t));
{
lexer_lit_location_t lit_location;
uint32_t status_flags = context_p->status_flags;
-#ifdef PARSER_DUMP_BYTE_CODE
- bool switch_to_strict_mode = false;
-#endif /* PARSER_DUMP_BYTE_CODE */
JERRY_ASSERT (context_p->stack_depth == 0);
&& memcmp (PARSER_USE_STRICT_LITERAL, lit_location.char_p, PARSER_USE_STRICT_LENGTH) == 0)
{
context_p->status_flags |= PARSER_IS_STRICT;
-
-#ifdef PARSER_DUMP_BYTE_CODE
- switch_to_strict_mode = true;
-#endif /* PARSER_DUMP_BYTE_CODE */
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_SEMICOLON
- && context_p->token.type != LEXER_RIGHT_BRACE)
+ && context_p->token.type != LEXER_RIGHT_BRACE
+ && (!(context_p->token.flags & LEXER_WAS_NEWLINE)
+ || LEXER_IS_BINARY_OP_TOKEN (context_p->token.type)
+ || context_p->token.type == LEXER_LEFT_PAREN
+ || context_p->token.type == LEXER_LEFT_SQUARE
+ || context_p->token.type == LEXER_DOT))
{
- if (!(context_p->token.flags & LEXER_WAS_NEWLINE)
- || LEXER_IS_BINARY_OP_TOKEN (context_p->token.type)
- || context_p->token.type == LEXER_LEFT_PAREN
- || context_p->token.type == LEXER_LEFT_SQUARE
- || context_p->token.type == LEXER_DOT)
- {
- /* The string is part of an expression statement. */
- context_p->status_flags = status_flags;
+ /* The string is part of an expression statement. */
+ context_p->status_flags = status_flags;
#ifdef JERRY_DEBUGGER
- if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
- {
- JERRY_ASSERT (context_p->last_breakpoint_line == 0);
+ if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
+ {
+ JERRY_ASSERT (context_p->last_breakpoint_line == 0);
- parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED);
- parser_flush_cbc (context_p);
+ parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED);
+ parser_flush_cbc (context_p);
- parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, context_p->token.line);
+ parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, context_p->token.line);
- context_p->last_breakpoint_line = context_p->token.line;
- }
+ 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);
+ 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);
- /* The extra_value is used for saving the token. */
- context_p->token.extra_value = context_p->token.type;
- context_p->token.type = LEXER_EXPRESSION_START;
- break;
- }
+ lexer_construct_literal_object (context_p, &lit_location, LEXER_STRING_LITERAL);
+ parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
+ /* The extra_value is used for saving the token. */
+ context_p->token.extra_value = context_p->token.type;
+ context_p->token.type = LEXER_EXPRESSION_START;
+ break;
}
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes
- && switch_to_strict_mode)
+ && !(status_flags & PARSER_IS_STRICT)
+ && (context_p->status_flags & PARSER_IS_STRICT))
{
JERRY_DEBUG_MSG (" Note: switch to strict mode\n\n");
}
}
/* The last directive prologue can be the result of the script. */
- if (!(context_p->status_flags & PARSER_IS_FUNCTION))
+ if (!(context_p->status_flags & PARSER_IS_FUNCTION)
+ && (context_p->token.type != LEXER_LITERAL
+ || context_p->token.lit_location.type != LEXER_STRING_LITERAL))
{
- if (context_p->token.type != LEXER_LITERAL
- || context_p->token.lit_location.type != LEXER_STRING_LITERAL)
- {
- lexer_construct_literal_object (context_p, &lit_location, LEXER_STRING_LITERAL);
- parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
- parser_emit_cbc (context_p, CBC_POP_BLOCK);
- parser_flush_cbc (context_p);
- }
+ lexer_construct_literal_object (context_p, &lit_location, LEXER_STRING_LITERAL);
+ parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
+ parser_emit_cbc (context_p, CBC_POP_BLOCK);
+ parser_flush_cbc (context_p);
}
}
break;
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ case LEXER_KEYW_CLASS:
+ {
+ parser_parse_class (context_p, true);
+ continue;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
case LEXER_KEYW_FUNCTION:
{
parser_parse_function_statement (context_p);
}
lexer_next_token (context_p);
+
if ((context_p->token.flags & LEXER_WAS_NEWLINE)
|| context_p->token.type == LEXER_SEMICOLON
|| context_p->token.type == LEXER_RIGHT_BRACE)
{
- parser_emit_cbc (context_p, CBC_RETURN_WITH_BLOCK);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags)))
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
+ parser_emit_cbc (context_p, CBC_RETURN);
+ }
+ else
+ {
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+ parser_emit_cbc (context_p, CBC_RETURN_WITH_BLOCK);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
break;
}
parser_parse_expression (context_p, PARSE_EXPR);
- if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
+
+ bool return_with_literal = (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ return_with_literal = return_with_literal && !PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
+ if (return_with_literal)
{
context_p->last_cbc_opcode = CBC_RETURN_WITH_LITERAL;
}
else
{
- parser_emit_cbc (context_p, CBC_RETURN);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags)))
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_CONSTRUCTOR_RETURN);
+ }
+ else
+ {
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+ parser_emit_cbc (context_p, CBC_RETURN);
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
}
break;
}
case LEXER_KEYW_DEBUGGER:
{
- parser_emit_cbc_ext (context_p, CBC_EXT_DEBUGGER);
+#ifdef JERRY_DEBUGGER
+ /* This breakpoint location is not reported to the
+ * debugger, so it is impossible to disable it. */
+ if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
+ {
+ parser_emit_cbc (context_p, CBC_BREAKPOINT_ENABLED);
+ }
+#endif /* JERRY_DEBUGGER */
lexer_next_token (context_p);
break;
}
-
case LEXER_LITERAL:
{
if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL
- && lexer_check_colon (context_p))
+ && lexer_check_next_character (context_p, LIT_CHAR_COLON))
{
parser_parse_label (context_p);
lexer_next_token (context_p);
#endif /* !JERRY_NDEBUG */
/* There is no lexer_next_token here, since the
* next token belongs to the parent context. */
+
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags)))
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
+ parser_emit_cbc (context_p, CBC_RETURN);
+ parser_flush_cbc (context_p);
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
return;
}
parser_raise_error (context_p, PARSER_ERR_INVALID_RIGHT_SQUARE);
/**
* Free jumps stored on the stack if a parse error is occured.
*/
-void __attr_noinline___
+void JERRY_ATTR_NOINLINE
parser_free_jumps (parser_stack_iterator_t iterator) /**< iterator position */
{
while (true)
}
} /* parser_emit_two_bytes */
+/**
+ * Append byte to the end of the current byte code stream.
+ *
+ * @param context_p parser context
+ * @param byte byte
+ */
#define PARSER_APPEND_TO_BYTE_CODE(context_p, byte) \
if ((context_p)->byte_code.last_position >= PARSER_CBC_STREAM_PAGE_SIZE) \
{ \
parser_flush_cbc (parser_context_t *context_p) /**< context */
{
uint8_t flags;
+ uint16_t last_opcode = context_p->last_cbc_opcode;
- if (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE)
+ if (last_opcode == PARSER_CBC_UNAVAILABLE)
{
return;
}
context_p->status_flags |= PARSER_NO_END_LABEL;
- if (PARSER_IS_BASIC_OPCODE (context_p->last_cbc_opcode))
+ if (PARSER_IS_BASIC_OPCODE (last_opcode))
{
- cbc_opcode_t opcode = (cbc_opcode_t) context_p->last_cbc_opcode;
+ cbc_opcode_t opcode = (cbc_opcode_t) last_opcode;
JERRY_ASSERT (opcode < CBC_END);
flags = cbc_flags[opcode];
}
else
{
- cbc_ext_opcode_t opcode = (cbc_ext_opcode_t) PARSER_GET_EXT_OPCODE (context_p->last_cbc_opcode);
+ cbc_ext_opcode_t opcode = (cbc_ext_opcode_t) PARSER_GET_EXT_OPCODE (last_opcode);
JERRY_ASSERT (opcode < CBC_EXT_END);
flags = cbc_ext_flags[opcode];
- parser_emit_two_bytes (context_p, CBC_EXT_OPCODE, opcode);
+ parser_emit_two_bytes (context_p, CBC_EXT_OPCODE, (uint8_t) opcode);
context_p->byte_code_size += 2;
}
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
- const char *name_p;
-
- if (PARSER_IS_BASIC_OPCODE (context_p->last_cbc_opcode))
- {
- name_p = cbc_names[context_p->last_cbc_opcode];
- }
- else
- {
- name_p = cbc_ext_names[PARSER_GET_EXT_OPCODE (context_p->last_cbc_opcode)];
- }
-
- JERRY_DEBUG_MSG (" [%3d] %s", (int) context_p->stack_depth, name_p);
+ JERRY_DEBUG_MSG (" [%3d] %s",
+ (int) context_p->stack_depth,
+ PARSER_IS_BASIC_OPCODE (last_opcode) ? cbc_names[last_opcode]
+ : cbc_ext_names[PARSER_GET_EXT_OPCODE (last_opcode)]);
if (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2))
{
if (flags & CBC_HAS_BYTE_ARG)
{
- JERRY_DEBUG_MSG (" byte_arg:%d", (int) context_p->last_cbc.value);
+ if ((last_opcode == CBC_PUSH_NUMBER_POS_BYTE)
+ || (last_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE)))
+ {
+ JERRY_DEBUG_MSG (" number:%d", (int) context_p->last_cbc.value + 1);
+ }
+ else if ((last_opcode == CBC_PUSH_NUMBER_NEG_BYTE)
+ || (last_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE)))
+ {
+ JERRY_DEBUG_MSG (" number:%d", -((int) context_p->last_cbc.value + 1));
+ }
+ else
+ {
+ JERRY_DEBUG_MSG (" byte_arg:%d", (int) context_p->last_cbc.value);
+ }
}
JERRY_DEBUG_MSG ("\n");
bool is_negative_number) /**< sign is negative */
{
uint16_t value = context_p->lit_object.index;
+ uint16_t lit_value = UINT16_MAX;
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
- parser_flush_cbc (context_p);
- }
-
- cbc_opcode_t opcode = is_negative_number ? CBC_PUSH_NUMBER_NEG_BYTE : CBC_PUSH_NUMBER_POS_BYTE;
-
- JERRY_ASSERT (value > 0 && value <= CBC_PUSH_NUMBER_BYTE_RANGE_END);
- JERRY_ASSERT (CBC_STACK_ADJUST_VALUE (cbc_flags[opcode]) == 1);
+ if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
+ {
+ lit_value = context_p->last_cbc.literal_index;
+ }
+ else
+ {
+ if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS)
+ {
+ context_p->last_cbc_opcode = CBC_PUSH_LITERAL;
+ lit_value = context_p->last_cbc.value;
+ }
+ else if (context_p->last_cbc_opcode == CBC_PUSH_THREE_LITERALS)
+ {
+ context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS;
+ lit_value = context_p->last_cbc.third_literal_index;
+ }
- context_p->stack_depth++;
+ parser_flush_cbc (context_p);
+ }
+ }
-#ifdef PARSER_DUMP_BYTE_CODE
- if (context_p->is_show_opcodes)
+ if (value == 0)
{
- int real_value = value;
-
- if (is_negative_number)
+ if (lit_value == UINT16_MAX)
{
- real_value = -real_value;
+ context_p->last_cbc_opcode = CBC_PUSH_NUMBER_0;
+ return;
}
- JERRY_DEBUG_MSG (" [%3d] %s number:%d\n",
- (int) context_p->stack_depth,
- cbc_names[opcode],
- real_value);
+ context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0);
+ context_p->last_cbc.literal_index = lit_value;
+ return;
}
-#endif /* PARSER_DUMP_BYTE_CODE */
- parser_emit_two_bytes (context_p, opcode, (uint8_t) (value - 1));
+ uint16_t opcode;
- context_p->byte_code_size += 2;
+ if (lit_value == UINT16_MAX)
+ {
+ opcode = (is_negative_number ? CBC_PUSH_NUMBER_NEG_BYTE
+ : CBC_PUSH_NUMBER_POS_BYTE);
- if (context_p->stack_depth > context_p->stack_limit)
+ JERRY_ASSERT (CBC_STACK_ADJUST_VALUE (PARSER_GET_FLAGS (opcode)) == 1);
+ }
+ else
{
- context_p->stack_limit = context_p->stack_depth;
- if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
- {
- parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
- }
+ opcode = PARSER_TO_EXT_OPCODE (is_negative_number ? CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE
+ : CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE);
+ JERRY_ASSERT (CBC_STACK_ADJUST_VALUE (PARSER_GET_FLAGS (opcode)) == 2);
+
+ context_p->last_cbc.literal_index = lit_value;
}
+
+ JERRY_ASSERT (value > 0 && value <= CBC_PUSH_NUMBER_BYTE_RANGE_END);
+
+ context_p->last_cbc_opcode = opcode;
+ context_p->last_cbc.value = (uint16_t) (value - 1);
} /* parser_emit_cbc_push_number */
#ifdef JERRY_ENABLE_LINE_INFO
context_p->last_line_info_line = line;
+ const uint32_t max_shift_plus_7 = 7 * 5;
+ uint32_t shift = 7;
+
+ while (shift < max_shift_plus_7 && (line >> shift) > 0)
+ {
+ shift += 7;
+ }
+
do
{
- uint8_t byte = (uint8_t) (line & CBC_LOWER_SEVEN_BIT_MASK);
+ shift -= 7;
- line >>= 7;
+ uint8_t byte = (uint8_t) ((line >> shift) & CBC_LOWER_SEVEN_BIT_MASK);
- if (line > 0)
+ if (shift > 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);
+ while (shift > 0);
} /* parser_emit_line_info */
#endif /* JERRY_ENABLE_LINE_INFO */
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
- if (extra_byte_code_increase == 0)
- {
- JERRY_DEBUG_MSG (" [%3d] %s\n", (int) context_p->stack_depth, cbc_names[opcode]);
- }
- else
- {
- JERRY_DEBUG_MSG (" [%3d] %s\n", (int) context_p->stack_depth, cbc_ext_names[opcode]);
- }
+ JERRY_DEBUG_MSG (" [%3d] %s\n",
+ (int) context_p->stack_depth,
+ extra_byte_code_increase == 0 ? cbc_names[opcode] : cbc_ext_names[opcode]);
}
#endif /* PARSER_DUMP_BYTE_CODE */
} /* parser_emit_cbc_forward_branch */
/**
- * Append a branch byte code and create an item
+ * Append a branch byte code and create an item.
+ *
+ * @return newly created parser branch node
*/
parser_branch_node_t *
parser_emit_cbc_forward_branch_item (parser_context_t *context_p, /**< context */
{
return "Case statement must be in a switch block.";
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ case PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS:
+ {
+ return "Multiple constructors are not allowed.";
+ }
+ case PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR:
+ {
+ return "Class constructor may not be an accessor.";
+ }
+ case PARSER_ERR_CLASS_STATIC_PROTOTYPE:
+ {
+ return "Classes may not have a static property called 'prototype'.";
+ }
+ case PARSER_ERR_UNEXPECTED_SUPER_REFERENCE:
+ {
+ return "Super is not allowed to be used here.";
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
case PARSER_ERR_LEFT_PAREN_EXPECTED:
{
return "Expected '(' token.";
{
return "Duplicated label.";
}
+#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
+ case PARSER_ERR_DUPLICATED_ARGUMENT_NAMES:
+ {
+ return "Duplicated function argument names are not allowed here.";
+ }
+#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
case PARSER_ERR_OBJECT_PROPERTY_REDEFINED:
{
return "Property of object literal redefined.";
#ifndef JERRY_DISABLE_JS_PARSER
+JERRY_STATIC_ASSERT ((int) ECMA_PARSE_STRICT_MODE == (int) PARSER_IS_STRICT,
+ ecma_parse_strict_mode_must_be_equal_to_parser_is_strict);
+
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+JERRY_STATIC_ASSERT ((ECMA_PARSE_CLASS_CONSTRUCTOR << PARSER_CLASS_PARSE_OPTS_OFFSET) == PARSER_CLASS_CONSTRUCTOR,
+ ecma_class_parse_options_must_be_able_to_be_shifted_to_ecma_general_flags);
+#endif /* !CONFIG_DISABLE_ES2015 */
+
/** \addtogroup parser Parser
* @{
*
if (!(literal_p->status_flags & LEXER_FLAG_SOURCE_PTR))
{
jmem_heap_free_block ((void *) char_p, literal_p->prop.length);
+ /* This literal should not be freed even if an error is encountered later. */
+ literal_p->status_flags |= LEXER_FLAG_SOURCE_PTR;
}
}
}
if (literal_p->status_flags & LEXER_FLAG_INITIALIZED)
{
- if (literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME)
- {
- JERRY_ASSERT (literal_p == PARSER_GET_LITERAL (0));
-
- status_flags |= PARSER_NAMED_FUNCTION_EXP;
- context_p->status_flags = status_flags;
-
- literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
- context_p->literal_count++;
- }
-
if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
{
if ((status_flags & PARSER_ARGUMENTS_NEEDED)
{
uint16_t init_index;
- if (literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT)
- {
- continue;
- }
-
if (literal_p->type != LEXER_IDENT_LITERAL)
{
if (literal_p->type == LEXER_STRING_LITERAL
continue;
}
+ if (literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT)
+ {
+ continue;
+ }
+
if (!(literal_p->status_flags & LEXER_FLAG_VAR))
{
literal_p->prop.index = ident_index;
init_index = literal_index;
literal_index++;
- if (!(literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME))
- {
- lexer_literal_t *func_literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator);
+ lexer_literal_t *func_literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator);
- JERRY_ASSERT (func_literal_p != NULL
- && func_literal_p->type == LEXER_FUNCTION_LITERAL);
- func_literal_p->prop.index = init_index;
- }
+ JERRY_ASSERT (func_literal_p != NULL
+ && func_literal_p->type == LEXER_FUNCTION_LITERAL);
+ func_literal_p->prop.index = init_index;
}
/* A CBC_INITIALIZE_VAR instruction or part of a CBC_INITIALIZE_VARS instruction. */
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 */
uint16_t literal_one_byte_limit) /**< maximum value of a literal
* encoded in one byte */
{
uint16_t next_index = uninitialized_var_end;
#endif /* !JERRY_NDEBUG */
- context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED;
-
*dst_p++ = CBC_INITIALIZE_VARS;
dst_p = parser_encode_literal (dst_p,
(uint16_t) uninitialized_var_end,
#endif /* !JERRY_NDEBUG */
literal_p->status_flags = (uint8_t) (literal_p->status_flags & ~LEXER_FLAG_INITIALIZED);
-
- if (literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME)
- {
- init_index = const_literal_end;
- }
- else if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
+ if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
{
init_index = (uint16_t) (argument_count - 1);
}
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);
- }
#else /* !PARSER_DUMP_BYTE_CODE */
if (!(literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT))
{
}
#endif /* PARSER_DUMP_BYTE_CODE */
}
+
+#ifdef PARSER_DUMP_BYTE_CODE
+ 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);
+ }
+#endif /* PARSER_DUMP_BYTE_CODE */
}
else if ((literal_p->type == LEXER_FUNCTION_LITERAL)
|| (literal_p->type == LEXER_REGEXP_LITERAL))
JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL);
- if (literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME)
- {
- init_index = const_literal_end;
- }
- else if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
+ if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
{
init_index = (uint16_t) (argument_count - 1);
}
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CONSTRUCTOR)
+ {
+ JERRY_DEBUG_MSG (",constructor");
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
JERRY_DEBUG_MSG ("]\n");
JERRY_DEBUG_MSG (" Argument range end: %d\n", (int) argument_end);
}
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;
while (byte_code_p < byte_code_end_p)
{
- cbc_opcode_t opcode;
- cbc_ext_opcode_t ext_opcode;
- size_t cbc_offset;
-
- opcode = (cbc_opcode_t) *byte_code_p;
- ext_opcode = CBC_EXT_NOP;
- cbc_offset = (size_t) (byte_code_p - byte_code_start_p);
+ cbc_opcode_t opcode = (cbc_opcode_t) *byte_code_p;
+ cbc_ext_opcode_t ext_opcode = CBC_EXT_NOP;
+ size_t cbc_offset = (size_t) (byte_code_p - byte_code_start_p);
if (opcode != CBC_EXT_OPCODE)
{
literal_pool_p);
continue;
}
-
- if (opcode == CBC_PUSH_NUMBER_POS_BYTE)
- {
- int value = *byte_code_p++;
- JERRY_DEBUG_MSG (" number:%d\n", value + 1);
- continue;
- }
-
- if (opcode == CBC_PUSH_NUMBER_NEG_BYTE)
- {
- int value = *byte_code_p++;
- JERRY_DEBUG_MSG (" number:%d\n", -(value + 1));
- continue;
- }
}
else
{
if (flags & CBC_HAS_BYTE_ARG)
{
- JERRY_DEBUG_MSG (" byte_arg:%d", *byte_code_p);
+ if (opcode == CBC_PUSH_NUMBER_POS_BYTE
+ || ext_opcode == CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE)
+ {
+ JERRY_DEBUG_MSG (" number:%d", (int) *byte_code_p + 1);
+ }
+ else if (opcode == CBC_PUSH_NUMBER_NEG_BYTE
+ || ext_opcode == CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE)
+ {
+ JERRY_DEBUG_MSG (" number:%d", -((int) *byte_code_p + 1));
+ }
+ else
+ {
+ JERRY_DEBUG_MSG (" byte_arg:%d", *byte_code_p);
+ }
byte_code_p++;
}
if (flags & CBC_HAS_BRANCH_ARG)
{
- size_t branch_offset_length = CBC_BRANCH_OFFSET_LENGTH (opcode);
+ size_t branch_offset_length = (opcode != CBC_EXT_OPCODE ? CBC_BRANCH_OFFSET_LENGTH (opcode)
+ : CBC_BRANCH_OFFSET_LENGTH (ext_opcode));
size_t offset = 0;
- if (opcode == CBC_EXT_OPCODE)
- {
- branch_offset_length = CBC_BRANCH_OFFSET_LENGTH (ext_opcode);
- }
-
do
{
offset = (offset << 8) | *byte_code_p++;
}
while (--branch_offset_length > 0);
- if (CBC_BRANCH_IS_FORWARD (flags))
- {
- JERRY_DEBUG_MSG (" offset:%d(->%d)", (int) offset, (int) (cbc_offset + offset));
- }
- else
- {
- JERRY_DEBUG_MSG (" offset:%d(->%d)", (int) offset, (int) (cbc_offset - offset));
- }
+ JERRY_DEBUG_MSG (" offset:%d(->%d)",
+ (int) offset,
+ (int) (cbc_offset + (CBC_BRANCH_IS_FORWARD (flags) ? offset : -offset)));
}
JERRY_DEBUG_MSG ("\n");
#endif /* PARSER_DUMP_BYTE_CODE */
+#ifdef JERRY_DEBUGGER
+
+/**
+ * Send current breakpoint list.
+ */
+static void
+parser_send_breakpoints (parser_context_t *context_p, /**< context */
+ jerry_debugger_header_type_t type) /**< message type */
+{
+ JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
+ JERRY_ASSERT (context_p->breakpoint_info_count > 0);
+
+ jerry_debugger_send_data (type,
+ context_p->breakpoint_info,
+ context_p->breakpoint_info_count * sizeof (parser_breakpoint_info_t));
+
+ context_p->breakpoint_info_count = 0;
+} /* parser_send_breakpoints */
+
+/**
+ * Append a breakpoint info.
+ */
+void
+parser_append_breakpoint_info (parser_context_t *context_p, /**< context */
+ jerry_debugger_header_type_t type, /**< message type */
+ uint32_t value) /**< line or offset of the breakpoint */
+{
+ JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
+
+ context_p->status_flags |= PARSER_DEBUGGER_BREAKPOINT_APPENDED;
+
+ if (context_p->breakpoint_info_count >= JERRY_DEBUGGER_SEND_MAX (parser_breakpoint_info_t))
+ {
+ parser_send_breakpoints (context_p, type);
+ }
+
+ context_p->breakpoint_info[context_p->breakpoint_info_count].value = value;
+ context_p->breakpoint_info_count = (uint16_t) (context_p->breakpoint_info_count + 1);
+} /* parser_append_breakpoint_info */
+
+#endif /* JERRY_DEBUGGER */
+
+/**
+ * Forward iterator: move to the next byte code
+ *
+ * @param page_p page
+ * @param offset offset
+ */
#define PARSER_NEXT_BYTE(page_p, offset) \
do { \
if (++(offset) >= PARSER_CBC_STREAM_PAGE_SIZE) \
} \
} while (0)
+/**
+ * Forward iterator: move to the next byte code. Also updates the offset of the previous byte code.
+ *
+ * @param page_p page
+ * @param offset offset
+ * @param real_offset real offset
+ */
#define PARSER_NEXT_BYTE_UPDATE(page_p, offset, real_offset) \
do { \
page_p->bytes[offset] = real_offset; \
PARSER_NEXT_BYTE (page_p, offset);
length++;
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (ext_opcode == CBC_EXT_CONSTRUCTOR_RETURN)
+ {
+ last_opcode = CBC_RETURN;
+ }
+#endif /* !CONFIG_DISABLE_ES2015 */
+
#ifdef JERRY_ENABLE_LINE_INFO
if (ext_opcode == CBC_EXT_LINE)
{
{
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;
}
}
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR)
+ {
+ compiled_code_p->status_flags |= CBC_CODE_FLAGS_CONSTRUCTOR;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
literal_pool_p = (ecma_value_t *) byte_code_p;
literal_pool_p -= context_p->register_count;
byte_code_p += literal_length;
literal_pool_p,
uninitialized_var_end,
initialized_var_end,
- const_literal_end,
literal_one_byte_limit);
JERRY_ASSERT (dst_p == byte_code_p + initializers_length);
}
/* Storing the opcode */
- *dst_p++ = opcode;
+ *dst_p++ = (uint8_t) opcode;
real_offset++;
PARSER_NEXT_BYTE_UPDATE (page_p, offset, real_offset);
flags = cbc_flags[opcode];
branch_offset_length = CBC_BRANCH_OFFSET_LENGTH (ext_opcode);
/* Storing the extended opcode */
- *dst_p++ = ext_opcode;
+ *dst_p++ = (uint8_t) ext_opcode;
opcode_p++;
real_offset++;
PARSER_NEXT_BYTE_UPDATE (page_p, offset, real_offset);
}
#endif /* JERRY_ENABLE_LINE_INFO */
- if (context_p->status_flags & PARSER_NAMED_FUNCTION_EXP)
- {
- ECMA_SET_INTERNAL_VALUE_POINTER (literal_pool_p[const_literal_end],
- compiled_code_p);
- }
-
#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
parser_parse_function_arguments (parser_context_t *context_p, /**< context */
lexer_token_type_t end_type) /**< expected end type */
{
+#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
+ bool duplicated_argument_names = false;
+ bool initializer_found = false;
+#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
+
if (context_p->token.type == end_type)
{
return;
{
lexer_literal_t *literal_p;
+#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
+ if (initializer_found)
+ {
+ parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES);
+ }
+ duplicated_argument_names = true;
+#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
+
if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
{
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
lexer_next_token (context_p);
+#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
+ if (context_p->token.type == LEXER_ASSIGN)
+ {
+ parser_branch_t skip_init;
+
+ if (duplicated_argument_names)
+ {
+ parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES);
+ }
+ initializer_found = true;
+
+ /* LEXER_ASSIGN does not overwrite lit_object. */
+ parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED);
+ parser_emit_cbc_literal (context_p, CBC_STRICT_EQUAL_RIGHT_LITERAL, context_p->lit_object.index);
+ parser_emit_cbc_forward_branch (context_p, CBC_BRANCH_IF_FALSE_FORWARD, &skip_init);
+
+ parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
+ parser_parse_expression (context_p, PARSE_EXPR_STATEMENT | PARSE_EXPR_NO_COMMA | PARSE_EXPR_HAS_LITERAL);
+
+ parser_set_branch_to_current_position (context_p, &skip_init);
+ }
+#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
+
if (context_p->token.type != LEXER_COMMA)
{
break;
size_t arg_list_size, /**< size of function argument list */
const uint8_t *source_p, /**< valid UTF-8 source code */
size_t source_size, /**< size of the source code */
- int strict_mode, /**< strict mode */
+ uint32_t parse_opts, /**< ecma_parse_opts_t option bits */
parser_error_location_t *error_location_p) /**< error location */
{
parser_context_t context;
context.stack_limit = 0;
context.last_context_p = NULL;
context.last_statement.current_p = NULL;
+ context.status_flags |= parse_opts & PARSER_STRICT_MODE_MASK;
- if (strict_mode)
- {
- context.status_flags |= PARSER_IS_STRICT;
- }
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ context.status_flags |= PARSER_GET_CLASS_PARSER_OPTS (parse_opts);
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
context.token.flags = 0;
context.line = 1;
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ JERRY_DEBUG_MSG ("\n--- %s parsing start ---\n\n",
+ (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR) ? "Class constructor"
+ : "Function");
+#else /* CONFIG_DISABLE_ES2015_CLASS */
JERRY_DEBUG_MSG ("\n--- Function parsing start ---\n\n");
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
}
#endif /* PARSER_DUMP_BYTE_CODE */
-#ifdef JERRY_DEBUGGER
- parser_line_counter_t debugger_line = context_p->token.line;
- parser_line_counter_t debugger_column = context_p->token.column;
-#endif /* JERRY_DEBUGGER */
-
- lexer_next_token (context_p);
-
- if (context_p->status_flags & PARSER_IS_FUNC_EXPRESSION
- && context_p->token.type == LEXER_LITERAL
- && context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
- {
- lexer_construct_literal_object (context_p,
- &context_p->token.lit_location,
- LEXER_IDENT_LITERAL);
-
-#ifdef JERRY_DEBUGGER
- if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
- {
- jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME,
- JERRY_DEBUGGER_NO_SUBTYPE,
- context_p->lit_object.literal_p->u.char_p,
- context_p->lit_object.literal_p->prop.length);
- }
-#endif /* JERRY_DEBUGGER */
-
- /* The arguments object is created later than the binding to the
- * function expression name, so there is no need to assign special flags. */
- if (context_p->lit_object.type != LEXER_LITERAL_OBJECT_ARGUMENTS)
- {
- uint8_t lexer_flags = LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED | LEXER_FLAG_FUNCTION_NAME;
- context_p->lit_object.literal_p->status_flags |= lexer_flags;
- }
-
- if (context_p->token.literal_is_reserved
- || context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY)
- {
- context_p->status_flags |= PARSER_HAS_NON_STRICT_ARG;
- }
-
- lexer_next_token (context_p);
- }
-
#ifdef JERRY_DEBUGGER
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
- && jerry_debugger_send_parse_function (debugger_line, debugger_column))
+ && jerry_debugger_send_parse_function (context_p->token.line, context_p->token.column))
{
/* This option has a high memory and performance costs,
* but it is necessary for executing eval operations by the debugger. */
}
#endif /* JERRY_DEBUGGER */
+ lexer_next_token (context_p);
+
if (context_p->token.type != LEXER_LEFT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED);
}
lexer_next_token (context_p);
+
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if ((context_p->status_flags & PARSER_CLASS_CONSTRUCTOR_SUPER) == PARSER_CLASS_CONSTRUCTOR_SUPER)
+ {
+ context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
parser_parse_statements (context_p);
compiled_code_p = parser_post_processing (context_p);
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ JERRY_DEBUG_MSG ("\n--- %s parsing end ---\n\n",
+ (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR) ? "Class constructor"
+ : "Function");
+#else /* CONFIG_DISABLE_ES2015_CLASS */
JERRY_DEBUG_MSG ("\n--- Function parsing end ---\n\n");
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
}
#endif /* PARSER_DUMP_BYTE_CODE */
&& (status_flags & PARSER_IS_ARROW_FUNCTION));
parser_save_context (context_p, &saved_context);
context_p->status_flags |= status_flags | PARSER_ARGUMENTS_NOT_NEEDED;
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ context_p->status_flags |= saved_context.status_flags & PARSER_CLASS_HAS_SUPER;
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
JERRY_ASSERT (0);
} /* parser_raise_error */
-#ifdef JERRY_DEBUGGER
-
-/**
- * Append a breakpoint info.
- */
-void
-parser_append_breakpoint_info (parser_context_t *context_p, /**< context */
- jerry_debugger_header_type_t type, /**< message type */
- uint32_t value) /**< line or offset of the breakpoint */
-{
- JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
-
- context_p->status_flags |= PARSER_DEBUGGER_BREAKPOINT_APPENDED;
-
- if (context_p->breakpoint_info_count >= JERRY_DEBUGGER_SEND_MAX (parser_breakpoint_info_t))
- {
- parser_send_breakpoints (context_p, type);
- }
-
- context_p->breakpoint_info[context_p->breakpoint_info_count].value = value;
- context_p->breakpoint_info_count = (uint16_t) (context_p->breakpoint_info_count + 1);
-} /* parser_append_breakpoint_info */
-
-/**
- * Send current breakpoint list.
- */
-void
-parser_send_breakpoints (parser_context_t *context_p, /**< context */
- jerry_debugger_header_type_t type) /**< message type */
-{
- JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
- JERRY_ASSERT (context_p->breakpoint_info_count > 0);
-
- jerry_debugger_send_data (type,
- context_p->breakpoint_info,
- context_p->breakpoint_info_count * sizeof (parser_breakpoint_info_t));
-
- context_p->breakpoint_info_count = 0;
-} /* parser_send_breakpoints */
-
-#endif /* JERRY_DEBUGGER */
-
#endif /* !JERRY_DISABLE_JS_PARSER */
/**
size_t arg_list_size, /**< size of function argument list */
const uint8_t *source_p, /**< source code */
size_t source_size, /**< size of the source code */
- bool is_strict, /**< strict mode */
+ uint32_t parse_opts, /**< ecma_parse_opts_t option bits */
ecma_compiled_code_t **bytecode_data_p) /**< [out] JS bytecode */
{
#ifndef JERRY_DISABLE_JS_PARSER
arg_list_size,
source_p,
source_size,
- is_strict,
+ parse_opts,
&parser_error);
if (!*bytecode_data_p)
break;
}
- jerry_debugger_sleep ();
+ jerry_debugger_transport_sleep ();
}
}
#endif /* JERRY_DEBUGGER */
JERRY_UNUSED (arg_list_size);
JERRY_UNUSED (source_p);
JERRY_UNUSED (source_size);
- JERRY_UNUSED (is_strict);
+ JERRY_UNUSED (parse_opts);
JERRY_UNUSED (bytecode_data_p);
return ecma_raise_syntax_error (ECMA_ERR_MSG ("The parser has been disabled."));
PARSER_ERR_MULTIPLE_DEFAULTS_NOT_ALLOWED, /**< multiple default cases are not allowed */
PARSER_ERR_DEFAULT_NOT_IN_SWITCH, /**< default statement is not in switch block */
PARSER_ERR_CASE_NOT_IN_SWITCH, /**< case statement is not in switch block */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS, /**< multiple class constructor */
+ PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR, /**< class constructor cannot be an accessor */
+ PARSER_ERR_CLASS_STATIC_PROTOTYPE, /**< static method name 'prototype' is not allowed */
+ PARSER_ERR_UNEXPECTED_SUPER_REFERENCE, /**< unexpected super keyword */
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
PARSER_ERR_LEFT_PAREN_EXPECTED, /**< left paren expected */
PARSER_ERR_LEFT_BRACE_EXPECTED, /**< left brace expected */
PARSER_ERR_INVALID_RETURN, /**< return must be inside a function */
PARSER_ERR_INVALID_RIGHT_SQUARE, /**< right square must terminate a block */
PARSER_ERR_DUPLICATED_LABEL, /**< duplicated label */
+#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
+ PARSER_ERR_DUPLICATED_ARGUMENT_NAMES, /**< duplicated argument names */
+#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
PARSER_ERR_OBJECT_PROPERTY_REDEFINED, /**< property of object literal redefined */
PARSER_ERR_NON_STRICT_ARG_DEFINITION /**< non-strict argument definition */
} parser_error_t;
-/* Source code line counter type. */
+/**
+ * Source code line counter type.
+ */
typedef uint32_t parser_line_counter_t;
/**
/* Note: source must be a valid UTF-8 string */
ecma_value_t parser_parse_script (const uint8_t *arg_list_p, size_t arg_list_size,
const uint8_t *source_p, size_t source_size,
- bool is_strict, ecma_compiled_code_t **bytecode_data_p);
+ uint32_t parse_opts, ecma_compiled_code_t **bytecode_data_p);
+#ifdef JERRY_ENABLE_ERROR_MESSAGES
const char *parser_error_to_string (parser_error_t);
+#endif /* JERRY_ENABLE_ERROR_MESSAGES */
/**
* @}
*
* @return ecma character
*/
-inline ecma_char_t __attr_always_inline___
+inline ecma_char_t JERRY_ATTR_ALWAYS_INLINE
re_get_char (uint8_t **bc_p) /**< pointer to bytecode start */
{
ecma_char_t chr;
*
* @return current RegExp opcode
*/
-inline re_opcode_t __attr_always_inline___
+inline re_opcode_t JERRY_ATTR_ALWAYS_INLINE
re_get_opcode (uint8_t **bc_p) /**< pointer to bytecode start */
{
uint8_t bytecode = **bc_p;
*
* @return opcode parameter
*/
-inline uint32_t __attr_always_inline___
+inline uint32_t JERRY_ATTR_ALWAYS_INLINE
re_get_value (uint8_t **bc_p) /**< pointer to bytecode start */
{
uint32_t value;
*
* @return bytecode length (unsigned integer)
*/
-inline uint32_t __attr_pure___ __attr_always_inline___
+inline uint32_t JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
re_get_bytecode_length (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytecode context */
{
return ((uint32_t) (bc_ctx_p->current_p - bc_ctx_p->block_start_p));
re_opcode_t re_get_opcode (uint8_t **bc_p);
ecma_char_t re_get_char (uint8_t **bc_p);
uint32_t re_get_value (uint8_t **bc_p);
-uint32_t re_get_bytecode_length (re_bytecode_ctx_t *bc_ctx_p) __attr_pure___;
+uint32_t JERRY_ATTR_PURE re_get_bytecode_length (re_bytecode_ctx_t *bc_ctx_p);
void re_append_opcode (re_bytecode_ctx_t *bc_ctx_p, re_opcode_t opcode);
void re_append_u32 (re_bytecode_ctx_t *bc_ctx_p, uint32_t value);
}
else if (qmin > qmax)
{
- return ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp quantifier error: qmin > qmax."));
+ /* ECMA-262 v5.1 15.10.2.5 */
+ return ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp quantifier error: min > max."));
}
/* TODO: optimize bytecode length. Store 0 rather than INF */
/**
* Enclose the given bytecode to a group
+ *
+ * @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_into_group (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */
uint32_t group_start_offset, /**< offset of group start */
uint32_t idx, /**< index of group */
bool is_capturable) /**< is capturable group */
{
- uint32_t qmin, qmax;
+ uint32_t qmin = re_ctx_p->current_token.qmin;
+ uint32_t qmax = re_ctx_p->current_token.qmax;
+
+ if (qmin > qmax)
+ {
+ /* ECMA-262 v5.1 15.10.2.5 */
+ return ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp quantifier error: min > max."));
+ }
+
re_opcode_t start_opcode = re_get_start_opcode_type (re_ctx_p, is_capturable);
re_opcode_t end_opcode = re_get_end_opcode_type (re_ctx_p, is_capturable);
- uint32_t start_head_offset_len;
- qmin = re_ctx_p->current_token.qmin;
- qmax = re_ctx_p->current_token.qmax;
- JERRY_ASSERT (qmin <= qmax);
-
- start_head_offset_len = re_get_bytecode_length (re_ctx_p->bytecode_ctx_p);
+ uint32_t start_head_offset_len = re_get_bytecode_length (re_ctx_p->bytecode_ctx_p);
re_insert_u32 (re_ctx_p->bytecode_ctx_p, group_start_offset, idx);
re_insert_opcode (re_ctx_p->bytecode_ctx_p, group_start_offset, start_opcode);
start_head_offset_len = re_get_bytecode_length (re_ctx_p->bytecode_ctx_p) - start_head_offset_len;
group_start_offset,
re_get_bytecode_length (re_ctx_p->bytecode_ctx_p) - group_start_offset);
}
+
+ return ECMA_VALUE_EMPTY;
} /* re_insert_into_group */
/**
* Enclose the given bytecode to a group and inster jump value
+ *
+ * @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_into_group_with_jump (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */
uint32_t group_start_offset, /**< offset of group start */
uint32_t idx, /**< index of group */
re_insert_u32 (re_ctx_p->bytecode_ctx_p,
group_start_offset,
re_get_bytecode_length (re_ctx_p->bytecode_ctx_p) - group_start_offset);
- re_insert_into_group (re_ctx_p, group_start_offset, idx, is_capturable);
+ return re_insert_into_group (re_ctx_p, group_start_offset, idx, is_capturable);
} /* re_insert_into_group_with_jump */
/**
if (ecma_is_value_empty (ret_value))
{
- re_insert_into_group (re_ctx_p, new_atom_start_offset, idx, true);
+ ret_value = re_insert_into_group (re_ctx_p, new_atom_start_offset, idx, true);
}
break;
if (ecma_is_value_empty (ret_value))
{
- re_insert_into_group (re_ctx_p, new_atom_start_offset, idx, false);
+ ret_value = re_insert_into_group (re_ctx_p, new_atom_start_offset, idx, false);
}
break;
{
re_append_opcode (bc_ctx_p, RE_OP_MATCH);
- re_insert_into_group_with_jump (re_ctx_p, new_atom_start_offset, idx, false);
+ ret_value = re_insert_into_group_with_jump (re_ctx_p, new_atom_start_offset, idx, false);
}
break;
{
re_append_opcode (bc_ctx_p, RE_OP_MATCH);
- re_insert_into_group_with_jump (re_ctx_p, new_atom_start_offset, idx, false);
+ ret_value = re_insert_into_group_with_jump (re_ctx_p, new_atom_start_offset, idx, false);
}
break;
re_append_opcode (bc_ctx_p, RE_OP_BACKREFERENCE);
re_append_u32 (bc_ctx_p, backref);
- re_insert_into_group_with_jump (re_ctx_p, new_atom_start_offset, idx, false);
+ ret_value = re_insert_into_group_with_jump (re_ctx_p, new_atom_start_offset, idx, false);
break;
}
case RE_TOK_DIGIT:
* @return true - if non-greedy character found
* false - otherwise
*/
-static inline bool __attr_always_inline___
+static inline bool JERRY_ATTR_ALWAYS_INLINE
re_parse_non_greedy_char (re_parser_ctx_t *parser_ctx_p) /**< RegExp parser context */
{
if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p
{
case LIT_CHAR_BACKSLASH:
{
- lit_utf8_incr (&curr_p);
+ if (curr_p < parser_ctx_p->input_end_p)
+ {
+ lit_utf8_incr (&curr_p);
+ }
break;
}
case LIT_CHAR_LEFT_SQUARE:
}
}
}
- else if (ch == LIT_CHAR_LOWERCASE_X)
+ else if (ch == LIT_CHAR_LOWERCASE_X && re_hex_lookup (parser_ctx_p, 2))
{
ecma_char_t code_unit;
}
parser_ctx_p->input_curr_p += 2;
- if (is_range == false && lit_utf8_peek_next (parser_ctx_p->input_curr_p) == LIT_CHAR_MINUS)
+ if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p
+ && is_range == false
+ && lit_utf8_peek_next (parser_ctx_p->input_curr_p) == LIT_CHAR_MINUS)
{
start = code_unit;
continue;
ch = code_unit;
}
- else if (ch == LIT_CHAR_LOWERCASE_U)
+ else if (ch == LIT_CHAR_LOWERCASE_U && re_hex_lookup (parser_ctx_p, 4))
{
ecma_char_t code_unit;
}
parser_ctx_p->input_curr_p += 4;
- if (is_range == false && lit_utf8_peek_next (parser_ctx_p->input_curr_p) == LIT_CHAR_MINUS)
+ if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p
+ && is_range == false
+ && lit_utf8_peek_next (parser_ctx_p->input_curr_p) == LIT_CHAR_MINUS)
{
start = code_unit;
continue;
-
### About profile files
Specify compile definitions in profile files to use when compiling the `jerry-core` target.
#### Restrictions
Only single line options are allowed in the profile file. Any line starting with hash-mark is ignored. Semicolon character is not allowed.
-### Example usage:
+
+### Example usage
#### 1. Using the build script
+If you want to use a predefined profile, run the build script as follows
+(assuming that you are in the project root folder):
+
```
-# assuming you are in jerryscript folder
-./tools/build.py --profile=/absolute/path/to/my_profile.any_extension
+./tools/build.py --profile=minimal
```
-or
+Alternatively, if you want to use a custom profile at
+`/absolute/path/to/my.profile`:
```
-# assuming you are in jerryscript folder
-./tools/build.py --profile=minimal
+# Turn off every ES2015 feature EXCEPT the arrow functions
+CONFIG_DISABLE_ES2015_BUILTIN
+CONFIG_DISABLE_ES2015_CLASS
+CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
+CONFIG_DISABLE_ES2015_MAP_BUILTIN
+CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
+CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS
+CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
+```
+
+Run the build script as follows (assuming that you are in the project root
+folder):
+
+```
+./tools/build.py --profile=/absolute/path/to/my.profile
```
-This command selects the profiles/minimal.profile file.
#### 2. Using only CMake build system
Set FEATURE_PROFILE option to one of the following values:
* the profile with absolute path
* name of the profile (which needs to exist in the `profiles` folder)
+
+
+### Configurations
+
+In JerryScript all of the features are enabled by default, so an empty profile file turns on all of the available ECMA features.
+
+* `CONFIG_DISABLE_ANNEXB_BUILTIN`:
+ Disable the [Annex B](http://www.ecma-international.org/ecma-262/5.1/index.html#sec-B) of the ECMA5.1 standard.
+* `CONFIG_DISABLE_ARRAY_BUILTIN`:
+ Disable the [Array](http://www.ecma-international.org/ecma-262/5.1/index.html#sec-15.4) built-in.
+* `CONFIG_DISABLE_BOOLEAN_BUILTIN`:
+ Disable the [Boolean](http://www.ecma-international.org/ecma-262/5.1/index.html#sec-15.6) built-in.
+* `CONFIG_DISABLE_DATE_BUILTIN`:
+ Disable the [Date](http://www.ecma-international.org/ecma-262/5.1/index.html#sec-15.9) built-in.
+* `CONFIG_DISABLE_ERROR_BUILTINS`:
+ Disable the [Native Error Types](http://www.ecma-international.org/ecma-262/5.1/index.html#sec-15.11.6) (EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError).
+ **Note**: The [Error](http://www.ecma-international.org/ecma-262/5.1/index.html#sec-15.11.2) object remains available.
+* `CONFIG_DISABLE_JSON_BUILTIN`:
+ Disable the [JSON](http://www.ecma-international.org/ecma-262/5.1/index.html#sec-15.12) built-in.
+* `CONFIG_DISABLE_MATH_BUILTIN`:
+ Disable the [Math](http://www.ecma-international.org/ecma-262/5.1/index.html#sec-15.8) built-in.
+* `CONFIG_DISABLE_NUMBER_BUILTIN`:
+ Disable the [Number](http://www.ecma-international.org/ecma-262/5.1/index.html#sec-15.7) built-in.
+* `CONFIG_DISABLE_REGEXP_BUILTIN`:
+ Disable the [RegExp](http://www.ecma-international.org/ecma-262/5.1/index.html#sec-15.10) built-in.
+* `CONFIG_DISABLE_STRING_BUILTIN`:
+ Disable the [String](http://www.ecma-international.org/ecma-262/5.1/index.html#sec-15.5) built-in.
+* `CONFIG_DISABLE_BUILTINS`:
+ Disable all of the [Standard Built-in ECMAScript 5.1 Objects](http://www.ecma-international.org/ecma-262/5.1/index.html#sec-15)
+ (equivalent to `CONFIG_DISABLE_ANNEXB_BUILTIN`, `CONFIG_DISABLE_ARRAY_BUILTIN`, `CONFIG_DISABLE_BOOLEAN_BUILTIN`, `CONFIG_DISABLE_DATE_BUILTIN`, `CONFIG_DISABLE_ERROR_BUILTINS`, `CONFIG_DISABLE_JSON_BUILTIN`, `CONFIG_DISABLE_MATH_BUILTIN`, `CONFIG_DISABLE_NUMBER_BUILTIN`, `CONFIG_DISABLE_REGEXP_BUILTIN`, and `CONFIG_DISABLE_STRING_BUILTIN`).
+
+* `CONFIG_DISABLE_ES2015_ARROW_FUNCTION`:
+ Disable the [arrow functions](http://www.ecma-international.org/ecma-262/6.0/#sec-arrow-function-definitions).
+* `CONFIG_DISABLE_ES2015_BUILTIN`:
+ Disable the built-in updates of the 5.1 standard. There are some differences in those built-ins which available in both [5.1](http://www.ecma-international.org/ecma-262/5.1/) and [2015](http://www.ecma-international.org/ecma-262/6.0/) versions of the standard. JerryScript uses the latest definition by default.
+* `CONFIG_DISABLE_ES2015_CLASS`:
+ Disable the [class](https://www.ecma-international.org/ecma-262/6.0/#sec-class-definitions) language element.
+* `CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER`:
+ Disable the [default value](http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions) for formal parameters.
+* `CONFIG_DISABLE_ES2015_MAP_BUILTIN`:
+ Disable the [Map](http://www.ecma-international.org/ecma-262/6.0/#sec-keyed-collection) built-ins.
+* `CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER`:
+ Disable the [enhanced object initializer](http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer) language element.
+* `CONFIG_DISABLE_ES2015_PROMISE_BUILTIN`:
+ Disable the [Promise](http://www.ecma-international.org/ecma-262/6.0/#sec-promise-objects) built-in.
+* `CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS`:
+ Disable the [template strings](http://www.ecma-international.org/ecma-262/6.0/#sec-static-semantics-templatestrings).
+* `CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN`:
+ Disable the [ArrayBuffer](http://www.ecma-international.org/ecma-262/6.0/#sec-arraybuffer-objects) and [TypedArray](http://www.ecma-international.org/ecma-262/6.0/#sec-typedarray-objects) built-ins.
+* `CONFIG_DISABLE_ES2015`: Disable all of the implemented [ECMAScript2015 features](http://www.ecma-international.org/ecma-262/6.0/).
+ (equivalent to `CONFIG_DISABLE_ES2015_ARROW_FUNCTION`, `CONFIG_DISABLE_ES2015_BUILTIN`, `CONFIG_DISABLE_ES2015_CLASS`,
+ `CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER`, `CONFIG_DISABLE_ES2015_MAP_BUILTIN`, `CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER`,
+ `CONFIG_DISABLE_ES2015_PROMISE_BUILTIN`, `CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS`, and `CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN`).
return ecma_raise_type_error (ECMA_ERR_MSG ("Expected an object in 'in' check."));
}
- ecma_value_t left_string_value = ecma_op_to_string (left_value);
- if (ECMA_IS_VALUE_ERROR (left_string_value))
+ bool to_string = !ecma_is_value_string (left_value);
+
+ if (to_string)
{
- return left_string_value;
+ left_value = ecma_op_to_string (left_value);
+
+ if (ECMA_IS_VALUE_ERROR (left_value))
+ {
+ return left_value;
+ }
}
- ecma_string_t *left_value_prop_name_p = ecma_get_string_from_value (left_string_value);
+ ecma_string_t *left_value_prop_name_p = ecma_get_string_from_value (left_value);
ecma_object_t *right_value_obj_p = ecma_get_object_from_value (right_value);
- ecma_free_value (left_string_value);
+ ecma_value_t result = ecma_make_boolean_value (ecma_op_object_has_property (right_value_obj_p,
+ left_value_prop_name_p));
- return ecma_make_boolean_value (ecma_op_object_has_property (right_value_obj_p, left_value_prop_name_p));
+ if (to_string)
+ {
+ ecma_free_value (left_value);
+ }
+ return result;
} /* opfunc_in */
/**
return ECMA_VALUE_EMPTY;
} /* vm_var_decl */
-/**
- * 'Logical NOT Operator' opcode handler.
- *
- * See also: ECMA-262 v5, 11.4.9
- *
- * @return ecma value
- * Returned value must be freed with ecma_free_value
- */
-ecma_value_t
-opfunc_logical_not (ecma_value_t left_value) /**< left value */
-{
- return ecma_make_boolean_value (!ecma_op_to_boolean (left_value));
-} /* opfunc_logical_not */
-
/**
* 'typeof' opcode handler.
*
void
opfunc_set_accessor (bool is_getter, /**< is getter accessor */
ecma_value_t object, /**< object value */
- ecma_value_t accessor_name, /**< accessor name value */
+ ecma_string_t *accessor_name_p, /**< accessor name */
ecma_value_t accessor) /**< accessor value */
{
ecma_object_t *object_p = ecma_get_object_from_value (object);
- JERRY_ASSERT (ecma_is_value_string (accessor_name) || ecma_is_value_number (accessor_name));
- ecma_string_t *accessor_name_p = ecma_get_string_from_value (ecma_op_to_string (accessor_name));
ecma_property_t *property_p = ecma_find_named_property (object_p, accessor_name_p);
if (property_p != NULL
ECMA_PROPERTY_VALUE_PTR (property_p),
setter_func_p);
}
-
- ecma_deref_ecma_string (accessor_name_p);
} /* opfunc_set_accessor */
/**
/* 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);
+ ecma_collection_header_t *prop_names_coll_p;
+ prop_names_coll_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_ENUMERABLE_PROTOTYPE);
if (prop_names_coll_p->item_count != 0)
{
ecma_value_t
opfunc_instanceof (ecma_value_t left_value, ecma_value_t right_value);
-ecma_value_t
-opfunc_logical_not (ecma_value_t left_value);
-
ecma_value_t
opfunc_typeof (ecma_value_t left_value);
void
-opfunc_set_accessor (bool is_getter, ecma_value_t object, ecma_value_t accessor_name, ecma_value_t accessor);
+opfunc_set_accessor (bool is_getter, ecma_value_t object, ecma_string_t *accessor_name_p, ecma_value_t accessor);
ecma_value_t
vm_op_delete_prop (ecma_value_t object, ecma_value_t property, bool is_strict);
*/
/**
- * Helpers for updating uint16_t values.
+ * Helper for += on uint16_t values.
*/
#define VM_PLUS_EQUAL_U16(base, value) (base) = (uint16_t) ((base) + (value))
+
+/**
+ * Helper for -= on uint16_t values.
+ */
#define VM_MINUS_EQUAL_U16(base, value) (base) = (uint16_t) ((base) - (value))
/**
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 */
+ ecma_value_t block_result; /**< block result */
#ifdef JERRY_ENABLE_LINE_INFO
ecma_value_t resource_name; /**< current resource name (usually a file name) */
uint32_t current_line; /**< currently executed line */
* @{
*/
+JERRY_STATIC_ASSERT (PARSER_WITH_CONTEXT_STACK_ALLOCATION == PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION,
+ parser_with_context_stack_allocation_must_be_equal_to_parser_super_class_context_stack_allocation);
+
/**
* Abort (finalize) the current stack context, and remove it.
*
break;
}
case VM_CONTEXT_CATCH:
- case VM_CONTEXT_WITH:
{
- ecma_deref_object (frame_ctx_p->lex_env_p);
- frame_ctx_p->lex_env_p = ecma_get_object_from_value (vm_stack_top_p[-2]);
+ JERRY_ASSERT (PARSER_TRY_CONTEXT_STACK_ALLOCATION > PARSER_WITH_CONTEXT_STACK_ALLOCATION);
- JERRY_ASSERT (PARSER_TRY_CONTEXT_STACK_ALLOCATION == PARSER_WITH_CONTEXT_STACK_ALLOCATION);
+ const uint16_t size_diff = PARSER_TRY_CONTEXT_STACK_ALLOCATION - PARSER_WITH_CONTEXT_STACK_ALLOCATION;
- VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
- vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
+ VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, size_diff);
+ vm_stack_top_p -= size_diff;
+ /* FALLTHRU */
+ }
+ case VM_CONTEXT_WITH:
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ case VM_CONTEXT_SUPER_CLASS:
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+ {
+ ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
+ frame_ctx_p->lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
+ ecma_deref_object (lex_env_p);
+
+ VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_WITH_CONTEXT_STACK_ALLOCATION);
+ vm_stack_top_p -= PARSER_WITH_CONTEXT_STACK_ALLOCATION;
break;
}
- case VM_CONTEXT_FOR_IN:
+ default:
{
+ JERRY_ASSERT (VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1]) == VM_CONTEXT_FOR_IN);
+
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];
{
ecma_value_t value = chunk_p->items[index];
- if (unlikely (ecma_is_value_collection_chunk (value)))
+ if (JERRY_UNLIKELY (ecma_is_value_pointer (value)))
{
- ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (value);
+ ecma_collection_chunk_t *next_chunk_p;
+ next_chunk_p = (ecma_collection_chunk_t *) ecma_get_pointer_from_value (value);
jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t));
chunk_p = next_chunk_p;
vm_stack_top_p -= PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION;
break;
}
- default:
- {
- JERRY_UNREACHABLE ();
- break;
- }
}
return vm_stack_top_p;
}
else
{
- ecma_deref_object (frame_ctx_p->lex_env_p);
- frame_ctx_p->lex_env_p = ecma_get_object_from_value (vm_stack_top_p[-2]);
+ ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
+ frame_ctx_p->lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
+ ecma_deref_object (lex_env_p);
if (byte_code_p[0] == CBC_CONTEXT_END)
{
* @{
*/
-/**
- * Number of ecma values inlined into stack frame
- */
-#define VM_STACK_FRAME_INLINED_VALUES_NUMBER CONFIG_VM_STACK_FRAME_INLINED_VALUES_NUMBER
-
/**
* Header of a ECMA stack frame's chunk
*/
VM_CONTEXT_TRY, /**< try context */
VM_CONTEXT_CATCH, /**< catch context */
VM_CONTEXT_WITH, /**< with context */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ VM_CONTEXT_SUPER_CLASS, /**< super class context */
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
VM_CONTEXT_FOR_IN, /**< for-in context */
} vm_stack_context_type_t;
* without 'this' argument,
* false - otherwise
*/
-inline bool __attr_always_inline___
+inline bool JERRY_ATTR_ALWAYS_INLINE
vm_is_direct_eval_form_call (void)
{
return (JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL) != 0;
if (ecma_string_is_empty (str_p))
{
- const char *unknown_str_p = "<unknown>:";
- str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) unknown_str_p,
- (lit_utf8_size_t) strlen (unknown_str_p));
+ const lit_utf8_byte_t unknown_str[] = "<unknown>:";
+ str_p = ecma_new_ecma_string_from_utf8 (unknown_str, sizeof (unknown_str) - 1);
}
else
{
{
if (ecma_is_value_object (object))
{
- ecma_object_t *object_p = ecma_get_object_from_value (object);
ecma_string_t *property_name_p = NULL;
if (ecma_is_value_integer_number (property))
if (property_name_p != NULL)
{
+#ifndef CONFIG_ECMA_LCACHE_DISABLE
+ ecma_object_t *object_p = ecma_get_object_from_value (object);
ecma_property_t *property_p = ecma_lcache_lookup (object_p, property_name_p);
if (property_p != NULL &&
{
return ecma_fast_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
}
+#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
/* There is no need to free the name. */
return ecma_op_object_get (ecma_get_object_from_value (object), property_name_p);
}
}
- if (unlikely (ecma_is_value_undefined (object) || ecma_is_value_null (object)))
+ if (JERRY_UNLIKELY (ecma_is_value_undefined (object) || ecma_is_value_null (object)))
{
#ifdef JERRY_ENABLE_ERROR_MESSAGES
ecma_value_t error_value = ecma_raise_standard_error_with_format (ECMA_ERROR_TYPE,
ecma_value_t value, /**< ecma value */
bool is_strict) /**< strict mode */
{
- if (unlikely (!ecma_is_value_object (object)))
+ if (JERRY_UNLIKELY (!ecma_is_value_object (object)))
{
ecma_value_t to_object = ecma_op_to_object (object);
ecma_free_value (object);
return completion_value;
} /* vm_op_set_value */
+/** Compact bytecode define */
#define CBC_OPCODE(arg1, arg2, arg3, arg4) arg4,
/**
ecma_value_t
vm_run_global (const ecma_compiled_code_t *bytecode_p) /**< pointer to bytecode to run */
{
- ecma_object_t *glob_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL);
-
- ecma_value_t ret_value = vm_run (bytecode_p,
- ecma_make_object_value (glob_obj_p),
- ecma_get_global_environment (),
- false,
- NULL,
- 0);
-
- ecma_deref_object (glob_obj_p);
- return ret_value;
+ ecma_object_t *glob_obj_p = ecma_builtin_get_global ();
+
+ return vm_run (bytecode_p,
+ ecma_make_object_value (glob_obj_p),
+ ecma_get_global_environment (),
+ false,
+ NULL,
+ 0);
} /* vm_run_global */
/**
*/
ecma_value_t
vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */
- bool is_direct) /**< is eval called in direct mode? */
+ uint32_t parse_opts) /**< ecma_parse_opts_t option bits */
{
ecma_value_t this_binding;
ecma_object_t *lex_env_p;
/* ECMA-262 v5, 10.4.2 */
- if (is_direct)
+ if (parse_opts & ECMA_PARSE_DIRECT_EVAL)
{
this_binding = ecma_copy_value (JERRY_CONTEXT (vm_top_context_p)->this_binding);
lex_env_p = JERRY_CONTEXT (vm_top_context_p)->lex_env_p;
+
+#ifdef JERRY_DEBUGGER
+ uint32_t chain_index = parse_opts >> ECMA_PARSE_CHAIN_INDEX_SHIFT;
+
+ while (chain_index != 0)
+ {
+ lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
+
+ if (JERRY_UNLIKELY (lex_env_p == NULL))
+ {
+ return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid scope chain index for eval"));
+ }
+
+ if ((ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND)
+ || (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE))
+ {
+ chain_index--;
+ }
+ }
+#endif
}
else
{
- this_binding = ecma_make_object_value (ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL));
+ ecma_object_t *global_obj_p = ecma_builtin_get_global ();
+ ecma_ref_object (global_obj_p);
+ this_binding = ecma_make_object_value (global_obj_p);
lex_env_p = ecma_get_global_environment ();
}
ecma_value_t completion_value = vm_run (bytecode_data_p,
this_binding,
lex_env_p,
- true,
+ parse_opts,
NULL,
0);
vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
ecma_value_t lit_value) /**< literal */
{
-#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)))
+#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
+ if (JERRY_LIKELY (!(frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)))
{
+#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */
bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t,
lit_value);
+#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
}
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)
- {
- ecma_object_t *func_obj_p;
-
-#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
- if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION))
- {
- func_obj_p = ecma_op_create_function_object (frame_ctx_p->lex_env_p,
- bytecode_p);
- }
- else
- {
- func_obj_p = ecma_op_create_arrow_function_object (frame_ctx_p->lex_env_p,
- bytecode_p,
- frame_ctx_p->this_binding);
- }
-#else /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
- func_obj_p = ecma_op_create_function_object (frame_ctx_p->lex_env_p,
- bytecode_p);
-#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
-
- return ecma_make_object_value (func_obj_p);
- }
- else
- {
#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
+ if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION))
+ {
ecma_value_t ret_value;
ret_value = ecma_op_create_regexp_object_from_bytecode ((re_compiled_code_t *) bytecode_p);
}
return ret_value;
-#else /* CONFIG_DISABLE_REGEXP_BUILTIN */
- JERRY_UNREACHABLE (); /* Regular Expressions are not supported in the selected profile! */
+ }
#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */
+
+ JERRY_ASSERT (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION);
+
+ ecma_object_t *func_obj_p;
+
+#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
+ if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION))
+ {
+#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
+ func_obj_p = ecma_op_create_function_object (frame_ctx_p->lex_env_p,
+ bytecode_p);
+#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
}
+ else
+ {
+ func_obj_p = ecma_op_create_arrow_function_object (frame_ctx_p->lex_env_p,
+ bytecode_p,
+ frame_ctx_p->this_binding);
+ }
+#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
+
+ return ecma_make_object_value (func_obj_p);
} /* vm_construct_literal_object */
/**
* @return true - if the implicit 'this' value is updated,
* false - otherwise
*/
-static inline bool __attr_always_inline___
+static inline bool JERRY_ATTR_ALWAYS_INLINE
vm_get_implicit_this_value (ecma_value_t *this_value_p) /**< [in,out] this value */
{
if (ecma_is_value_object (*this_value_p))
return false;
} /* vm_get_implicit_this_value */
+/**
+ * Special bytecode sequence for error handling while the vm_loop
+ * is preserved for an execute operation
+ */
+static const uint8_t vm_error_byte_code_p[] =
+{
+ CBC_EXT_OPCODE, CBC_EXT_ERROR
+};
+
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+/**
+ * 'super(...)' function call handler.
+ */
+static void
+vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
+{
+ JERRY_ASSERT (frame_ctx_p->call_operation == VM_EXEC_SUPER_CALL);
+ JERRY_ASSERT (frame_ctx_p->byte_code_p[0] == CBC_EXT_OPCODE);
+
+ uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 3;
+ uint8_t opcode = byte_code_p[-2];
+ uint32_t arguments_list_len = byte_code_p[-1];
+
+ ecma_value_t *stack_top_p = frame_ctx_p->stack_top_p - arguments_list_len;
+
+ ecma_value_t func_value = stack_top_p[-1];
+ ecma_value_t completion_value;
+ ecma_op_set_super_called (frame_ctx_p->lex_env_p);
+ ecma_value_t this_value = ecma_op_get_class_this_binding (frame_ctx_p->lex_env_p);
+
+ if (!ecma_is_constructor (func_value))
+ {
+ completion_value = ecma_raise_type_error ("Class extends value is not a constructor.");
+ }
+ else
+ {
+ completion_value = ecma_op_function_construct (ecma_get_object_from_value (func_value),
+ this_value,
+ stack_top_p,
+ arguments_list_len);
+
+ if (this_value != completion_value && ecma_is_value_object (completion_value))
+ {
+ ecma_op_set_class_prototype (completion_value, this_value);
+ ecma_op_set_class_this_binding (frame_ctx_p->lex_env_p, completion_value);
+ }
+ }
+
+ /* Free registers. */
+ for (uint32_t i = 0; i < arguments_list_len; i++)
+ {
+ ecma_fast_free_value (stack_top_p[i]);
+ }
+
+ if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (completion_value)))
+ {
+#ifdef JERRY_DEBUGGER
+ JERRY_CONTEXT (debugger_exception_byte_code_p) = frame_ctx_p->byte_code_p;
+#endif /* JERRY_DEBUGGER */
+ frame_ctx_p->byte_code_p = (uint8_t *) vm_error_byte_code_p;
+ }
+ else
+ {
+ frame_ctx_p->byte_code_p = byte_code_p;
+ ecma_free_value (*(--stack_top_p));
+ uint32_t opcode_data = vm_decode_table[(CBC_END + 1) + opcode];
+
+ if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
+ {
+ ecma_fast_free_value (completion_value);
+ }
+ else if (opcode_data & VM_OC_PUT_STACK)
+ {
+ *stack_top_p++ = completion_value;
+ }
+ else
+ {
+ ecma_fast_free_value (frame_ctx_p->block_result);
+ frame_ctx_p->block_result = completion_value;
+ }
+ }
+
+ frame_ctx_p->stack_top_p = stack_top_p;
+} /* vm_super_call */
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
/**
* 'Function call' opcode handler.
*
static void
opfunc_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
- uint8_t opcode = frame_ctx_p->byte_code_p[0];
+ uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 1;
+ uint8_t opcode = byte_code_p[-1];
uint32_t arguments_list_len;
if (opcode >= CBC_CALL0)
}
else
{
- arguments_list_len = frame_ctx_p->byte_code_p[1];
+ arguments_list_len = *byte_code_p++;
}
bool is_call_prop = ((opcode - CBC_CALL) % 6) >= 3;
- ecma_value_t this_value = ECMA_VALUE_UNDEFINED;
ecma_value_t *stack_top_p = frame_ctx_p->stack_top_p - arguments_list_len;
-
- if (is_call_prop)
- {
- this_value = stack_top_p[-3];
-
- if (this_value == ECMA_VALUE_REGISTER_REF)
- {
- /* Lexical environment cannot be 'this' value. */
- stack_top_p[-2] = ECMA_VALUE_UNDEFINED;
- this_value = ECMA_VALUE_UNDEFINED;
- }
- else if (vm_get_implicit_this_value (&this_value))
- {
- ecma_free_value (stack_top_p[-3]);
- stack_top_p[-3] = this_value;
- }
- }
-
+ ecma_value_t this_value = is_call_prop ? stack_top_p[-3] : ECMA_VALUE_UNDEFINED;
ecma_value_t func_value = stack_top_p[-1];
ecma_value_t completion_value;
ecma_free_value (*(--stack_top_p));
}
- ecma_free_value (stack_top_p[-1]);
- stack_top_p[-1] = completion_value;
+ if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (completion_value)))
+ {
+#ifdef JERRY_DEBUGGER
+ JERRY_CONTEXT (debugger_exception_byte_code_p) = frame_ctx_p->byte_code_p;
+#endif /* JERRY_DEBUGGER */
+ frame_ctx_p->byte_code_p = (uint8_t *) vm_error_byte_code_p;
+ }
+ else
+ {
+ frame_ctx_p->byte_code_p = byte_code_p;
+ ecma_free_value (*(--stack_top_p));
+ uint32_t opcode_data = vm_decode_table[opcode];
+
+ if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
+ {
+ ecma_fast_free_value (completion_value);
+ }
+ else if (opcode_data & VM_OC_PUT_STACK)
+ {
+ *stack_top_p++ = completion_value;
+ }
+ else
+ {
+ ecma_fast_free_value (frame_ctx_p->block_result);
+ frame_ctx_p->block_result = completion_value;
+ }
+ }
frame_ctx_p->stack_top_p = stack_top_p;
} /* opfunc_call */
static void
opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
- uint8_t opcode = frame_ctx_p->byte_code_p[0];
+ uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 1;
+ uint8_t opcode = byte_code_p[-1];
unsigned int arguments_list_len;
if (opcode >= CBC_NEW0)
}
else
{
- arguments_list_len = frame_ctx_p->byte_code_p[1];
+ arguments_list_len = *byte_code_p++;
}
ecma_value_t *stack_top_p = frame_ctx_p->stack_top_p - arguments_list_len;
ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor_value);
completion_value = ecma_op_function_construct (constructor_obj_p,
+ ECMA_VALUE_UNDEFINED,
stack_top_p,
arguments_list_len);
}
ecma_fast_free_value (stack_top_p[i]);
}
- ecma_free_value (stack_top_p[-1]);
- stack_top_p[-1] = completion_value;
+ if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (completion_value)))
+ {
+#ifdef JERRY_DEBUGGER
+ JERRY_CONTEXT (debugger_exception_byte_code_p) = frame_ctx_p->byte_code_p;
+#endif /* JERRY_DEBUGGER */
+ frame_ctx_p->byte_code_p = (uint8_t *) vm_error_byte_code_p;
+ }
+ else
+ {
+ ecma_free_value (stack_top_p[-1]);
+ frame_ctx_p->byte_code_p = byte_code_p;
+ stack_top_p[-1] = completion_value;
+ }
frame_ctx_p->stack_top_p = stack_top_p;
} /* opfunc_construct */
+/**
+ * Read literal index from the byte code stream into destination.
+ *
+ * @param destination destination
+ */
#define READ_LITERAL_INDEX(destination) \
do \
{ \
} \
while (0)
-/* TODO: For performance reasons, we define this as a macro.
+/**
+ * Get literal value by literal index.
+ *
+ * @param literal_index literal index
+ * @param target_value target value
+ *
+ * TODO: For performance reasons, we define this as a macro.
* When we are able to construct a function with similar speed,
- * we can remove this macro. */
+ * we can remove this macro.
+ */
#define READ_LITERAL(literal_index, target_value) \
do \
{ \
uint16_t register_end;
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);
- 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))
{
uint32_t value_index;
ecma_value_t lit_value;
- bool is_immutable_binding = false;
READ_LITERAL_INDEX (value_index);
}
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]);
}
{
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
- if (likely (!is_immutable_binding))
- {
- vm_var_decl (frame_ctx_p, name_p);
+ vm_var_decl (frame_ctx_p, name_p);
- ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p, name_p);
+ ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p, name_p);
- ecma_value_t put_value_result = ecma_op_put_value_lex_env_base (ref_base_lex_env_p,
- name_p,
- is_strict,
- lit_value);
+ ecma_value_t put_value_result = ecma_op_put_value_lex_env_base (ref_base_lex_env_p,
+ name_p,
+ is_strict,
+ lit_value);
- JERRY_ASSERT (ecma_is_value_boolean (put_value_result)
- || ecma_is_value_empty (put_value_result)
- || ECMA_IS_VALUE_ERROR (put_value_result));
+ JERRY_ASSERT (ecma_is_value_boolean (put_value_result)
+ || ecma_is_value_empty (put_value_result)
+ || ECMA_IS_VALUE_ERROR (put_value_result));
- if (ECMA_IS_VALUE_ERROR (put_value_result))
- {
- ecma_free_value (JERRY_CONTEXT (error_value));
- }
- }
- else
+ if (ECMA_IS_VALUE_ERROR (put_value_result))
{
- ecma_op_create_immutable_binding (frame_ctx_p->lex_env_p, name_p, lit_value);
+ ecma_free_value (JERRY_CONTEXT (error_value));
}
if (value_index >= register_end)
*
* @return ecma value
*/
-static ecma_value_t __attr_noinline___
+static ecma_value_t JERRY_ATTR_NOINLINE
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;
ecma_value_t left_value;
ecma_value_t right_value;
ecma_value_t result = ECMA_VALUE_EMPTY;
- ecma_value_t block_result = ECMA_VALUE_UNDEFINED;
bool is_strict = ((frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0);
/* Prepare for byte code execution. */
default:
{
JERRY_ASSERT (operands == VM_OC_GET_THIS_LITERAL);
+
right_value = left_value;
left_value = ecma_copy_value (frame_ctx_p->this_binding);
break;
branch_offset = *(byte_code_p++);
- if (unlikely (branch_offset_length != 1))
+ if (JERRY_UNLIKELY (branch_offset_length != 1))
{
branch_offset <<= 8;
branch_offset |= *(byte_code_p++);
- if (unlikely (branch_offset_length == 3))
+ if (JERRY_UNLIKELY (branch_offset_length == 3))
{
branch_offset <<= 8;
branch_offset |= *(byte_code_p++);
switch (VM_OC_GROUP_GET_INDEX (opcode_data))
{
- case VM_OC_NONE:
- {
- JERRY_ASSERT (opcode == CBC_EXT_DEBUGGER);
- continue;
- }
case VM_OC_POP:
{
JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end);
}
case VM_OC_POP_BLOCK:
{
- ecma_fast_free_value (block_result);
- block_result = *(--stack_top_p);
+ ecma_fast_free_value (frame_ctx_p->block_result);
+ frame_ctx_p->block_result = *(--stack_top_p);
continue;
}
case VM_OC_PUSH:
*stack_top_p++ = ecma_copy_value (frame_ctx_p->this_binding);
continue;
}
- case VM_OC_PUSH_NUMBER_0:
+ case VM_OC_PUSH_0:
{
*stack_top_p++ = ecma_make_integer_value (0);
continue;
}
- case VM_OC_PUSH_NUMBER_POS_BYTE:
+ case VM_OC_PUSH_POS_BYTE:
{
ecma_integer_value_t number = *byte_code_p++;
*stack_top_p++ = ecma_make_integer_value (number + 1);
continue;
}
- case VM_OC_PUSH_NUMBER_NEG_BYTE:
+ case VM_OC_PUSH_NEG_BYTE:
{
ecma_integer_value_t number = *byte_code_p++;
*stack_top_p++ = ecma_make_integer_value (-(number + 1));
continue;
}
+ case VM_OC_PUSH_LIT_0:
+ {
+ stack_top_p[0] = left_value;
+ stack_top_p[1] = ecma_make_integer_value (0);
+ stack_top_p += 2;
+ continue;
+ }
+ case VM_OC_PUSH_LIT_POS_BYTE:
+ {
+ ecma_integer_value_t number = *byte_code_p++;
+ stack_top_p[0] = left_value;
+ stack_top_p[1] = ecma_make_integer_value (number + 1);
+ stack_top_p += 2;
+ continue;
+ }
+ case VM_OC_PUSH_LIT_NEG_BYTE:
+ {
+ ecma_integer_value_t number = *byte_code_p++;
+ stack_top_p[0] = left_value;
+ stack_top_p[1] = ecma_make_integer_value (-(number + 1));
+ stack_top_p += 2;
+ continue;
+ }
case VM_OC_PUSH_OBJECT:
{
- ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
- ecma_object_t *obj_p = ecma_create_object (prototype_p,
+ ecma_object_t *obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE),
0,
ECMA_OBJECT_TYPE_GENERAL);
- ecma_deref_object (prototype_p);
*stack_top_p++ = ecma_make_object_value (obj_p);
continue;
}
+ case VM_OC_PUSH_NAMED_FUNC_EXPR:
+ {
+ ecma_object_t *func_p = ecma_get_object_from_value (left_value);
+
+ JERRY_ASSERT (ecma_get_object_type (func_p) == ECMA_OBJECT_TYPE_FUNCTION);
+
+ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_p;
+
+ JERRY_ASSERT (frame_ctx_p->lex_env_p == ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
+ ext_func_p->u.function.scope_cp));
+
+ ecma_object_t *name_lex_env = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p);
+
+ ecma_op_create_immutable_binding (name_lex_env, ecma_get_string_from_value (right_value), left_value);
+
+ ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.scope_cp, name_lex_env);
+
+ ecma_free_value (right_value);
+ ecma_deref_object (name_lex_env);
+ *stack_top_p++ = left_value;
+ continue;
+ }
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ case VM_OC_SET_COMPUTED_PROPERTY:
+ {
+ /* Swap values. */
+ left_value ^= right_value;
+ right_value ^= left_value;
+ left_value ^= right_value;
+ /* FALLTHRU */
+ }
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
case VM_OC_SET_PROPERTY:
{
- ecma_object_t *object_p = ecma_get_object_from_value (stack_top_p[-1]);
- ecma_string_t *prop_name_p;
- ecma_property_t *property_p;
+ JERRY_STATIC_ASSERT (VM_OC_NON_STATIC_FLAG == VM_OC_BACKWARD_BRANCH,
+ vm_oc_non_static_flag_must_be_equal_to_vm_oc_backward_branch);
- if (ecma_is_value_string (right_value))
- {
- prop_name_p = ecma_get_string_from_value (right_value);
- }
- else
+ JERRY_ASSERT ((opcode_data >> VM_OC_NON_STATIC_SHIFT) <= 0x1);
+
+ result = right_value;
+
+ if (JERRY_UNLIKELY (!ecma_is_value_string (right_value)))
{
result = ecma_op_to_string (right_value);
{
goto error;
}
+ }
+
+ ecma_string_t *prop_name_p = ecma_get_string_from_value (result);
+
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (JERRY_UNLIKELY (ecma_compare_ecma_string_to_magic_id (prop_name_p, LIT_MAGIC_STRING_PROTOTYPE))
+ && !(opcode_data & VM_OC_NON_STATIC_FLAG))
+ {
+ if (!ecma_is_value_string (right_value))
+ {
+ ecma_deref_ecma_string (prop_name_p);
+ }
- prop_name_p = ecma_get_string_from_value (result);
+ result = ecma_raise_type_error (ECMA_ERR_MSG ("prototype property of a class is non-configurable"));
+ goto error;
}
- property_p = ecma_find_named_property (object_p, prop_name_p);
+ const int index = (int) (opcode_data >> VM_OC_NON_STATIC_SHIFT) - 2;
+#else /* CONFIG_DISABLE_ES2015_CLASS */
+ const int index = -1;
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
+ ecma_object_t *object_p = ecma_get_object_from_value (stack_top_p[index]);
+ ecma_property_t *property_p = ecma_find_named_property (object_p, prop_name_p);
if (property_p != NULL
&& ECMA_PROPERTY_GET_TYPE (*property_p) != ECMA_PROPERTY_TYPE_NAMEDDATA)
case VM_OC_SET_GETTER:
case VM_OC_SET_SETTER:
{
+ JERRY_ASSERT ((opcode_data >> VM_OC_NON_STATIC_SHIFT) <= 0x1);
+
+ result = left_value;
+
+ if (JERRY_UNLIKELY (!ecma_is_value_string (left_value)))
+ {
+ result = ecma_op_to_string (left_value);
+
+ if (ECMA_IS_VALUE_ERROR (result))
+ {
+ goto error;
+ }
+ }
+
+ ecma_string_t *prop_name_p = ecma_get_string_from_value (result);
+
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ if (JERRY_UNLIKELY (ecma_compare_ecma_string_to_magic_id (prop_name_p, LIT_MAGIC_STRING_PROTOTYPE))
+ && !(opcode_data & VM_OC_NON_STATIC_FLAG))
+ {
+ if (!ecma_is_value_string (left_value))
+ {
+ ecma_deref_ecma_string (prop_name_p);
+ }
+
+ result = ecma_raise_type_error (ECMA_ERR_MSG ("prototype property of a class is non-configurable"));
+ goto error;
+ }
+
+ const int index = (int) (opcode_data >> VM_OC_NON_STATIC_SHIFT) - 2;
+#else /* CONFIG_DISABLE_ES2015_CLASS */
+ const int index = -1;
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+
opfunc_set_accessor (VM_OC_GROUP_GET_INDEX (opcode_data) == VM_OC_SET_GETTER,
- stack_top_p[-1],
- left_value,
+ stack_top_p[index],
+ prop_name_p,
right_value);
+ if (!ecma_is_value_string (left_value))
+ {
+ ecma_deref_ecma_string (prop_name_p);
+ }
+
goto free_both_values;
}
case VM_OC_PUSH_ARRAY:
*stack_top_p++ = result;
continue;
}
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ case VM_OC_SUPER_CALL:
+ {
+ frame_ctx_p->call_operation = VM_EXEC_SUPER_CALL;
+ frame_ctx_p->byte_code_p = byte_code_start_p;
+ frame_ctx_p->stack_top_p = stack_top_p;
+ return ECMA_VALUE_UNDEFINED;
+ }
+ case VM_OC_CLASS_HERITAGE:
+ {
+ ecma_value_t super_value = *(--stack_top_p);
+ ecma_object_t *super_class_p;
+ branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p);
+
+ JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p);
+
+ if (ecma_is_value_null (super_value))
+ {
+ super_class_p = ecma_create_object (NULL, 0, ECMA_OBJECT_TYPE_GENERAL);
+ }
+ else
+ {
+ result = ecma_op_to_object (super_value);
+ ecma_free_value (super_value);
+
+ if (ECMA_IS_VALUE_ERROR (result) || !ecma_is_constructor (result))
+ {
+ if (ECMA_IS_VALUE_ERROR (result))
+ {
+ ecma_free_value (JERRY_CONTEXT (error_value));
+ }
+
+ ecma_free_value (result);
+
+ result = ecma_raise_type_error ("Value provided by class extends is not an object or null.");
+ goto error;
+ }
+ else
+ {
+ super_class_p = ecma_get_object_from_value (result);
+ }
+ }
+
+ ecma_object_t *super_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p,
+ super_class_p,
+ ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
+
+ ecma_deref_object (super_class_p);
+
+ VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION);
+ stack_top_p += PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION;
+
+ stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_SUPER_CLASS, branch_offset);
+
+ frame_ctx_p->lex_env_p = super_env_p;
+
+ continue;
+ }
+ case VM_OC_CLASS_INHERITANCE:
+ {
+ ecma_value_t child_value = stack_top_p[-2];
+ ecma_value_t child_prototype_value = stack_top_p[-1];
+
+ ecma_object_t *child_class_p = ecma_get_object_from_value (child_value);
+ ecma_object_t *child_prototype_class_p = ecma_get_object_from_value (child_prototype_value);
+ ecma_property_value_t *prop_value_p;
+
+ prop_value_p = ecma_create_named_data_property (child_prototype_class_p,
+ ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR),
+ ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
+ NULL);
+
+ ecma_named_data_property_assign_value (child_prototype_class_p, prop_value_p, child_value);
+
+ ecma_object_t *super_class_p = ecma_get_lex_env_binding_object (frame_ctx_p->lex_env_p);
+
+ if (ecma_get_object_prototype (super_class_p))
+ {
+ ecma_value_t super_prototype_value = ecma_op_object_get_by_magic_id (super_class_p,
+ LIT_MAGIC_STRING_PROTOTYPE);
+ if (ecma_get_object_type (super_class_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION
+ && !ecma_is_value_object (super_prototype_value))
+ {
+ ecma_free_value (super_prototype_value);
+ result = ecma_raise_type_error (ECMA_ERR_MSG ("Class extends value does not have valid "
+ "prototype property."));
+ goto error;
+ }
+ if (!(ECMA_IS_VALUE_ERROR (super_prototype_value) || !ecma_is_value_object (super_prototype_value)))
+ {
+ ecma_object_t *super_prototype_class_p = ecma_get_object_from_value (super_prototype_value);
+
+ ECMA_SET_POINTER (child_prototype_class_p->prototype_or_outer_reference_cp, super_prototype_class_p);
+ ECMA_SET_POINTER (child_class_p->prototype_or_outer_reference_cp, super_class_p);
+
+ }
+ ecma_free_value (super_prototype_value);
+ }
+
+ continue;
+ }
+ case VM_OC_PUSH_CLASS_CONSTRUCTOR:
+ {
+ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
+
+ ecma_object_t *function_obj_p = ecma_create_object (prototype_obj_p,
+ sizeof (ecma_extended_object_t),
+ ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
+
+ ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) function_obj_p;
+ ext_func_obj_p->u.external_handler_cb = ecma_op_function_implicit_constructor_handler_cb;
+
+ *stack_top_p++ = ecma_make_object_value (function_obj_p);
+
+ continue;
+ }
+ case VM_OC_SET_CLASS_CONSTRUCTOR:
+ {
+ ecma_object_t *new_constructor_obj_p = ecma_get_object_from_value (left_value);
+ ecma_object_t *current_constructor_obj_p = ecma_get_object_from_value (stack_top_p[-2]);
+
+ ecma_extended_object_t *new_ext_func_obj_p = (ecma_extended_object_t *) new_constructor_obj_p;
+ ecma_extended_object_t *current_ext_func_obj_p = (ecma_extended_object_t *) current_constructor_obj_p;
+
+ uint16_t type_flags_refs = current_constructor_obj_p->type_flags_refs;
+ const int new_type = ECMA_OBJECT_TYPE_FUNCTION - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION;
+ current_constructor_obj_p->type_flags_refs = (uint16_t) (type_flags_refs + new_type);
+
+ ecma_compiled_code_t *bytecode_p;
+ bytecode_p = (ecma_compiled_code_t *) ecma_op_function_get_compiled_code (new_ext_func_obj_p);
+ bytecode_p->status_flags |= CBC_CODE_FLAGS_CONSTRUCTOR;
+ ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_p);
+ ECMA_SET_INTERNAL_VALUE_POINTER (current_ext_func_obj_p->u.function.bytecode_cp,
+ bytecode_p);
+ ECMA_SET_INTERNAL_VALUE_POINTER (current_ext_func_obj_p->u.function.scope_cp,
+ ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_object_t,
+ new_ext_func_obj_p->u.function.scope_cp));
+ ecma_deref_object (new_constructor_obj_p);
+ continue;
+ }
+ case VM_OC_PUSH_IMPL_CONSTRUCTOR:
+ {
+ ecma_object_t *current_constructor_obj_p = ecma_get_object_from_value (stack_top_p[-2]);
+
+ uint16_t type_flags_refs = current_constructor_obj_p->type_flags_refs;
+ const int new_type = ECMA_OBJECT_TYPE_BOUND_FUNCTION - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION;
+ current_constructor_obj_p->type_flags_refs = (uint16_t) (type_flags_refs + new_type);
+
+ ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) current_constructor_obj_p;
+ ecma_object_t *super_obj_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p);
+
+ ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function,
+ super_obj_p);
+ ext_function_p->u.bound_function.args_len_or_this = ECMA_VALUE_IMPLICIT_CONSTRUCTOR;
+
+ continue;
+ }
+ case VM_OC_CLASS_EXPR_CONTEXT_END:
+ {
+ JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p - 1);
+
+ JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-2]) == VM_CONTEXT_SUPER_CLASS);
+ stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p - 1);
+
+ JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p);
+ stack_top_p++;
+ stack_top_p[-1] = *stack_top_p;
+ continue;
+ }
+ case VM_OC_CLASS_EVAL:
+ {
+ ECMA_SET_SUPER_EVAL_PARSER_OPTS (*byte_code_p++);
+ continue;
+ }
+ case VM_OC_PUSH_CONSTRUCTOR_SUPER:
+ {
+ JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE);
+
+ bool is_super_called = ecma_op_is_super_called (frame_ctx_p->lex_env_p);
+
+ if (byte_code_start_p[1] != CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP)
+ {
+ /* Calling super(...) */
+ if (is_super_called)
+ {
+ result = ecma_raise_reference_error (ECMA_ERR_MSG ("Super constructor may only be called once."));
+
+ goto error;
+ }
+ }
+ else if (!is_super_called)
+ {
+ /* Reference to super.method or super["method"] */
+ result = ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before "
+ "accessing 'super'."));
+ goto error;
+ }
+
+ /* FALLTHRU */
+ }
+ case VM_OC_PUSH_SUPER:
+ {
+ JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE);
+
+ if (byte_code_start_p[1] == CBC_EXT_PUSH_SUPER
+ || byte_code_start_p[1] == CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP)
+ {
+ ecma_object_t *super_class_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p);
+
+ ecma_value_t super_prototype = ecma_op_object_get_by_magic_id (super_class_p,
+ LIT_MAGIC_STRING_PROTOTYPE);
+
+ if (ECMA_IS_VALUE_ERROR (super_prototype))
+ {
+ result = super_prototype;
+ goto error;
+ }
+
+ *stack_top_p++ = super_prototype;
+ }
+ else
+ {
+ ecma_object_t *super_class_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p);
+ *stack_top_p++ = ecma_fast_copy_value (ecma_make_object_value (super_class_p));
+ }
+
+ continue;
+ }
+ case VM_OC_PUSH_CONSTRUCTOR_THIS:
+ {
+ if (!ecma_op_is_super_called (frame_ctx_p->lex_env_p))
+ {
+ result = ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before "
+ "accessing 'this' or returning from it."));
+ goto error;
+ }
+
+ *stack_top_p++ = ecma_copy_value (ecma_op_get_class_this_binding (frame_ctx_p->lex_env_p));
+ continue;
+ }
+ case VM_OC_SUPER_PROP_REFERENCE:
+ {
+ const int index = (byte_code_start_p[1] == CBC_EXT_SUPER_PROP_ASSIGN) ? -1 : -3;
+ ecma_free_value (stack_top_p[index]);
+ stack_top_p[index] = ecma_copy_value (frame_ctx_p->this_binding);
+ continue;
+ }
+ case VM_OC_CONSTRUCTOR_RET:
+ {
+ result = left_value;
+ left_value = ECMA_VALUE_UNDEFINED;
+
+ if (!ecma_is_value_object (result))
+ {
+ if (ecma_is_value_undefined (result))
+ {
+ if (!ecma_op_is_super_called (frame_ctx_p->lex_env_p))
+ {
+ result = ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class "
+ "before returning from derived constructor"));
+ }
+ }
+ else
+ {
+ ecma_free_value (result);
+ result = ecma_raise_type_error (ECMA_ERR_MSG ("Derived constructors may only "
+ "return object or undefined."));
+ }
+ }
+
+ goto error;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
case VM_OC_PUSH_ELISON:
{
*stack_top_p++ = ECMA_VALUE_ARRAY_HOLE;
}
continue;
}
+ case VM_OC_PROP_GET:
+ {
+ result = vm_op_get_value (left_value, right_value);
+
+ if (ECMA_IS_VALUE_ERROR (result))
+ {
+ goto error;
+ }
+
+ *stack_top_p++ = result;
+ goto free_both_values;
+ }
case VM_OC_PROP_REFERENCE:
{
/* Forms with reference requires preserving the base and offset. */
}
/* FALLTHRU */
}
- case VM_OC_PROP_GET:
case VM_OC_PROP_PRE_INCR:
case VM_OC_PROP_PRE_DECR:
case VM_OC_PROP_POST_INCR:
result = vm_op_get_value (left_value,
right_value);
- if (ECMA_IS_VALUE_ERROR (result))
- {
- if (opcode >= CBC_PUSH_PROP_REFERENCE && opcode < CBC_PRE_INCR)
- {
- left_value = ECMA_VALUE_UNDEFINED;
- right_value = ECMA_VALUE_UNDEFINED;
- }
- goto error;
- }
-
if (opcode < CBC_PRE_INCR)
{
- if (opcode >= CBC_PUSH_PROP_REFERENCE)
+ left_value = ECMA_VALUE_UNDEFINED;
+ right_value = ECMA_VALUE_UNDEFINED;
+
+ if (ECMA_IS_VALUE_ERROR (result))
{
- left_value = ECMA_VALUE_UNDEFINED;
- right_value = ECMA_VALUE_UNDEFINED;
+ goto error;
}
+
break;
}
int_increase = 1 << ECMA_DIRECT_SHIFT;
}
- if (likely (int_increase != 0))
+ if (JERRY_LIKELY (int_increase != 0))
{
/* Postfix operators require the unmodifed number value. */
if (opcode_flags & VM_OC_POST_INCR_DECR_OPERATOR_FLAG)
}
else if (opcode_data & VM_OC_PUT_BLOCK)
{
- ecma_free_value (block_result);
- block_result = result;
+ ecma_free_value (frame_ctx_p->block_result);
+ frame_ctx_p->block_result = result;
opcode_data &= (uint32_t) ~VM_OC_PUT_BLOCK;
}
}
}
else if (opcode_data & VM_OC_PUT_BLOCK)
{
- ecma_free_value (block_result);
- block_result = ecma_copy_value (result);
+ ecma_free_value (frame_ctx_p->block_result);
+ frame_ctx_p->block_result = ecma_copy_value (result);
opcode_data &= (uint32_t) ~VM_OC_PUT_BLOCK;
}
}
if (opcode == CBC_RETURN_WITH_BLOCK)
{
- left_value = block_result;
- block_result = ECMA_VALUE_UNDEFINED;
+ left_value = frame_ctx_p->block_result;
+ frame_ctx_p->block_result = ECMA_VALUE_UNDEFINED;
}
result = left_value;
}
case VM_OC_CALL:
{
- if (frame_ctx_p->call_operation == VM_NO_EXEC_OP)
- {
- frame_ctx_p->call_operation = VM_EXEC_CALL;
- frame_ctx_p->byte_code_p = byte_code_start_p;
- frame_ctx_p->stack_top_p = stack_top_p;
- frame_ctx_p->call_block_result = block_result;
- return ECMA_VALUE_UNDEFINED;
- }
-
- if (opcode < CBC_CALL0)
- {
- byte_code_p++;
- }
-
- frame_ctx_p->call_operation = VM_NO_EXEC_OP;
-
- result = *(--stack_top_p);
- block_result = frame_ctx_p->call_block_result;
-
- if (ECMA_IS_VALUE_ERROR (result))
- {
- goto error;
- }
-
- if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
- {
- ecma_fast_free_value (result);
- }
- else if (opcode_data & VM_OC_PUT_STACK)
- {
- *stack_top_p++ = result;
- }
- else
- {
- ecma_fast_free_value (block_result);
- block_result = result;
- }
- continue;
+ frame_ctx_p->call_operation = VM_EXEC_CALL;
+ frame_ctx_p->byte_code_p = byte_code_start_p;
+ frame_ctx_p->stack_top_p = stack_top_p;
+ return ECMA_VALUE_UNDEFINED;
}
case VM_OC_NEW:
{
- if (frame_ctx_p->call_operation == VM_NO_EXEC_OP)
- {
- frame_ctx_p->call_operation = VM_EXEC_CONSTRUCT;
- frame_ctx_p->byte_code_p = byte_code_start_p;
- frame_ctx_p->stack_top_p = stack_top_p;
- frame_ctx_p->call_block_result = block_result;
- return ECMA_VALUE_UNDEFINED;
- }
+ frame_ctx_p->call_operation = VM_EXEC_CONSTRUCT;
+ frame_ctx_p->byte_code_p = byte_code_start_p;
+ frame_ctx_p->stack_top_p = stack_top_p;
+ return ECMA_VALUE_UNDEFINED;
+ }
+ case VM_OC_ERROR:
+ {
+ JERRY_ASSERT (frame_ctx_p->byte_code_p[1] == CBC_EXT_ERROR);
+#ifdef JERRY_DEBUGGER
+ frame_ctx_p->byte_code_p = JERRY_CONTEXT (debugger_exception_byte_code_p);
+#endif /* JERRY_DEBUGGER */
+
+ result = ECMA_VALUE_ERROR;
+ goto error;
+ }
+ case VM_OC_RESOLVE_BASE_FOR_CALL:
+ {
+ ecma_value_t this_value = stack_top_p[-3];
- if (opcode < CBC_NEW0)
+ if (this_value == ECMA_VALUE_REGISTER_REF)
{
- byte_code_p++;
+ /* Lexical environment cannot be 'this' value. */
+ stack_top_p[-2] = ECMA_VALUE_UNDEFINED;
+ stack_top_p[-3] = ECMA_VALUE_UNDEFINED;
}
-
- frame_ctx_p->call_operation = VM_NO_EXEC_OP;
-
- result = *(--stack_top_p);
- block_result = frame_ctx_p->call_block_result;
-
- if (ECMA_IS_VALUE_ERROR (result))
+ else if (vm_get_implicit_this_value (&this_value))
{
- goto error;
+ ecma_free_value (stack_top_p[-3]);
+ stack_top_p[-3] = this_value;
}
- *stack_top_p++ = result;
continue;
}
case VM_OC_PROP_DELETE:
}
case VM_OC_NOT:
{
- result = opfunc_logical_not (left_value);
-
- if (ECMA_IS_VALUE_ERROR (result))
- {
- goto error;
- }
-
- *stack_top_p++ = result;
+ *stack_top_p++ = ecma_make_boolean_value (!ecma_op_to_boolean (left_value));
+ JERRY_ASSERT (ecma_is_value_boolean (stack_top_p[-1]));
goto free_left_value;
}
case VM_OC_BIT_NOT:
{
branch_offset = *(byte_code_p++);
- if (unlikely (branch_offset_length != 1))
+ if (JERRY_UNLIKELY (branch_offset_length != 1))
{
branch_offset <<= 8;
branch_offset |= *(byte_code_p++);
- if (unlikely (branch_offset_length == 3))
+ if (JERRY_UNLIKELY (branch_offset_length == 3))
{
branch_offset <<= 8;
branch_offset |= *(byte_code_p++);
with_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p,
object_p,
- true);
-
+ ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
ecma_deref_object (object_p);
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_WITH_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_WITH_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_WITH, branch_offset);
- stack_top_p[-2] = ecma_make_object_value (frame_ctx_p->lex_env_p);
frame_ctx_p->lex_env_p = with_env_p;
continue;
uint32_t index = context_top_p[-3];
- JERRY_ASSERT (!ecma_is_value_collection_chunk (chunk_p->items[index]));
+ JERRY_ASSERT (!ecma_is_value_pointer (chunk_p->items[index]));
*stack_top_p++ = chunk_p->items[index];
index++;
- if (likely (!ecma_is_value_collection_chunk (chunk_p->items[index])))
+ if (JERRY_LIKELY (!ecma_is_value_pointer (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_collection_chunk_t *next_chunk_p;
+ next_chunk_p = (ecma_collection_chunk_t *) ecma_get_pointer_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));
ecma_string_t *prop_name_p = ecma_get_string_from_value (chunk_p->items[index]);
- if (likely (ecma_op_object_has_property (object_p, prop_name_p)))
+ if (JERRY_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 (likely (!ecma_is_value_collection_chunk (value)))
+ if (JERRY_LIKELY (!ecma_is_value_pointer (value)))
{
stack_top_p[-3] = index;
}
index = 0;
stack_top_p[-3] = 0;
- ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (value);
+ ecma_collection_chunk_t *next_chunk_p;
+ next_chunk_p = (ecma_collection_chunk_t *) ecma_get_pointer_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));
if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH)
{
- ecma_deref_object (frame_ctx_p->lex_env_p);
- frame_ctx_p->lex_env_p = ecma_get_object_from_value (stack_top_p[-2]);
+ ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
+ frame_ctx_p->lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
+ ecma_deref_object (lex_env_p);
}
stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_FINALLY_JUMP, branch_offset);
JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p);
continue;
}
+#ifdef JERRY_DEBUGGER
case VM_OC_BREAKPOINT_ENABLED:
{
-#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE)
{
continue;
result = ECMA_VALUE_ERROR;
goto error;
}
-#endif /* JERRY_DEBUGGER */
continue;
}
case VM_OC_BREAKPOINT_DISABLED:
{
-#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE)
{
continue;
goto error;
}
}
-#endif /* JERRY_DEBUGGER */
continue;
}
+#endif /* JERRY_DEBUGGER */
#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 (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_header_p))
{
if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
#endif /* JERRY_ENABLE_LINE_INFO */
default:
{
+ JERRY_ASSERT (VM_OC_GROUP_GET_INDEX (opcode_data) == VM_OC_NONE);
+
+ jerry_fatal (ERR_DISABLED_BYTE_CODE);
JERRY_UNREACHABLE ();
- continue;
}
}
}
else if (opcode_data & VM_OC_PUT_BLOCK)
{
- ecma_fast_free_value (block_result);
- block_result = result;
+ ecma_fast_free_value (frame_ctx_p->block_result);
+ frame_ctx_p->block_result = result;
}
free_both_values:
| 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)
+ && !(frame_ctx_p->bytecode_header_p->status_flags
+ & (CBC_CODE_FLAGS_DEBUGGER_IGNORE | CBC_CODE_FLAGS_STATIC_FUNCTION))
&& !(JERRY_CONTEXT (debugger_flags) & dont_stop))
{
/* Save the error to a local value, because the engine enters breakpoint mode after,
{
/* In most cases there is no context. */
- ecma_fast_free_value (block_result);
+ ecma_fast_free_value (frame_ctx_p->block_result);
+ frame_ctx_p->call_operation = VM_NO_EXEC_OP;
return result;
}
}
ecma_object_t *catch_env_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p);
+#ifdef JERRY_DEBUGGER
+ catch_env_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_NON_CLOSURE;
+#endif /* JERRY_DEBUGGER */
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);
frame_ctx_p->lex_env_p = catch_env_p;
}
else
while (frame_ctx_p->context_depth > 0);
}
- ecma_free_value (block_result);
+ ecma_free_value (frame_ctx_p->block_result);
+ frame_ctx_p->call_operation = VM_NO_EXEC_OP;
+
return result;
}
} /* vm_loop */
*
* @return ecma value
*/
-static ecma_value_t __attr_noinline___
+static ecma_value_t JERRY_ATTR_NOINLINE
vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
const ecma_value_t *arg_p, /**< arguments list */
ecma_length_t arg_list_len) /**< length of arguments list */
{
completion_value = vm_loop (frame_ctx_p);
- if (frame_ctx_p->call_operation == VM_NO_EXEC_OP)
- {
- break;
- }
-
- if (frame_ctx_p->call_operation == VM_EXEC_CALL)
- {
- opfunc_call (frame_ctx_p);
- }
- else
+ switch (frame_ctx_p->call_operation)
{
- JERRY_ASSERT (frame_ctx_p->call_operation == VM_EXEC_CONSTRUCT);
- opfunc_construct (frame_ctx_p);
- }
- }
+ case VM_EXEC_CALL:
+ {
+ opfunc_call (frame_ctx_p);
+ break;
+ }
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ case VM_EXEC_SUPER_CALL:
+ {
+ vm_super_call (frame_ctx_p);
+ break;
+ }
+#endif /* !CONFIG_DISABLE_ES2015_CLASS */
+ case VM_EXEC_CONSTRUCT:
+ {
+ opfunc_construct (frame_ctx_p);
+ break;
+ }
+ default:
+ {
+ JERRY_ASSERT (frame_ctx_p->call_operation == VM_NO_EXEC_OP);
- /* Free arguments and registers */
- for (uint32_t i = 0; i < register_end; i++)
- {
- ecma_fast_free_value (frame_ctx_p->registers_p[i]);
- }
+ /* Free arguments and registers */
+ for (uint32_t i = 0; i < register_end; i++)
+ {
+ ecma_fast_free_value (frame_ctx_p->registers_p[i]);
+ }
#ifdef JERRY_DEBUGGER
- if (JERRY_CONTEXT (debugger_stop_context) == JERRY_CONTEXT (vm_top_context_p))
- {
- /* The engine will stop when the next breakpoint is reached. */
- JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_STOP);
- JERRY_CONTEXT (debugger_stop_context) = NULL;
- }
+ if (JERRY_CONTEXT (debugger_stop_context) == JERRY_CONTEXT (vm_top_context_p))
+ {
+ /* The engine will stop when the next breakpoint is reached. */
+ JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_STOP);
+ JERRY_CONTEXT (debugger_stop_context) = NULL;
+ }
#endif /* JERRY_DEBUGGER */
- JERRY_CONTEXT (vm_top_context_p) = frame_ctx_p->prev_context_p;
- return completion_value;
+ JERRY_CONTEXT (vm_top_context_p) = frame_ctx_p->prev_context_p;
+ return completion_value;
+ }
+ }
+ }
} /* vm_execute */
/**
vm_run (const ecma_compiled_code_t *bytecode_header_p, /**< byte-code data header */
ecma_value_t this_binding_value, /**< value of 'ThisBinding' */
ecma_object_t *lex_env_p, /**< lexical environment to use */
- bool is_eval_code, /**< is the code is eval code (ECMA-262 v5, 10.1) */
+ uint32_t parse_opts, /**< ecma_parse_opts_t option bits */
const ecma_value_t *arg_list_p, /**< arguments list */
ecma_length_t arg_list_len) /**< length of arguments list */
{
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;
+ frame_ctx.block_result = ECMA_VALUE_UNDEFINED;
#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;
+ frame_ctx.is_eval_code = parse_opts & ECMA_PARSE_DIRECT_EVAL;
/* Use JERRY_MAX() to avoid array declaration with size 0. */
- ecma_value_t stack[JERRY_MAX (call_stack_size, 1)];
+ JERRY_VLA (ecma_value_t, stack, JERRY_MAX (call_stack_size, 1));
frame_ctx.registers_p = stack;
return vm_execute (&frame_ctx, arg_list_p, arg_list_len);
*/
/**
- * Branch argument is a backward branch
+ * If VM_OC_GET_ARGS_INDEX(opcode) == VM_OC_GET_BRANCH,
+ * this flag signals that the branch is a backward branch.
*/
#define VM_OC_BACKWARD_BRANCH 0x4000
*/
typedef enum
{
- VM_OC_NONE, /**< do nothing */
VM_OC_POP, /**< pop from stack */
VM_OC_POP_BLOCK, /**< pop block */
- VM_OC_PUSH, /**< push one element */
- VM_OC_PUSH_TWO, /**< push two elements onto the stack */
- VM_OC_PUSH_THREE, /**< push three elements onto the stack */
+ VM_OC_PUSH, /**< push one literal */
+ VM_OC_PUSH_TWO, /**< push two literals */
+ VM_OC_PUSH_THREE, /**< push three literals */
VM_OC_PUSH_UNDEFINED, /**< push undefined value */
VM_OC_PUSH_TRUE, /**< push true value */
VM_OC_PUSH_FALSE, /**< push false value */
VM_OC_PUSH_NULL, /**< push null value */
VM_OC_PUSH_THIS, /**< push this */
- VM_OC_PUSH_NUMBER_0, /**< push number zero */
- VM_OC_PUSH_NUMBER_POS_BYTE, /**< push number between 1 and 256 */
- VM_OC_PUSH_NUMBER_NEG_BYTE, /**< push number between -1 and -256 */
+ VM_OC_PUSH_0, /**< push number zero */
+ VM_OC_PUSH_POS_BYTE, /**< push number between 1 and 256 */
+ VM_OC_PUSH_NEG_BYTE, /**< push number between -1 and -256 */
+ VM_OC_PUSH_LIT_0, /**< push literal and number zero */
+ VM_OC_PUSH_LIT_POS_BYTE, /**< push literal and number between 1 and 256 */
+ VM_OC_PUSH_LIT_NEG_BYTE, /**< push literal and number between -1 and -256 */
VM_OC_PUSH_OBJECT, /**< push object */
+ VM_OC_PUSH_NAMED_FUNC_EXPR, /**< push named function expression */
VM_OC_SET_PROPERTY, /**< set property */
+#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ VM_OC_SET_COMPUTED_PROPERTY, /**< set computed property */
+#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
VM_OC_SET_GETTER, /**< set getter */
VM_OC_SET_SETTER, /**< set setter */
VM_OC_PUSH_UNDEFINED_BASE, /**< push undefined base */
VM_OC_EVAL, /**< eval */
VM_OC_CALL, /**< call */
VM_OC_NEW, /**< new */
+ VM_OC_RESOLVE_BASE_FOR_CALL, /**< resolve base value before call */
+ VM_OC_ERROR, /**< error while the vm_loop is suspended */
VM_OC_JUMP, /**< jump */
VM_OC_BRANCH_IF_STRICT_EQUAL, /**< branch if stric equal */
VM_OC_FINALLY, /**< finally */
VM_OC_CONTEXT_END, /**< context end */
VM_OC_JUMP_AND_EXIT_CONTEXT, /**< jump and exit context */
+#ifndef CONFIG_DISABLE_ES2015_CLASS
+ VM_OC_CLASS_HERITAGE, /**< create a super class context */
+ VM_OC_CLASS_INHERITANCE, /**< inherit properties from the 'super' class */
+ VM_OC_PUSH_CLASS_CONSTRUCTOR, /**< push class constructor */
+ VM_OC_SET_CLASS_CONSTRUCTOR, /**< set class constructor to the given function literal */
+ VM_OC_PUSH_IMPL_CONSTRUCTOR, /**< create implicit class constructor */
+ VM_OC_CLASS_EXPR_CONTEXT_END, /**< class expression heritage context end */
+ VM_OC_CLASS_EVAL, /**< eval inside a class */
+ VM_OC_SUPER_CALL, /**< call the 'super' constructor */
+ VM_OC_SUPER_PROP_REFERENCE, /**< resolve super property reference */
+ VM_OC_PUSH_SUPER, /**< push resolvable super reference */
+ VM_OC_PUSH_CONSTRUCTOR_SUPER, /**< push 'super' inside a class constructor */
+ VM_OC_PUSH_CONSTRUCTOR_THIS, /**< push 'this' inside a class constructor */
+ VM_OC_CONSTRUCTOR_RET, /**< explicit return from a class constructor */
+#endif /* !CONFIG_DISABLE_ES2015 */
+#ifdef JERRY_DEBUGGER
VM_OC_BREAKPOINT_ENABLED, /**< enabled breakpoint for debugger */
VM_OC_BREAKPOINT_DISABLED, /**< disabled breakpoint for debugger */
+#endif /* JERRY_DEBUGGER */
+#ifdef JERRY_ENABLE_LINE_INFO
VM_OC_RESOURCE_NAME, /**< resource name of the current function */
VM_OC_LINE, /**< line number of the next statement */
+#endif /* JERRY_ENABLE_LINE_INFO */
+ VM_OC_NONE, /**< a special opcode for unsupported byte codes */
} vm_oc_types;
+/**
+ * Unused opcodes, but required by byte-code types.
+ */
+typedef enum
+{
+#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
+ VM_OC_SET_COMPUTED_PROPERTY = VM_OC_NONE, /**< set computed property is unused */
+#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
+#ifndef JERRY_DEBUGGER
+ VM_OC_BREAKPOINT_ENABLED = VM_OC_NONE, /**< enabled breakpoint for debugger is unused */
+ VM_OC_BREAKPOINT_DISABLED = VM_OC_NONE, /**< disabled breakpoint for debugger is unused */
+#endif /* !JERRY_DEBUGGER */
+#ifndef JERRY_ENABLE_LINE_INFO
+ VM_OC_RESOURCE_NAME = VM_OC_NONE, /**< resource name of the current function is unused */
+ VM_OC_LINE = VM_OC_NONE, /**< line number of the next statement is unused */
+#endif /* !JERRY_ENABLE_LINE_INFO */
+#ifdef CONFIG_DISABLE_ES2015_CLASS
+ VM_OC_CLASS_HERITAGE = VM_OC_NONE, /**< create a super class context */
+ VM_OC_CLASS_INHERITANCE = VM_OC_NONE, /**< inherit properties from the 'super' class */
+ VM_OC_PUSH_CLASS_CONSTRUCTOR = VM_OC_NONE, /**< push class constructor */
+ VM_OC_SET_CLASS_CONSTRUCTOR = VM_OC_NONE, /**< set class constructor to the given function literal */
+ VM_OC_PUSH_IMPL_CONSTRUCTOR = VM_OC_NONE, /**< create implicit class constructor */
+ VM_OC_CLASS_EXPR_CONTEXT_END = VM_OC_NONE, /**< class expression heritage context end */
+ VM_OC_CLASS_EVAL = VM_OC_NONE, /**< eval inside a class */
+ VM_OC_SUPER_CALL = VM_OC_NONE, /**< call the 'super' constructor */
+ VM_OC_SUPER_PROP_REFERENCE = VM_OC_NONE, /**< resolve super property reference */
+ VM_OC_PUSH_SUPER = VM_OC_NONE, /**< push resolvable super reference */
+ VM_OC_PUSH_CONSTRUCTOR_SUPER = VM_OC_NONE, /**< push 'super' inside a class constructor */
+ VM_OC_PUSH_CONSTRUCTOR_THIS = VM_OC_NONE, /**< push 'this' inside a class constructor */
+ VM_OC_CONSTRUCTOR_RET = VM_OC_NONE, /**< explicit return from a class constructor */
+#endif /* CONFIG_DISABLE_ES2015 */
+ VM_OC_UNUSED = VM_OC_NONE /**< placeholder if the list is empty */
+} vm_oc_unused_types;
+
/**
* Decrement operator.
*/
*/
#define VM_OC_LOGICAL_BRANCH_FLAG 0x2
+/**
+ * Bit index shift for non-static property initializers.
+ */
+#define VM_OC_NON_STATIC_SHIFT 14
+
+/**
+ * This flag is set for static property initializers.
+ */
+#define VM_OC_NON_STATIC_FLAG (0x1 << VM_OC_NON_STATIC_SHIFT)
+
/**
* Position of "put result" opcode.
*/
{
VM_NO_EXEC_OP, /**< do nothing */
VM_EXEC_CALL, /**< invoke a function */
+ VM_EXEC_SUPER_CALL, /**< invoke a function through 'super' keyword */
VM_EXEC_CONSTRUCT, /**< construct a new object */
} vm_call_operation;
ecma_value_t vm_run_global (const ecma_compiled_code_t *bytecode_p);
-ecma_value_t vm_run_eval (ecma_compiled_code_t *bytecode_data_p, bool is_direct);
+ecma_value_t vm_run_eval (ecma_compiled_code_t *bytecode_data_p, uint32_t parse_opts);
ecma_value_t vm_run (const ecma_compiled_code_t *bytecode_header_p, ecma_value_t this_binding_value,
- ecma_object_t *lex_env_p, bool is_eval_code, const ecma_value_t *arg_list_p,
+ ecma_object_t *lex_env_p, uint32_t parse_opts, const ecma_value_t *arg_list_p,
ecma_length_t arg_list_len);
bool vm_is_strict_mode (void);
--- /dev/null
+# Available JerryScript debugger tools
+
+ - JerryScript console debugger client ( jerry_client.py )
+ - IoT.js Code ( https://github.com/Samsung/iotjscode )
+ - JerryScript debugger Chrome webtool ( https://github.com/jerryscript-project/jerryscript-debugger-ts )
+++ /dev/null
-#!/usr/bin/env python
-
-# 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.
-
-import argparse
-import os
-import webbrowser
-
-
-def main():
- parser = argparse.ArgumentParser(description="JerryScript debugger client in HTML")
- parser.add_argument("address", action="store", nargs="?", default="localhost:5001",
- help="specify a unique network address for connection (default: %(default)s)")
- args = parser.parse_args()
-
- webbrowser.open_new("file://%s?address=%s" % (os.path.abspath("jerry-client-ws.html"), args.address))
-
-
-if __name__ == "__main__":
- main()
+++ /dev/null
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="UTF-8">
-<title>
-JerryScript HTML (WebSocket) Debugger Client
-</title>
-<style>
-body {
- background-color: #feffd6;
- text-align: center;
-}
-
-input {
- margin-top: 10px;
- width: 650px;
-}
-
-textarea {
- width: 750px;
- margin-top: 30px;
- resize: none;
-}
-</style>
-</head>
-<body>
-<h2>JerryScript HTML (WebSocket) Debugger Client</h2>
-<div class="container">
- <div>
- <textarea readonly rows="16" id="log"></textarea>
- </div>
- <p role="alert">Getting help: type <b>help</b> in the command line below.</p>
- <div>
- <input id="command" rows="1" type="text" onkeypress="debuggerCommand(event); return true;">
- <div>
-</div>
-<script>
-// Expected JerryScript debugger protocol version
-var JERRY_DEBUGGER_VERSION = 3;
-
-// Messages sent by the server to client.
-var JERRY_DEBUGGER_CONFIGURATION = 1;
-var JERRY_DEBUGGER_PARSE_ERROR = 2;
-var JERRY_DEBUGGER_BYTE_CODE_CP = 3;
-var JERRY_DEBUGGER_PARSE_FUNCTION = 4;
-var JERRY_DEBUGGER_BREAKPOINT_LIST = 5;
-var JERRY_DEBUGGER_BREAKPOINT_OFFSET_LIST = 6;
-var JERRY_DEBUGGER_SOURCE_CODE = 7;
-var JERRY_DEBUGGER_SOURCE_CODE_END = 8;
-var JERRY_DEBUGGER_SOURCE_CODE_NAME = 9;
-var JERRY_DEBUGGER_SOURCE_CODE_NAME_END = 10;
-var JERRY_DEBUGGER_FUNCTION_NAME = 11;
-var JERRY_DEBUGGER_FUNCTION_NAME_END = 12;
-var JERRY_DEBUGGER_WAITING_AFTER_PARSE = 13;
-var JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 14;
-var JERRY_DEBUGGER_MEMSTATS_RECEIVE = 15;
-var JERRY_DEBUGGER_BREAKPOINT_HIT = 16;
-var JERRY_DEBUGGER_EXCEPTION_HIT = 17;
-var JERRY_DEBUGGER_EXCEPTION_STR = 18;
-var JERRY_DEBUGGER_EXCEPTION_STR_END = 19;
-var JERRY_DEBUGGER_BACKTRACE = 20;
-var JERRY_DEBUGGER_BACKTRACE_END = 21;
-var JERRY_DEBUGGER_EVAL_RESULT = 22;
-var JERRY_DEBUGGER_EVAL_RESULT_END = 23;
-var JERRY_DEBUGGER_WAIT_FOR_SOURCE = 24;
-var JERRY_DEBUGGER_OUTPUT_RESULT = 25;
-var JERRY_DEBUGGER_OUTPUT_RESULT_END = 26;
-
-// Subtypes of eval
-JERRY_DEBUGGER_EVAL_EVAL = "\0"
-JERRY_DEBUGGER_EVAL_THROW = "\1"
-JERRY_DEBUGGER_EVAL_ABORT = "\2"
-
-// Subtypes of eval result
-var JERRY_DEBUGGER_EVAL_OK = 1;
-var JERRY_DEBUGGER_EVAL_ERROR = 2;
-
-// Subtypes of output result
-var JERRY_DEBUGGER_OUTPUT_OK = 1;
-var JERRY_DEBUGGER_OUTPUT_ERROR = 2;
-var JERRY_DEBUGGER_OUTPUT_WARNING = 3;
-var JERRY_DEBUGGER_OUTPUT_DEBUG = 4;
-var JERRY_DEBUGGER_OUTPUT_TRACE = 5;
-
-// Messages sent by the client to server.
-var JERRY_DEBUGGER_FREE_BYTE_CODE_CP = 1;
-var JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2;
-var JERRY_DEBUGGER_EXCEPTION_CONFIG = 3;
-var JERRY_DEBUGGER_PARSER_CONFIG = 4;
-var JERRY_DEBUGGER_MEMSTATS = 5;
-var JERRY_DEBUGGER_STOP = 6;
-var JERRY_DEBUGGER_PARSER_RESUME = 7;
-var JERRY_DEBUGGER_CLIENT_SOURCE = 8;
-var JERRY_DEBUGGER_CLIENT_SOURCE_PART = 9;
-var JERRY_DEBUGGER_NO_MORE_SOURCES = 10;
-var JERRY_DEBUGGER_CONTEXT_RESET = 11;
-var JERRY_DEBUGGER_CONTINUE = 12;
-var JERRY_DEBUGGER_STEP = 13;
-var JERRY_DEBUGGER_NEXT = 14;
-var JERRY_DEBUGGER_FINISH = 15;
-var JERRY_DEBUGGER_GET_BACKTRACE = 16;
-var JERRY_DEBUGGER_EVAL = 17;
-var JERRY_DEBUGGER_EVAL_PART = 18;
-
-var textBox = document.getElementById("log");
-var commandBox = document.getElementById("command");
-var socket = null;
-
-var address = "localhost";
-var params = window.location.search.slice(1).split("&");
-for (var i = 0; i < params.length; i++)
-{
- var nv = params[i].split("=");
- var name = nv[0], value = nv[1];
- if (name == "address")
- {
- address = value;
- }
-}
-
-textBox.value = ""
-commandBox.value = "connect " + address
-
-function appendLog(str)
-{
- textBox.value += str + "\n";
- textBox.scrollTop = textBox.scrollHeight;
-}
-
-var debuggerObj = null;
-
-function DebuggerClient(address)
-{
- appendLog("ws://" + address + "/jerry-debugger");
-
- var parseObj = null;
- var maxMessageSize = 0;
- var cpointerSize = 0;
- var littleEndian = true;
- var functions = { };
- var lineList = new Multimap();
- var lastBreakpointHit = null;
- var activeBreakpoints = { };
- var nextBreakpointIndex = 1;
- var pendingBreakpoints = [ ];
- var backtraceFrame = 0;
- var evalResult = null;
- var outputResult = null;
- var exceptionData = null;
- var display = 0;
- var version = 0;
-
- function assert(expr)
- {
- if (!expr)
- {
- throw new Error("Assertion failed.");
- }
- }
-
- function setUint32(array, offset, value)
- {
- if (littleEndian)
- {
- array[offset] = value & 0xff;
- array[offset + 1] = (value >> 8) & 0xff;
- array[offset + 2] = (value >> 16) & 0xff;
- array[offset + 3] = (value >> 24) & 0xff;
- }
- else
- {
- array[offset] = (value >> 24) & 0xff;
- array[offset + 1] = (value >> 16) & 0xff;
- array[offset + 2] = (value >> 8) & 0xff;
- array[offset + 3] = value & 0xff;
- }
- }
-
- /* Concat the two arrays. The first byte (opcode) of nextArray is ignored. */
- function concatUint8Arrays(baseArray, nextArray)
- {
- if (nextArray.byteLength <= 1)
- {
- /* Nothing to append. */
- return baseArray;
- }
-
- if (!baseArray)
- {
- /* Cut the first byte (opcode). */
- return nextArray.slice(1);
- }
-
- var baseLength = baseArray.byteLength;
- var nextLength = nextArray.byteLength - 1;
-
- var result = new Uint8Array(baseLength + nextLength);
- result.set(nextArray, baseLength - 1);
-
- /* This set operation overwrites the opcode. */
- result.set(baseArray);
-
- return result;
- }
-
- function cesu8ToString(array)
- {
- if (!array)
- {
- return "";
- }
-
- var length = array.byteLength;
-
- var i = 0;
- var result = "";
-
- while (i < length)
- {
- var chr = array[i];
-
- ++i;
-
- if (chr >= 0x7f)
- {
- if (chr & 0x20)
- {
- /* Three byte long character. */
- chr = ((chr & 0xf) << 12) | ((array[i] & 0x3f) << 6) | (array[i + 1] & 0x3f);
- i += 2;
- }
- else
- {
- /* Two byte long character. */
- chr = ((chr & 0x1f) << 6) | (array[i] & 0x3f);
- ++i;
- }
- }
-
- result += String.fromCharCode(chr);
- }
-
- return result;
- }
-
- function stringToCesu8(string)
- {
- assert(string != "");
-
- var length = string.length;
- var byteLength = length;
-
- for (var i = 0; i < length; i++)
- {
- var chr = string.charCodeAt(i);
-
- if (chr > 0x7ff)
- {
- byteLength++;
- }
-
- if (chr >= 0x7f)
- {
- byteLength++;
- }
- }
-
- var result = new Uint8Array(byteLength + 1 + 4);
-
- result[0] = JERRY_DEBUGGER_EVAL;
-
- setUint32(result, 1, byteLength);
-
- var offset = 5;
-
- for (var i = 0; i < length; i++)
- {
- var chr = string.charCodeAt(i);
-
- if (chr > 0x7ff)
- {
- result[offset] = 0xe0 | (chr >> 12);
- result[offset + 1] = 0x80 | ((chr >> 6) & 0x3f);
- result[offset + 2] = 0x80 | (chr & 0x3f);
- offset += 3;
- }
- else if (chr >= 0x7f)
- {
- result[offset] = 0xc0 | (chr >> 6);
- result[offset + 1] = 0x80 | (chr & 0x3f);
- }
- else
- {
- result[offset] = chr;
- offset++;
- }
- }
-
- return result;
- }
-
- function breakpointToString(breakpoint)
- {
- var name = breakpoint.func.name;
-
- var result = breakpoint.func.sourceName;
-
- if (!result)
- {
- result = "<unknown>";
- }
-
- result += ":" + breakpoint.line;
-
- if (breakpoint.func.is_func)
- {
- result += " (in "
- + (breakpoint.func.name ? breakpoint.func.name : "function")
- + "() at line:"
- + breakpoint.func.line
- + ", col:"
- + breakpoint.func.column
- + ")";
- }
-
- return result;
- }
-
- function Multimap()
- {
- /* Each item is an array of items. */
-
- var map = { };
-
- this.get = function(key)
- {
- var item = map[key];
- return item ? item : [ ];
- }
-
- this.insert = function(key, value)
- {
- var item = map[key];
-
- if (item)
- {
- item.push(value);
- return;
- }
-
- map[key] = [ value ];
- }
-
- this.delete = function(key, value)
- {
- var array = map[key];
-
- assert(array);
-
- var newLength = array.length - 1;
- var i = array.indexOf(value);
-
- assert(i != -1);
-
- array.splice(i, 1);
- array.length = newLength;
- }
- }
-
- var socket = new WebSocket("ws://" + address + "/jerry-debugger");
- socket.binaryType = 'arraybuffer';
-
- function abortConnection(message)
- {
- assert(socket && debuggerObj);
-
- socket.close();
- socket = null;
- debuggerObj = null;
-
- appendLog("Abort connection: " + message);
- throw new Error(message);
- }
-
- socket.onerror = function(event)
- {
- if (socket)
- {
- socket = null;
- debuggerObj = null;
- appendLog("Connection closed.");
- }
- }
- socket.onclose = socket.onerror;
-
- socket.onopen = function(event)
- {
- appendLog("Connection created.");
- }
-
- function getFormatSize(format)
- {
- var length = 0;
-
- for (var i = 0; i < format.length; i++)
- {
- if (format[i] == "B")
- {
- length++;
- continue;
- }
-
- if (format[i] == "C")
- {
- length += cpointerSize;
- continue;
- }
-
- assert(format[i] == "I")
-
- length += 4;
- }
-
- return length;
- }
-
- function decodeMessage(format, message, offset)
- {
- /* Format: B=byte I=int32 C=cpointer.
- * Returns an array of decoded numbers. */
-
- var result = []
- var value;
-
- if (!offset)
- {
- offset = 0;
- }
-
- if (offset + getFormatSize(format) > message.byteLength)
- {
- abortConnection("received message too short.");
- }
-
- for (var i = 0; i < format.length; i++)
- {
- if (format[i] == "B")
- {
- result.push(message[offset])
- offset++;
- continue;
- }
-
- if (format[i] == "C" && cpointerSize == 2)
- {
- if (littleEndian)
- {
- value = message[offset] | (message[offset + 1] << 8);
- }
- else
- {
- value = (message[offset] << 8) | message[offset + 1];
- }
-
- result.push(value);
- offset += 2;
- continue;
- }
-
- assert(format[i] == "I" || (format[i] == "C" && cpointerSize == 4));
-
- if (littleEndian)
- {
- value = (message[offset] | (message[offset + 1] << 8)
- | (message[offset + 2] << 16) | (message[offset + 3] << 24));
- }
- else
- {
- value = ((message[offset] << 24) | (message[offset + 1] << 16)
- | (message[offset + 2] << 8) | message[offset + 3] << 24);
- }
-
- result.push(value);
- offset += 4;
- }
-
- return result;
- }
-
- function encodeMessage(format, values)
- {
- /* Format: B=byte I=int32 C=cpointer.
- * Sends a message after the encoding is completed. */
-
- var length = getFormatSize(format);
- var message = new Uint8Array(length);
- var offset = 0;
-
- for (var i = 0; i < format.length; i++)
- {
- var value = values[i];
-
- if (format[i] == "B")
- {
- message[offset] = value;
- offset++;
- continue;
- }
-
- if (format[i] == "C" && cpointerSize == 2)
- {
- if (littleEndian)
- {
- message[offset] = value & 0xff;
- message[offset + 1] = (value >> 8) & 0xff;
- }
- else
- {
- message[offset] = (value >> 8) & 0xff;
- message[offset + 1] = value & 0xff;
- }
-
- offset += 2;
- continue;
- }
-
- setUint32(message, offset, value);
- offset += 4;
- }
-
- socket.send(message);
- }
-
- function releaseFunction(message)
- {
- var byte_code_cp = decodeMessage("C", message, 1)[0];
- var func = functions[byte_code_cp];
-
- for (var i in func.lines)
- {
- lineList.delete(i, func);
-
- var breakpoint = func.lines[i];
-
- assert(i == breakpoint.line);
-
- if (breakpoint.activeIndex >= 0)
- {
- delete activeBreakpoints[breakpoint.activeIndex];
- }
- }
-
- delete functions[byte_code_cp];
-
- message[0] = JERRY_DEBUGGER_FREE_BYTE_CODE_CP;
- socket.send(message);
- }
-
- function getBreakpoint(breakpointData)
- {
- var returnValue = {};
- var func = functions[breakpointData[0]];
- var offset = breakpointData[1];
-
- if (offset in func.offsets)
- {
- returnValue.breakpoint = func.offsets[offset];
- returnValue.at = true;
- return returnValue;
- }
-
- if (offset < func.firstBreakpointOffset)
- {
- returnValue.breakpoint = func.offsets[func.firstBreakpointOffset];
- returnValue.at = true;
- return returnValue;
- }
-
- nearest_offset = -1;
-
- for (var current_offset in func.offsets)
- {
- if ((current_offset <= offset) && (current_offset > nearest_offset))
- {
- nearest_offset = current_offset;
- }
- }
-
- returnValue.breakpoint = func.offsets[nearest_offset];
- returnValue.at = false;
- return returnValue;
- }
-
- this.encodeMessage = encodeMessage;
-
- function ParseSource()
- {
- var source = "";
- var sourceData = null;
- var sourceName = "";
- var sourceNameData = null;
- var functionName = null;
- var stack = [{ is_func: false,
- line: 1,
- column: 1,
- name: "",
- source: "",
- lines: [],
- offsets: [] }];
- var newFunctions = { };
-
- this.receive = function(message)
- {
- switch (message[0])
- {
- case JERRY_DEBUGGER_PARSE_ERROR:
- {
- /* Parse error occured in JerryScript. */
- parseObj = null;
- return;
- }
-
- case JERRY_DEBUGGER_SOURCE_CODE:
- case JERRY_DEBUGGER_SOURCE_CODE_END:
- {
- sourceData = concatUint8Arrays(sourceData, message);
-
- if (message[0] == JERRY_DEBUGGER_SOURCE_CODE_END)
- {
- source = cesu8ToString(sourceData);
- }
- return;
- }
-
- case JERRY_DEBUGGER_SOURCE_CODE_NAME:
- case JERRY_DEBUGGER_SOURCE_CODE_NAME_END:
- {
- sourceNameData = concatUint8Arrays(sourceNameData, message);
-
- if (message[0] == JERRY_DEBUGGER_SOURCE_CODE_NAME_END)
- {
- sourceName = cesu8ToString(sourceNameData);
- }
- return;
- }
-
- case JERRY_DEBUGGER_FUNCTION_NAME:
- case JERRY_DEBUGGER_FUNCTION_NAME_END:
- {
- functionName = concatUint8Arrays(functionName, message);
- return;
- }
-
- case JERRY_DEBUGGER_PARSE_FUNCTION:
- {
- position = decodeMessage("II", message, 1);
-
- stack.push({ is_func: true,
- line: position[0],
- column: position[1],
- name: cesu8ToString(functionName),
- source: source,
- sourceName: sourceName,
- lines: [],
- offsets: [] });
- functionName = null;
- return;
- }
-
- case JERRY_DEBUGGER_BREAKPOINT_LIST:
- case JERRY_DEBUGGER_BREAKPOINT_OFFSET_LIST:
- {
- var array;
-
- if (message.byteLength < 1 + 4)
- {
- abortConnection("message too short.");
- }
-
- if (message[0] == JERRY_DEBUGGER_BREAKPOINT_LIST)
- {
- array = stack[stack.length - 1].lines;
- }
- else
- {
- array = stack[stack.length - 1].offsets;
- }
-
- for (var i = 1; i < message.byteLength; i += 4)
- {
- array.push(decodeMessage("I", message, i)[0]);
- }
- return;
- }
-
- case JERRY_DEBUGGER_BYTE_CODE_CP:
- {
- var func = stack.pop();
- func.byte_code_cp = decodeMessage("C", message, 1)[0];
-
- lines = {}
- offsets = {}
-
- func.firstBreakpointLine = func.lines[0];
- func.firstBreakpointOffset = func.offsets[0];
-
- for (var i = 0; i < func.lines.length; i++)
- {
- var breakpoint = { line: func.lines[i], offset: func.offsets[i], func: func, activeIndex: -1 };
-
- lines[breakpoint.line] = breakpoint;
- offsets[breakpoint.offset] = breakpoint;
- }
-
- func.lines = lines;
- func.offsets = offsets;
-
- newFunctions[func.byte_code_cp] = func;
-
- if (stack.length > 0)
- {
- return;
- }
-
- func.source = source.split(/\r\n|[\r\n]/);
- func.sourceName = sourceName;
- break;
- }
-
- case JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP:
- {
- var byte_code_cp = decodeMessage("C", message, 1)[0];
-
- if (byte_code_cp in newFunctions)
- {
- delete newFunctions[byte_code_cp];
- }
- else
- {
- releaseFunction(message);
- }
- return;
- }
-
- default:
- {
- abortConnection("unexpected message.");
- return;
- }
- }
-
- for (var i in newFunctions)
- {
- var func = newFunctions[i];
-
- functions[i] = func;
-
- for (var j in func.lines)
- {
- lineList.insert(j, func);
- }
- }
-
- if (pendingBreakpoints.length != 0)
- {
- appendLog("Available pending breakpoints");
-
- for (var i in pendingBreakpoints)
- {
- if (Number.isInteger(pendingBreakpoints[i]))
- {
- pendingBreakpoints[i] = sourceName + ":" + pendingBreakpoints[i];
- }
- appendLog("Try to add: " + pendingBreakpoints[i]);
- debuggerObj.setBreakpoint(pendingBreakpoints[i], false);
- }
- }
- else
- {
- appendLog("No pending breakpoints");
- }
-
- parseObj = null;
- }
- }
-
- socket.onmessage = function(event)
- {
- var message = new Uint8Array(event.data);
-
- if (message.byteLength < 1)
- {
- abortConnection("message too short.");
- }
-
- if (cpointerSize == 0)
- {
- if (message[0] != JERRY_DEBUGGER_CONFIGURATION
- || message.byteLength != 5)
- {
- abortConnection("the first message must be configuration.");
- }
-
- maxMessageSize = message[1]
- cpointerSize = message[2]
- littleEndian = (message[3] != 0);
-
- version = message[4];
-
- if (cpointerSize != 2 && cpointerSize != 4)
- {
- abortConnection("compressed pointer must be 2 or 4 byte long.");
- }
-
- if (version != JERRY_DEBUGGER_VERSION)
- {
- abortConnection("incorrect target debugger version detected: "
- + version + " expected: " + JERRY_DEBUGGER_VERSION);
- }
-
- config = false;
- return;
- }
-
- if (parseObj)
- {
- parseObj.receive(message)
- return;
- }
-
- switch (message[0])
- {
- case JERRY_DEBUGGER_PARSE_ERROR:
- case JERRY_DEBUGGER_BYTE_CODE_CP:
- case JERRY_DEBUGGER_PARSE_FUNCTION:
- case JERRY_DEBUGGER_BREAKPOINT_LIST:
- case JERRY_DEBUGGER_SOURCE_CODE:
- case JERRY_DEBUGGER_SOURCE_CODE_END:
- case JERRY_DEBUGGER_SOURCE_CODE_NAME:
- case JERRY_DEBUGGER_SOURCE_CODE_NAME_END:
- case JERRY_DEBUGGER_FUNCTION_NAME:
- case JERRY_DEBUGGER_FUNCTION_NAME_END:
- {
- parseObj = new ParseSource()
- parseObj.receive(message)
- return;
- }
-
- case JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP:
- {
- releaseFunction(message);
- return;
- }
-
- case JERRY_DEBUGGER_MEMSTATS_RECEIVE:
- {
- var messagedata = decodeMessage("IIIII", message, 1);
-
- appendLog("Allocated bytes: " + messagedata[0]);
- appendLog("Byte code bytes: " + messagedata[1]);
- appendLog("String bytes: " + messagedata[2]);
- appendLog("Object bytes: " + messagedata[3]);
- appendLog("Property bytes: " + messagedata[4]);
- return;
- }
-
- case JERRY_DEBUGGER_BREAKPOINT_HIT:
- case JERRY_DEBUGGER_EXCEPTION_HIT:
- {
- var breakpointData = decodeMessage("CI", message, 1);
- var breakpointRef = getBreakpoint(breakpointData);
- var breakpoint = breakpointRef.breakpoint;
-
- if (message[0] == JERRY_DEBUGGER_EXCEPTION_HIT)
- {
- appendLog("Exception throw detected (to disable automatic stop type exception 0)");
- if (exceptionData)
- {
- appendLog("Exception hint: " + cesu8ToString(exceptionData));
- exceptionData = null;
- }
- }
-
- lastBreakpointHit = breakpoint;
-
- var breakpointInfo = "";
- if (breakpoint.offset.activeIndex >= 0)
- {
- breakpointInfo = " breakpoint:" + breakpoint.offset.activeIndex + " ";
- }
-
- appendLog("Stopped "
- + (breakpoint.at ? "at " : "around ")
- + breakpointInfo
- + breakpointToString(breakpoint));
-
- if (debuggerObj.display)
- {
- debuggerObj.printSource(debuggerObj.display);
- }
- return;
- }
-
- case JERRY_DEBUGGER_EXCEPTION_STR:
- case JERRY_DEBUGGER_EXCEPTION_STR_END:
- {
- exceptionData = concatUint8Arrays(exceptionData, message);
- return;
- }
-
- case JERRY_DEBUGGER_BACKTRACE:
- case JERRY_DEBUGGER_BACKTRACE_END:
- {
- for (var i = 1; i < message.byteLength; i += cpointerSize + 4)
- {
- var breakpointData = decodeMessage("CI", message, i);
-
- breakpoint = getBreakpoint(breakpointData).breakpoint;
-
- appendLog(" frame "
- + backtraceFrame
- + ": "
- + breakpointToString(breakpoint));
-
- ++backtraceFrame;
- }
-
- if (message[0] == JERRY_DEBUGGER_BACKTRACE_END)
- {
- backtraceFrame = 0;
- }
- return;
- }
-
- case JERRY_DEBUGGER_EVAL_RESULT:
- case JERRY_DEBUGGER_EVAL_RESULT_END:
- {
- evalResult = concatUint8Arrays(evalResult, message);
- var subType = evalResult[evalResult.length - 1];
- evalResult = evalResult.slice(0, -1);
- if (subType == JERRY_DEBUGGER_EVAL_OK)
- {
- appendLog(cesu8ToString(evalResult));
- evalResult = null;
- return;
- }
-
- if (subType == JERRY_DEBUGGER_EVAL_ERROR)
- {
- appendLog("Uncaught exception: " + cesu8ToString(evalResult));
- evalResult = null;
- return;
- }
-
- return;
- }
- case JERRY_DEBUGGER_OUTPUT_RESULT:
- case JERRY_DEBUGGER_OUTPUT_RESULT_END:
- {
- outputResult = concatUint8Arrays(outputResult, message);
-
- if (message[0] == JERRY_DEBUGGER_OUTPUT_RESULT_END)
- {
- var subType = outputResult[outputResult.length - 1];
- var outString;
- outputResult = outputResult.slice(0, -1);
-
- switch (subType)
- {
- case JERRY_DEBUGGER_OUTPUT_OK:
- case JERRY_DEBUGGER_OUTPUT_DEBUG:
- outString = "out: " + cesu8ToString(outputResult);
- break;
- case JERRY_DEBUGGER_OUTPUT_WARNING:
- outString = "warning: " + cesu8ToString(outputResult);
- break;
- case JERRY_DEBUGGER_OUTPUT_ERROR:
- outString = "err: " + cesu8ToString(outputResult);
- break;
- case JERRY_DEBUGGER_OUTPUT_TRACE:
- outString = "trace: " + cesu8ToString(outputResult);
- break;
- }
-
- appendLog(outString);
- outputResult = null;
- }
-
- return;
- }
-
- case JERRY_DEBUGGER_WAIT_FOR_SOURCE:
- {
- // This message does not have effect in this client.
- return;
- }
-
- default:
- {
- abortConnection("unexpected message.");
- return;
- }
- }
- }
-
- function insertBreakpoint(breakpoint)
- {
- if (breakpoint.activeIndex < 0)
- {
- breakpoint.activeIndex = nextBreakpointIndex;
- activeBreakpoints[nextBreakpointIndex] = breakpoint;
- nextBreakpointIndex++;
-
- var values = [ JERRY_DEBUGGER_UPDATE_BREAKPOINT,
- 1,
- breakpoint.func.byte_code_cp,
- breakpoint.offset ];
-
- encodeMessage("BBCI", values);
- }
-
- appendLog("Breakpoint " + breakpoint.activeIndex + " at " + breakpointToString(breakpoint));
- }
-
- this.setBreakpoint = function(str, pending)
- {
- line = /^(.+):([1-9][0-9]*)$/.exec(str);
- var found = false;
-
- if (line)
- {
- var functionList = lineList.get(line[2]);
-
- for (var i = 0; i < functionList.length; ++i)
- {
- var func = functionList[i];
- var sourceName = func.sourceName;
-
- if (sourceName == line[1]
- || sourceName.endsWith("/" + line[1])
- || sourceName.endsWith("\\" + line[1]))
- {
- insertBreakpoint(func.lines[line[2]]);
- found = true;
- }
- }
- }
- else
- {
- for (var i in functions)
- {
- var func = functions[i];
-
- if (func.name == str)
- {
- insertBreakpoint(func.lines[func.firstBreakpointLine]);
- found = true;
- }
- }
- }
- if (!found)
- {
- appendLog("Breakpoint not found");
- if (pending)
- {
- if (line)
- {
- pendingBreakpoints.push(Number(line[2]));
- appendLog("Pending breakpoint index: " + line[0] + " added");
- }
- else
- {
- pendingBreakpoints.push(str);
- appendLog("Pending breakpoint function name: " + str + " added");
- }
- }
- }
- }
-
- this.sendExceptionConfig = function(enable)
- {
- if (enable == "")
- {
- appendLog("Argument required");
- return;
- }
-
- if (enable == 1)
- {
- appendLog("Stop at exception enabled");
- }
- else if (enable == 0)
- {
- appendLog("Stop at exception disabled");
- }
- else
- {
- appendLog("Invalid input. Usage 1: [Enable] or 0: [Disable].");
- return;
- }
-
- encodeMessage("BB", [ JERRY_DEBUGGER_EXCEPTION_CONFIG, enable ]);
- }
-
- this.deleteBreakpoint = function(index)
- {
- breakpoint = activeBreakpoints[index];
-
- if (index == "all")
- {
- var found = false;
-
- for (var i in activeBreakpoints)
- {
- delete activeBreakpoints[i];
- found = true;
- }
-
- if (!found)
- {
- appendLog("No active breakpoints.")
- }
- }
-
- else if (!breakpoint)
- {
- appendLog("No breakpoint found with index " + index);
- return;
- }
-
- assert(breakpoint.activeIndex == index);
-
- delete activeBreakpoints[index];
- breakpoint.activeIndex = -1;
-
- var values = [ JERRY_DEBUGGER_UPDATE_BREAKPOINT,
- 0,
- breakpoint.func.byte_code_cp,
- breakpoint.offset ];
-
- encodeMessage("BBCI", values);
-
- appendLog("Breakpoint " + index + " is deleted.");
- }
-
- this.deletePendingBreakpoint = function(index)
- {
- if (index >= pendingBreakpoints.length)
- {
- appendLog("Pending breakpoint not found");
- }
- else
- {
- pendingBreakpoints.splice(index, 1);
- appendLog("Pending breakpoint " + index + " is deleted.");
- }
- }
-
- this.listBreakpoints = function()
- {
- appendLog("List of active breakpoints:");
- var found = false;
-
- for (var i in activeBreakpoints)
- {
- appendLog(" breakpoint " + i + " at " + breakpointToString(activeBreakpoints[i]));
- found = true;
- }
-
- if (!found)
- {
- appendLog(" no active breakpoints");
- }
-
- if (pendingBreakpoints.length != 0)
- {
- appendLog("List of pending breakpoints:");
- for (var i in pendingBreakpoints)
- {
- appendLog(" pending breakpoint " + i + " at " + pendingBreakpoints[i]);
- }
- }
- else {
- appendLog("No pending breakpoints");
- }
- }
-
- this.sendResumeExec = function(command)
- {
- if (!lastBreakpointHit)
- {
- appendLog("This command is allowed only if JavaScript execution is stopped at a breakpoint.");
- return;
- }
-
- encodeMessage("B", [ command ]);
-
- lastBreakpointHit = null;
- }
-
- this.sendGetBacktrace = function(depth)
- {
- if (!lastBreakpointHit)
- {
- appendLog("This command is allowed only if JavaScript execution is stopped at a breakpoint.");
- return;
- }
-
- encodeMessage("BI", [ JERRY_DEBUGGER_GET_BACKTRACE, max_depth ]);
-
- appendLog("Backtrace:");
- }
-
- this.sendEval = function(str)
- {
- if (!lastBreakpointHit)
- {
- appendLog("This command is allowed only if JavaScript execution is stopped at a breakpoint.");
- return;
- }
-
- if (str == "")
- {
- appendLog("Argument required");
- return;
- }
-
- var array = stringToCesu8(JERRY_DEBUGGER_EVAL_EVAL + str);
- var byteLength = array.byteLength;
-
- if (byteLength <= maxMessageSize)
- {
- socket.send(array);
- return;
- }
-
- socket.send(array.slice(0, maxMessageSize));
-
- var offset = maxMessageSize - 1;
-
- while (offset < byteLength)
- {
- array[offset] = JERRY_DEBUGGER_EVAL_PART;
- socket.send(array.slice(offset, offset + maxMessageSize));
- offset += maxMessageSize - 1;
- }
- }
-
- this.printSource = function(line_num)
- {
- if (!lastBreakpointHit)
- return;
-
- lines = lastBreakpointHit.func.source;
- if (line_num === 0)
- {
- var start = 0;
- var end = lastBreakpointHit.func.source.length - 1;
- }
- else
- {
- var start = Math.max(lastBreakpointHit.line - line_num, 0)
- var end = Math.min(lastBreakpointHit.line + line_num - 1,
- lastBreakpointHit.func.source.length - 1)
- }
-
- if (lastBreakpointHit.func.sourceName)
- appendLog("Source: " + lastBreakpointHit.func.sourceName);
-
- for (i = start; i < end; i++)
- {
- var str = (i + 1).toString();
- while (str.length < 4)
- {
- str = " " + str;
- }
-
- if (i == lastBreakpointHit.line - 1)
- {
- appendLog(str + " > " + lines[i]);
- }
- else
- {
- appendLog(str + " " + lines[i]);
- }
- }
- }
-
- this.srcCheckArgs = function(line_num)
- {
- line_num = parseInt(line_num);
- if (isNaN(line_num) || line_num < 0)
- {
- appendLog("Non-negative integer number expected");
- return -1;
- }
- else
- {
- return line_num;
- }
- }
-
- this.dump = function()
- {
- for (var i in functions)
- {
- var func = functions[i];
- var sourceName = func.sourceName;
-
- if (!sourceName)
- {
- sourceName = "<unknown>";
- }
-
- appendLog("Function 0x"
- + Number(i).toString(16)
- + " '"
- + func.name
- + "' at "
- + sourceName
- + ":"
- + func.line
- + ","
- + func.column);
-
- for (var j in func.lines)
- {
- var active = "";
-
- if (func.lines[j].active >= 0)
- {
- active = " (active: " + func.lines[j].active + ")";
- }
-
- appendLog(" Breakpoint line: " + j + " at memory offset: " + func.lines[j].offset + active);
- }
- }
- }
-}
-
-function debuggerCommand(event)
-{
- if (event.keyCode != 13)
- {
- return true;
- }
-
- var command = commandBox.value.trim();
-
- args = /^([a-zA-Z]+)(?:\s+([^\s].*)|)$/.exec(command);
-
- if (!args)
- {
- appendLog("Invalid command");
- document.getElementById("command").value = "";
- return true;
- }
-
- if (!args[2])
- {
- args[2] = "";
- }
-
- if (args[1] == "help")
- {
- appendLog("Debugger commands:\n" +
- " connect <IP address:PORT> - connect to server (default is localhost:5001)\n" +
- " break|b <file_name:line>|<function_name> - set breakpoint\n" +
- " fbreak <file_name:line>|<function_name> - set breakpoint if not found, add to pending list\n" +
- " delete|d <id> - delete breakpoint\n" +
- " pendingdel <id> - delete pending breakpoint\n" +
- " list - list breakpoints\n" +
- " continue|c - continue execution\n" +
- " step|s - step-in execution\n" +
- " next|n - execution until the next breakpoint\n" +
- " finish|f - continue running until the current function returns\n" +
- " eval|e - evaluate expression\n" +
- " backtrace|bt <max-depth> - get backtrace\n" +
- " src - print current source code\n" +
- " dump - dump all breakpoint data");
-
- commandBox.value = "";
- return true;
- }
-
- if (args[1] == "connect")
- {
- if (debuggerObj)
- {
- appendLog("Debugger is connected");
- return true;
- }
-
- var ipAddr = args[2];
- var PORT = "5001";
-
- if (ipAddr == "")
- {
- ipAddr = "localhost";
- }
-
- if (ipAddr.match(/.*:\d/))
- {
- var fields = ipAddr.split(":");
- ipAddr = fields[0];
- PORT = fields[1];
- }
-
- var address = ipAddr + ":" + PORT;
-
- appendLog("Connect to: " + address);
-
- debuggerObj = new DebuggerClient(address);
-
- commandBox.value = "";
- return true;
- }
-
- if (!debuggerObj)
- {
- appendLog("Debugger is NOT connected");
-
- commandBox.value = "";
- return true;
- }
-
- switch(args[1])
- {
- case "b":
- case "break":
- debuggerObj.setBreakpoint(args[2], false);
- break;
-
- case "fbreak":
- debuggerObj.setBreakpoint(args[2], true);
- break;
-
- case "d":
- case "delete":
- debuggerObj.deleteBreakpoint(args[2]);
- break;
-
- case "pendingdel":
- debuggerObj.deletePendingBreakpoint(args[2]);
-
- case "st":
- case "stop":
- debuggerObj.encodeMessage("B", [ JERRY_DEBUGGER_STOP ]);
- break;
-
- case "ms":
- case "memstats":
- debuggerObj.encodeMessage("B", [ JERRY_DEBUGGER_MEMSTATS ]);
- break;
-
- case "c":
- case "continue":
- debuggerObj.sendResumeExec(JERRY_DEBUGGER_CONTINUE);
- break;
-
- case "s":
- case "step":
- debuggerObj.sendResumeExec(JERRY_DEBUGGER_STEP);
- break;
-
- case "n":
- case "next":
- debuggerObj.sendResumeExec(JERRY_DEBUGGER_NEXT);
- break;
-
- case "f":
- case "finish":
- debuggerObj.sendResumeExec(JERRY_DEBUGGER_FINISH);
- break;
-
- case "e":
- case "eval":
- debuggerObj.sendEval(args[2]);
- break;
-
- case "bt":
- case "backtrace":
- max_depth = 0;
-
- if (args[2])
- {
- if (/[1-9][0-9]*/.exec(args[2]))
- {
- max_depth = parseInt(args[2]);
- }
- else
- {
- appendLog("Invalid maximum depth argument.");
- break;
- }
- }
-
- debuggerObj.sendGetBacktrace(max_depth);
- break;
-
- case "exception":
- debuggerObj.sendExceptionConfig(args[2]);
- break;
-
- case "source":
- case "src":
- if (!args[2])
- {
- debuggerObj.printSource(3);
- break;
- }
- var line_num = debuggerObj.srcCheckArgs(args[2]);
- if (line_num >= 0)
- {
- debuggerObj.printSource(line_num);
- break;
- }
- break;
-
- case "display":
- if (!args[2])
- {
- appendLog("Non-negative integer number expected,\
- 0 turns off the automatic source code display");
- break;
- }
- var line_num = debuggerObj.srcCheckArgs(args[2]);
- if (line_num >= 0)
- {
- debuggerObj.display = line_num;
- break;
- }
- break;
-
- case "list":
- debuggerObj.listBreakpoints();
- break;
-
- case "dump":
- debuggerObj.dump();
- break;
-
- default:
- appendLog("Unknown command: " + args[1]);
- break;
- }
-
- commandBox.value = "";
- return true;
-}
-
-</script>
-
-</body>
-</html>
+++ /dev/null
-#!/usr/bin/env python
-
-# 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.
-
-from __future__ import print_function
-from cmd import Cmd
-from pprint import pprint # For the readable stack printing.
-import argparse
-import logging
-import re
-import select
-import socket
-import struct
-import sys
-import math
-import time
-
-# Expected debugger protocol version.
-JERRY_DEBUGGER_VERSION = 3
-
-# Messages sent by the server to client.
-JERRY_DEBUGGER_CONFIGURATION = 1
-JERRY_DEBUGGER_PARSE_ERROR = 2
-JERRY_DEBUGGER_BYTE_CODE_CP = 3
-JERRY_DEBUGGER_PARSE_FUNCTION = 4
-JERRY_DEBUGGER_BREAKPOINT_LIST = 5
-JERRY_DEBUGGER_BREAKPOINT_OFFSET_LIST = 6
-JERRY_DEBUGGER_SOURCE_CODE = 7
-JERRY_DEBUGGER_SOURCE_CODE_END = 8
-JERRY_DEBUGGER_SOURCE_CODE_NAME = 9
-JERRY_DEBUGGER_SOURCE_CODE_NAME_END = 10
-JERRY_DEBUGGER_FUNCTION_NAME = 11
-JERRY_DEBUGGER_FUNCTION_NAME_END = 12
-JERRY_DEBUGGER_WAITING_AFTER_PARSE = 13
-JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 14
-JERRY_DEBUGGER_MEMSTATS_RECEIVE = 15
-JERRY_DEBUGGER_BREAKPOINT_HIT = 16
-JERRY_DEBUGGER_EXCEPTION_HIT = 17
-JERRY_DEBUGGER_EXCEPTION_STR = 18
-JERRY_DEBUGGER_EXCEPTION_STR_END = 19
-JERRY_DEBUGGER_BACKTRACE = 20
-JERRY_DEBUGGER_BACKTRACE_END = 21
-JERRY_DEBUGGER_EVAL_RESULT = 22
-JERRY_DEBUGGER_EVAL_RESULT_END = 23
-JERRY_DEBUGGER_WAIT_FOR_SOURCE = 24
-JERRY_DEBUGGER_OUTPUT_RESULT = 25
-JERRY_DEBUGGER_OUTPUT_RESULT_END = 26
-
-# Subtypes of eval
-JERRY_DEBUGGER_EVAL_EVAL = "\0"
-JERRY_DEBUGGER_EVAL_THROW = "\1"
-JERRY_DEBUGGER_EVAL_ABORT = "\2"
-
-# Subtypes of eval result
-JERRY_DEBUGGER_EVAL_OK = 1
-JERRY_DEBUGGER_EVAL_ERROR = 2
-
-# Subtypes of output
-JERRY_DEBUGGER_OUTPUT_OK = 1
-JERRY_DEBUGGER_OUTPUT_ERROR = 2
-JERRY_DEBUGGER_OUTPUT_WARNING = 3
-JERRY_DEBUGGER_OUTPUT_DEBUG = 4
-JERRY_DEBUGGER_OUTPUT_TRACE = 5
-
-
-# Messages sent by the client to server.
-JERRY_DEBUGGER_FREE_BYTE_CODE_CP = 1
-JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2
-JERRY_DEBUGGER_EXCEPTION_CONFIG = 3
-JERRY_DEBUGGER_PARSER_CONFIG = 4
-JERRY_DEBUGGER_MEMSTATS = 5
-JERRY_DEBUGGER_STOP = 6
-JERRY_DEBUGGER_PARSER_RESUME = 7
-JERRY_DEBUGGER_CLIENT_SOURCE = 8
-JERRY_DEBUGGER_CLIENT_SOURCE_PART = 9
-JERRY_DEBUGGER_NO_MORE_SOURCES = 10
-JERRY_DEBUGGER_CONTEXT_RESET = 11
-JERRY_DEBUGGER_CONTINUE = 12
-JERRY_DEBUGGER_STEP = 13
-JERRY_DEBUGGER_NEXT = 14
-JERRY_DEBUGGER_FINISH = 15
-JERRY_DEBUGGER_GET_BACKTRACE = 16
-JERRY_DEBUGGER_EVAL = 17
-JERRY_DEBUGGER_EVAL_PART = 18
-
-MAX_BUFFER_SIZE = 128
-WEBSOCKET_BINARY_FRAME = 2
-WEBSOCKET_FIN_BIT = 0x80
-
-
-def arguments_parse():
- parser = argparse.ArgumentParser(description="JerryScript debugger client")
-
- parser.add_argument("address", action="store", nargs="?", default="localhost:5001",
- help="specify a unique network address for connection (default: %(default)s)")
- parser.add_argument("-v", "--verbose", action="store_true", default=False,
- help="increase verbosity (default: %(default)s)")
- parser.add_argument("--non-interactive", action="store_true", default=False,
- help="disable stop when newline is pressed (default: %(default)s)")
- parser.add_argument("--color", action="store_true", default=False,
- help="enable color highlighting on source commands (default: %(default)s)")
- parser.add_argument("--display", action="store", default=None, type=int,
- help="set display range")
- parser.add_argument("--exception", action="store", default=None, type=int, choices=[0, 1],
- help="set exception config, usage 1: [Enable] or 0: [Disable]")
- parser.add_argument("--client-source", action="store", default=[], type=str, nargs="+",
- help="specify a javascript source file to execute")
-
- args = parser.parse_args()
-
- if args.verbose:
- logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.DEBUG)
- logging.debug("Debug logging mode: ON")
-
- return args
-
-
-class JerryBreakpoint(object):
-
- def __init__(self, line, offset, function):
- self.line = line
- self.offset = offset
- self.function = function
- self.active_index = -1
-
- def __str__(self):
- result = self.function.source_name or "<unknown>"
- result += ":%d" % (self.line)
-
- if self.function.is_func:
- result += " (in "
- result += self.function.name or "function"
- result += "() at line:%d, col:%d)" % (self.function.line, self.function.column)
- return result
-
- def __repr__(self):
- return ("Breakpoint(line:%d, offset:%d, active_index:%d)"
- % (self.line, self.offset, self.active_index))
-
-class JerryPendingBreakpoint(object):
- def __init__(self, line=None, source_name=None, function=None):
- self.function = function
- self.line = line
- self.source_name = source_name
-
- self.index = -1
-
- def __str__(self):
- result = self.source_name or ""
- if self.line:
- result += ":%d" % (self.line)
- else:
- result += "%s()" % (self.function)
- return result
-
-
-class JerryFunction(object):
- # pylint: disable=too-many-instance-attributes,too-many-arguments
- def __init__(self, is_func, byte_code_cp, source, source_name, line, column, name, lines, offsets):
- self.is_func = is_func
- self.byte_code_cp = byte_code_cp
- self.source = re.split("\r\n|[\r\n]", source)
- self.source_name = source_name
- self.name = name
- self.lines = {}
- self.offsets = {}
- self.line = line
- self.column = column
- self.first_breakpoint_line = lines[0]
- self.first_breakpoint_offset = offsets[0]
-
- if len(self.source) > 1 and not self.source[-1]:
- self.source.pop()
-
- for i, line in enumerate(lines):
- offset = offsets[i]
- breakpoint = JerryBreakpoint(line, offset, self)
- self.lines[line] = breakpoint
- self.offsets[offset] = breakpoint
-
- def __repr__(self):
- result = ("Function(byte_code_cp:0x%x, source_name:%r, name:%r, line:%d, column:%d { "
- % (self.byte_code_cp, self.source_name, self.name, self.line, self.column))
-
- result += ','.join([str(breakpoint) for breakpoint in self.lines.values()])
-
- return result + " })"
-
-
-class DebuggerPrompt(Cmd):
-
- def __init__(self, debugger):
- Cmd.__init__(self)
- self.debugger = debugger
- self.stop = False
- self.quit = False
- self.cont = True
- self.non_interactive = False
- self.client_sources = []
-
- def precmd(self, line):
- self.stop = False
- self.cont = False
- if self.non_interactive:
- print("%s" % line)
- return line
-
- def postcmd(self, stop, line):
- return self.stop
-
- def do_quit(self, args):
- """ Exit JerryScript debugger """
- self.do_delete("all")
- self.do_exception("0") # disable the exception handler
- self._exec_command(args, JERRY_DEBUGGER_CONTINUE)
- self.stop = True
- self.quit = True
-
- def do_break(self, args):
- """ Insert breakpoints on the given lines or functions """
- if args == "":
- print("Error: Breakpoint index expected")
- elif ':' in args:
- try:
- args_second = int(args.split(':', 1)[1])
- if args_second < 0:
- print("Error: Positive breakpoint index expected")
- else:
- set_breakpoint(self.debugger, args, False)
- except ValueError as val_errno:
- print("Error: Positive breakpoint index expected: %s" % val_errno)
- else:
- set_breakpoint(self.debugger, args, False)
-
- do_b = do_break
-
- def _exec_command(self, args, command_id):
- self.stop = True
- if args != "":
- print("Error: No argument expected")
- else:
- self.debugger.send_command(command_id)
-
- def do_continue(self, args):
- """ Continue execution """
- self._exec_command(args, JERRY_DEBUGGER_CONTINUE)
- self.stop = True
- self.cont = True
- if not self.non_interactive:
- print("Press enter to stop JavaScript execution.")
-
- do_c = do_continue
-
- def do_step(self, args):
- """ Next breakpoint, step into functions """
- self._exec_command(args, JERRY_DEBUGGER_STEP)
- self.cont = True
-
- do_s = do_step
-
- def do_next(self, args):
- """ Next breakpoint in the same context """
- if not args:
- args = 0
- else:
- try:
- args = int(args)
- if args <= 0:
- raise ValueError(args)
- except ValueError as val_errno:
- print("Error: expected a positive integer: %s" % val_errno)
- return
-
- args = min(args, len(self.debugger.last_breakpoint_hit.function.lines) -
- self.debugger.last_breakpoint_hit.function.line) - 1
- self.debugger.repeats_remain = args
-
- self._exec_command("", JERRY_DEBUGGER_NEXT)
- self.cont = True
-
- do_n = do_next
-
- def do_finish(self, args):
- """ Continue running until the current function returns """
- self._exec_command(args, JERRY_DEBUGGER_FINISH)
- self.cont = True
-
- do_f = do_finish
-
- def do_list(self, _):
- """ Lists the available breakpoints """
- if self.debugger.active_breakpoint_list:
- print("=== %sActive breakpoints %s ===" % (self.debugger.green_bg, self.debugger.nocolor))
- for breakpoint in self.debugger.active_breakpoint_list.values():
- print(" %d: %s" % (breakpoint.active_index, breakpoint))
-
- if self.debugger.pending_breakpoint_list:
- print("=== %sPending breakpoints%s ===" % (self.debugger.yellow_bg, self.debugger.nocolor))
- for breakpoint in self.debugger.pending_breakpoint_list.values():
- print(" %d: %s (pending)" % (breakpoint.index, breakpoint))
-
- if not self.debugger.active_breakpoint_list and not self.debugger.pending_breakpoint_list:
- print("No breakpoints")
-
- def do_delete(self, args):
- """ Delete the given breakpoint, use 'delete all|active|pending' to clear all the given breakpoints """
- if not args:
- print("Error: Breakpoint index expected")
- return
- elif args == "all":
- self.debugger.delete_active()
- self.debugger.delete_pending()
- elif args == "pending":
- self.debugger.delete_pending()
- elif args == "active":
- self.debugger.delete_active()
- else:
- try:
- breakpoint_index = int(args)
- except ValueError as val_errno:
- print("Error: Integer number expected, %s" % (val_errno))
- return
-
- if breakpoint_index in self.debugger.active_breakpoint_list:
- breakpoint = self.debugger.active_breakpoint_list[breakpoint_index]
- del self.debugger.active_breakpoint_list[breakpoint_index]
- breakpoint.active_index = -1
- self.debugger.send_breakpoint(breakpoint)
- elif breakpoint_index in self.debugger.pending_breakpoint_list:
- del self.debugger.pending_breakpoint_list[breakpoint_index]
- if not self.debugger.pending_breakpoint_list:
- self.debugger.send_parser_config(0)
- else:
- print("Error: Breakpoint %d not found" % (breakpoint_index))
-
- def do_backtrace(self, args):
- """ Get backtrace data from debugger """
- max_depth = 0
-
- if args:
- try:
- max_depth = int(args)
- if max_depth <= 0:
- print("Error: Positive integer number expected")
- return
- except ValueError as val_errno:
- print("Error: Positive integer number expected, %s" % (val_errno))
- return
-
- message = struct.pack(self.debugger.byte_order + "BBIB" + self.debugger.idx_format,
- WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
- WEBSOCKET_FIN_BIT + 1 + 4,
- 0,
- JERRY_DEBUGGER_GET_BACKTRACE,
- max_depth)
- self.debugger.send_message(message)
- self.stop = True
-
- do_bt = do_backtrace
-
- def do_src(self, args):
- """ Get current source code """
- if args:
- line_num = src_check_args(args)
- if line_num >= 0:
- print_source(self.debugger, line_num, 0)
- elif line_num == 0:
- print_source(self.debugger, self.debugger.default_viewrange, 0)
- else:
- return
-
- do_source = do_src
-
- def _scroll_direction(self, args):
- """ Helper function for do_scroll """
- self.debugger.src_offset_diff = int(max(math.floor(self.debugger.display / 3), 1))
- if args in "up":
- self.debugger.src_offset -= self.debugger.src_offset_diff
- print_source(self.debugger, self.debugger.display, self.debugger.src_offset)
- else:
- self.debugger.src_offset += self.debugger.src_offset_diff
- print_source(self.debugger, self.debugger.display, self.debugger.src_offset)
-
- def do_scroll(self, _):
- """ Scroll the source up or down """
- while True:
- key = sys.stdin.readline()
- if key == 'w\n':
- self._scroll_direction("up")
- elif key == 's\n':
- self._scroll_direction("down")
- elif key == 'q\n':
- break
- else:
- print("Invalid key")
-
- def do_display(self, args):
- """ Toggle source code display after breakpoints """
- if args:
- line_num = src_check_args(args)
- if line_num >= 0:
- self.debugger.display = line_num
- else:
- return
-
- else:
- print("Non-negative integer number expected, 0 turns off this function")
- return
-
- def do_dump(self, args):
- """ Dump all of the debugger data """
- if args:
- print("Error: No argument expected")
- return
-
- pprint(self.debugger.function_list)
-
- def _send_string(self, args, message_type):
- size = len(args)
-
- # 1: length of type byte
- # 4: length of an uint32 value
- message_header = 1 + 4
- max_fragment = min(self.debugger.max_message_size - message_header, size)
-
- message = struct.pack(self.debugger.byte_order + "BBIBI",
- WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
- WEBSOCKET_FIN_BIT + max_fragment + message_header,
- 0,
- message_type,
- size)
-
- if size == max_fragment:
- self.debugger.send_message(message + args)
- self.stop = True
- return
-
- self.debugger.send_message(message + args[0:max_fragment])
- offset = max_fragment
-
- if message_type == JERRY_DEBUGGER_EVAL:
- message_type = JERRY_DEBUGGER_EVAL_PART
- else:
- message_type = JERRY_DEBUGGER_CLIENT_SOURCE_PART
-
- # 1: length of type byte
- message_header = 1
-
- max_fragment = self.debugger.max_message_size - message_header
- while offset < size:
- next_fragment = min(max_fragment, size - offset)
-
- message = struct.pack(self.debugger.byte_order + "BBIB",
- WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
- WEBSOCKET_FIN_BIT + next_fragment + message_header,
- 0,
- message_type)
-
- prev_offset = offset
- offset += next_fragment
- self.debugger.send_message(message + args[prev_offset:offset])
-
- self.stop = True
-
- def do_eval(self, args):
- """ Evaluate JavaScript source code """
- self._send_string(JERRY_DEBUGGER_EVAL_EVAL + args, JERRY_DEBUGGER_EVAL)
-
- do_e = do_eval
-
- def do_throw(self, args):
- """ Throw an exception """
- self._send_string(JERRY_DEBUGGER_EVAL_THROW + args, JERRY_DEBUGGER_EVAL)
-
- def do_abort(self, args):
- """ Throw an exception """
- self._send_string(JERRY_DEBUGGER_EVAL_ABORT + args, JERRY_DEBUGGER_EVAL)
-
- def do_exception(self, args):
- """ Config the exception handler module """
- if not args:
- print("Error: Status expected!")
- return
-
- enable = int(args)
-
- if enable == 1:
- logging.debug("Stop at exception enabled")
- elif enable == 0:
- logging.debug("Stop at exception disabled")
- else:
- print("Error: Invalid input! Usage 1: [Enable] or 0: [Disable].")
- return
-
- self.debugger.send_exception_config(enable)
-
- def do_memstats(self, args):
- """ Memory statistics """
- self._exec_command(args, JERRY_DEBUGGER_MEMSTATS)
- return
-
- do_ms = do_memstats
-
- def store_client_sources(self, args):
- self.client_sources = args
-
- def send_client_source(self):
- # Send no more source message if there is no source
- if not self.client_sources:
- self.send_no_more_source()
- return
-
- path = self.client_sources.pop(0)
- if not path.lower().endswith('.js'):
- sys.exit("Error: Javascript file expected!")
- return
-
- with open(path, 'r') as src_file:
- content = path + "\0" + src_file.read()
- self._send_string(content, JERRY_DEBUGGER_CLIENT_SOURCE)
-
- def send_no_more_source(self):
- self._exec_command("", JERRY_DEBUGGER_NO_MORE_SOURCES)
- self.cont = True
-
-class Multimap(object):
-
- def __init__(self):
- self.map = {}
-
- def get(self, key):
- if key in self.map:
- return self.map[key]
- return []
-
- def insert(self, key, value):
- if key in self.map:
- self.map[key].append(value)
- else:
- self.map[key] = [value]
-
- def delete(self, key, value):
- items = self.map[key]
-
- if len(items) == 1:
- del self.map[key]
- else:
- del items[items.index(value)]
-
- def __repr__(self):
- return "Multimap(%r)" % (self.map)
-
-
-class JerryDebugger(object):
- # pylint: disable=too-many-instance-attributes,too-many-statements
- def __init__(self, address):
-
- if ":" not in address:
- self.host = address
- self.port = 5001 # use default port
- else:
- self.host, self.port = address.split(":")
- self.port = int(self.port)
-
- print("Connecting to: %s:%s" % (self.host, self.port))
-
- self.message_data = b""
- self.function_list = {}
- self.last_breakpoint_hit = None
- self.next_breakpoint_index = 0
- self.active_breakpoint_list = {}
- self.pending_breakpoint_list = {}
- self.line_list = Multimap()
- self.display = 0
- self.default_viewrange = 3
- self.green = ''
- self.red = ''
- self.yellow = ''
- self.green_bg = ''
- self.yellow_bg = ''
- self.blue = ''
- self.nocolor = ''
- self.src_offset = 0
- self.src_offset_diff = 0
- self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.client_socket.connect((self.host, self.port))
- self.repeats_remain = 0
-
- self.send_message(b"GET /jerry-debugger HTTP/1.1\r\n" +
- b"Upgrade: websocket\r\n" +
- b"Connection: Upgrade\r\n" +
- b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
- result = b""
- expected = (b"HTTP/1.1 101 Switching Protocols\r\n" +
- b"Upgrade: websocket\r\n" +
- b"Connection: Upgrade\r\n" +
- b"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")
-
- len_expected = len(expected)
-
- while len(result) < len_expected:
- result += self.client_socket.recv(1024)
-
- len_result = len(result)
-
- if result[0:len_expected] != expected:
- raise Exception("Unexpected handshake")
-
- if len_result > len_expected:
- result = result[len_expected:]
- else:
- result = b""
-
- len_expected = 7
- # Network configurations, which has the following struct:
- # header [2] - opcode[1], size[1]
- # type [1]
- # max_message_size [1]
- # cpointer_size [1]
- # little_endian [1]
- # version [1]
-
- while len(result) < len_expected:
- result += self.client_socket.recv(1024)
-
- len_result = len(result)
-
- expected = struct.pack("BBB",
- WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
- 5,
- JERRY_DEBUGGER_CONFIGURATION)
-
- if result[0:3] != expected:
- raise Exception("Unexpected configuration")
-
- self.max_message_size = ord(result[3])
- self.cp_size = ord(result[4])
- self.little_endian = ord(result[5])
- self.version = ord(result[6])
-
- if self.version != JERRY_DEBUGGER_VERSION:
- raise Exception("Incorrect debugger version from target: %d expected: %d" %
- (self.version, JERRY_DEBUGGER_VERSION))
-
-
- if self.little_endian:
- self.byte_order = "<"
- logging.debug("Little-endian machine")
- else:
- self.byte_order = ">"
- logging.debug("Big-endian machine")
-
- if self.cp_size == 2:
- self.cp_format = "H"
- else:
- self.cp_format = "I"
-
- self.idx_format = "I"
-
- logging.debug("Compressed pointer size: %d", self.cp_size)
-
- if len_result > len_expected:
- self.message_data = result[len_expected:]
-
- def __del__(self):
- self.client_socket.close()
-
- def send_message(self, message):
- size = len(message)
- while size > 0:
- bytes_send = self.client_socket.send(message)
- if bytes_send < size:
- message = message[bytes_send:]
- size -= bytes_send
-
- def delete_active(self):
- for i in self.active_breakpoint_list.values():
- breakpoint = self.active_breakpoint_list[i.active_index]
- del self.active_breakpoint_list[i.active_index]
- breakpoint.active_index = -1
- self.send_breakpoint(breakpoint)
-
- def delete_pending(self):
- if self.pending_breakpoint_list:
- self.pending_breakpoint_list.clear()
- self.send_parser_config(0)
-
- def breakpoint_pending_exists(self, breakpoint):
- for existing_bp in self.pending_breakpoint_list.values():
- if (breakpoint.line and existing_bp.source_name == breakpoint.source_name and \
- existing_bp.line == breakpoint.line) \
- or (not breakpoint.line and existing_bp.function == breakpoint.function):
- return True
-
- return False
-
- def send_breakpoint(self, breakpoint):
- message = struct.pack(self.byte_order + "BBIBB" + self.cp_format + self.idx_format,
- WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
- WEBSOCKET_FIN_BIT + 1 + 1 + self.cp_size + 4,
- 0,
- JERRY_DEBUGGER_UPDATE_BREAKPOINT,
- int(breakpoint.active_index >= 0),
- breakpoint.function.byte_code_cp,
- breakpoint.offset)
- self.send_message(message)
-
- def send_bytecode_cp(self, byte_code_cp):
- message = struct.pack(self.byte_order + "BBIB" + self.cp_format,
- WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
- WEBSOCKET_FIN_BIT + 1 + self.cp_size,
- 0,
- JERRY_DEBUGGER_FREE_BYTE_CODE_CP,
- byte_code_cp)
- self.send_message(message)
-
- def send_command(self, command):
- message = struct.pack(self.byte_order + "BBIB",
- WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
- WEBSOCKET_FIN_BIT + 1,
- 0,
- command)
- self.send_message(message)
-
- def send_exception_config(self, enable):
- message = struct.pack(self.byte_order + "BBIBB",
- WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
- WEBSOCKET_FIN_BIT + 1 + 1,
- 0,
- JERRY_DEBUGGER_EXCEPTION_CONFIG,
- enable)
- self.send_message(message)
-
- def send_parser_config(self, enable):
- message = struct.pack(self.byte_order + "BBIBB",
- WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
- WEBSOCKET_FIN_BIT + 1 + 1,
- 0,
- JERRY_DEBUGGER_PARSER_CONFIG,
- enable)
- self.send_message(message)
-
- def set_colors(self):
- self.nocolor = '\033[0m'
- self.green = '\033[92m'
- self.red = '\033[31m'
- self.yellow = '\033[93m'
- self.green_bg = '\033[42m\033[30m'
- self.yellow_bg = '\033[43m\033[30m'
- self.blue = '\033[94m'
-
- def get_message(self, blocking):
- # Connection was closed
- if self.message_data is None:
- return None
-
- while True:
- if len(self.message_data) >= 2:
- if ord(self.message_data[0]) != WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT:
- raise Exception("Unexpected data frame")
-
- size = ord(self.message_data[1])
- if size == 0 or size >= 126:
- raise Exception("Unexpected data frame")
-
- if len(self.message_data) >= size + 2:
- result = self.message_data[0:size + 2]
- self.message_data = self.message_data[size + 2:]
- return result
-
- if not blocking:
- select_result = select.select([self.client_socket], [], [], 0)[0]
- if self.client_socket not in select_result:
- return b''
-
- data = self.client_socket.recv(MAX_BUFFER_SIZE)
-
- if not data:
- self.message_data = None
- return None
-
- self.message_data += data
-
-
-# pylint: disable=too-many-branches,too-many-locals,too-many-statements
-def parse_source(debugger, data):
- source_code = ""
- source_code_name = ""
- function_name = ""
- stack = [{"line": 1,
- "column": 1,
- "name": "",
- "lines": [],
- "offsets": []}]
- new_function_list = {}
-
- while True:
- if data is None:
- return
-
- buffer_type = ord(data[2])
- buffer_size = ord(data[1]) - 1
-
- logging.debug("Parser buffer type: %d, message size: %d", buffer_type, buffer_size)
-
- if buffer_type == JERRY_DEBUGGER_PARSE_ERROR:
- logging.error("Parser error!")
- return
-
- elif buffer_type in [JERRY_DEBUGGER_SOURCE_CODE, JERRY_DEBUGGER_SOURCE_CODE_END]:
- source_code += data[3:]
-
- elif buffer_type in [JERRY_DEBUGGER_SOURCE_CODE_NAME, JERRY_DEBUGGER_SOURCE_CODE_NAME_END]:
- source_code_name += data[3:]
-
- elif buffer_type in [JERRY_DEBUGGER_FUNCTION_NAME, JERRY_DEBUGGER_FUNCTION_NAME_END]:
- function_name += data[3:]
-
- elif buffer_type == JERRY_DEBUGGER_PARSE_FUNCTION:
- logging.debug("Source name: %s, function name: %s", source_code_name, function_name)
-
- position = struct.unpack(debugger.byte_order + debugger.idx_format + debugger.idx_format,
- data[3: 3 + 4 + 4])
-
- stack.append({"source": source_code,
- "source_name": source_code_name,
- "line": position[0],
- "column": position[1],
- "name": function_name,
- "lines": [],
- "offsets": []})
- function_name = ""
-
- elif buffer_type in [JERRY_DEBUGGER_BREAKPOINT_LIST, JERRY_DEBUGGER_BREAKPOINT_OFFSET_LIST]:
- name = "lines"
- if buffer_type == JERRY_DEBUGGER_BREAKPOINT_OFFSET_LIST:
- name = "offsets"
-
- logging.debug("Breakpoint %s received", name)
-
- buffer_pos = 3
- while buffer_size > 0:
- line = struct.unpack(debugger.byte_order + debugger.idx_format,
- data[buffer_pos: buffer_pos + 4])
- stack[-1][name].append(line[0])
- buffer_pos += 4
- buffer_size -= 4
-
- elif buffer_type == JERRY_DEBUGGER_BYTE_CODE_CP:
- byte_code_cp = struct.unpack(debugger.byte_order + debugger.cp_format,
- data[3: 3 + debugger.cp_size])[0]
-
- logging.debug("Byte code cptr received: {0x%x}", byte_code_cp)
-
- func_desc = stack.pop()
-
- # We know the last item in the list is the general byte code.
- if len(stack) == 0:
- func_desc["source"] = source_code
- func_desc["source_name"] = source_code_name
-
- function = JerryFunction(len(stack) != 0,
- byte_code_cp,
- func_desc["source"],
- func_desc["source_name"],
- func_desc["line"],
- func_desc["column"],
- func_desc["name"],
- func_desc["lines"],
- func_desc["offsets"])
-
- new_function_list[byte_code_cp] = function
-
- if len(stack) == 0:
- logging.debug("Parse completed.")
- break
-
- elif buffer_type == JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP:
- # Redefined functions are dropped during parsing.
- byte_code_cp = struct.unpack(debugger.byte_order + debugger.cp_format,
- data[3: 3 + debugger.cp_size])[0]
-
- if byte_code_cp in new_function_list:
- del new_function_list[byte_code_cp]
- debugger.send_bytecode_cp(byte_code_cp)
- else:
- release_function(debugger, data)
-
- else:
- logging.error("Parser error!")
- return
-
- data = debugger.get_message(True)
-
- # Copy the ready list to the global storage.
- debugger.function_list.update(new_function_list)
-
- for function in new_function_list.values():
- for line, breakpoint in function.lines.items():
- debugger.line_list.insert(line, breakpoint)
-
- # Try to set the pending breakpoints
- if debugger.pending_breakpoint_list:
- logging.debug("Pending breakpoints list: %s", debugger.pending_breakpoint_list)
- bp_list = debugger.pending_breakpoint_list
-
- for breakpoint_index, breakpoint in bp_list.items():
- for src in debugger.function_list.values():
- if src.source_name == breakpoint.source_name:
- source_lines = len(src.source)
- else:
- source_lines = 0
-
- if breakpoint.line:
- if breakpoint.line <= source_lines:
- command = breakpoint.source_name + ":" + str(breakpoint.line)
- if set_breakpoint(debugger, command, True):
- del bp_list[breakpoint_index]
- elif breakpoint.function:
- command = breakpoint.function
- if set_breakpoint(debugger, command, True):
- del bp_list[breakpoint_index]
-
- if not bp_list:
- debugger.send_parser_config(0)
-
- else:
- logging.debug("No pending breakpoints")
-
-
-def src_check_args(args):
- try:
- line_num = int(args)
- if line_num < 0:
- print("Error: Non-negative integer number expected")
- return -1
-
- return line_num
- except ValueError as val_errno:
- print("Error: Non-negative integer number expected: %s" % (val_errno))
- return -1
-
-
-def print_source(debugger, line_num, offset):
- last_bp = debugger.last_breakpoint_hit
- if not last_bp:
- return
-
- lines = last_bp.function.source
- if last_bp.function.source_name:
- print("Source: %s" % (last_bp.function.source_name))
-
- if line_num == 0:
- start = 0
- end = len(last_bp.function.source)
- else:
- start = max(last_bp.line - line_num, 0)
- end = min(last_bp.line + line_num - 1, len(last_bp.function.source))
- if offset:
- if start + offset < 0:
- debugger.src_offset += debugger.src_offset_diff
- offset += debugger.src_offset_diff
- elif end + offset > len(last_bp.function.source):
- debugger.src_offset -= debugger.src_offset_diff
- offset -= debugger.src_offset_diff
-
- start = max(start + offset, 0)
- end = min(end + offset, len(last_bp.function.source))
-
- for i in range(start, end):
- if i == last_bp.line - 1:
- print("%s%4d%s %s>%s %s" % (debugger.green, i + 1, debugger.nocolor, debugger.red, \
- debugger.nocolor, lines[i]))
- else:
- print("%s%4d%s %s" % (debugger.green, i + 1, debugger.nocolor, lines[i]))
-
-
-def release_function(debugger, data):
- byte_code_cp = struct.unpack(debugger.byte_order + debugger.cp_format,
- data[3: 3 + debugger.cp_size])[0]
-
- function = debugger.function_list[byte_code_cp]
-
- for line, breakpoint in function.lines.items():
- debugger.line_list.delete(line, breakpoint)
- if breakpoint.active_index >= 0:
- del debugger.active_breakpoint_list[breakpoint.active_index]
-
- del debugger.function_list[byte_code_cp]
-
- debugger.send_bytecode_cp(byte_code_cp)
-
- logging.debug("Function {0x%x} byte-code released", byte_code_cp)
-
-
-def enable_breakpoint(debugger, breakpoint):
- if isinstance(breakpoint, JerryPendingBreakpoint):
- if not debugger.breakpoint_pending_exists(breakpoint):
- debugger.next_breakpoint_index += 1
- breakpoint.index = debugger.next_breakpoint_index
- debugger.pending_breakpoint_list[debugger.next_breakpoint_index] = breakpoint
- print("%sPending breakpoint%s at %s" % (debugger.yellow, debugger.nocolor, breakpoint))
- else:
- print("%sPending breakpoint%s already exists" % (debugger.yellow, debugger.nocolor))
-
- else:
- if breakpoint.active_index < 0:
- debugger.next_breakpoint_index += 1
- debugger.active_breakpoint_list[debugger.next_breakpoint_index] = breakpoint
- breakpoint.active_index = debugger.next_breakpoint_index
- debugger.send_breakpoint(breakpoint)
-
- print("%sBreakpoint %d %sat %s" % (debugger.green, breakpoint.active_index, debugger.nocolor, breakpoint))
-
-
-def set_breakpoint(debugger, string, pending):
- line = re.match("(.*):(\\d+)$", string)
- found = False
-
- if line:
- source_name = line.group(1)
- new_line = int(line.group(2))
-
- for breakpoint in debugger.line_list.get(new_line):
- func_source = breakpoint.function.source_name
- if (source_name == func_source or
- func_source.endswith("/" + source_name) or
- func_source.endswith("\\" + source_name)):
-
- enable_breakpoint(debugger, breakpoint)
- found = True
-
- else:
- for function in debugger.function_list.values():
- if function.name == string:
- enable_breakpoint(debugger, function.lines[function.first_breakpoint_line])
- found = True
-
- if not found and not pending:
- print("No breakpoint found, do you want to add a %spending breakpoint%s? (y or [n])" % \
- (debugger.yellow, debugger.nocolor))
-
- ans = sys.stdin.readline()
- if ans in ['yes\n', 'y\n']:
- if not debugger.pending_breakpoint_list:
- debugger.send_parser_config(1)
-
- if line:
- breakpoint = JerryPendingBreakpoint(int(line.group(2)), line.group(1))
- else:
- breakpoint = JerryPendingBreakpoint(function=string)
- enable_breakpoint(debugger, breakpoint)
-
- elif not found and pending:
- return False
-
- return True
-
-
-def get_breakpoint(debugger, breakpoint_data):
- function = debugger.function_list[breakpoint_data[0]]
- offset = breakpoint_data[1]
-
- if offset in function.offsets:
- return (function.offsets[offset], True)
-
- if offset < function.first_breakpoint_offset:
- return (function.offsets[function.first_breakpoint_offset], False)
-
- nearest_offset = -1
-
- for current_offset in function.offsets:
- if current_offset <= offset and current_offset > nearest_offset:
- nearest_offset = current_offset
-
- return (function.offsets[nearest_offset], False)
-
-
-# pylint: disable=too-many-branches,too-many-locals,too-many-statements
-def main():
- args = arguments_parse()
-
- debugger = JerryDebugger(args.address)
- exception_string = ""
-
- if args.color:
- debugger.set_colors()
-
- non_interactive = args.non_interactive
-
- logging.debug("Connected to JerryScript on %d port", debugger.port)
-
- prompt = DebuggerPrompt(debugger)
- prompt.prompt = "(jerry-debugger) "
- prompt.non_interactive = non_interactive
-
- if args.display:
- prompt.do_display(args.display)
-
- if args.exception is not None:
- prompt.do_exception(str(args.exception))
-
- if args.client_source is not None:
- prompt.store_client_sources(args.client_source)
-
- while True:
- if not non_interactive and prompt.cont:
- if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
- sys.stdin.readline()
- prompt.cont = False
- debugger.send_command(JERRY_DEBUGGER_STOP)
-
- data = debugger.get_message(False)
-
- if data == b'':
- continue
-
- if not data: # Break the while loop if there is no more data.
- break
-
- buffer_type = ord(data[2])
- buffer_size = ord(data[1]) - 1
-
- logging.debug("Main buffer type: %d, message size: %d", buffer_type, buffer_size)
-
- if buffer_type in [JERRY_DEBUGGER_PARSE_ERROR,
- JERRY_DEBUGGER_BYTE_CODE_CP,
- JERRY_DEBUGGER_PARSE_FUNCTION,
- JERRY_DEBUGGER_BREAKPOINT_LIST,
- JERRY_DEBUGGER_SOURCE_CODE,
- JERRY_DEBUGGER_SOURCE_CODE_END,
- JERRY_DEBUGGER_SOURCE_CODE_NAME,
- JERRY_DEBUGGER_SOURCE_CODE_NAME_END,
- JERRY_DEBUGGER_FUNCTION_NAME,
- JERRY_DEBUGGER_FUNCTION_NAME_END]:
- parse_source(debugger, data)
-
- elif buffer_type == JERRY_DEBUGGER_WAITING_AFTER_PARSE:
- debugger.send_command(JERRY_DEBUGGER_PARSER_RESUME)
-
- elif buffer_type == JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP:
- release_function(debugger, data)
-
- elif buffer_type in [JERRY_DEBUGGER_BREAKPOINT_HIT, JERRY_DEBUGGER_EXCEPTION_HIT]:
- breakpoint_data = struct.unpack(debugger.byte_order + debugger.cp_format + debugger.idx_format, data[3:])
-
- breakpoint = get_breakpoint(debugger, breakpoint_data)
- debugger.last_breakpoint_hit = breakpoint[0]
-
- if buffer_type == JERRY_DEBUGGER_EXCEPTION_HIT:
- print("Exception throw detected (to disable automatic stop type exception 0)")
- if exception_string:
- print("Exception hint: %s" % (exception_string))
- exception_string = ""
-
- if breakpoint[1]:
- breakpoint_info = "at"
- else:
- breakpoint_info = "around"
-
- if breakpoint[0].active_index >= 0:
- breakpoint_info += " breakpoint:%s%d%s" % (debugger.red, breakpoint[0].active_index, debugger.nocolor)
-
- print("Stopped %s %s" % (breakpoint_info, breakpoint[0]))
- if debugger.display:
- print_source(prompt.debugger, debugger.display, 0)
-
- if debugger.repeats_remain:
- prompt.do_next(debugger.repeats_remain)
- time.sleep(0.1)
- else:
- prompt.cmdloop()
-
- if prompt.quit:
- break
-
- elif buffer_type == JERRY_DEBUGGER_EXCEPTION_STR:
- exception_string += data[3:]
-
- elif buffer_type == JERRY_DEBUGGER_EXCEPTION_STR_END:
- exception_string += data[3:]
-
- elif buffer_type in [JERRY_DEBUGGER_BACKTRACE, JERRY_DEBUGGER_BACKTRACE_END]:
- frame_index = 0
-
- while True:
-
- buffer_pos = 3
- while buffer_size > 0:
- breakpoint_data = struct.unpack(debugger.byte_order + debugger.cp_format + debugger.idx_format,
- data[buffer_pos: buffer_pos + debugger.cp_size + 4])
-
- breakpoint = get_breakpoint(debugger, breakpoint_data)
-
- print("Frame %d: %s" % (frame_index, breakpoint[0]))
-
- frame_index += 1
- buffer_pos += 6
- buffer_size -= 6
-
- if buffer_type == JERRY_DEBUGGER_BACKTRACE_END:
- break
-
- data = debugger.get_message(True)
- buffer_type = ord(data[2])
- buffer_size = ord(data[1]) - 1
-
- if buffer_type not in [JERRY_DEBUGGER_BACKTRACE,
- JERRY_DEBUGGER_BACKTRACE_END]:
- raise Exception("Backtrace data expected")
-
- prompt.cmdloop()
-
-
- elif buffer_type in [JERRY_DEBUGGER_EVAL_RESULT,
- JERRY_DEBUGGER_EVAL_RESULT_END,
- JERRY_DEBUGGER_OUTPUT_RESULT,
- JERRY_DEBUGGER_OUTPUT_RESULT_END]:
- message = b""
- msg_type = buffer_type
- while True:
- if buffer_type in [JERRY_DEBUGGER_EVAL_RESULT_END,
- JERRY_DEBUGGER_OUTPUT_RESULT_END]:
- subtype = ord(data[-1])
- message += data[3:-1]
- break
- else:
- message += data[3:]
-
- data = debugger.get_message(True)
- buffer_type = ord(data[2])
- buffer_size = ord(data[1]) - 1
- # Checks if the next frame would be an invalid data frame.
- # If it is not the message type, or the end type of it, an exception is thrown.
- if buffer_type not in [msg_type, msg_type + 1]:
- raise Exception("Invalid data caught")
-
- # Subtypes of output
- if buffer_type == JERRY_DEBUGGER_OUTPUT_RESULT_END:
- message = message.rstrip('\n')
- if subtype in [JERRY_DEBUGGER_OUTPUT_OK,
- JERRY_DEBUGGER_OUTPUT_DEBUG]:
- print("%sout: %s%s" % (debugger.blue, debugger.nocolor, message))
- elif subtype == JERRY_DEBUGGER_OUTPUT_WARNING:
- print("%swarning: %s%s" % (debugger.yellow, debugger.nocolor, message))
- elif subtype == JERRY_DEBUGGER_OUTPUT_ERROR:
- print("%serr: %s%s" % (debugger.red, debugger.nocolor, message))
- elif subtype == JERRY_DEBUGGER_OUTPUT_TRACE:
- print("%strace: %s%s" % (debugger.blue, debugger.nocolor, message))
-
- # Subtypes of eval
- elif buffer_type == JERRY_DEBUGGER_EVAL_RESULT_END:
- if subtype == JERRY_DEBUGGER_EVAL_ERROR:
- print("Uncaught exception: %s" % (message))
- else:
- print(message)
-
- prompt.cmdloop()
-
- elif buffer_type == JERRY_DEBUGGER_MEMSTATS_RECEIVE:
-
- memory_stats = struct.unpack(debugger.byte_order + debugger.idx_format *5,
- data[3: 3 + 4 *5])
-
- print("Allocated bytes: %d" % (memory_stats[0]))
- print("Byte code bytes: %d" % (memory_stats[1]))
- print("String bytes: %d" % (memory_stats[2]))
- print("Object bytes: %d" % (memory_stats[3]))
- print("Property bytes: %d" % (memory_stats[4]))
-
- prompt.cmdloop()
-
- elif buffer_type == JERRY_DEBUGGER_WAIT_FOR_SOURCE:
- prompt.send_client_source()
-
-
- else:
- raise Exception("Unknown message")
-
-
-if __name__ == "__main__":
- try:
- main()
- except socket.error as error_msg:
- ERRNO = error_msg.errno
- MSG = str(error_msg)
-
- if ERRNO == 111:
- sys.exit("Failed to connect to the JerryScript debugger.")
- elif ERRNO == 32 or ERRNO == 104:
- sys.exit("Connection closed.")
- else:
- sys.exit("Failed to connect to the JerryScript debugger.\nError: %s" % (MSG))
--- /dev/null
+#!/usr/bin/env python
+
+# 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.
+
+from __future__ import print_function
+from cmd import Cmd
+from pprint import pprint
+import math
+import socket
+import sys
+import logging
+import time
+import jerry_client_ws
+
+def write(string):
+ print(string, end='')
+
+class DebuggerPrompt(Cmd):
+ # pylint: disable=too-many-instance-attributes,too-many-arguments
+ def __init__(self, debugger):
+ Cmd.__init__(self)
+ self.debugger = debugger
+ self.stop = False
+ self.quit = False
+
+ def precmd(self, line):
+ self.stop = False
+ if self.debugger.non_interactive:
+ print("%s" % line)
+ return line
+
+ def postcmd(self, stop, line):
+ return self.stop
+
+ def do_quit(self, _):
+ """ Exit JerryScript debugger """
+ self.debugger.quit()
+ self.quit = True
+ self.stop = True
+
+ def do_display(self, args):
+ """ Toggle source code display after breakpoints """
+ if args:
+ line_num = src_check_args(args)
+ if line_num >= 0:
+ self.debugger.display = line_num
+ else:
+ print("Non-negative integer number expected, 0 turns off this function")
+
+ def do_break(self, args):
+ """ Insert breakpoints on the given lines or functions """
+ write(self.debugger.set_break(args))
+ do_b = do_break
+
+ def do_list(self, _):
+ """ Lists the available breakpoints """
+ write(self.debugger.breakpoint_list())
+
+ def do_delete(self, args):
+ """ Delete the given breakpoint, use 'delete all|active|pending' to clear all the given breakpoints """
+ write(self.debugger.delete(args))
+
+ def do_next(self, args):
+ """ Next breakpoint in the same context """
+ self.stop = True
+ if not args:
+ args = 0
+ self.debugger.next()
+ return
+
+ try:
+ args = int(args)
+ if args <= 0:
+ raise ValueError(args)
+
+ while args > 0:
+ self.debugger.next()
+ time.sleep(0.1)
+
+ while True:
+ result = self.debugger.process_messages()
+ res_type = result.get_type()
+
+ if res_type == result.END:
+ self.quit = True
+ return
+ elif res_type == result.TEXT:
+ write(result.get_text())
+ elif res_type == result.PROMPT:
+ break
+
+ args -= 1
+ except ValueError as val_errno:
+ print("Error: expected a positive integer: %s" % val_errno)
+ do_n = do_next
+
+ def do_step(self, _):
+ """ Next breakpoint, step into functions """
+ self.debugger.step()
+ self.stop = True
+ do_s = do_step
+
+ def do_backtrace(self, args):
+ """ Get backtrace data from debugger """
+ write(self.debugger.backtrace(args))
+ self.stop = True
+ do_bt = do_backtrace
+
+ def do_variables(self, args):
+ """ Get scope variables from debugger """
+ write(self.debugger.scope_variables(args))
+ self.stop = True
+
+ def do_src(self, args):
+ """ Get current source code """
+ if args:
+ line_num = src_check_args(args)
+ if line_num >= 0:
+ write(self.debugger.print_source(line_num, 0))
+ do_source = do_src
+
+ def do_scroll(self, _):
+ """ Scroll the source up or down """
+ while True:
+ key = sys.stdin.readline()
+ if key == 'w\n':
+ _scroll_direction(self.debugger, "up")
+ elif key == 's\n':
+ _scroll_direction(self.debugger, "down")
+ elif key == 'q\n':
+ break
+ else:
+ print("Invalid key")
+
+ def do_continue(self, _):
+ """ Continue execution """
+ self.debugger.get_continue()
+ self.stop = True
+ if not self.debugger.non_interactive:
+ print("Press enter to stop JavaScript execution.")
+ do_c = do_continue
+
+ def do_finish(self, _):
+ """ Continue running until the current function returns """
+ self.debugger.finish()
+ self.stop = True
+ do_f = do_finish
+
+ def do_dump(self, args):
+ """ Dump all of the debugger data """
+ if args:
+ print("Error: No argument expected")
+ else:
+ pprint(self.debugger.function_list)
+
+ def do_eval(self, args):
+ """ Evaluate JavaScript source code """
+ self.debugger.eval(args)
+ self.stop = True
+ do_e = do_eval
+
+ def do_eval_at(self, args):
+ """ Evaluate JavaScript source code at a scope chain level """
+
+ code = ''
+ index = 0
+ try:
+ args = args.split(" ", 1)
+
+ index = int(args[0])
+
+ if len(args) == 2:
+ code = args[1]
+
+ if index < 0 or index > 65535:
+ raise ValueError("Invalid scope chain index: %d (must be between 0 and 65535)" % index)
+
+ except ValueError as val_errno:
+ print("Error: %s" % (val_errno))
+ return
+
+ self.debugger.eval_at(code, index)
+ self.stop = True
+
+ def do_memstats(self, _):
+ """ Memory statistics """
+ self.debugger.memstats()
+ self.stop = True
+ do_ms = do_memstats
+
+ def do_scopes(self, _):
+ """ Memory statistics """
+ self.debugger.scope_chain()
+ self.stop = True
+
+ def do_abort(self, args):
+ """ Throw an exception """
+ self.debugger.abort(args)
+ self.stop = True
+
+ def do_restart(self, _):
+ """ Restart the engine's debug session """
+ self.debugger.restart()
+ self.stop = True
+ do_res = do_restart
+
+ def do_throw(self, args):
+ """ Throw an exception """
+ self.debugger.throw(args)
+ self.stop = True
+
+ def do_exception(self, args):
+ """ Config the exception handler module """
+ write(self.debugger.exception(args))
+
+def _scroll_direction(debugger, direction):
+ """ Helper function for do_scroll """
+ debugger.src_offset_diff = int(max(math.floor(debugger.display / 3), 1))
+ if direction == "up":
+ debugger.src_offset -= debugger.src_offset_diff
+ else:
+ debugger.src_offset += debugger.src_offset_diff
+ print(debugger.print_source(debugger.display, debugger.src_offset)['value'])
+
+def src_check_args(args):
+ try:
+ line_num = int(args)
+ if line_num < 0:
+ print("Error: Non-negative integer number expected")
+ return -1
+
+ return line_num
+ except ValueError as val_errno:
+ print("Error: Non-negative integer number expected: %s" % (val_errno))
+ return -1
+
+# pylint: disable=too-many-branches,too-many-locals,too-many-statements
+def main():
+ args = jerry_client_ws.arguments_parse()
+
+ debugger = jerry_client_ws.JerryDebugger(args.address)
+ debugger.non_interactive = args.non_interactive
+
+ logging.debug("Connected to JerryScript on %d port", debugger.port)
+
+ prompt = DebuggerPrompt(debugger)
+ prompt.prompt = "(jerry-debugger) "
+
+ if args.color:
+ debugger.set_colors()
+
+ if args.display:
+ debugger.display = args.display
+ prompt.do_display(args.display)
+ else:
+ prompt.stop = False
+
+ if args.exception is not None:
+ prompt.do_exception(str(args.exception))
+
+ if args.client_source:
+ debugger.store_client_sources(args.client_source)
+
+ while True:
+ if prompt.quit:
+ break
+
+ result = debugger.process_messages()
+ res_type = result.get_type()
+
+ if res_type == result.END:
+ break
+ elif res_type == result.PROMPT:
+ prompt.cmdloop()
+ elif res_type == result.TEXT:
+ write(result.get_text())
+ continue
+
+if __name__ == "__main__":
+ try:
+ main()
+ except socket.error as error_msg:
+ ERRNO = error_msg.errno
+ MSG = str(error_msg)
+ if ERRNO == 111:
+ sys.exit("Failed to connect to the JerryScript debugger.")
+ elif ERRNO == 32 or ERRNO == 104:
+ sys.exit("Connection closed.")
+ else:
+ sys.exit("Failed to connect to the JerryScript debugger.\nError: %s" % (MSG))
--- /dev/null
+#!/usr/bin/env python
+
+# 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.
+
+from __future__ import print_function
+import argparse
+import logging
+import re
+import select
+import socket
+import struct
+import sys
+
+# Expected debugger protocol version.
+JERRY_DEBUGGER_VERSION = 8
+
+# Messages sent by the server to client.
+JERRY_DEBUGGER_CONFIGURATION = 1
+JERRY_DEBUGGER_PARSE_ERROR = 2
+JERRY_DEBUGGER_BYTE_CODE_CP = 3
+JERRY_DEBUGGER_PARSE_FUNCTION = 4
+JERRY_DEBUGGER_BREAKPOINT_LIST = 5
+JERRY_DEBUGGER_BREAKPOINT_OFFSET_LIST = 6
+JERRY_DEBUGGER_SOURCE_CODE = 7
+JERRY_DEBUGGER_SOURCE_CODE_END = 8
+JERRY_DEBUGGER_SOURCE_CODE_NAME = 9
+JERRY_DEBUGGER_SOURCE_CODE_NAME_END = 10
+JERRY_DEBUGGER_FUNCTION_NAME = 11
+JERRY_DEBUGGER_FUNCTION_NAME_END = 12
+JERRY_DEBUGGER_WAITING_AFTER_PARSE = 13
+JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 14
+JERRY_DEBUGGER_MEMSTATS_RECEIVE = 15
+JERRY_DEBUGGER_BREAKPOINT_HIT = 16
+JERRY_DEBUGGER_EXCEPTION_HIT = 17
+JERRY_DEBUGGER_EXCEPTION_STR = 18
+JERRY_DEBUGGER_EXCEPTION_STR_END = 19
+JERRY_DEBUGGER_BACKTRACE_TOTAL = 20
+JERRY_DEBUGGER_BACKTRACE = 21
+JERRY_DEBUGGER_BACKTRACE_END = 22
+JERRY_DEBUGGER_EVAL_RESULT = 23
+JERRY_DEBUGGER_EVAL_RESULT_END = 24
+JERRY_DEBUGGER_WAIT_FOR_SOURCE = 25
+JERRY_DEBUGGER_OUTPUT_RESULT = 26
+JERRY_DEBUGGER_OUTPUT_RESULT_END = 27
+JERRY_DEBUGGER_SCOPE_CHAIN = 28
+JERRY_DEBUGGER_SCOPE_CHAIN_END = 29
+JERRY_DEBUGGER_SCOPE_VARIABLES = 30
+JERRY_DEBUGGER_SCOPE_VARIABLES_END = 31
+
+# Debugger option flags
+JERRY_DEBUGGER_LITTLE_ENDIAN = 0x1
+
+# Subtypes of eval
+JERRY_DEBUGGER_EVAL_EVAL = "\0"
+JERRY_DEBUGGER_EVAL_THROW = "\1"
+JERRY_DEBUGGER_EVAL_ABORT = "\2"
+
+# Subtypes of eval result
+JERRY_DEBUGGER_EVAL_OK = 1
+JERRY_DEBUGGER_EVAL_ERROR = 2
+
+# Subtypes of output
+JERRY_DEBUGGER_OUTPUT_OK = 1
+JERRY_DEBUGGER_OUTPUT_ERROR = 2
+JERRY_DEBUGGER_OUTPUT_WARNING = 3
+JERRY_DEBUGGER_OUTPUT_DEBUG = 4
+JERRY_DEBUGGER_OUTPUT_TRACE = 5
+
+
+# Messages sent by the client to server.
+JERRY_DEBUGGER_FREE_BYTE_CODE_CP = 1
+JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2
+JERRY_DEBUGGER_EXCEPTION_CONFIG = 3
+JERRY_DEBUGGER_PARSER_CONFIG = 4
+JERRY_DEBUGGER_MEMSTATS = 5
+JERRY_DEBUGGER_STOP = 6
+JERRY_DEBUGGER_PARSER_RESUME = 7
+JERRY_DEBUGGER_CLIENT_SOURCE = 8
+JERRY_DEBUGGER_CLIENT_SOURCE_PART = 9
+JERRY_DEBUGGER_NO_MORE_SOURCES = 10
+JERRY_DEBUGGER_CONTEXT_RESET = 11
+JERRY_DEBUGGER_CONTINUE = 12
+JERRY_DEBUGGER_STEP = 13
+JERRY_DEBUGGER_NEXT = 14
+JERRY_DEBUGGER_FINISH = 15
+JERRY_DEBUGGER_GET_BACKTRACE = 16
+JERRY_DEBUGGER_EVAL = 17
+JERRY_DEBUGGER_EVAL_PART = 18
+JERRY_DEBUGGER_GET_SCOPE_CHAIN = 19
+JERRY_DEBUGGER_GET_SCOPE_VARIABLES = 20
+
+MAX_BUFFER_SIZE = 128
+WEBSOCKET_BINARY_FRAME = 2
+WEBSOCKET_FIN_BIT = 0x80
+
+JERRY_DEBUGGER_SCOPE_WITH = 1
+JERRY_DEBUGGER_SCOPE_LOCAL = 2
+JERRY_DEBUGGER_SCOPE_CLOSURE = 3
+JERRY_DEBUGGER_SCOPE_GLOBAL = 4
+JERRY_DEBUGGER_SCOPE_NON_CLOSURE = 5
+
+JERRY_DEBUGGER_VALUE_NONE = 1
+JERRY_DEBUGGER_VALUE_UNDEFINED = 2
+JERRY_DEBUGGER_VALUE_NULL = 3
+JERRY_DEBUGGER_VALUE_BOOLEAN = 4
+JERRY_DEBUGGER_VALUE_NUMBER = 5
+JERRY_DEBUGGER_VALUE_STRING = 6
+JERRY_DEBUGGER_VALUE_FUNCTION = 7
+JERRY_DEBUGGER_VALUE_ARRAY = 8
+JERRY_DEBUGGER_VALUE_OBJECT = 9
+
+def arguments_parse():
+ parser = argparse.ArgumentParser(description="JerryScript debugger client")
+
+ parser.add_argument("address", action="store", nargs="?", default="localhost:5001",
+ help="specify a unique network address for connection (default: %(default)s)")
+ parser.add_argument("-v", "--verbose", action="store_true", default=False,
+ help="increase verbosity (default: %(default)s)")
+ parser.add_argument("--non-interactive", action="store_true", default=False,
+ help="disable stop when newline is pressed (default: %(default)s)")
+ parser.add_argument("--color", action="store_true", default=False,
+ help="enable color highlighting on source commands (default: %(default)s)")
+ parser.add_argument("--display", action="store", default=None, type=int,
+ help="set display range")
+ parser.add_argument("--exception", action="store", default=None, type=int, choices=[0, 1],
+ help="set exception config, usage 1: [Enable] or 0: [Disable]")
+ parser.add_argument("--client-source", action="store", default=[], type=str, nargs="+",
+ help="specify a javascript source file to execute")
+
+ args = parser.parse_args()
+
+ if args.verbose:
+ logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.DEBUG)
+ logging.debug("Debug logging mode: ON")
+
+ return args
+
+
+class JerryBreakpoint(object):
+
+ def __init__(self, line, offset, function):
+ self.line = line
+ self.offset = offset
+ self.function = function
+ self.active_index = -1
+
+ def __str__(self):
+ result = self.function.source_name or "<unknown>"
+ result += ":%d" % (self.line)
+
+ if self.function.is_func:
+ result += " (in "
+ result += self.function.name or "function"
+ result += "() at line:%d, col:%d)" % (self.function.line, self.function.column)
+ return result
+
+ def __repr__(self):
+ return ("Breakpoint(line:%d, offset:%d, active_index:%d)"
+ % (self.line, self.offset, self.active_index))
+
+class JerryPendingBreakpoint(object):
+ def __init__(self, line=None, source_name=None, function=None):
+ self.function = function
+ self.line = line
+ self.source_name = source_name
+
+ self.index = -1
+
+ def __str__(self):
+ result = self.source_name or ""
+ if self.line:
+ result += ":%d" % (self.line)
+ else:
+ result += "%s()" % (self.function)
+ return result
+
+
+class JerryFunction(object):
+ # pylint: disable=too-many-instance-attributes,too-many-arguments
+ def __init__(self, is_func, byte_code_cp, source, source_name, line, column, name, lines, offsets):
+ self.is_func = bool(is_func)
+ self.byte_code_cp = byte_code_cp
+ self.source = re.split("\r\n|[\r\n]", source)
+ self.source_name = source_name
+ self.name = name
+ self.lines = {}
+ self.offsets = {}
+ self.line = line
+ self.column = column
+ self.first_breakpoint_line = lines[0]
+ self.first_breakpoint_offset = offsets[0]
+
+ if len(self.source) > 1 and not self.source[-1]:
+ self.source.pop()
+
+ for i, _line in enumerate(lines):
+ offset = offsets[i]
+ breakpoint = JerryBreakpoint(_line, offset, self)
+ self.lines[_line] = breakpoint
+ self.offsets[offset] = breakpoint
+
+ def __repr__(self):
+ result = ("Function(byte_code_cp:0x%x, source_name:%r, name:%r, line:%d, column:%d { "
+ % (self.byte_code_cp, self.source_name, self.name, self.line, self.column))
+
+ result += ','.join([str(breakpoint) for breakpoint in self.lines.values()])
+
+ return result + " })"
+
+
+class Multimap(object):
+
+ def __init__(self):
+ self.map = {}
+
+ def get(self, key):
+ if key in self.map:
+ return self.map[key]
+ return []
+
+ def insert(self, key, value):
+ if key in self.map:
+ self.map[key].append(value)
+ else:
+ self.map[key] = [value]
+
+ def delete(self, key, value):
+ items = self.map[key]
+
+ if len(items) == 1:
+ del self.map[key]
+ else:
+ del items[items.index(value)]
+
+ def __repr__(self):
+ return "Multimap(%r)" % (self.map)
+
+
+class DebuggerAction(object):
+ END = 0
+ WAIT = 1
+ TEXT = 2
+ PROMPT = 3
+
+ def __init__(self, action_type, action_text):
+ self.action_type = action_type
+ self.action_text = action_text
+
+ def get_type(self):
+ return self.action_type
+
+ def get_text(self):
+ return self.action_text
+
+
+class JerryDebugger(object):
+ # pylint: disable=too-many-instance-attributes,too-many-statements,too-many-public-methods,no-self-use
+ def __init__(self, address):
+
+ if ":" not in address:
+ self.host = address
+ self.port = 5001 # use default port
+ else:
+ self.host, self.port = address.split(":")
+ self.port = int(self.port)
+
+ print("Connecting to: %s:%s" % (self.host, self.port))
+
+ self.message_data = b""
+ self.prompt = False
+ self.function_list = {}
+ self.source = ''
+ self.source_name = ''
+ self.exception_string = ''
+ self.frame_index = 0
+ self.scope_vars = ""
+ self.scopes = ""
+ self.client_sources = []
+ self.last_breakpoint_hit = None
+ self.next_breakpoint_index = 0
+ self.active_breakpoint_list = {}
+ self.pending_breakpoint_list = {}
+ self.line_list = Multimap()
+ self.display = 0
+ self.green = ''
+ self.red = ''
+ self.yellow = ''
+ self.green_bg = ''
+ self.yellow_bg = ''
+ self.blue = ''
+ self.nocolor = ''
+ self.src_offset = 0
+ self.src_offset_diff = 0
+ self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.client_socket.connect((self.host, self.port))
+ self.non_interactive = False
+ self.current_out = b""
+ self.current_log = b""
+
+ self.send_message(b"GET /jerry-debugger HTTP/1.1\r\n" +
+ b"Upgrade: websocket\r\n" +
+ b"Connection: Upgrade\r\n" +
+ b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
+ result = b""
+ expected = (b"HTTP/1.1 101 Switching Protocols\r\n" +
+ b"Upgrade: websocket\r\n" +
+ b"Connection: Upgrade\r\n" +
+ b"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")
+
+ len_expected = len(expected)
+
+ while len(result) < len_expected:
+ result += self.client_socket.recv(1024)
+
+ len_result = len(result)
+
+ if result[0:len_expected] != expected:
+ raise Exception("Unexpected handshake")
+
+ if len_result > len_expected:
+ result = result[len_expected:]
+ else:
+ result = b""
+
+ len_expected = 10
+ # Network configurations, which has the following struct:
+ # header [2] - opcode[1], size[1]
+ # type [1]
+ # configuration [1]
+ # version [4]
+ # max_message_size [1]
+ # cpointer_size [1]
+
+ while len(result) < len_expected:
+ result += self.client_socket.recv(1024)
+
+ len_result = len(result)
+
+ expected = struct.pack("BBB",
+ WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
+ 8,
+ JERRY_DEBUGGER_CONFIGURATION)
+
+ if result[0:3] != expected:
+ raise Exception("Unexpected configuration")
+
+ self.little_endian = ord(result[3]) & JERRY_DEBUGGER_LITTLE_ENDIAN
+ self.max_message_size = ord(result[8])
+ self.cp_size = ord(result[9])
+
+ if self.little_endian:
+ self.byte_order = "<"
+ logging.debug("Little-endian machine")
+ else:
+ self.byte_order = ">"
+ logging.debug("Big-endian machine")
+
+ if self.cp_size == 2:
+ self.cp_format = "H"
+ else:
+ self.cp_format = "I"
+
+ self.idx_format = "I"
+
+ self.version = struct.unpack(self.byte_order + self.idx_format, result[4:8])[0]
+ if self.version != JERRY_DEBUGGER_VERSION:
+ raise Exception("Incorrect debugger version from target: %d expected: %d" %
+ (self.version, JERRY_DEBUGGER_VERSION))
+
+ logging.debug("Compressed pointer size: %d", self.cp_size)
+
+ if len_result > len_expected:
+ self.message_data = result[len_expected:]
+
+ def __del__(self):
+ self.client_socket.close()
+
+ def _exec_command(self, command_id):
+ self.send_command(command_id)
+
+ def quit(self):
+ self.prompt = False
+ self._exec_command(JERRY_DEBUGGER_CONTINUE)
+
+ def stop(self):
+ self.send_command(JERRY_DEBUGGER_STOP)
+
+ def get_continue(self):
+ self.prompt = False
+ self._exec_command(JERRY_DEBUGGER_CONTINUE)
+
+ def finish(self):
+ self.prompt = False
+ self._exec_command(JERRY_DEBUGGER_FINISH)
+
+ def next(self):
+ self.prompt = False
+ self._exec_command(JERRY_DEBUGGER_NEXT)
+
+ def step(self):
+ self.prompt = False
+ self._exec_command(JERRY_DEBUGGER_STEP)
+
+ def memstats(self):
+ self.prompt = False
+ self._exec_command(JERRY_DEBUGGER_MEMSTATS)
+
+ def scope_chain(self):
+ self.prompt = False
+ self._exec_command(JERRY_DEBUGGER_GET_SCOPE_CHAIN)
+
+ def set_break(self, args):
+ if not args:
+ return "Error: Breakpoint index expected"
+
+ if ':' in args:
+ try:
+ if int(args.split(':', 1)[1]) <= 0:
+ return "Error: Positive breakpoint index expected"
+
+ return self._set_breakpoint(args, False)
+
+ except ValueError as val_errno:
+ return "Error: Positive breakpoint index expected: %s" % (val_errno)
+
+ return self._set_breakpoint(args, False)
+
+ def delete(self, args):
+ if not args:
+ return "Error: Breakpoint index expected\n" \
+ "Delete the given breakpoint, use 'delete all|active|pending' " \
+ "to clear all the given breakpoints\n "
+ elif args in ['all', 'pending', 'active']:
+ if args == "all":
+ self.delete_active()
+ self.delete_pending()
+ elif args == "pending":
+ self.delete_pending()
+ elif args == "active":
+ self.delete_active()
+ return ""
+
+ try:
+ breakpoint_index = int(args)
+ except ValueError as val_errno:
+ return "Error: Integer number expected, %s\n" % (val_errno)
+
+ if breakpoint_index in self.active_breakpoint_list:
+ breakpoint = self.active_breakpoint_list[breakpoint_index]
+ del self.active_breakpoint_list[breakpoint_index]
+ breakpoint.active_index = -1
+ self.send_breakpoint(breakpoint)
+ return "Breakpoint %d deleted\n" % (breakpoint_index)
+ elif breakpoint_index in self.pending_breakpoint_list:
+ del self.pending_breakpoint_list[breakpoint_index]
+ if not self.pending_breakpoint_list:
+ self.send_parser_config(0)
+ return "Pending breakpoint %d deleted\n" % (breakpoint_index)
+ else:
+ return "Error: Breakpoint %d not found\n" % (breakpoint_index)
+
+ def breakpoint_list(self):
+ result = ''
+ if self.active_breakpoint_list:
+ result += "=== %sActive breakpoints %s ===\n" % (self.green_bg, self.nocolor)
+ for breakpoint in self.active_breakpoint_list.values():
+ result += " %d: %s\n" % (breakpoint.active_index, breakpoint)
+ if self.pending_breakpoint_list:
+ result += "=== %sPending breakpoints%s ===\n" % (self.yellow_bg, self.nocolor)
+ for breakpoint in self.pending_breakpoint_list.values():
+ result += " %d: %s (pending)\n" % (breakpoint.index, breakpoint)
+
+ if not self.active_breakpoint_list and not self.pending_breakpoint_list:
+ result += "No breakpoints\n"
+
+ return result
+
+ def backtrace(self, args):
+ max_depth = 0
+ min_depth = 0
+ get_total = 0
+
+ if args:
+ args = args.split(" ")
+ try:
+ if "t" in args:
+ get_total = 1
+ args.remove("t")
+
+ if len(args) >= 2:
+ min_depth = int(args[0])
+ max_depth = int(args[1])
+ if max_depth <= 0 or min_depth < 0:
+ return "Error: Positive integer number expected\n"
+ if min_depth > max_depth:
+ return "Error: Start depth needs to be lower than or equal to max depth\n"
+ elif len(args) >= 1:
+ max_depth = int(args[0])
+ if max_depth <= 0:
+ return "Error: Positive integer number expected\n"
+
+ except ValueError as val_errno:
+ return "Error: Positive integer number expected, %s\n" % (val_errno)
+
+ self.frame_index = min_depth
+ message = struct.pack(self.byte_order + "BBIB" + self.idx_format + self.idx_format + "B",
+ WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
+ WEBSOCKET_FIN_BIT + 1 + 4 + 4 + 1,
+ 0,
+ JERRY_DEBUGGER_GET_BACKTRACE,
+ min_depth,
+ max_depth,
+ get_total)
+ self.send_message(message)
+ self.prompt = False
+ return ""
+
+ def scope_variables(self, args):
+ index = 0
+ if args:
+ try:
+ index = int(args)
+ if index < 0:
+ print ("Error: A non negative integer number expected")
+ return
+
+ except ValueError as val_errno:
+ return "Error: Non negative integer number expected, %s\n" % (val_errno)
+
+ message = struct.pack(self.byte_order + "BBIB" + self.idx_format,
+ WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
+ WEBSOCKET_FIN_BIT + 1 + 4,
+ 0,
+ JERRY_DEBUGGER_GET_SCOPE_VARIABLES,
+ index)
+ self.send_message(message)
+ self.prompt = False
+ return ""
+
+ def eval(self, code):
+ self._send_string(JERRY_DEBUGGER_EVAL_EVAL + code, JERRY_DEBUGGER_EVAL)
+ self.prompt = False
+
+ def eval_at(self, code, index):
+ self._send_string(JERRY_DEBUGGER_EVAL_EVAL + code, JERRY_DEBUGGER_EVAL, index)
+ self.prompt = False
+
+ def throw(self, code):
+ self._send_string(JERRY_DEBUGGER_EVAL_THROW + code, JERRY_DEBUGGER_EVAL)
+ self.prompt = False
+
+ def abort(self, args):
+ self.delete("all")
+ self.exception("0") # disable the exception handler
+ self._send_string(JERRY_DEBUGGER_EVAL_ABORT + args, JERRY_DEBUGGER_EVAL)
+ self.prompt = False
+
+ def restart(self):
+ self._send_string(JERRY_DEBUGGER_EVAL_ABORT + "\"r353t\"", JERRY_DEBUGGER_EVAL)
+ self.prompt = False
+
+ def exception(self, args):
+ try:
+ enabled = int(args)
+ except (ValueError, TypeError):
+ enabled = -1
+
+ if enabled not in [0, 1]:
+ return "Error: Invalid input! Usage 1: [Enable] or 0: [Disable]\n"
+
+ if enabled:
+ logging.debug("Stop at exception enabled")
+ self.send_exception_config(enabled)
+
+ return "Stop at exception enabled\n"
+
+ logging.debug("Stop at exception disabled")
+ self.send_exception_config(enabled)
+
+ return "Stop at exception disabled\n"
+
+ def _send_string(self, args, message_type, index=0):
+
+ # 1: length of type byte
+ # 4: length of an uint32 value
+ message_header = 1 + 4
+
+ # Add scope chain index
+ if message_type == JERRY_DEBUGGER_EVAL:
+ args = struct.pack(self.byte_order + "I", index) + args
+
+ size = len(args)
+
+ max_fragment = min(self.max_message_size - message_header, size)
+
+ message = struct.pack(self.byte_order + "BBIBI",
+ WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
+ WEBSOCKET_FIN_BIT + max_fragment + message_header,
+ 0,
+ message_type,
+ size)
+
+ if size == max_fragment:
+ self.send_message(message + args)
+ return
+
+ self.send_message(message + args[0:max_fragment])
+ offset = max_fragment
+
+ if message_type == JERRY_DEBUGGER_EVAL:
+ message_type = JERRY_DEBUGGER_EVAL_PART
+ else:
+ message_type = JERRY_DEBUGGER_CLIENT_SOURCE_PART
+
+ # 1: length of type byte
+ message_header = 1
+
+ max_fragment = self.max_message_size - message_header
+ while offset < size:
+ next_fragment = min(max_fragment, size - offset)
+
+ message = struct.pack(self.byte_order + "BBIB",
+ WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
+ WEBSOCKET_FIN_BIT + next_fragment + message_header,
+ 0,
+ message_type)
+
+ prev_offset = offset
+ offset += next_fragment
+ self.send_message(message + args[prev_offset:offset])
+
+ def delete_active(self):
+ for i in self.active_breakpoint_list.values():
+ breakpoint = self.active_breakpoint_list[i.active_index]
+ del self.active_breakpoint_list[i.active_index]
+ breakpoint.active_index = -1
+ self.send_breakpoint(breakpoint)
+
+ def delete_pending(self):
+ if self.pending_breakpoint_list:
+ self.pending_breakpoint_list.clear()
+ self.send_parser_config(0)
+
+ def breakpoint_pending_exists(self, breakpoint):
+ for existing_bp in self.pending_breakpoint_list.values():
+ if (breakpoint.line and existing_bp.source_name == breakpoint.source_name and \
+ existing_bp.line == breakpoint.line) \
+ or (not breakpoint.line and existing_bp.function == breakpoint.function):
+ return True
+
+ return False
+
+ def send_breakpoint(self, breakpoint):
+ message = struct.pack(self.byte_order + "BBIBB" + self.cp_format + self.idx_format,
+ WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
+ WEBSOCKET_FIN_BIT + 1 + 1 + self.cp_size + 4,
+ 0,
+ JERRY_DEBUGGER_UPDATE_BREAKPOINT,
+ int(breakpoint.active_index >= 0),
+ breakpoint.function.byte_code_cp,
+ breakpoint.offset)
+ self.send_message(message)
+
+ def send_bytecode_cp(self, byte_code_cp):
+ message = struct.pack(self.byte_order + "BBIB" + self.cp_format,
+ WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
+ WEBSOCKET_FIN_BIT + 1 + self.cp_size,
+ 0,
+ JERRY_DEBUGGER_FREE_BYTE_CODE_CP,
+ byte_code_cp)
+ self.send_message(message)
+
+ def send_command(self, command):
+ message = struct.pack(self.byte_order + "BBIB",
+ WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
+ WEBSOCKET_FIN_BIT + 1,
+ 0,
+ command)
+ self.send_message(message)
+
+ def send_exception_config(self, enable):
+ message = struct.pack(self.byte_order + "BBIBB",
+ WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
+ WEBSOCKET_FIN_BIT + 1 + 1,
+ 0,
+ JERRY_DEBUGGER_EXCEPTION_CONFIG,
+ enable)
+ self.send_message(message)
+
+ def send_parser_config(self, enable):
+ message = struct.pack(self.byte_order + "BBIBB",
+ WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
+ WEBSOCKET_FIN_BIT + 1 + 1,
+ 0,
+ JERRY_DEBUGGER_PARSER_CONFIG,
+ enable)
+ self.send_message(message)
+
+ def set_colors(self):
+ self.nocolor = '\033[0m'
+ self.green = '\033[92m'
+ self.red = '\033[31m'
+ self.yellow = '\033[93m'
+ self.green_bg = '\033[42m\033[30m'
+ self.yellow_bg = '\033[43m\033[30m'
+ self.blue = '\033[94m'
+
+ def send_message(self, message):
+ size = len(message)
+ while size > 0:
+ bytes_send = self.client_socket.send(message)
+ if bytes_send < size:
+ message = message[bytes_send:]
+ size -= bytes_send
+
+
+ def get_message(self, blocking):
+ # Connection was closed
+ if self.message_data is None:
+ return None
+
+ while True:
+ if len(self.message_data) >= 2:
+ if ord(self.message_data[0]) != WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT:
+ raise Exception("Unexpected data frame")
+
+ size = ord(self.message_data[1])
+ if size == 0 or size >= 126:
+ raise Exception("Unexpected data frame")
+
+ if len(self.message_data) >= size + 2:
+ result = self.message_data[0:size + 2]
+ self.message_data = self.message_data[size + 2:]
+ return result
+
+ if not blocking:
+ select_result = select.select([self.client_socket], [], [], 0)[0]
+ if self.client_socket not in select_result:
+ return b''
+
+ data = self.client_socket.recv(MAX_BUFFER_SIZE)
+
+ if not data:
+ self.message_data = None
+ return None
+ self.message_data += data
+
+ def store_client_sources(self, args):
+ self.client_sources = args
+
+ def send_client_source(self):
+ # Send no more source message if there is no source
+ if not self.client_sources:
+ self.send_no_more_source()
+ return
+
+ path = self.client_sources.pop(0)
+ if not path.lower().endswith('.js'):
+ sys.exit("Error: Javascript file expected!")
+ return
+
+ with open(path, 'r') as src_file:
+ content = path + "\0" + src_file.read()
+ self._send_string(content, JERRY_DEBUGGER_CLIENT_SOURCE)
+
+ def send_no_more_source(self):
+ self._exec_command(JERRY_DEBUGGER_NO_MORE_SOURCES)
+
+ # pylint: disable=too-many-branches,too-many-locals,too-many-statements,too-many-return-statements
+ def process_messages(self):
+ result = ""
+
+ while True:
+ data = self.get_message(False)
+ if not self.non_interactive:
+ if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
+ sys.stdin.readline()
+ self.stop()
+
+ if data == b'':
+ action_type = DebuggerAction.PROMPT if self.prompt else DebuggerAction.WAIT
+ return DebuggerAction(action_type, "")
+
+ if not data: # Break the while loop if there is no more data.
+ return DebuggerAction(DebuggerAction.END, "")
+
+ buffer_type = ord(data[2])
+ buffer_size = ord(data[1]) - 1
+
+ logging.debug("Main buffer type: %d, message size: %d", buffer_type, buffer_size)
+
+ if buffer_type in [JERRY_DEBUGGER_PARSE_ERROR,
+ JERRY_DEBUGGER_BYTE_CODE_CP,
+ JERRY_DEBUGGER_PARSE_FUNCTION,
+ JERRY_DEBUGGER_BREAKPOINT_LIST,
+ JERRY_DEBUGGER_SOURCE_CODE,
+ JERRY_DEBUGGER_SOURCE_CODE_END,
+ JERRY_DEBUGGER_SOURCE_CODE_NAME,
+ JERRY_DEBUGGER_SOURCE_CODE_NAME_END,
+ JERRY_DEBUGGER_FUNCTION_NAME,
+ JERRY_DEBUGGER_FUNCTION_NAME_END]:
+ result = self._parse_source(data)
+ if result:
+ return DebuggerAction(DebuggerAction.TEXT, result)
+
+ elif buffer_type == JERRY_DEBUGGER_WAITING_AFTER_PARSE:
+ self.send_command(JERRY_DEBUGGER_PARSER_RESUME)
+
+ elif buffer_type == JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP:
+ self._release_function(data)
+
+ elif buffer_type in [JERRY_DEBUGGER_BREAKPOINT_HIT, JERRY_DEBUGGER_EXCEPTION_HIT]:
+ breakpoint_data = struct.unpack(self.byte_order + self.cp_format + self.idx_format, data[3:])
+
+ breakpoint = self._get_breakpoint(breakpoint_data)
+ self.last_breakpoint_hit = breakpoint[0]
+
+ if buffer_type == JERRY_DEBUGGER_EXCEPTION_HIT:
+ result += "Exception throw detected (to disable automatic stop type exception 0)\n"
+ if self.exception_string:
+ result += "Exception hint: %s\n" % (self.exception_string)
+ self.exception_string = ""
+
+ if breakpoint[1]:
+ breakpoint_info = "at"
+ else:
+ breakpoint_info = "around"
+
+ if breakpoint[0].active_index >= 0:
+ breakpoint_info += " breakpoint:%s%d%s" % (self.red, breakpoint[0].active_index, self.nocolor)
+
+ result += "Stopped %s %s\n" % (breakpoint_info, breakpoint[0])
+
+ if self.display > 0:
+ result += self.print_source(self.display, self.src_offset)
+
+ self.prompt = True
+ return DebuggerAction(DebuggerAction.TEXT, result)
+
+ elif buffer_type == JERRY_DEBUGGER_EXCEPTION_STR:
+ self.exception_string += data[3:]
+
+ elif buffer_type == JERRY_DEBUGGER_EXCEPTION_STR_END:
+ self.exception_string += data[3:]
+
+ elif buffer_type == JERRY_DEBUGGER_BACKTRACE_TOTAL:
+ total = struct.unpack(self.byte_order + self.idx_format, data[3:])[0]
+ result += "Total number of frames: %d\n" % (total)
+ return DebuggerAction(DebuggerAction.TEXT, result)
+
+ elif buffer_type in [JERRY_DEBUGGER_BACKTRACE, JERRY_DEBUGGER_BACKTRACE_END]:
+ frame_index = self.frame_index
+
+ buffer_pos = 3
+ while buffer_size > 0:
+ breakpoint_data = struct.unpack(self.byte_order + self.cp_format + self.idx_format,
+ data[buffer_pos: buffer_pos + self.cp_size + 4])
+
+ breakpoint = self._get_breakpoint(breakpoint_data)
+
+ result += "Frame %d: %s\n" % (frame_index, breakpoint[0])
+
+ frame_index += 1
+ buffer_pos += 6
+ buffer_size -= 6
+
+ if buffer_type == JERRY_DEBUGGER_BACKTRACE_END:
+ self.prompt = True
+ else:
+ self.frame_index = frame_index
+
+ return DebuggerAction(DebuggerAction.TEXT, result)
+
+ elif buffer_type in [JERRY_DEBUGGER_EVAL_RESULT,
+ JERRY_DEBUGGER_EVAL_RESULT_END,
+ JERRY_DEBUGGER_OUTPUT_RESULT,
+ JERRY_DEBUGGER_OUTPUT_RESULT_END]:
+
+ result = self._process_incoming_text(buffer_type, data)
+ return DebuggerAction(DebuggerAction.TEXT, result)
+
+ elif buffer_type == JERRY_DEBUGGER_MEMSTATS_RECEIVE:
+
+ memory_stats = struct.unpack(self.byte_order + self.idx_format * 5,
+ data[3: 3 + 4 * 5])
+
+ result += "Allocated bytes: %s\n" % memory_stats[0]
+ result += "Byte code bytes: %s\n" % memory_stats[1]
+ result += "String bytes: %s\n" % memory_stats[2]
+ result += "Object bytes: %s\n" % memory_stats[3]
+ result += "Property bytes: %s\n" % memory_stats[4]
+
+ self.prompt = True
+ return DebuggerAction(DebuggerAction.TEXT, result)
+
+ elif buffer_type == JERRY_DEBUGGER_WAIT_FOR_SOURCE:
+ self.send_client_source()
+
+ elif buffer_type in [JERRY_DEBUGGER_SCOPE_CHAIN, JERRY_DEBUGGER_SCOPE_CHAIN_END]:
+ self.scopes = data[3:]
+
+ if buffer_type == JERRY_DEBUGGER_SCOPE_CHAIN_END:
+ result = self.process_scopes()
+ self.scopes = ""
+
+ self.prompt = True
+
+ return DebuggerAction(DebuggerAction.TEXT, result)
+
+ elif buffer_type in [JERRY_DEBUGGER_SCOPE_VARIABLES, JERRY_DEBUGGER_SCOPE_VARIABLES_END]:
+ self.scope_vars += "".join(data[3:])
+
+ if buffer_type == JERRY_DEBUGGER_SCOPE_VARIABLES_END:
+ result = self.process_scope_variables()
+ self.scope_vars = ""
+
+ self.prompt = True
+
+ return DebuggerAction(DebuggerAction.TEXT, result)
+
+ else:
+ raise Exception("Unknown message")
+
+ def print_source(self, line_num, offset):
+ msg = ""
+ last_bp = self.last_breakpoint_hit
+
+ if not last_bp:
+ return ""
+
+ lines = last_bp.function.source
+ if last_bp.function.source_name:
+ msg += "Source: %s\n" % (last_bp.function.source_name)
+
+ if line_num == 0:
+ start = 0
+ end = len(last_bp.function.source)
+ else:
+ start = max(last_bp.line - line_num, 0)
+ end = min(last_bp.line + line_num - 1, len(last_bp.function.source))
+ if offset:
+ if start + offset < 0:
+ self.src_offset += self.src_offset_diff
+ offset += self.src_offset_diff
+ elif end + offset > len(last_bp.function.source):
+ self.src_offset -= self.src_offset_diff
+ offset -= self.src_offset_diff
+
+ start = max(start + offset, 0)
+ end = min(end + offset, len(last_bp.function.source))
+
+ for i in range(start, end):
+ if i == last_bp.line - 1:
+ msg += "%s%4d%s %s>%s %s\n" % (self.green, i + 1, self.nocolor, self.red, \
+ self.nocolor, lines[i])
+ else:
+ msg += "%s%4d%s %s\n" % (self.green, i + 1, self.nocolor, lines[i])
+
+ return msg
+
+
+ # pylint: disable=too-many-branches,too-many-locals,too-many-statements
+ def _parse_source(self, data):
+ source_code = ""
+ source_code_name = ""
+ function_name = ""
+ stack = [{"line": 1,
+ "column": 1,
+ "name": "",
+ "lines": [],
+ "offsets": []}]
+ new_function_list = {}
+ result = ""
+
+ while True:
+ if data is None:
+ return "Error: connection lost during source code receiving"
+
+ buffer_type = ord(data[2])
+ buffer_size = ord(data[1]) - 1
+
+ logging.debug("Parser buffer type: %d, message size: %d", buffer_type, buffer_size)
+
+ if buffer_type == JERRY_DEBUGGER_PARSE_ERROR:
+ logging.error("Syntax error found")
+ return ""
+
+ elif buffer_type in [JERRY_DEBUGGER_SOURCE_CODE, JERRY_DEBUGGER_SOURCE_CODE_END]:
+ source_code += data[3:]
+
+ elif buffer_type in [JERRY_DEBUGGER_SOURCE_CODE_NAME, JERRY_DEBUGGER_SOURCE_CODE_NAME_END]:
+ source_code_name += data[3:]
+
+ elif buffer_type in [JERRY_DEBUGGER_FUNCTION_NAME, JERRY_DEBUGGER_FUNCTION_NAME_END]:
+ function_name += data[3:]
+
+ elif buffer_type == JERRY_DEBUGGER_PARSE_FUNCTION:
+ logging.debug("Source name: %s, function name: %s", source_code_name, function_name)
+
+ position = struct.unpack(self.byte_order + self.idx_format + self.idx_format,
+ data[3: 3 + 4 + 4])
+
+ stack.append({"source": source_code,
+ "source_name": source_code_name,
+ "line": position[0],
+ "column": position[1],
+ "name": function_name,
+ "lines": [],
+ "offsets": []})
+ function_name = ""
+
+ elif buffer_type in [JERRY_DEBUGGER_BREAKPOINT_LIST, JERRY_DEBUGGER_BREAKPOINT_OFFSET_LIST]:
+ name = "lines"
+ if buffer_type == JERRY_DEBUGGER_BREAKPOINT_OFFSET_LIST:
+ name = "offsets"
+
+ logging.debug("Breakpoint %s received", name)
+
+ buffer_pos = 3
+ while buffer_size > 0:
+ line = struct.unpack(self.byte_order + self.idx_format,
+ data[buffer_pos: buffer_pos + 4])
+ stack[-1][name].append(line[0])
+ buffer_pos += 4
+ buffer_size -= 4
+
+ elif buffer_type == JERRY_DEBUGGER_BYTE_CODE_CP:
+ byte_code_cp = struct.unpack(self.byte_order + self.cp_format,
+ data[3: 3 + self.cp_size])[0]
+
+ logging.debug("Byte code cptr received: {0x%x}", byte_code_cp)
+
+ func_desc = stack.pop()
+
+ # We know the last item in the list is the general byte code.
+ if not stack:
+ func_desc["source"] = source_code
+ func_desc["source_name"] = source_code_name
+
+ function = JerryFunction(stack,
+ byte_code_cp,
+ func_desc["source"],
+ func_desc["source_name"],
+ func_desc["line"],
+ func_desc["column"],
+ func_desc["name"],
+ func_desc["lines"],
+ func_desc["offsets"])
+
+ new_function_list[byte_code_cp] = function
+
+ if not stack:
+ logging.debug("Parse completed.")
+ break
+
+ elif buffer_type == JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP:
+ # Redefined functions are dropped during parsing.
+ byte_code_cp = struct.unpack(self.byte_order + self.cp_format,
+ data[3: 3 + self.cp_size])[0]
+
+ if byte_code_cp in new_function_list:
+ del new_function_list[byte_code_cp]
+ self.send_bytecode_cp(byte_code_cp)
+ else:
+ self._release_function(data)
+
+ elif buffer_type in [JERRY_DEBUGGER_OUTPUT_RESULT,
+ JERRY_DEBUGGER_OUTPUT_RESULT_END]:
+ result += self._process_incoming_text(buffer_type, data)
+
+ else:
+ logging.error("Parser error!")
+ raise Exception("Unexpected message")
+
+ data = self.get_message(True)
+
+ # Copy the ready list to the global storage.
+ self.function_list.update(new_function_list)
+
+ for function in new_function_list.values():
+ for line, breakpoint in function.lines.items():
+ self.line_list.insert(line, breakpoint)
+
+ # Try to set the pending breakpoints
+ if self.pending_breakpoint_list:
+ logging.debug("Pending breakpoints available")
+ bp_list = self.pending_breakpoint_list
+
+ for breakpoint_index, breakpoint in bp_list.items():
+ source_lines = 0
+ for src in new_function_list.values():
+ if src.source_name == breakpoint.source_name:
+ source_lines = len(src.source)
+ break
+
+ if breakpoint.line:
+ if breakpoint.line <= source_lines:
+ command = breakpoint.source_name + ":" + str(breakpoint.line)
+ set_result = self._set_breakpoint(command, True)
+
+ if set_result:
+ result += set_result
+ del bp_list[breakpoint_index]
+ elif breakpoint.function:
+ command = breakpoint.function
+ set_result = self._set_breakpoint(command, True)
+
+ if set_result:
+ result += set_result
+ del bp_list[breakpoint_index]
+
+ if not bp_list:
+ self.send_parser_config(0)
+ return result
+
+ logging.debug("No pending breakpoints")
+ return result
+
+
+ def _release_function(self, data):
+ byte_code_cp = struct.unpack(self.byte_order + self.cp_format,
+ data[3: 3 + self.cp_size])[0]
+
+ function = self.function_list[byte_code_cp]
+
+ for line, breakpoint in function.lines.items():
+ self.line_list.delete(line, breakpoint)
+ if breakpoint.active_index >= 0:
+ del self.active_breakpoint_list[breakpoint.active_index]
+
+ del self.function_list[byte_code_cp]
+ self.send_bytecode_cp(byte_code_cp)
+ logging.debug("Function {0x%x} byte-code released", byte_code_cp)
+
+
+ def _enable_breakpoint(self, breakpoint):
+ if isinstance(breakpoint, JerryPendingBreakpoint):
+ if self.breakpoint_pending_exists(breakpoint):
+ return "%sPending breakpoint%s already exists\n" % (self.yellow, self.nocolor)
+
+ self.next_breakpoint_index += 1
+ breakpoint.index = self.next_breakpoint_index
+ self.pending_breakpoint_list[self.next_breakpoint_index] = breakpoint
+ return ("%sPending breakpoint %d%s at %s\n" % (self.yellow,
+ breakpoint.index,
+ self.nocolor,
+ breakpoint))
+
+ if breakpoint.active_index < 0:
+ self.next_breakpoint_index += 1
+ self.active_breakpoint_list[self.next_breakpoint_index] = breakpoint
+ breakpoint.active_index = self.next_breakpoint_index
+ self.send_breakpoint(breakpoint)
+
+ return "%sBreakpoint %d%s at %s\n" % (self.green,
+ breakpoint.active_index,
+ self.nocolor,
+ breakpoint)
+
+
+ def _set_breakpoint(self, string, pending):
+ line = re.match("(.*):(\\d+)$", string)
+ result = ""
+
+ if line:
+ source_name = line.group(1)
+ new_line = int(line.group(2))
+
+ for breakpoint in self.line_list.get(new_line):
+ func_source = breakpoint.function.source_name
+ if (source_name == func_source or
+ func_source.endswith("/" + source_name) or
+ func_source.endswith("\\" + source_name)):
+
+ result += self._enable_breakpoint(breakpoint)
+
+ else:
+ for function in self.function_list.values():
+ if function.name == string:
+ result += self._enable_breakpoint(function.lines[function.first_breakpoint_line])
+
+ if not result and not pending:
+ print("No breakpoint found, do you want to add a %spending breakpoint%s? (y or [n])" % \
+ (self.yellow, self.nocolor))
+
+ ans = sys.stdin.readline()
+ if ans in ['yes\n', 'y\n']:
+ if not self.pending_breakpoint_list:
+ self.send_parser_config(1)
+
+ if line:
+ breakpoint = JerryPendingBreakpoint(int(line.group(2)), line.group(1))
+ else:
+ breakpoint = JerryPendingBreakpoint(function=string)
+ result += self._enable_breakpoint(breakpoint)
+
+ return result
+
+
+ def _get_breakpoint(self, breakpoint_data):
+ function = self.function_list[breakpoint_data[0]]
+ offset = breakpoint_data[1]
+
+ if offset in function.offsets:
+ return (function.offsets[offset], True)
+
+ if offset < function.first_breakpoint_offset:
+ return (function.offsets[function.first_breakpoint_offset], False)
+
+ nearest_offset = -1
+
+ for current_offset in function.offsets:
+ if current_offset <= offset and current_offset > nearest_offset:
+ nearest_offset = current_offset
+
+ return (function.offsets[nearest_offset], False)
+
+ def _process_incoming_text(self, buffer_type, data):
+ message = b""
+ msg_type = buffer_type
+ while True:
+ if buffer_type in [JERRY_DEBUGGER_EVAL_RESULT_END,
+ JERRY_DEBUGGER_OUTPUT_RESULT_END]:
+ subtype = ord(data[-1])
+ message += data[3:-1]
+ break
+ else:
+ message += data[3:]
+
+ data = self.get_message(True)
+ buffer_type = ord(data[2])
+ # Checks if the next frame would be an invalid data frame.
+ # If it is not the message type, or the end type of it, an exception is thrown.
+ if buffer_type not in [msg_type, msg_type + 1]:
+ raise Exception("Invalid data caught")
+
+ # Subtypes of output
+ if buffer_type == JERRY_DEBUGGER_OUTPUT_RESULT_END:
+ if subtype == JERRY_DEBUGGER_OUTPUT_OK:
+ log_type = "%sout:%s " % (self.blue, self.nocolor)
+
+ message = self.current_out + message
+ lines = message.split("\n")
+ self.current_out = lines.pop()
+
+ return "".join(["%s%s\n" % (log_type, line) for line in lines])
+
+ if subtype == JERRY_DEBUGGER_OUTPUT_DEBUG:
+ log_type = "%slog:%s " % (self.yellow, self.nocolor)
+
+ message = self.current_log + message
+ lines = message.split("\n")
+ self.current_log = lines.pop()
+
+ return "".join(["%s%s\n" % (log_type, line) for line in lines])
+
+ if not message.endswith("\n"):
+ message += "\n"
+
+ if subtype == JERRY_DEBUGGER_OUTPUT_WARNING:
+ return "%swarning: %s%s" % (self.yellow, self.nocolor, message)
+ elif subtype == JERRY_DEBUGGER_OUTPUT_ERROR:
+ return "%serr: %s%s" % (self.red, self.nocolor, message)
+ elif subtype == JERRY_DEBUGGER_OUTPUT_TRACE:
+ return "%strace: %s%s" % (self.blue, self.nocolor, message)
+
+ # Subtypes of eval
+ self.prompt = True
+
+ if not message.endswith("\n"):
+ message += "\n"
+
+ if subtype == JERRY_DEBUGGER_EVAL_ERROR:
+ return "Uncaught exception: %s" % (message)
+ return message
+
+ def process_scope_variables(self):
+ buff_size = len(self.scope_vars)
+ buff_pos = 0
+
+ table = [['name', 'type', 'value']]
+
+ while buff_pos != buff_size:
+ # Process name
+ name_length = ord(self.scope_vars[buff_pos:buff_pos + 1])
+ buff_pos += 1
+ name = self.scope_vars[buff_pos:buff_pos + name_length]
+ buff_pos += name_length
+
+ # Process type
+ value_type = ord(self.scope_vars[buff_pos:buff_pos + 1])
+
+ buff_pos += 1
+
+ value_length = ord(self.scope_vars[buff_pos:buff_pos + 1])
+ buff_pos += 1
+ value = self.scope_vars[buff_pos: buff_pos + value_length]
+ buff_pos += value_length
+
+ if value_type == JERRY_DEBUGGER_VALUE_UNDEFINED:
+ table.append([name, 'undefined', value])
+ elif value_type == JERRY_DEBUGGER_VALUE_NULL:
+ table.append([name, 'Null', value])
+ elif value_type == JERRY_DEBUGGER_VALUE_BOOLEAN:
+ table.append([name, 'Boolean', value])
+ elif value_type == JERRY_DEBUGGER_VALUE_NUMBER:
+ table.append([name, 'Number', value])
+ elif value_type == JERRY_DEBUGGER_VALUE_STRING:
+ table.append([name, 'String', value])
+ elif value_type == JERRY_DEBUGGER_VALUE_FUNCTION:
+ table.append([name, 'Function', value])
+ elif value_type == JERRY_DEBUGGER_VALUE_ARRAY:
+ table.append([name, 'Array', '[' + value + ']'])
+ elif value_type == JERRY_DEBUGGER_VALUE_OBJECT:
+ table.append([name, 'Object', value])
+
+ result = self.form_table(table)
+
+ return result
+
+ def process_scopes(self):
+ result = ""
+ table = [['level', 'type']]
+
+ for i, level in enumerate(self.scopes):
+ if ord(level) == JERRY_DEBUGGER_SCOPE_WITH:
+ table.append([str(i), 'with'])
+ elif ord(level) == JERRY_DEBUGGER_SCOPE_GLOBAL:
+ table.append([str(i), 'global'])
+ elif ord(level) == JERRY_DEBUGGER_SCOPE_NON_CLOSURE:
+ # Currently it is only marks the catch closure.
+ table.append([str(i), 'catch'])
+ elif ord(level) == JERRY_DEBUGGER_SCOPE_LOCAL:
+ table.append([str(i), 'local'])
+ elif ord(level) == JERRY_DEBUGGER_SCOPE_CLOSURE:
+ table.append([str(i), 'closure'])
+ else:
+ raise Exception("Unexpected scope chain element")
+
+ result = self.form_table(table)
+
+ return result
+
+ def form_table(self, table):
+ result = ""
+ col_width = [max(len(x) for x in col) for col in zip(*table)]
+ for line in table:
+ result += " | ".join("{:{}}".format(x, col_width[i])
+ for i, x in enumerate(line)) + " \n"
+
+ return result
set(JERRY_EXT_NAME jerry-ext)
project (${JERRY_EXT_NAME} C)
+# Optional features
+set(FEATURE_INIT_FINI OFF CACHE BOOL "Enable init/fini arrays?")
+
+# Status messages
+message(STATUS "FEATURE_INIT_FINI " ${FEATURE_INIT_FINI})
+
# Include directories
-set(INCLUDE_EXT "${CMAKE_CURRENT_SOURCE_DIR}/include")
+set(INCLUDE_EXT_PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
+set(INCLUDE_EXT_PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/common")
+
+set(INCLUDE_EXT_PUBLIC ${INCLUDE_EXT_PUBLIC} PARENT_SCOPE) # for jerry-port
if(FEATURE_INIT_FINI)
set(DEFINES_EXT ${DEFINES_EXT} ENABLE_INIT_FINI)
endif()
# Source directories
-file(GLOB SOURCE_EXT_ARG arg/*.c)
-file(GLOB SOURCE_EXT_MODULE module/*.c)
-file(GLOB SOURCE_EXT_HANDLER handler/*.c)
+file(GLOB SOURCE_EXT_ARG arg/*.c)
+file(GLOB SOURCE_EXT_COMMON common/*.c)
+file(GLOB SOURCE_EXT_DEBUGGER debugger/*.c)
+file(GLOB SOURCE_EXT_HANDLER handler/*.c)
+file(GLOB SOURCE_EXT_MODULE module/*.c)
set(SOURCE_EXT
${SOURCE_EXT_ARG}
- ${SOURCE_EXT_MODULE}
- ${SOURCE_EXT_HANDLER})
+ ${SOURCE_EXT_COMMON}
+ ${SOURCE_EXT_DEBUGGER}
+ ${SOURCE_EXT_HANDLER}
+ ${SOURCE_EXT_MODULE})
-add_library(${JERRY_EXT_NAME} STATIC ${SOURCE_EXT})
+add_library(${JERRY_EXT_NAME} ${SOURCE_EXT})
-target_include_directories(${JERRY_EXT_NAME} PUBLIC ${INCLUDE_EXT})
+target_include_directories(${JERRY_EXT_NAME} PUBLIC ${INCLUDE_EXT_PUBLIC})
+target_include_directories(${JERRY_EXT_NAME} PRIVATE ${INCLUDE_EXT_PRIVATE})
target_compile_definitions(${JERRY_EXT_NAME} PUBLIC ${DEFINES_EXT})
target_link_libraries(${JERRY_EXT_NAME} jerry-core)
install(TARGETS ${JERRY_EXT_NAME} DESTINATION lib)
-install(DIRECTORY ${INCLUDE_EXT}/ DESTINATION include)
+install(DIRECTORY ${INCLUDE_EXT_PUBLIC}/ DESTINATION include)
jerry_value_t to_number = jerry_value_to_number (js_arg);
- if (jerry_value_has_error_flag (to_number))
+ if (jerry_value_is_error (to_number))
{
jerry_release_value (to_number);
{ \
double tmp = 0.0; \
jerry_value_t rv = jerryx_arg_transform_number ## suffix ## _common (js_arg_iter_p, &tmp); \
- if (jerry_value_has_error_flag (rv)) \
+ if (jerry_value_is_error (rv)) \
{ \
return rv; \
} \
jerry_release_value (rv); \
jerryx_arg_int_option_t *options_p = (jerryx_arg_int_option_t *) &c_arg_p->extra_info; \
rv = jerryx_arg_helper_process_double (&tmp, min, max, *options_p); \
- if (jerry_value_has_error_flag (rv)) \
+ if (jerry_value_is_error (rv)) \
{ \
return rv; \
} \
jerry_value_t to_string = jerry_value_to_string (js_arg);
- if (jerry_value_has_error_flag (to_string))
+ if (jerry_value_is_error (to_string))
{
jerry_release_value (to_string);
.js_arg_idx = 0
};
- for (; c_arg_cnt != 0 && !jerry_value_has_error_flag (ret); c_arg_cnt--, c_arg_p++)
+ for (; c_arg_cnt != 0 && !jerry_value_is_error (ret); c_arg_cnt--, c_arg_p++)
{
ret = c_arg_p->func (&iterator, c_arg_p);
}
jerry_value_t ret = c_arg_p->func (&iterator, c_arg_p);
- if (jerry_value_has_error_flag (ret))
+ if (jerry_value_is_error (ret))
{
jerry_release_value (ret);
return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "Not an object.");
}
- jerry_value_t prop[name_cnt];
+ JERRY_VLA (jerry_value_t, prop, name_cnt);
for (jerry_length_t i = 0; i < name_cnt; i++, name_p++)
{
prop[i] = jerry_get_property (obj_val, name_str);
jerry_release_value (name_str);
- if (jerry_value_has_error_flag (prop[i]))
+ if (jerry_value_is_error (prop[i]))
{
for (jerry_length_t j = 0; j < i; j++)
{
return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "Not an array.");
}
- jerry_value_t arr[c_arg_cnt];
+ JERRY_VLA (jerry_value_t, arr, c_arg_cnt);
for (jerry_length_t i = 0; i < c_arg_cnt; i++)
{
arr[i] = jerry_get_property_by_index (array_val, i);
- if (jerry_value_has_error_flag (arr[i]))
+ if (jerry_value_is_error (arr[i]))
{
for (jerry_length_t j = 0; j < i; j++)
{
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef JEXT_COMMON_H
+#define JEXT_COMMON_H
+
+#include <stdio.h>
+#include <string.h>
+
+#include "jerryscript.h"
+#include "jerryscript-port.h"
+
+/*
+ * Make sure unused parameters, variables, or expressions trigger no compiler warning.
+ */
+#define JERRYX_UNUSED(x) ((void) (x))
+
+/*
+ * Asserts
+ *
+ * Warning:
+ * Don't use JERRY_STATIC_ASSERT in headers, because
+ * __LINE__ may be the same for asserts in a header
+ * and in an implementation file.
+ */
+#define JERRYX_STATIC_ASSERT_GLUE_(a, b, c) a ## b ## _ ## c
+#define JERRYX_STATIC_ASSERT_GLUE(a, b, c) JERRYX_STATIC_ASSERT_GLUE_ (a, b, c)
+#define JERRYX_STATIC_ASSERT(x, msg) \
+ enum { JERRYX_STATIC_ASSERT_GLUE (static_assertion_failed_, __LINE__, msg) = 1 / (!!(x)) }
+
+#ifndef JERRY_NDEBUG
+void JERRY_ATTR_NORETURN
+jerry_assert_fail (const char *assertion, const char *file, const char *function, const uint32_t line);
+void JERRY_ATTR_NORETURN
+jerry_unreachable (const char *file, const char *function, const uint32_t line);
+
+#define JERRYX_ASSERT(x) \
+ do \
+ { \
+ if (JERRY_UNLIKELY (!(x))) \
+ { \
+ jerry_assert_fail (#x, __FILE__, __func__, __LINE__); \
+ } \
+ } while (0)
+
+#define JERRYX_UNREACHABLE() \
+ do \
+ { \
+ jerry_unreachable (__FILE__, __func__, __LINE__); \
+ } while (0)
+#else /* JERRY_NDEBUG */
+#define JERRYX_ASSERT(x) \
+ do \
+ { \
+ if (false) \
+ { \
+ JERRYX_UNUSED (x); \
+ } \
+ } while (0)
+
+#ifdef __GNUC__
+#define JERRYX_UNREACHABLE() __builtin_unreachable ()
+#endif /* __GNUC__ */
+
+#ifdef _MSC_VER
+#define JERRYX_UNREACHABLE() _assume (0)
+#endif /* _MSC_VER */
+
+#ifndef JERRYX_UNREACHABLE
+#define JERRYX_UNREACHABLE()
+#endif /* !JERRYX_UNREACHABLE */
+
+#endif /* !JERRY_NDEBUG */
+
+/*
+ * Logging
+ */
+#define JERRYX_ERROR_MSG(...) jerry_port_log (JERRY_LOG_LEVEL_ERROR, __VA_ARGS__)
+#define JERRYX_WARNING_MSG(...) jerry_port_log (JERRY_LOG_LEVEL_WARNING, __VA_ARGS__)
+#define JERRYX_DEBUG_MSG(...) jerry_port_log (JERRY_LOG_LEVEL_DEBUG, __VA_ARGS__)
+#define JERRYX_TRACE_MSG(...) jerry_port_log (JERRY_LOG_LEVEL_TRACE, __VA_ARGS__)
+
+#endif /* !JEXT_COMMON_H */
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jerryscript-ext/debugger.h"
+#include "jext-common.h"
+
+/**
+ * Must be called after the connection has been initialized.
+ */
+void
+jerryx_debugger_after_connect (bool success) /**< tells whether the connection
+ * has been successfully established */
+{
+#ifdef JERRY_DEBUGGER
+ if (success)
+ {
+ jerry_debugger_transport_start ();
+ }
+ else
+ {
+ jerry_debugger_transport_close ();
+ }
+#else /* !JERRY_DEBUGGER */
+ JERRYX_UNUSED (success);
+#endif /* JERRY_DEBUGGER */
+} /* jerryx_debugger_after_connect */
--- /dev/null
+/* 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.
+ */
+
+/*
+ * FIPS-180-1 compliant SHA-1 implementation
+ *
+ * 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)
+ */
+
+/*
+ * The SHA-1 standard was published by NIST in 1993.
+ *
+ * http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ */
+
+#include "debugger-sha1.h"
+#include "jext-common.h"
+
+#ifdef JERRY_DEBUGGER
+
+/**
+ * SHA-1 context structure.
+ */
+typedef struct
+{
+ uint32_t total[2]; /**< number of bytes processed */
+ uint32_t state[5]; /**< intermediate digest state */
+ uint8_t buffer[64]; /**< data block being processed */
+} jerryx_sha1_context;
+
+/* 32-bit integer manipulation macros (big endian). */
+
+#define JERRYX_SHA1_GET_UINT32_BE(n, b, i) \
+{ \
+ (n) = (((uint32_t) (b)[(i) + 0]) << 24) \
+ | (((uint32_t) (b)[(i) + 1]) << 16) \
+ | (((uint32_t) (b)[(i) + 2]) << 8) \
+ | ((uint32_t) (b)[(i) + 3]); \
+}
+
+#define JERRYX_SHA1_PUT_UINT32_BE(n, b, i) \
+{ \
+ (b)[(i) + 0] = (uint8_t) ((n) >> 24); \
+ (b)[(i) + 1] = (uint8_t) ((n) >> 16); \
+ (b)[(i) + 2] = (uint8_t) ((n) >> 8); \
+ (b)[(i) + 3] = (uint8_t) ((n)); \
+}
+
+/**
+ * Initialize SHA-1 context.
+ */
+static void
+jerryx_sha1_init (jerryx_sha1_context *sha1_context_p) /**< SHA-1 context */
+{
+ memset (sha1_context_p, 0, sizeof (jerryx_sha1_context));
+
+ sha1_context_p->total[0] = 0;
+ sha1_context_p->total[1] = 0;
+
+ sha1_context_p->state[0] = 0x67452301;
+ sha1_context_p->state[1] = 0xEFCDAB89;
+ sha1_context_p->state[2] = 0x98BADCFE;
+ sha1_context_p->state[3] = 0x10325476;
+ sha1_context_p->state[4] = 0xC3D2E1F0;
+} /* jerryx_sha1_init */
+
+#define JERRYX_SHA1_P(a, b, c, d, e, x) \
+do { \
+ e += JERRYX_SHA1_SHIFT (a, 5) + JERRYX_SHA1_F (b, c, d) + K + x; \
+ b = JERRYX_SHA1_SHIFT (b, 30); \
+} while (0)
+
+/**
+ * Update SHA-1 internal buffer status.
+ */
+static void
+jerryx_sha1_process (jerryx_sha1_context *sha1_context_p, /**< SHA-1 context */
+ const uint8_t data[64]) /**< data buffer */
+{
+ uint32_t temp, W[16], A, B, C, D, E;
+
+ JERRYX_SHA1_GET_UINT32_BE (W[0], data, 0);
+ JERRYX_SHA1_GET_UINT32_BE (W[1], data, 4);
+ JERRYX_SHA1_GET_UINT32_BE (W[2], data, 8);
+ JERRYX_SHA1_GET_UINT32_BE (W[3], data, 12);
+ JERRYX_SHA1_GET_UINT32_BE (W[4], data, 16);
+ JERRYX_SHA1_GET_UINT32_BE (W[5], data, 20);
+ JERRYX_SHA1_GET_UINT32_BE (W[6], data, 24);
+ JERRYX_SHA1_GET_UINT32_BE (W[7], data, 28);
+ JERRYX_SHA1_GET_UINT32_BE (W[8], data, 32);
+ JERRYX_SHA1_GET_UINT32_BE (W[9], data, 36);
+ JERRYX_SHA1_GET_UINT32_BE (W[10], data, 40);
+ JERRYX_SHA1_GET_UINT32_BE (W[11], data, 44);
+ JERRYX_SHA1_GET_UINT32_BE (W[12], data, 48);
+ JERRYX_SHA1_GET_UINT32_BE (W[13], data, 52);
+ JERRYX_SHA1_GET_UINT32_BE (W[14], data, 56);
+ JERRYX_SHA1_GET_UINT32_BE (W[15], data, 60);
+
+#define JERRYX_SHA1_SHIFT(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define JERRYX_SHA1_R(t) \
+( \
+ temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ W[t & 0x0F], \
+ W[t & 0x0F] = JERRYX_SHA1_SHIFT (temp, 1) \
+)
+
+ A = sha1_context_p->state[0];
+ B = sha1_context_p->state[1];
+ C = sha1_context_p->state[2];
+ D = sha1_context_p->state[3];
+ E = sha1_context_p->state[4];
+
+ uint32_t K = 0x5A827999;
+
+#define JERRYX_SHA1_F(x, y, z) (z ^ (x & (y ^ z)))
+
+ JERRYX_SHA1_P (A, B, C, D, E, W[0]);
+ JERRYX_SHA1_P (E, A, B, C, D, W[1]);
+ JERRYX_SHA1_P (D, E, A, B, C, W[2]);
+ JERRYX_SHA1_P (C, D, E, A, B, W[3]);
+ JERRYX_SHA1_P (B, C, D, E, A, W[4]);
+ JERRYX_SHA1_P (A, B, C, D, E, W[5]);
+ JERRYX_SHA1_P (E, A, B, C, D, W[6]);
+ JERRYX_SHA1_P (D, E, A, B, C, W[7]);
+ JERRYX_SHA1_P (C, D, E, A, B, W[8]);
+ JERRYX_SHA1_P (B, C, D, E, A, W[9]);
+ JERRYX_SHA1_P (A, B, C, D, E, W[10]);
+ JERRYX_SHA1_P (E, A, B, C, D, W[11]);
+ JERRYX_SHA1_P (D, E, A, B, C, W[12]);
+ JERRYX_SHA1_P (C, D, E, A, B, W[13]);
+ JERRYX_SHA1_P (B, C, D, E, A, W[14]);
+ JERRYX_SHA1_P (A, B, C, D, E, W[15]);
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (16));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (17));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (18));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (19));
+
+#undef JERRYX_SHA1_F
+
+ K = 0x6ED9EBA1;
+
+#define JERRYX_SHA1_F(x, y, z) (x ^ y ^ z)
+
+ JERRYX_SHA1_P (A, B, C, D, E, JERRYX_SHA1_R (20));
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (21));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (22));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (23));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (24));
+ JERRYX_SHA1_P (A, B, C, D, E, JERRYX_SHA1_R (25));
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (26));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (27));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (28));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (29));
+ JERRYX_SHA1_P (A, B, C, D, E, JERRYX_SHA1_R (30));
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (31));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (32));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (33));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (34));
+ JERRYX_SHA1_P (A, B, C, D, E, JERRYX_SHA1_R (35));
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (36));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (37));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (38));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (39));
+
+#undef JERRYX_SHA1_F
+
+ K = 0x8F1BBCDC;
+
+#define JERRYX_SHA1_F(x, y, z) ((x & y) | (z & (x | y)))
+
+ JERRYX_SHA1_P (A, B, C, D, E, JERRYX_SHA1_R (40));
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (41));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (42));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (43));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (44));
+ JERRYX_SHA1_P (A, B, C, D, E, JERRYX_SHA1_R (45));
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (46));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (47));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (48));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (49));
+ JERRYX_SHA1_P (A, B, C, D, E, JERRYX_SHA1_R (50));
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (51));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (52));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (53));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (54));
+ JERRYX_SHA1_P (A, B, C, D, E, JERRYX_SHA1_R (55));
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (56));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (57));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (58));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (59));
+
+#undef JERRYX_SHA1_F
+
+ K = 0xCA62C1D6;
+
+#define JERRYX_SHA1_F(x, y, z) (x ^ y ^ z)
+
+ JERRYX_SHA1_P (A, B, C, D, E, JERRYX_SHA1_R (60));
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (61));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (62));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (63));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (64));
+ JERRYX_SHA1_P (A, B, C, D, E, JERRYX_SHA1_R (65));
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (66));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (67));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (68));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (69));
+ JERRYX_SHA1_P (A, B, C, D, E, JERRYX_SHA1_R (70));
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (71));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (72));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (73));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (74));
+ JERRYX_SHA1_P (A, B, C, D, E, JERRYX_SHA1_R (75));
+ JERRYX_SHA1_P (E, A, B, C, D, JERRYX_SHA1_R (76));
+ JERRYX_SHA1_P (D, E, A, B, C, JERRYX_SHA1_R (77));
+ JERRYX_SHA1_P (C, D, E, A, B, JERRYX_SHA1_R (78));
+ JERRYX_SHA1_P (B, C, D, E, A, JERRYX_SHA1_R (79));
+
+#undef JERRYX_SHA1_F
+
+ sha1_context_p->state[0] += A;
+ sha1_context_p->state[1] += B;
+ sha1_context_p->state[2] += C;
+ sha1_context_p->state[3] += D;
+ sha1_context_p->state[4] += E;
+
+#undef JERRYX_SHA1_SHIFT
+#undef JERRYX_SHA1_R
+} /* jerryx_sha1_process */
+
+#undef JERRYX_SHA1_P
+
+/**
+ * SHA-1 update buffer.
+ */
+static void
+jerryx_sha1_update (jerryx_sha1_context *sha1_context_p, /**< SHA-1 context */
+ const uint8_t *source_p, /**< source buffer */
+ size_t source_length) /**< length of source buffer */
+{
+ size_t fill;
+ uint32_t left;
+
+ if (source_length == 0)
+ {
+ return;
+ }
+
+ left = sha1_context_p->total[0] & 0x3F;
+ fill = 64 - left;
+
+ sha1_context_p->total[0] += (uint32_t) source_length;
+
+ /* Check overflow. */
+ if (sha1_context_p->total[0] < (uint32_t) source_length)
+ {
+ sha1_context_p->total[1]++;
+ }
+
+ if (left && source_length >= fill)
+ {
+ memcpy ((void *) (sha1_context_p->buffer + left), source_p, fill);
+ jerryx_sha1_process (sha1_context_p, sha1_context_p->buffer);
+ source_p += fill;
+ source_length -= fill;
+ left = 0;
+ }
+
+ while (source_length >= 64)
+ {
+ jerryx_sha1_process (sha1_context_p, source_p);
+ source_p += 64;
+ source_length -= 64;
+ }
+
+ if (source_length > 0)
+ {
+ memcpy ((void *) (sha1_context_p->buffer + left), source_p, source_length);
+ }
+} /* jerryx_sha1_update */
+
+/**
+ * SHA-1 final digest.
+ */
+static void
+jerryx_sha1_finish (jerryx_sha1_context *sha1_context_p, /**< SHA-1 context */
+ uint8_t destination_p[20]) /**< result */
+{
+ uint8_t buffer[16];
+
+ uint32_t high = (sha1_context_p->total[0] >> 29) | (sha1_context_p->total[1] << 3);
+ uint32_t low = (sha1_context_p->total[0] << 3);
+
+ uint32_t last = sha1_context_p->total[0] & 0x3F;
+ uint32_t padn = (last < 56) ? (56 - last) : (120 - last);
+
+ memset (buffer, 0, sizeof (buffer));
+ buffer[0] = 0x80;
+
+ while (padn > sizeof (buffer))
+ {
+ jerryx_sha1_update (sha1_context_p, buffer, sizeof (buffer));
+ buffer[0] = 0;
+ padn -= (uint32_t) sizeof (buffer);
+ }
+
+ jerryx_sha1_update (sha1_context_p, buffer, padn);
+
+ JERRYX_SHA1_PUT_UINT32_BE (high, buffer, 0);
+ JERRYX_SHA1_PUT_UINT32_BE (low, buffer, 4);
+
+ jerryx_sha1_update (sha1_context_p, buffer, 8);
+
+ JERRYX_SHA1_PUT_UINT32_BE (sha1_context_p->state[0], destination_p, 0);
+ JERRYX_SHA1_PUT_UINT32_BE (sha1_context_p->state[1], destination_p, 4);
+ JERRYX_SHA1_PUT_UINT32_BE (sha1_context_p->state[2], destination_p, 8);
+ JERRYX_SHA1_PUT_UINT32_BE (sha1_context_p->state[3], destination_p, 12);
+ JERRYX_SHA1_PUT_UINT32_BE (sha1_context_p->state[4], destination_p, 16);
+} /* jerryx_sha1_finish */
+
+#undef JERRYX_SHA1_GET_UINT32_BE
+#undef JERRYX_SHA1_PUT_UINT32_BE
+
+/**
+ * Computes the SHA-1 value of the combination of the two input buffers.
+ */
+void
+jerryx_debugger_compute_sha1 (const uint8_t *source1_p, /**< first part of the input */
+ size_t source1_length, /**< length of the first part */
+ const uint8_t *source2_p, /**< second part of the input */
+ size_t source2_length, /**< length of the second part */
+ uint8_t destination_p[20]) /**< result */
+{
+ jerryx_sha1_context sha1_context;
+
+ jerryx_sha1_init (&sha1_context);
+ jerryx_sha1_update (&sha1_context, source1_p, source1_length);
+ jerryx_sha1_update (&sha1_context, source2_p, source2_length);
+ jerryx_sha1_finish (&sha1_context, destination_p);
+} /* jerryx_debugger_compute_sha1 */
+
+#endif /* JERRY_DEBUGGER */
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DEBUGGER_SHA1_H
+#define DEBUGGER_SHA1_H
+
+#include "jerryscript-debugger-transport.h"
+
+#ifdef JERRY_DEBUGGER
+
+/* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */
+
+void jerryx_debugger_compute_sha1 (const uint8_t *input1, size_t input1_len,
+ const uint8_t *input2, size_t input2_len,
+ uint8_t output[20]);
+
+#endif /* JERRY_DEBUGGER */
+
+#endif /* !DEBUGGER_SHA1_H */
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jerryscript-debugger-transport.h"
+#include "jerryscript-ext/debugger.h"
+#include "jext-common.h"
+
+#ifdef JERRY_DEBUGGER
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+/**
+ * Implementation of transport over tcp/ip.
+ */
+typedef struct
+{
+ jerry_debugger_transport_header_t header; /**< transport header */
+ int tcp_socket; /**< tcp socket */
+} jerryx_debugger_transport_tcp_t;
+
+/**
+ * Log tcp error message.
+ */
+static void
+jerryx_debugger_tcp_log_error (int err_val)
+{
+ JERRYX_ERROR_MSG ("TCP Error: %s\n", strerror (err_val));
+} /* jerryx_debugger_tcp_log_error */
+
+/**
+ * Close a tcp connection.
+ */
+static void
+jerryx_debugger_tcp_close (jerry_debugger_transport_header_t *header_p) /**< tcp implementation */
+{
+ JERRYX_ASSERT (!jerry_debugger_transport_is_connected ());
+
+ jerryx_debugger_transport_tcp_t *tcp_p = (jerryx_debugger_transport_tcp_t *) header_p;
+
+ JERRYX_DEBUG_MSG ("TCP connection closed.\n");
+
+ close (tcp_p->tcp_socket);
+
+ jerry_heap_free ((void *) header_p, sizeof (jerryx_debugger_transport_tcp_t));
+} /* jerryx_debugger_tcp_close */
+
+/**
+ * Send data over a tcp connection.
+ *
+ * @return true - if the data has been sent successfully
+ * false - otherwise
+ */
+static bool
+jerryx_debugger_tcp_send (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */
+ uint8_t *message_p, /**< message to be sent */
+ size_t message_length) /**< message length in bytes */
+{
+ JERRYX_ASSERT (jerry_debugger_transport_is_connected ());
+
+ jerryx_debugger_transport_tcp_t *tcp_p = (jerryx_debugger_transport_tcp_t *) header_p;
+
+ do
+ {
+#ifdef __linux__
+ ssize_t is_err = recv (tcp_p->tcp_socket, NULL, 0, MSG_PEEK);
+
+ if (is_err == 0 && errno != EWOULDBLOCK)
+ {
+ int err_val = errno;
+ jerry_debugger_transport_close ();
+ jerryx_debugger_tcp_log_error (err_val);
+ return false;
+ }
+#endif /* __linux__ */
+
+ ssize_t sent_bytes = send (tcp_p->tcp_socket, message_p, message_length, 0);
+
+ if (sent_bytes < 0)
+ {
+ if (errno == EWOULDBLOCK)
+ {
+ continue;
+ }
+
+ int err_val = errno;
+ jerry_debugger_transport_close ();
+ jerryx_debugger_tcp_log_error (err_val);
+ return false;
+ }
+
+ message_p += sent_bytes;
+ message_length -= (size_t) sent_bytes;
+ }
+ while (message_length > 0);
+
+ return true;
+} /* jerryx_debugger_tcp_send */
+
+/**
+ * Receive data from a tcp connection.
+ */
+static bool
+jerryx_debugger_tcp_receive (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */
+ jerry_debugger_transport_receive_context_t *receive_context_p) /**< receive context */
+{
+ jerryx_debugger_transport_tcp_t *tcp_p = (jerryx_debugger_transport_tcp_t *) header_p;
+
+ uint8_t *buffer_p = receive_context_p->buffer_p + receive_context_p->received_length;
+ size_t buffer_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE - receive_context_p->received_length;
+
+ ssize_t length = recv (tcp_p->tcp_socket, buffer_p, buffer_size, 0);
+
+ if (length <= 0)
+ {
+ if (errno != EWOULDBLOCK || length == 0)
+ {
+ int err_val = errno;
+ jerry_debugger_transport_close ();
+ jerryx_debugger_tcp_log_error (err_val);
+ return false;
+ }
+ length = 0;
+ }
+
+ receive_context_p->received_length += (size_t) length;
+
+ if (receive_context_p->received_length > 0)
+ {
+ receive_context_p->message_p = receive_context_p->buffer_p;
+ receive_context_p->message_length = receive_context_p->received_length;
+ }
+
+ return true;
+} /* jerryx_debugger_tcp_receive */
+
+/**
+ * Create a tcp connection.
+ *
+ * @return true if successful,
+ * false otherwise
+ */
+bool
+jerryx_debugger_tcp_create (uint16_t port) /**< listening port */
+{
+ int server_socket;
+ struct sockaddr_in addr;
+ socklen_t sin_size = sizeof (struct sockaddr_in);
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons (port);
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ if ((server_socket = socket (AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ JERRYX_ERROR_MSG ("Error: %s\n", strerror (errno));
+ return false;
+ }
+
+ int opt_value = 1;
+
+ if (setsockopt (server_socket, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof (int)) == -1)
+ {
+ close (server_socket);
+ JERRYX_ERROR_MSG ("Error: %s\n", strerror (errno));
+ return false;
+ }
+
+ if (bind (server_socket, (struct sockaddr *)&addr, sizeof (struct sockaddr)) == -1)
+ {
+ close (server_socket);
+ JERRYX_ERROR_MSG ("Error: %s\n", strerror (errno));
+ return false;
+ }
+
+ if (listen (server_socket, 1) == -1)
+ {
+ close (server_socket);
+ JERRYX_ERROR_MSG ("Error: %s\n", strerror (errno));
+ return false;
+ }
+
+ JERRYX_DEBUG_MSG ("Waiting for client connection\n");
+
+ int tcp_socket = accept (server_socket, (struct sockaddr *)&addr, &sin_size);
+
+ close (server_socket);
+
+ if (tcp_socket == -1)
+ {
+ JERRYX_ERROR_MSG ("Error: %s\n", strerror (errno));
+ return false;
+ }
+
+ /* Set non-blocking mode. */
+ int socket_flags = fcntl (tcp_socket, F_GETFL, 0);
+
+ if (socket_flags < 0)
+ {
+ close (tcp_socket);
+ return false;
+ }
+
+ if (fcntl (tcp_socket, F_SETFL, socket_flags | O_NONBLOCK) == -1)
+ {
+ close (tcp_socket);
+ return false;
+ }
+
+ JERRYX_DEBUG_MSG ("Connected from: %s\n", inet_ntoa (addr.sin_addr));
+
+ size_t size = sizeof (jerryx_debugger_transport_tcp_t);
+
+ jerry_debugger_transport_header_t *header_p;
+ header_p = (jerry_debugger_transport_header_t *) jerry_heap_alloc (size);
+
+ if (!header_p)
+ {
+ close (tcp_socket);
+ return false;
+ }
+
+ header_p->close = jerryx_debugger_tcp_close;
+ header_p->send = jerryx_debugger_tcp_send;
+ header_p->receive = jerryx_debugger_tcp_receive;
+
+ ((jerryx_debugger_transport_tcp_t *) header_p)->tcp_socket = tcp_socket;
+
+ jerry_debugger_transport_add (header_p,
+ 0,
+ JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE,
+ 0,
+ JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE);
+
+ return true;
+} /* jerryx_debugger_tcp_create */
+
+#else /* !JERRY_DEBUGGER */
+
+/**
+ * Dummy function when debugger is disabled.
+ *
+ * @return false
+ */
+bool
+jerryx_debugger_tcp_create (uint16_t port)
+{
+ JERRYX_UNUSED (port);
+ return false;
+} /* jerryx_debugger_tcp_create */
+
+#endif /* JERRY_DEBUGGER */
--- /dev/null
+/* 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 "debugger-sha1.h"
+#include "jerryscript-ext/debugger.h"
+#include "jext-common.h"
+
+#ifdef JERRY_DEBUGGER
+
+/* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */
+
+/**
+ * Last fragment of a Websocket package.
+ */
+#define JERRYX_DEBUGGER_WEBSOCKET_FIN_BIT 0x80
+
+/**
+ * Masking-key is available.
+ */
+#define JERRYX_DEBUGGER_WEBSOCKET_MASK_BIT 0x80
+
+/**
+ * Opcode type mask.
+ */
+#define JERRYX_DEBUGGER_WEBSOCKET_OPCODE_MASK 0x0fu
+
+/**
+ * Packet length mask.
+ */
+#define JERRYX_DEBUGGER_WEBSOCKET_LENGTH_MASK 0x7fu
+
+/**
+ * Size of websocket header size.
+ */
+#define JERRYX_DEBUGGER_WEBSOCKET_HEADER_SIZE 2
+
+/**
+ * Payload mask size in bytes of a websocket package.
+ */
+#define JERRYX_DEBUGGER_WEBSOCKET_MASK_SIZE 4
+
+/**
+ * Maximum message size with 1 byte size field.
+ */
+#define JERRYX_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX 125
+
+/**
+ * WebSocket opcode types.
+ */
+typedef enum
+{
+ JERRYX_DEBUGGER_WEBSOCKET_TEXT_FRAME = 1, /**< text frame */
+ JERRYX_DEBUGGER_WEBSOCKET_BINARY_FRAME = 2, /**< binary frame */
+ JERRYX_DEBUGGER_WEBSOCKET_CLOSE_CONNECTION = 8, /**< close connection */
+ JERRYX_DEBUGGER_WEBSOCKET_PING = 9, /**< ping (keep alive) frame */
+ JERRYX_DEBUGGER_WEBSOCKET_PONG = 10, /**< reply to ping frame */
+} jerryx_websocket_opcode_type_t;
+
+/**
+ * Header for incoming packets.
+ */
+typedef struct
+{
+ uint8_t ws_opcode; /**< websocket opcode */
+ uint8_t size; /**< size of the message */
+ uint8_t mask[4]; /**< mask bytes */
+} jerryx_websocket_receive_header_t;
+
+/**
+ * Convert a 6-bit value to a Base64 character.
+ *
+ * @return Base64 character
+ */
+static uint8_t
+jerryx_to_base64_character (uint8_t value) /**< 6-bit value */
+{
+ if (value < 26)
+ {
+ return (uint8_t) (value + 'A');
+ }
+
+ if (value < 52)
+ {
+ return (uint8_t) (value - 26 + 'a');
+ }
+
+ if (value < 62)
+ {
+ return (uint8_t) (value - 52 + '0');
+ }
+
+ if (value == 62)
+ {
+ return (uint8_t) '+';
+ }
+
+ return (uint8_t) '/';
+} /* jerryx_to_base64_character */
+
+/**
+ * Encode a byte sequence into Base64 string.
+ */
+static void
+jerryx_to_base64 (const uint8_t *source_p, /**< source data */
+ uint8_t *destination_p, /**< destination buffer */
+ size_t length) /**< length of source, must be divisible by 3 */
+{
+ while (length >= 3)
+ {
+ uint8_t value = (source_p[0] >> 2);
+ destination_p[0] = jerryx_to_base64_character (value);
+
+ value = (uint8_t) (((source_p[0] << 4) | (source_p[1] >> 4)) & 0x3f);
+ destination_p[1] = jerryx_to_base64_character (value);
+
+ value = (uint8_t) (((source_p[1] << 2) | (source_p[2] >> 6)) & 0x3f);
+ destination_p[2] = jerryx_to_base64_character (value);
+
+ value = (uint8_t) (source_p[2] & 0x3f);
+ destination_p[3] = jerryx_to_base64_character (value);
+
+ source_p += 3;
+ destination_p += 4;
+ length -= 3;
+ }
+} /* jerryx_to_base64 */
+
+/**
+ * Process WebSocket handshake.
+ *
+ * @return true - if the handshake was completed successfully
+ * false - otherwise
+ */
+static bool
+jerryx_process_handshake (uint8_t *request_buffer_p) /**< temporary buffer */
+{
+ size_t request_buffer_size = 1024;
+ uint8_t *request_end_p = request_buffer_p;
+
+ /* Buffer request text until the double newlines are received. */
+ while (true)
+ {
+ jerry_debugger_transport_receive_context_t context;
+ if (!jerry_debugger_transport_receive (&context))
+ {
+ JERRYX_ASSERT (!jerry_debugger_transport_is_connected ());
+ return false;
+ }
+
+ if (context.message_p == NULL)
+ {
+ jerry_debugger_transport_sleep ();
+ continue;
+ }
+
+ size_t length = request_buffer_size - 1u - (size_t) (request_end_p - request_buffer_p);
+
+ if (length < context.message_length)
+ {
+ JERRYX_ERROR_MSG ("Handshake buffer too small.\n");
+ return false;
+ }
+
+ /* Both stream and datagram packets are supported. */
+ memcpy (request_end_p, context.message_p, context.message_length);
+
+ jerry_debugger_transport_receive_completed (&context);
+
+ request_end_p += (size_t) context.message_length;
+ *request_end_p = 0;
+
+ if (request_end_p > request_buffer_p + 4
+ && memcmp (request_end_p - 4, "\r\n\r\n", 4) == 0)
+ {
+ break;
+ }
+ }
+
+ /* Check protocol. */
+ const char get_text[] = "GET /jerry-debugger";
+ size_t text_len = sizeof (get_text) - 1;
+
+ if ((size_t) (request_end_p - request_buffer_p) < text_len
+ || memcmp (request_buffer_p, get_text, text_len) != 0)
+ {
+ JERRYX_ERROR_MSG ("Invalid handshake format.\n");
+ return false;
+ }
+
+ uint8_t *websocket_key_p = request_buffer_p + text_len;
+
+ const char key_text[] = "Sec-WebSocket-Key:";
+ text_len = sizeof (key_text) - 1;
+
+ while (true)
+ {
+ if ((size_t) (request_end_p - websocket_key_p) < text_len)
+ {
+ JERRYX_ERROR_MSG ("Sec-WebSocket-Key not found.\n");
+ return false;
+ }
+
+ if (websocket_key_p[0] == 'S'
+ && websocket_key_p[-1] == '\n'
+ && websocket_key_p[-2] == '\r'
+ && memcmp (websocket_key_p, key_text, text_len) == 0)
+ {
+ websocket_key_p += text_len;
+ break;
+ }
+
+ websocket_key_p++;
+ }
+
+ /* String terminated by double newlines. */
+
+ while (*websocket_key_p == ' ')
+ {
+ websocket_key_p++;
+ }
+
+ uint8_t *websocket_key_end_p = websocket_key_p;
+
+ while (*websocket_key_end_p > ' ')
+ {
+ websocket_key_end_p++;
+ }
+
+ /* Since the request_buffer_p is not needed anymore it can
+ * be reused for storing the SHA-1 key and Base64 string. */
+
+ const size_t sha1_length = 20;
+
+ jerryx_debugger_compute_sha1 (websocket_key_p,
+ (size_t) (websocket_key_end_p - websocket_key_p),
+ (const uint8_t *) "258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
+ 36,
+ request_buffer_p);
+
+ /* The SHA-1 key is 20 bytes long but jerryx_to_base64 expects
+ * a length divisible by 3 so an extra 0 is appended at the end. */
+ request_buffer_p[sha1_length] = 0;
+
+ jerryx_to_base64 (request_buffer_p, request_buffer_p + sha1_length + 1, sha1_length + 1);
+
+ /* Last value must be replaced by equal sign. */
+
+ const uint8_t response_prefix[] =
+ "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ";
+
+ if (!jerry_debugger_transport_send (response_prefix, sizeof (response_prefix) - 1)
+ || !jerry_debugger_transport_send (request_buffer_p + sha1_length + 1, 27))
+ {
+ return false;
+ }
+
+ const uint8_t response_suffix[] = "=\r\n\r\n";
+ return jerry_debugger_transport_send (response_suffix, sizeof (response_suffix) - 1);
+} /* jerryx_process_handshake */
+
+/**
+ * Close a tcp connection.
+ */
+static void
+jerryx_debugger_ws_close (jerry_debugger_transport_header_t *header_p) /**< tcp implementation */
+{
+ JERRYX_ASSERT (!jerry_debugger_transport_is_connected ());
+
+ jerry_heap_free ((void *) header_p, sizeof (jerry_debugger_transport_header_t));
+} /* jerryx_debugger_ws_close */
+
+/**
+ * Send data over a websocket connection.
+ *
+ * @return true - if the data has been sent successfully
+ * false - otherwise
+ */
+static bool
+jerryx_debugger_ws_send (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */
+ uint8_t *message_p, /**< message to be sent */
+ size_t message_length) /**< message length in bytes */
+{
+ JERRYX_ASSERT (message_length <= JERRYX_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX);
+
+ message_p[-2] = JERRYX_DEBUGGER_WEBSOCKET_FIN_BIT | JERRYX_DEBUGGER_WEBSOCKET_BINARY_FRAME;
+ message_p[-1] = (uint8_t) message_length;
+
+ return header_p->next_p->send (header_p->next_p, message_p - 2, message_length + 2);
+} /* jerryx_debugger_ws_send */
+
+/**
+ * Receive data from a websocket connection.
+ */
+static bool
+jerryx_debugger_ws_receive (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */
+ jerry_debugger_transport_receive_context_t *receive_context_p) /**< receive context */
+{
+ if (!header_p->next_p->receive (header_p->next_p, receive_context_p))
+ {
+ return false;
+ }
+
+ if (receive_context_p->message_p == NULL)
+ {
+ return true;
+ }
+
+ size_t message_total_length = receive_context_p->message_total_length;
+
+ if (message_total_length == 0)
+ {
+ /* Byte stream. */
+ if (receive_context_p->message_length < sizeof (jerryx_websocket_receive_header_t))
+ {
+ receive_context_p->message_p = NULL;
+ return true;
+ }
+ }
+ else
+ {
+ /* Datagram packet. */
+ JERRYX_ASSERT (receive_context_p->message_length >= sizeof (jerryx_websocket_receive_header_t));
+ }
+
+ uint8_t *message_p = receive_context_p->message_p;
+
+ if ((message_p[0] & ~JERRYX_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRYX_DEBUGGER_WEBSOCKET_FIN_BIT
+ || (message_p[1] & JERRYX_DEBUGGER_WEBSOCKET_LENGTH_MASK) > JERRYX_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX
+ || !(message_p[1] & JERRYX_DEBUGGER_WEBSOCKET_MASK_BIT))
+ {
+ JERRYX_ERROR_MSG ("Unsupported Websocket message.\n");
+ jerry_debugger_transport_close ();
+ return false;
+ }
+
+ if ((message_p[0] & JERRYX_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRYX_DEBUGGER_WEBSOCKET_BINARY_FRAME)
+ {
+ JERRYX_ERROR_MSG ("Unsupported Websocket opcode.\n");
+ jerry_debugger_transport_close ();
+ return false;
+ }
+
+ size_t message_length = (size_t) (message_p[1] & JERRYX_DEBUGGER_WEBSOCKET_LENGTH_MASK);
+
+ if (message_total_length == 0)
+ {
+ size_t new_total_length = message_length + sizeof (jerryx_websocket_receive_header_t);
+
+ /* Byte stream. */
+ if (receive_context_p->message_length < new_total_length)
+ {
+ receive_context_p->message_p = NULL;
+ return true;
+ }
+
+ receive_context_p->message_total_length = new_total_length;
+ }
+ else
+ {
+ /* Datagram packet. */
+ JERRYX_ASSERT (receive_context_p->message_length == (message_length + sizeof (jerryx_websocket_receive_header_t)));
+ }
+
+ message_p += sizeof (jerryx_websocket_receive_header_t);
+
+ receive_context_p->message_p = message_p;
+ receive_context_p->message_length = message_length;
+
+ /* Unmask data bytes. */
+ const uint8_t *mask_p = message_p - JERRYX_DEBUGGER_WEBSOCKET_MASK_SIZE;
+ const uint8_t *mask_end_p = message_p;
+ const uint8_t *message_end_p = message_p + message_length;
+
+ while (message_p < message_end_p)
+ {
+ /* Invert certain bits with xor operation. */
+ *message_p = *message_p ^ *mask_p;
+
+ message_p++;
+ mask_p++;
+
+ if (JERRY_UNLIKELY (mask_p >= mask_end_p))
+ {
+ mask_p -= JERRYX_DEBUGGER_WEBSOCKET_MASK_SIZE;
+ }
+ }
+
+ return true;
+} /* jerryx_debugger_ws_receive */
+
+/**
+ * Initialize the websocket transportation layer.
+ *
+ * @return true - if the connection succeeded
+ * false - otherwise
+ */
+bool
+jerryx_debugger_ws_create (void)
+{
+ bool is_handshake_ok = false;
+
+ const size_t buffer_size = 1024;
+ uint8_t *request_buffer_p = (uint8_t *) jerry_heap_alloc (buffer_size);
+
+ if (!request_buffer_p)
+ {
+ return false;
+ }
+
+ is_handshake_ok = jerryx_process_handshake (request_buffer_p);
+
+ jerry_heap_free ((void *) request_buffer_p, buffer_size);
+
+ if (!is_handshake_ok && jerry_debugger_transport_is_connected ())
+ {
+ return false;
+ }
+
+ const size_t interface_size = sizeof (jerry_debugger_transport_header_t);
+ jerry_debugger_transport_header_t *header_p;
+ header_p = (jerry_debugger_transport_header_t *) jerry_heap_alloc (interface_size);
+
+ if (!header_p)
+ {
+ return false;
+ }
+
+ header_p->close = jerryx_debugger_ws_close;
+ header_p->send = jerryx_debugger_ws_send;
+ header_p->receive = jerryx_debugger_ws_receive;
+
+ jerry_debugger_transport_add (header_p,
+ JERRYX_DEBUGGER_WEBSOCKET_HEADER_SIZE,
+ JERRYX_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX,
+ JERRYX_DEBUGGER_WEBSOCKET_HEADER_SIZE + JERRYX_DEBUGGER_WEBSOCKET_MASK_SIZE,
+ JERRYX_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX);
+
+ return true;
+} /* jerryx_debugger_ws_create */
+
+#else /* !JERRY_DEBUGGER */
+
+/**
+ * Dummy function when debugger is disabled.
+ *
+ * @return false
+ */
+bool
+jerryx_debugger_ws_create (void)
+{
+ return false;
+} /* jerryx_debugger_ws_create */
+
+#endif /* JERRY_DEBUGGER */
#include "jerryscript-port.h"
/**
- * Assert for scripts. The routine calls jerry_port_fatal on assertion failure.
+ * Hard assert for scripts. The routine calls jerry_port_fatal on assertion failure.
*
* @return true - if only one argument was passed and that argument was a boolean true.
* Note that the function does not return otherwise.
*/
jerry_value_t
-jerryx_handler_assert (const jerry_value_t func_obj_val, /**< function object */
- const jerry_value_t this_p, /**< this arg */
- const jerry_value_t args_p[], /**< function arguments */
- const jerry_length_t args_cnt) /**< number of function arguments */
+jerryx_handler_assert_fatal (const jerry_value_t func_obj_val, /**< function object */
+ const jerry_value_t this_p, /**< this arg */
+ const jerry_value_t args_p[], /**< function arguments */
+ const jerry_length_t args_cnt) /**< number of function arguments */
{
(void) func_obj_val; /* unused */
(void) this_p; /* unused */
{
return jerry_create_boolean (true);
}
- else
+
+ jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Script Error: assertion failed\n");
+ jerry_port_fatal (ERR_FAILED_INTERNAL_ASSERTION);
+} /* jerryx_handler_assert_fatal */
+
+/**
+ * Soft assert for scripts. The routine throws an error on assertion failure.
+ *
+ * @return true - if only one argument was passed and that argument was a boolean true.
+ * error - otherwise.
+ */
+jerry_value_t
+jerryx_handler_assert_throw (const jerry_value_t func_obj_val, /**< function object */
+ const jerry_value_t this_p, /**< this arg */
+ const jerry_value_t args_p[], /**< function arguments */
+ const jerry_length_t args_cnt) /**< number of function arguments */
+{
+ (void) func_obj_val; /* unused */
+ (void) this_p; /* unused */
+
+ if (args_cnt == 1
+ && jerry_value_is_boolean (args_p[0])
+ && jerry_get_boolean_value (args_p[0]))
{
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Script Error: assertion failed\n");
- jerry_port_fatal (ERR_FAILED_INTERNAL_ASSERTION);
+ return jerry_create_boolean (true);
}
+
+ return jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) "assertion failed");
+} /* jerryx_handler_assert_throw */
+
+/**
+ * An alias to `jerryx_handler_assert_fatal`.
+ *
+ * @return true - if only one argument was passed and that argument was a boolean true.
+ * Note that the function does not return otherwise.
+ */
+jerry_value_t
+jerryx_handler_assert (const jerry_value_t func_obj_val, /**< function object */
+ const jerry_value_t this_p, /**< this arg */
+ const jerry_value_t args_p[], /**< function arguments */
+ const jerry_length_t args_cnt) /**< number of function arguments */
+{
+ return jerryx_handler_assert_fatal (func_obj_val, this_p, args_p, args_cnt);
} /* jerryx_handler_assert */
{
(void) func_obj_val; /* unused */
(void) this_p; /* unused */
- (void) args_p; /* unused */
- (void) args_cnt; /* unused */
- jerry_gc ();
+ jerry_gc_mode_t mode = ((args_cnt > 0 && jerry_value_to_boolean (args_p[0])) ? JERRY_GC_SEVERITY_HIGH
+ : JERRY_GC_SEVERITY_LOW);
+
+ jerry_gc (mode);
return jerry_create_undefined ();
} /* jerryx_handler_gc */
*/
#include "jerryscript-ext/handler.h"
-#include "debugger.h"
+#include "jerryscript-debugger.h"
/**
* Provide a 'print' implementation for scripts.
(void) func_obj_val; /* unused */
(void) this_p; /* unused */
- static const char *null_str = "\\u0000";
+ const char * const null_str = "\\u0000";
jerry_value_t ret_val = jerry_create_undefined ();
- for (jerry_length_t arg_index = 0;
- jerry_value_is_undefined (ret_val) && arg_index < args_cnt;
- arg_index++)
+ for (jerry_length_t arg_index = 0; arg_index < args_cnt; arg_index++)
{
jerry_value_t str_val = jerry_value_to_string (args_p[arg_index]);
- if (!jerry_value_has_error_flag (str_val))
+ if (jerry_value_is_error (str_val))
{
- if (arg_index != 0)
+ /* There is no need to free the undefined value. */
+ ret_val = str_val;
+ break;
+ }
+
+ jerry_length_t length = jerry_get_utf8_string_length (str_val);
+ jerry_length_t substr_pos = 0;
+ jerry_char_t substr_buf[256];
+
+ do
+ {
+ jerry_size_t substr_size = jerry_substring_to_utf8_char_buffer (str_val,
+ substr_pos,
+ length,
+ substr_buf,
+ 256 - 1);
+
+ jerry_char_t *buf_end_p = substr_buf + substr_size;
+
+ /* Update start position by the number of utf-8 characters. */
+ for (jerry_char_t *buf_p = substr_buf; buf_p < buf_end_p; buf_p++)
{
- jerryx_port_handler_print_char (' ');
+ /* Skip intermediate utf-8 octets. */
+ if ((*buf_p & 0xc0) != 0x80)
+ {
+ substr_pos++;
+ }
}
- jerry_size_t substr_size;
- jerry_length_t substr_pos = 0;
- jerry_char_t substr_buf[256];
+ if (substr_pos == length)
+ {
+ *buf_end_p++ = (arg_index < args_cnt - 1) ? ' ' : '\n';
+ }
- while ((substr_size = jerry_substring_to_char_buffer (str_val,
- substr_pos,
- substr_pos + 256,
- substr_buf,
- 256)) != 0)
+ for (jerry_char_t *buf_p = substr_buf; buf_p < buf_end_p; buf_p++)
{
-#ifdef JERRY_DEBUGGER
- jerry_debugger_send_output (substr_buf, substr_size, JERRY_DEBUGGER_OUTPUT_OK);
-#endif /* JERRY_DEBUGGER */
- for (jerry_size_t chr_index = 0; chr_index < substr_size; chr_index++)
+ char chr = (char) *buf_p;
+
+ if (chr != '\0')
{
- char chr = (char) substr_buf[chr_index];
- if (chr == '\0')
- {
- for (jerry_size_t null_index = 0; null_str[null_index] != 0; null_index++)
- {
- jerryx_port_handler_print_char (null_str[null_index]);
- }
- }
- else
- {
- jerryx_port_handler_print_char (chr);
- }
+ jerryx_port_handler_print_char (chr);
+ continue;
}
- substr_pos += substr_size;
+ for (jerry_size_t null_index = 0; null_str[null_index] != '\0'; null_index++)
+ {
+ jerryx_port_handler_print_char (null_str[null_index]);
+ }
}
-
- jerry_release_value (str_val);
- }
- else
- {
- ret_val = str_val;
}
+ while (substr_pos < length);
+
+ jerry_release_value (str_val);
}
- jerryx_port_handler_print_char ('\n');
+ if (args_cnt == 0 || jerry_value_is_error (ret_val))
+ {
+ jerryx_port_handler_print_char ('\n');
+ }
return ret_val;
} /* jerryx_handler_print */
func = jerryx_arg_transform_ ## type; \
} \
} \
- const jerryx_arg_int_option_t int_option = { .round = round_flag, .clamp = clamp_flag }; \
+ const jerryx_arg_int_option_t int_option = { .round = (uint8_t) round_flag, .clamp = (uint8_t) clamp_flag }; \
return (jerryx_arg_t) \
{ \
.func = func, \
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef JERRYX_DEBUGGER_H
+#define JERRYX_DEBUGGER_H
+
+#include "jerryscript.h"
+#include "jerryscript-debugger-transport.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+void jerryx_debugger_after_connect (bool success);
+
+/*
+ * Message transmission interfaces.
+ */
+bool jerryx_debugger_tcp_create (uint16_t port);
+
+/*
+ * Message encoding interfaces.
+ */
+bool jerryx_debugger_ws_create (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* !JERRYX_HANDLER_H */
* Common external function handlers
*/
+jerry_value_t jerryx_handler_assert_fatal (const jerry_value_t func_obj_val, const jerry_value_t this_p,
+ const jerry_value_t args_p[], const jerry_length_t args_cnt);
+jerry_value_t jerryx_handler_assert_throw (const jerry_value_t func_obj_val, const jerry_value_t this_p,
+ const jerry_value_t args_p[], const jerry_length_t args_cnt);
jerry_value_t jerryx_handler_assert (const jerry_value_t func_obj_val, const jerry_value_t this_p,
const jerry_value_t args_p[], const jerry_length_t args_cnt);
jerry_value_t jerryx_handler_gc (const jerry_value_t func_obj_val, const jerry_value_t this_p,
const jerryx_module_resolver_t **resolvers,
size_t count);
+/**
+ * Delete a module from the cache or, if name has the JavaScript value of undefined, clear the entire cache.
+ */
+void jerryx_module_clear_cache (const jerry_value_t name,
+ const jerryx_module_resolver_t **resolvers,
+ size_t count);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
const jerry_value_t module_name) /**< the module name */
{
jerry_value_t ret = jerry_create_error (error_type, message);
+
+ jerry_value_t error_object = jerry_get_value_from_error (ret, false);
jerry_value_t property_name = jerry_create_string (module_name_property_name);
- jerry_release_value (jerry_set_property (ret, property_name, module_name));
+ jerry_release_value (jerry_set_property (error_object, property_name, module_name));
+
jerry_release_value (property_name);
+ jerry_release_value (error_object);
return ret;
} /* jerryx_module_create_error */
jerry_value_t js_has_property = jerry_has_property (cache, module_name);
/* If we succeed in getting an answer, we examine the answer. */
- if (!jerry_value_has_error_flag (js_has_property))
+ if (!jerry_value_is_error (js_has_property))
{
bool has_property = jerry_get_boolean_value (js_has_property);
/* If the module is indeed in the cache, we return it. */
if (has_property)
{
- (*result) = jerry_get_property (cache, module_name);
+ if (result != NULL)
+ {
+ (*result) = jerry_get_property (cache, module_name);
+ }
ret = true;
}
}
{
jerry_value_t ret = jerry_set_property (cache, module_name, module);
- if (jerry_value_has_error_flag (ret))
+ if (jerry_value_is_error (ret))
{
jerry_release_value (module);
}
const jerryx_native_module_t *module_p = NULL;
jerry_size_t name_size = jerry_get_utf8_string_size (canonical_name);
- jerry_char_t name_string[name_size];
+ JERRY_VLA (jerry_char_t, name_string, name_size);
jerry_string_to_utf8_char_buffer (canonical_name, name_string, name_size);
/* Look for the module by its name in the list of module definitions. */
.resolve_p = jerryx_resolve_native_module
};
-/**
- * Resolve a single module using the module resolvers available in the section declared above and load it into the
- * current context.
- *
- * @p name - name of the module to resolve
- * @p resolvers - list of resolvers to invoke
- * @p count - number of resolvers in the list
- *
- * @return a jerry_value_t containing one of the followings:
- * - the result of having loaded the module named @p name, or
- * - the result of a previous successful load, or
- * - an error indicating that something went wrong during the attempt to load the module.
- */
-jerry_value_t
-jerryx_module_resolve (const jerry_value_t name, /**< name of the module to load */
- const jerryx_module_resolver_t **resolvers_p, /**< list of resolvers */
- size_t resolver_count) /**< number of resolvers in @p resolvers */
+
+static void
+jerryx_module_resolve_local (const jerry_value_t name, /**< name of the module to load */
+ const jerryx_module_resolver_t **resolvers_p, /**< list of resolvers */
+ size_t resolver_count, /**< number of resolvers in @p resolvers */
+ jerry_value_t *result) /**< location to store the result, or NULL to remove the module */
{
size_t index;
size_t canonical_names_used = 0;
- jerry_value_t ret;
jerry_value_t instances;
- jerry_value_t canonical_names[resolver_count];
+ JERRY_VLA (jerry_value_t, canonical_names, resolver_count);
jerry_value_t (*get_canonical_name_p) (const jerry_value_t name);
bool (*resolve_p) (const jerry_value_t canonical_name,
jerry_value_t *result);
if (!jerry_value_is_string (name))
{
- ret = jerryx_module_create_error (JERRY_ERROR_COMMON, module_name_not_string, name);
+ if (result != NULL)
+ {
+ *result = jerryx_module_create_error (JERRY_ERROR_COMMON, module_name_not_string, name);
+ }
goto done;
}
canonical_names[index] = ((get_canonical_name_p == NULL) ? jerry_acquire_value (name)
: get_canonical_name_p (name));
canonical_names_used++;
- if (jerryx_module_check_cache (instances, canonical_names[index], &ret))
+ if (jerryx_module_check_cache (instances, canonical_names[index], result))
{
+ /* A NULL for result indicates that we are to delete the module from the cache if found. Let's do that here.*/
+ if (result == NULL)
+ {
+ jerry_delete_property (instances, canonical_names[index]);
+ }
goto done;
}
}
- /* Try each resolver until one manages to find the module. */
+ if (result == NULL)
+ {
+ goto done;
+ }
+
+ /**
+ * Past this point we assume a module is wanted, and therefore result is not NULL. So, we try each resolver until one
+ * manages to resolve the module.
+ */
for (index = 0; index < resolver_count; index++)
{
resolve_p = (resolvers_p[index] == NULL ? NULL : resolvers_p[index]->resolve_p);
- if (resolve_p != NULL && resolve_p (canonical_names[index], &ret))
+ if (resolve_p != NULL && resolve_p (canonical_names[index], result))
{
- if (!jerry_value_has_error_flag (ret))
+ if (!jerry_value_is_error (*result))
{
- ret = jerryx_module_add_to_cache (instances, canonical_names[index], ret);
+ *result = jerryx_module_add_to_cache (instances, canonical_names[index], *result);
}
goto done;
}
}
/* If none of the resolvers manage to find the module, complain with "Module not found" */
- ret = jerryx_module_create_error (JERRY_ERROR_COMMON, module_not_found, name);
+ *result = jerryx_module_create_error (JERRY_ERROR_COMMON, module_not_found, name);
done:
/* Release the canonical names as returned by the various resolvers. */
{
jerry_release_value (canonical_names[index]);
}
+} /* jerryx_module_resolve_local */
+
+/**
+ * Resolve a single module using the module resolvers available in the section declared above and load it into the
+ * current context.
+ *
+ * @p name - name of the module to resolve
+ * @p resolvers - list of resolvers to invoke
+ * @p count - number of resolvers in the list
+ *
+ * @return a jerry_value_t containing one of the followings:
+ * - the result of having loaded the module named @p name, or
+ * - the result of a previous successful load, or
+ * - an error indicating that something went wrong during the attempt to load the module.
+ */
+jerry_value_t
+jerryx_module_resolve (const jerry_value_t name, /**< name of the module to load */
+ const jerryx_module_resolver_t **resolvers_p, /**< list of resolvers */
+ size_t resolver_count) /**< number of resolvers in @p resolvers */
+{
+ /* Set to zero to circumvent fatal warning. */
+ jerry_value_t ret = 0;
+ jerryx_module_resolve_local (name, resolvers_p, resolver_count, &ret);
return ret;
} /* jerryx_module_resolve */
+
+void
+jerryx_module_clear_cache (const jerry_value_t name, /**< name of the module to remove, or undefined */
+ const jerryx_module_resolver_t **resolvers_p, /**< list of resolvers */
+ size_t resolver_count) /**< number of resolvers in @p resolvers */
+{
+ void *instances_p = jerry_get_context_data (&jerryx_module_manager);
+
+ if (jerry_value_is_undefined (name))
+ {
+ /* We were requested to clear the entire cache, so we bounce the context data in the most agnostic way possible. */
+ jerryx_module_manager.deinit_cb (instances_p);
+ jerryx_module_manager.init_cb (instances_p);
+ return;
+ }
+
+ /* Delete the requested module from the cache if it's there. */
+ jerryx_module_resolve_local (name, resolvers_p, resolver_count, NULL);
+} /* jerryx_module_clear_cache */
+++ /dev/null
-# 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.
-
-cmake_minimum_required (VERSION 2.8.12)
-set(JERRY_LIBC_NAME jerry-libc)
-project (${JERRY_LIBC_NAME} C ASM)
-
-# Checks the optional features
-# Enable init/fini arrays
-if(FEATURE_INIT_FINI)
- set(DEFINES_LIBC ${DEFINES_LIBC} ENABLE_INIT_FINI)
-endif()
-
-# Include directories
-set(INCLUDE_LIBC "${CMAKE_CURRENT_SOURCE_DIR}")
-
-# Sources
-file(GLOB SOURCE_LIBC *.c)
-
-# Platform-specific
-# Linux
-if(DEFINED PLATFORM AND ((PLATFORM STREQUAL "LINUX") OR (PLATFORM STREQUAL "DARWIN")))
- file(GLOB TARGET_SPECIFIC_LIBC_SOURCE target/posix/*.c target/posix/*.S)
-endif()
-
-add_library(${JERRY_LIBC_NAME} STATIC ${SOURCE_LIBC} ${TARGET_SPECIFIC_LIBC_SOURCE})
-
-target_compile_definitions(${JERRY_LIBC_NAME} PRIVATE ${DEFINES_LIBC})
-target_include_directories(${JERRY_LIBC_NAME} PRIVATE ${INCLUDE_LIBC})
-target_include_directories(${JERRY_LIBC_NAME} SYSTEM PUBLIC "${CMAKE_SOURCE_DIR}/jerry-libc/include")
-target_link_libraries(${JERRY_LIBC_NAME} -lgcc)
-
-install(TARGETS ${JERRY_LIBC_NAME} DESTINATION lib)
-install(DIRECTORY ${INCLUDE_LIBC}/include/ DESTINATION include/jerry-libc)
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ASM_ARM_H
-#define ASM_ARM_H
-
-/*
- * mov syscall_no (%r0) -> %r7
- * svc #0
- */
-#define SYSCALL_0 \
- push {r4-r12, lr}; \
- \
- mov r7, r0; \
- \
- svc #0; \
- \
- pop {r4-r12, pc};
-
-/*
- * mov syscall_no (%r0) -> %r7
- * mov arg1 (%r1) -> %r0
- * svc #0
- */
-#define SYSCALL_1 \
- push {r4-r12, lr}; \
- \
- mov r7, r0; \
- mov r0, r1; \
- \
- svc #0; \
- \
- pop {r4-r12, pc};
-
-/*
- * mov syscall_no (%r0) -> %r7
- * mov arg1 (%r1) -> %r0
- * mov arg2 (%r2) -> %r1
- * svc #0
- */
-#define SYSCALL_2 \
- push {r4-r12, lr}; \
- \
- mov r7, r0; \
- mov r0, r1; \
- mov r1, r2; \
- \
- svc #0; \
- \
- pop {r4-r12, pc};
-
-/*
- * mov syscall_no (%r0) -> %r7
- * mov arg1 (%r1) -> %r0
- * mov arg2 (%r2) -> %r1
- * mov arg3 (%r3) -> %r2
- * svc #0
- */
-#define SYSCALL_3 \
- push {r4-r12, lr}; \
- \
- mov r7, r0; \
- mov r0, r1; \
- mov r1, r2; \
- mov r2, r3; \
- \
- svc #0; \
- \
- pop {r4-r12, pc};
-
-#ifdef ENABLE_INIT_FINI
-/*
- * bl libc_init_array
- */
-#define _INIT \
- bl libc_init_array;
-#else /* !ENABLE_INIT_FINI */
-#define _INIT
-#endif /* ENABLE_INIT_FINI */
-
-/*
- * bl libc_init_array
- *
- * ldr argc ([sp + 0x0]) -> r0
- * add argv (sp + 0x4) -> r1
- * bl main
- *
- * bl exit
- *
- * infinite loop
- */
-#define _START \
- _INIT; \
- \
- ldr r0, [sp, #0]; \
- add r1, sp, #4; \
- bl main; \
- \
- bl exit; \
- 1: \
- b 1b;
-
-/**
- * If hard-float mode:
- * store s16-s31 vfp registers to buffer, pointed with r0 register,
- * and increase the register on size of stored data.
- */
-#if defined (__VFP_FP__) && !defined (__SOFTFP__)
-# define _STORE_VFP_S16_S31_IF_HARD_FLOAT \
- vstm r0!, {s16 - s31};
-# define _LOAD_VFP_S16_S31_IF_HARD_FLOAT \
- vldm r0!, {s16 - s31};
-#else /* !__VFP_FP__ || __SOFTFP__ */
-# define _STORE_VFP_S16_S31_IF_HARD_FLOAT
-# define _LOAD_VFP_S16_S31_IF_HARD_FLOAT
-#endif /* __VFP_FP__ && !__SOFTFP__ */
-
-/*
- * setjmp
- *
- * According to procedure call standard for the ARM architecture, the following
- * registers are callee-saved, and so need to be stored in context:
- * - r4 - r11
- * - sp
- * - s16 - s31
- *
- * Also, we should store:
- * - lr
- *
- * stmia {r4-r11, sp, lr} -> jmp_buf_0 (r0)!
- *
- * If hard-float build
- * vstm {s16-s31} -> jmp_buf_32 (r0)!
- *
- * mov r0, #0
- *
- * bx lr
- */
-#define _SETJMP \
- stmia r0!, {r4 - r11, sp, lr}; \
- \
- _STORE_VFP_S16_S31_IF_HARD_FLOAT \
- \
- mov r0, #0; \
- \
- bx lr;
-
-/*
- * longjmp
- *
- * See also:
- * _SETJMP
- *
- * ldmia jmp_buf_0 (r0)! -> {r4-r11, sp, lr}
- *
- * If hard-float build
- * vldm jmp_buf_32 (r0)! -> {s16-s31}
- *
- * mov r1 -> r0
- * cmp r0, #0
- * bne 1f
- * mov #1 -> r0
- * 1:
- *
- * bx lr
- */
-#define _LONGJMP \
- ldmia r0!, {r4 - r11, sp, lr}; \
- \
- _LOAD_VFP_S16_S31_IF_HARD_FLOAT \
- \
- mov r0, r1; \
- cmp r0, #0; \
- bne 1f; \
- mov r0, #1; \
- 1: \
- \
- bx lr;
-
-#endif /* !ASM_ARM_H */
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ASM_X86_H
-#define ASM_X86_H
-
-/*
- * mov syscall_no -> %eax
- * int $0x80
- * mov %eax -> ret
- */
-#define SYSCALL_0 \
- push %edi; \
- push %esi; \
- push %ebx; \
- mov 0x10 (%esp), %eax; \
- int $0x80; \
- pop %ebx; \
- pop %esi; \
- pop %edi; \
- ret;
-
-/*
- * mov syscall_no -> %eax
- * mov arg1 -> %ebx
- * int $0x80
- * mov %eax -> ret
- */
-#define SYSCALL_1 \
- push %edi; \
- push %esi; \
- push %ebx; \
- mov 0x10 (%esp), %eax; \
- mov 0x14 (%esp), %ebx; \
- int $0x80; \
- pop %ebx; \
- pop %esi; \
- pop %edi; \
- ret;
-
-/*
- * mov syscall_no -> %eax
- * mov arg1 -> %ebx
- * mov arg2 -> %ecx
- * int $0x80
- * mov %eax -> ret
- */
-#define SYSCALL_2 \
- push %edi; \
- push %esi; \
- push %ebx; \
- mov 0x10 (%esp), %eax; \
- mov 0x14 (%esp), %ebx; \
- mov 0x18 (%esp), %ecx; \
- int $0x80; \
- pop %ebx; \
- pop %esi; \
- pop %edi; \
- ret;
-
-/*
- * mov syscall_no -> %eax
- * mov arg1 -> %ebx
- * mov arg2 -> %ecx
- * mov arg3 -> %edx
- * int $0x80
- * mov %eax -> ret
- */
-#define SYSCALL_3 \
- push %edi; \
- push %esi; \
- push %ebx; \
- mov 0x10 (%esp), %eax; \
- mov 0x14 (%esp), %ebx; \
- mov 0x18 (%esp), %ecx; \
- mov 0x1c (%esp), %edx; \
- int $0x80; \
- pop %ebx; \
- pop %esi; \
- pop %edi; \
- ret;
-
-#ifdef ENABLE_INIT_FINI
-/*
- * call libc_init_array
- */
-#define _INIT \
- call libc_init_array;
-#else /* !ENABLE_INIT_FINI */
-#define _INIT
-#endif /* ENABLE_INIT_FINI */
-
-/*
- * call libc_init_array
- *
- * push argv (%esp + 4)
- * push argc ([%esp + 0x4])
- *
- * call main
- *
- * push main_ret (%eax)
- * call exit
- *
- * infinite loop
- */
-#define _START \
- _INIT; \
- \
- mov %esp, %eax; \
- add $4, %eax; \
- push %eax; \
- mov 0x4 (%esp), %eax; \
- push %eax; \
- \
- call main; \
- \
- push %eax; \
- call exit; \
- \
- 1: \
- jmp 1b;
-
-/*
- * setjmp
- *
- * According to x86_32 System V ABI, the following registers are
- * callee-saved, and so need to be stored in context:
- * - %ebx
- * - %esp
- * - %ebp
- * - %esi
- * - %edi
- * - x87 control word
- *
- * Also, we should store:
- * - return address (to jump to upon longjmp)
- *
- * mov return_address ([%esp]) -> %eax
- *
- * mov env ([%esp + 0x4]) -> %edx
- *
- * mov %ebx -> jmp_buf_0 ([%edx + 0x0])
- * mov %esp -> jmp_buf_4 ([%edx + 0x4])
- * mov %ebp -> jmp_buf_8 ([%edx + 0x8])
- * mov %esi -> jmp_buf_12 ([%edx + 0xc])
- * mov %edi -> jmp_buf_16 ([%edx + 0x10])
- * mov %eax -> jmp_buf_20 ([%edx + 0x14])
- * fnstcw -> jmp_buf_24 ([%edx + 0x18])
- *
- * ret
- */
-#define _SETJMP \
- mov (%esp), %eax; \
- mov 0x4 (%esp), %edx; \
- \
- mov %ebx, 0x00 (%edx); \
- mov %esp, 0x04 (%edx); \
- mov %ebp, 0x08 (%edx); \
- mov %esi, 0x0c (%edx); \
- mov %edi, 0x10 (%edx); \
- mov %eax, 0x14 (%edx); \
- fnstcw 0x18 (%edx); \
- \
- xor %eax, %eax; \
- \
- ret
-
-/*
- * longjmp
- *
- * See also:
- * _SETJMP
- *
- * mov env ([%esp + 0x4]) -> %edx
- * mov val ([%esp + 0x8]) -> %eax
- *
- * mov jmp_buf_0 ([%edx + 0x0]) -> %ebx
- * mov jmp_buf_4 ([%edx + 0x8]) -> %esp
- * mov jmp_buf_8 ([%edx + 0x10]) -> %ebp
- * mov jmp_buf_12 ([%edx + 0x18]) -> %esi
- * mov jmp_buf_16 ([%edx + 0x20]) -> %edi
- * mov jmp_buf_20 ([%edx + 0x28]) -> %ecx
- * fldcw jmp_buf_24 ([%edx + 0x30])
- *
- * mov return_address (%ecx) -> ([%esp])
- *
- * cmp (%eax), 0x0
- * jnz 1f
- * xor %eax, %eax
- * 1:
- *
- * ret
- */
-#define _LONGJMP \
- mov 0x4 (%esp), %edx; \
- mov 0x8 (%esp), %eax; \
- \
- mov 0x0 (%edx), %ebx; \
- mov 0x4 (%edx), %esp; \
- mov 0x8 (%edx), %ebp; \
- mov 0xc (%edx), %esi; \
- mov 0x10 (%edx), %edi; \
- mov 0x14 (%edx), %ecx; \
- fldcw 0x18 (%edx); \
- \
- mov %ecx, (%esp); \
- \
- test %eax, %eax; \
- jnz 1f; \
- xor %eax, %eax; \
- 1: \
- \
- ret
-
-#endif /* !ASM_X86_H */
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ASM_X64_H
-#define ASM_X64_H
-
-/*
- * mov syscall_no (%rdi) -> %rax
- * syscall
- */
-#define SYSCALL_0 \
- mov %rdi, %rax; \
- syscall; \
- ret;
-
-/*
- * mov syscall_no (%rdi) -> %rax
- * mov arg1 (%rsi) -> %rdi
- * syscall
- */
-#define SYSCALL_1 \
- mov %rdi, %rax; \
- mov %rsi, %rdi; \
- syscall; \
- ret;
-
-/*
- * mov syscall_no (%rdi) -> %rax
- * mov arg1 (%rsi) -> %rdi
- * mov arg2 (%rdx) -> %rsi
- * syscall
- */
-#define SYSCALL_2 \
- mov %rdi, %rax; \
- mov %rsi, %rdi; \
- mov %rdx, %rsi; \
- syscall; \
- ret;
-
-/*
- * mov syscall_no (%rdi) -> %rax
- * mov arg1 (%rsi) -> %rdi
- * mov arg2 (%rdx) -> %rsi
- * mov arg3 (%rcx) -> %rdx
- * syscall
- */
-#define SYSCALL_3 \
- mov %rdi, %rax; \
- mov %rsi, %rdi; \
- mov %rdx, %rsi; \
- mov %rcx, %rdx; \
- syscall; \
- ret;
-
-#ifdef ENABLE_INIT_FINI
-/*
- * call libc_init_array
- */
-#define _INIT \
- call libc_init_array;
-#else /* !ENABLE_INIT_FINI */
-#define _INIT
-#endif /* ENABLE_INIT_FINI */
-
-/*
- * call libc_init_array
- *
- * mov argc ([%rsp]) -> %rdi
- * mov argv (%rsp + 0x8) -> %rsi
- *
- * call main
- *
- * mov main_ret (%rax) -> %rdi
- * call exit
- *
- * infinite loop
- */
-#define _START \
- _INIT; \
- \
- mov (%rsp), %rdi; \
- mov %rsp, %rsi; \
- add $8, %rsi; \
- callq main; \
- \
- mov %rax, %rdi; \
- callq exit; \
- 1: \
- jmp 1b;
-
-/*
- * setjmp
- *
- * According to x86_64 System V ABI, the following registers are
- * callee-saved, and so need to be stored in context:
- * - %rbp
- * - %rbx
- * - %r12
- * - %r13
- * - %r14
- * - %r15
- * - x87 control word
- *
- * Also, we should store:
- * - %rsp (stack pointer)
- * - return address (to jump to upon longjmp)
- *
- * mov return_address ([%rsp]) -> %rax
- *
- * mov %rsp -> jmp_buf_0 ([%rdi + 0x0])
- * mov %rax -> jmp_buf_8 ([%rdi + 0x8])
- * mov %rbp -> jmp_buf_16 ([%rdi + 0x10])
- * mov %rbx -> jmp_buf_24 ([%rdi + 0x18])
- * mov %r12 -> jmp_buf_32 ([%rdi + 0x20])
- * mov %r13 -> jmp_buf_40 ([%rdi + 0x28])
- * mov %r14 -> jmp_buf_48 ([%rdi + 0x30])
- * mov %r15 -> jmp_buf_56 ([%rdi + 0x38])
- * fnstcw -> jmp_buf_64 ([%rdi + 0x40])
- *
- * ret
- */
-#define _SETJMP \
- mov (%rsp), %rax; \
- \
- mov %rsp, 0x00(%rdi); \
- mov %rax, 0x08(%rdi); \
- mov %rbp, 0x10(%rdi); \
- mov %rbx, 0x18(%rdi); \
- mov %r12, 0x20(%rdi); \
- mov %r13, 0x28(%rdi); \
- mov %r14, 0x30(%rdi); \
- mov %r15, 0x38(%rdi); \
- fnstcw 0x40(%rdi); \
- \
- xor %rax, %rax; \
- \
- ret;
-
-/*
- * longjmp
- *
- * See also:
- * _SETJMP
- *
- * mov jmp_buf_0 ([%rdi + 0x0]) -> %rsp
- * mov jmp_buf_8 ([%rdi + 0x8]) -> %rax
- * mov jmp_buf_16 ([%rdi + 0x10]) -> %rbp
- * mov jmp_buf_24 ([%rdi + 0x18]) -> %rbx
- * mov jmp_buf_32 ([%rdi + 0x20]) -> %r12
- * mov jmp_buf_40 ([%rdi + 0x28]) -> %r13
- * mov jmp_buf_48 ([%rdi + 0x30]) -> %r14
- * mov jmp_buf_56 ([%rdi + 0x38]) -> %r15
- * fldcw jmp_buf_64 ([%rdi + 0x40])
- *
- * mov return_address (%rax) -> ([%rsp])
- *
- * mov val (%rsi) -> %rax
- *
- * test (%rax), (%rax)
- * jnz 1f
- * mov $1, %rax
- * 1:
- *
- * ret
- */
-#define _LONGJMP \
- mov 0x00(%rdi), %rsp; \
- mov 0x08(%rdi), %rax; \
- mov 0x10(%rdi), %rbp; \
- mov 0x18(%rdi), %rbx; \
- mov 0x20(%rdi), %r12; \
- mov 0x28(%rdi), %r13; \
- mov 0x30(%rdi), %r14; \
- mov 0x38(%rdi), %r15; \
- fldcw 0x40(%rdi); \
- \
- mov %rax, (%rsp); \
- \
- mov %rsi, %rax; \
- \
- test %rax, %rax; \
- jnz 1f; \
- mov $1, %rax; \
- 1: \
- \
- ret
-
-
-
-#endif /* !ASM_X64_H */
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JERRY_LIBC_ASSERT_H
-#define JERRY_LIBC_ASSERT_H
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-#ifndef NDEBUG
-#define assert(x) \
- do \
- { \
- if (!(x)) \
- { \
- fprintf (stderr, "%s:%d: %s: Assertion `%s' failed.", __FILE__, __LINE__, __func__, #x); \
- abort (); \
- } \
- } while (0)
-#else /* NDEBUG */
-#define assert(x) ((void) 0)
-#endif /* !NDEBUG */
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* !JERRY_LIBC_ASSERT_H */
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JERRY_LIBC_SETJMP_H
-#define JERRY_LIBC_SETJMP_H
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-/**
- * Storage for context, used for nonlocal goto
- *
- * x86_64 (8 * 8 + 2 bytes):
- * 0x00 - %rsp
- * 0x08 - return address
- * 0x10 - %rbp
- * 0x18 - %rbx
- * 0x20 - %r12
- * 0x28 - %r13
- * 0x30 - %r14
- * 0x38 - %r15
- * 0x40 - x87 control word
- *
- * x86_32 (6 * 4 + 2 bytes):
- * - %ebx
- * - %esp
- * - %ebp
- * - %esi
- * - %edi
- * - return address (to jump to upon longjmp)
- * - x87 control word
- *
- * ARMv7 (10 * 4 + 16 * 4 bytes):
- * - r4 - r11, sp, lr
- * - s16 - s31 (if hardfp enabled)
- *
- * See also:
- * setjmp, longjmp
- */
-typedef uint64_t jmp_buf[14];
-
-int setjmp (jmp_buf env);
-void longjmp (jmp_buf env, int val);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* !JERRY_LIBC_SETJMP_H */
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JERRY_LIBC_STDIO_H
-#define JERRY_LIBC_STDIO_H
-
-#include <stdarg.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-/**
- * File descriptor type
- */
-typedef void FILE;
-
-/**
- * Standard file descriptors
- */
-extern FILE *stdin;
-extern FILE *stdout;
-extern FILE *stderr;
-
-/**
- * I/O routines
- */
-int vfprintf (FILE *stream, const char *format, va_list ap);
-FILE *fopen (const char *path, const char *mode);
-int fclose (FILE *fp);
-size_t fread (void *ptr, size_t size, size_t nmemb, FILE *stream);
-size_t fwrite (const void *ptr, size_t size, size_t nmemb, FILE *stream);
-int printf (const char *format, ...);
-int fprintf (FILE *stream, const char *format, ...);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* !JERRY_LIBC_STDIO_H */
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JERRY_LIBC_STDLIB_H
-#define JERRY_LIBC_STDLIB_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-/**
- * Maximum integer that could be returned by random number generator
- *
- * See also:
- * rand
- */
-#define RAND_MAX (0x7fffffffu)
-
-void __attribute__ ((noreturn)) exit (int);
-void __attribute__ ((noreturn)) abort (void);
-int rand (void);
-void srand (unsigned int);
-long int strtol (const char *, char **, int);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* !JERRY_LIBC_STDLIB_H */
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JERRY_LIBC_STRING_H
-#define JERRY_LIBC_STRING_H
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-void *memcpy (void *dest, const void *src, size_t n);
-void *memset (void *s, int c, size_t n);
-void *memmove (void *dest, const void *src, size_t n);
-int memcmp (const void *s1, const void *s2, size_t n);
-int strcmp (const char *s1, const char *s2);
-int strncmp (const char *s1, const char *s2, size_t n);
-char *strncpy (char *dest, const char *src, size_t n);
-size_t strlen (const char *s);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* !JERRY_LIBC_STRING_H */
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JERRY_LIBC_TIME_H
-#define JERRY_LIBC_TIME_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-/**
- * Time value structure
- */
-struct timeval
-{
- unsigned long tv_sec; /**< seconds */
- unsigned long tv_usec; /**< microseconds */
-};
-
-/**
- * Timezone structure
- */
-struct timezone
-{
- int tz_minuteswest; /**< minutes west of Greenwich */
- int tz_dsttime; /**< type of DST correction */
-};
-
-int gettimeofday (void *tp, void *tzp);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* !JERRY_LIBC_TIME_H */
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DEFS_H
-#define DEFS_H
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <stddef.h>
-
-/**
- * Attributes
- */
-#define __attr_unused___ __attribute__((unused))
-#define __attr_used___ __attribute__((used))
-#define __attr_noreturn___ __attribute__((noreturn))
-#define __attr_noinline___ __attribute__((noinline))
-#define __attr_weak___ __attribute__((weak))
-
-#ifdef ENABLE_INIT_FINI
-void libc_init_array (void);
-void libc_fini_array (void);
-#endif /* ENABLE_INIT_FINI */
-
-#endif /* !DEFS_H */
+++ /dev/null
-/* 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.
- *
- * This file is based on work under the following copyright and permission
- * notice:
- *
- * Copyright (C) 2004 CodeSourcery, LLC
- *
- * Permission to use, copy, modify, and distribute this file
- * for any purpose is hereby granted without fee, provided that
- * the above copyright notice and this notice appears in all
- * copies.
- *
- * This file is distributed WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#include "jerry-libc-defs.h"
-
-#ifdef ENABLE_INIT_FINI
-
-/* These magic symbols are provided by the linker. */
-typedef void (*libc_init_fn_t) (void);
-
-extern libc_init_fn_t __preinit_array_start[] __attr_weak___;
-extern libc_init_fn_t __preinit_array_end[] __attr_weak___;
-extern libc_init_fn_t __init_array_start[] __attr_weak___;
-extern libc_init_fn_t __init_array_end[] __attr_weak___;
-extern libc_init_fn_t __fini_array_start[] __attr_weak___;
-extern libc_init_fn_t __fini_array_end[] __attr_weak___;
-extern void _init (void);
-extern void _fini (void);
-
-
-/**
- * No-op default _init.
- */
-void __attr_weak___
-_init (void)
-{
-} /* _init */
-
-/**
- * No-op default _fini.
- */
-void __attr_weak___
-_fini (void)
-{
-} /* _fini */
-
-/**
- * Iterate over all the init routines.
- */
-void
-libc_init_array (void)
-{
- size_t count = (size_t) (__preinit_array_end - __preinit_array_start);
- for (size_t i = 0; i < count; i++)
- {
- __preinit_array_start[i] ();
- }
-
- _init ();
-
- count = (size_t) (__init_array_end - __init_array_start);
- for (size_t i = 0; i < count; i++)
- {
- __init_array_start[i] ();
- }
-} /* libc_init_array */
-
-/**
- * Run all the cleanup routines.
- */
-void
-libc_fini_array (void)
-{
- size_t count = (size_t) (__fini_array_end - __fini_array_start);
- for (size_t i = count; i > 0; i--)
- {
- __fini_array_start[i - 1] ();
- }
-
- _fini ();
-} /* libc_fini_array */
-
-#endif /* ENABLE_INIT_FINI */
+++ /dev/null
-/* 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.
- */
-
-/**
- * Jerry printf implementation
- */
-
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "jerry-libc-defs.h"
-
-/**
- * printf's length type
- */
-typedef enum
-{
- LIBC_PRINTF_ARG_LENGTH_TYPE_NONE, /**< (none) */
- LIBC_PRINTF_ARG_LENGTH_TYPE_HH, /**< hh */
- LIBC_PRINTF_ARG_LENGTH_TYPE_H, /**< h */
- LIBC_PRINTF_ARG_LENGTH_TYPE_L, /**< l */
- LIBC_PRINTF_ARG_LENGTH_TYPE_LL, /**< ll */
- LIBC_PRINTF_ARG_LENGTH_TYPE_J, /**< j */
- LIBC_PRINTF_ARG_LENGTH_TYPE_Z, /**< z */
- LIBC_PRINTF_ARG_LENGTH_TYPE_T, /**< t */
- LIBC_PRINTF_ARG_LENGTH_TYPE_HIGHL /**< L */
-} libc_printf_arg_length_type_t;
-
-/**
- * printf's flags mask
- */
-typedef uint8_t libc_printf_arg_flags_mask_t;
-
-/**
- * Left justification of field's contents
- */
-#define LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY (1 << 0)
-
-/**
- * Force print of number's sign
- */
-#define LIBC_PRINTF_ARG_FLAG_PRINT_SIGN (1 << 1)
-
-/**
- * If no sign is printed, print space before value
- */
-#define LIBC_PRINTF_ARG_FLAG_SPACE (1 << 2)
-
-/**
- * For o, x, X preceed value with 0, 0x or 0X for non-zero values.
- */
-#define LIBC_PRINTF_ARG_FLAG_SHARP (1 << 3)
-
-/**
- * Left-pad field with zeroes instead of spaces
- */
-#define LIBC_PRINTF_ARG_FLAG_ZERO_PADDING (1 << 4)
-
-/**
- * printf helper function that outputs a char
- */
-static void
-libc_printf_putchar (FILE *stream, /**< stream pointer */
- char character) /**< character */
-{
- fwrite (&character, 1, sizeof (character), stream);
-} /* libc_printf_putchar */
-
-/**
- * printf helper function that outputs justified string
- */
-static void
-libc_printf_justified_string_output (FILE *stream, /**< stream pointer */
- const char *string_p, /**< string */
- size_t width, /**< minimum field width */
- bool is_left_justify, /**< justify to left (true) or right (false) */
- bool is_zero_padding) /**< left-pad with zeroes (true) or spaces (false) */
-{
- const size_t str_length = strlen (string_p);
-
- size_t outputted_length = 0;
-
- if (!is_left_justify)
- {
- char padding_char = is_zero_padding ? '0' : ' ';
-
- while (outputted_length + str_length < width)
- {
- libc_printf_putchar (stream, padding_char);
- outputted_length++;
- }
- }
-
- fwrite (string_p, 1, str_length * sizeof (*string_p), stream);
- outputted_length += str_length;
-
- if (is_left_justify)
- {
- while (outputted_length < width)
- {
- libc_printf_putchar (stream, ' ');
- outputted_length++;
- }
- }
-} /* libc_printf_justified_string_output */
-
-/**
- * printf helper function that converts unsigned integer to string
- *
- * @return start of the string representation (within the output string buffer
- * but not necessarily at its start)
- */
-static char *
-libc_printf_uint_to_string (uintmax_t value, /**< integer value */
- char *buffer_p, /**< buffer for output string */
- size_t buffer_size, /**< buffer size */
- const char *alphabet, /**< alphabet used for digits */
- uint32_t radix) /**< radix */
-{
- char *str_buffer_end = buffer_p + buffer_size;
- char *str_p = str_buffer_end;
- *--str_p = '\0';
-
- assert (radix >= 2);
-
- if ((radix & (radix - 1)) != 0)
- {
- /*
- * Radix is not power of 2. Only 32-bit numbers are supported in this mode.
- */
- assert ((value >> 32) == 0);
-
- uint32_t value_lo = (uint32_t) value;
-
- while (value_lo != 0)
- {
- assert (str_p != buffer_p);
-
- *--str_p = alphabet[ value_lo % radix ];
- value_lo /= radix;
- }
- }
- else
- {
- uint32_t shift = 0;
- while (!(radix & (1u << shift)))
- {
- shift++;
-
- assert (shift <= 32);
- }
-
- uint32_t value_lo = (uint32_t) value;
- uint32_t value_hi = (uint32_t) (value >> 32);
-
- while (value_lo != 0
- || value_hi != 0)
- {
- assert (str_p != buffer_p);
-
- *--str_p = alphabet[ value_lo & (radix - 1) ];
- value_lo >>= shift;
- value_lo += (value_hi & (radix - 1)) << (32 - shift);
- value_hi >>= shift;
- }
- }
-
- if (*str_p == '\0')
- {
- *--str_p = '0';
- }
-
- assert (str_p >= buffer_p && str_p < str_buffer_end);
-
- return str_p;
-} /* libc_printf_uint_to_string */
-
-/**
- * printf helper function that prints d and i arguments
- *
- * @return updated va_list
- */
-static void
-libc_printf_write_d_i (FILE *stream, /**< stream pointer */
- va_list *args_list_p, /**< args' list */
- libc_printf_arg_flags_mask_t flags, /**< field's flags */
- libc_printf_arg_length_type_t length, /**< field's length type */
- uint32_t width) /**< minimum field width to output */
-{
- assert ((flags & LIBC_PRINTF_ARG_FLAG_SHARP) == 0);
-
- bool is_signed = true;
- uintmax_t value = 0;
-
- /* true - positive, false - negative */
- bool sign = true;
- const size_t bits_in_byte = 8;
- const uintmax_t value_sign_mask = ((uintmax_t) 1) << (sizeof (value) * bits_in_byte - 1);
-
- switch (length)
- {
- case LIBC_PRINTF_ARG_LENGTH_TYPE_NONE:
- case LIBC_PRINTF_ARG_LENGTH_TYPE_HH: /* char is promoted to int */
- case LIBC_PRINTF_ARG_LENGTH_TYPE_H: /* short int is promoted to int */
- {
- value = (uintmax_t) va_arg (*args_list_p, int);
- break;
- }
-
- case LIBC_PRINTF_ARG_LENGTH_TYPE_L:
- {
- value = (uintmax_t) va_arg (*args_list_p, long int);
- break;
- }
-
- case LIBC_PRINTF_ARG_LENGTH_TYPE_LL:
- {
- value = (uintmax_t) va_arg (*args_list_p, long long int);
- break;
- }
-
- case LIBC_PRINTF_ARG_LENGTH_TYPE_J:
- {
- value = (uintmax_t) va_arg (*args_list_p, intmax_t);
- break;
- }
-
- case LIBC_PRINTF_ARG_LENGTH_TYPE_Z:
- {
- is_signed = false;
- value = (uintmax_t) va_arg (*args_list_p, size_t);
- break;
- }
-
- case LIBC_PRINTF_ARG_LENGTH_TYPE_T:
- {
- is_signed = false;
- value = (uintmax_t) va_arg (*args_list_p, ptrdiff_t);
- break;
- }
-
- case LIBC_PRINTF_ARG_LENGTH_TYPE_HIGHL:
- {
- assert (false && "unsupported length field L");
- }
- }
-
- if (is_signed)
- {
- sign = ((value & value_sign_mask) == 0);
-
- if (!sign)
- {
- value = (uintmax_t) (-value);
- }
- }
-
- char str_buffer[ 32 ];
- char *string_p = libc_printf_uint_to_string (value,
- str_buffer,
- sizeof (str_buffer),
- "0123456789",
- 10);
-
- if (!sign
- || (flags & LIBC_PRINTF_ARG_FLAG_PRINT_SIGN))
- {
- assert (string_p > str_buffer);
- *--string_p = (sign ? '+' : '-');
- }
- else if (flags & LIBC_PRINTF_ARG_FLAG_SPACE)
- {
- /* no sign and space flag, printing one space */
-
- libc_printf_putchar (stream, ' ');
- if (width > 0)
- {
- width--;
- }
- }
-
- libc_printf_justified_string_output (stream,
- string_p,
- width,
- flags & LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY,
- flags & LIBC_PRINTF_ARG_FLAG_ZERO_PADDING);
-} /* libc_printf_write_d_i */
-
-/**
- * printf helper function that prints d and i arguments
- *
- * @return updated va_list
- */
-static void
-libc_printf_write_u_o_x_X (FILE *stream, /**< stream pointer */
- char specifier, /**< specifier (u, o, x, X) */
- va_list *args_list_p, /**< args' list */
- libc_printf_arg_flags_mask_t flags, /**< field's flags */
- libc_printf_arg_length_type_t length, /**< field's length type */
- uint32_t width) /**< minimum field width to output */
-{
- uintmax_t value;
-
- switch (length)
- {
- case LIBC_PRINTF_ARG_LENGTH_TYPE_NONE:
- case LIBC_PRINTF_ARG_LENGTH_TYPE_HH: /* char is promoted to int */
- case LIBC_PRINTF_ARG_LENGTH_TYPE_H: /* short int is promoted to int */
- {
- value = (uintmax_t) va_arg (*args_list_p, unsigned int);
- break;
- }
-
- case LIBC_PRINTF_ARG_LENGTH_TYPE_L:
- {
- value = (uintmax_t) va_arg (*args_list_p, unsigned long int);
- break;
- }
-
- case LIBC_PRINTF_ARG_LENGTH_TYPE_LL:
- {
- value = (uintmax_t) va_arg (*args_list_p, unsigned long long int);
- break;
- }
-
- case LIBC_PRINTF_ARG_LENGTH_TYPE_J:
- {
- value = (uintmax_t) va_arg (*args_list_p, uintmax_t);
- break;
- }
-
- case LIBC_PRINTF_ARG_LENGTH_TYPE_Z:
- {
- value = (uintmax_t) va_arg (*args_list_p, size_t);
- break;
- }
-
- case LIBC_PRINTF_ARG_LENGTH_TYPE_T:
- {
- value = (uintmax_t) va_arg (*args_list_p, ptrdiff_t);
- break;
- }
-
- case LIBC_PRINTF_ARG_LENGTH_TYPE_HIGHL:
- {
- assert (false && "unsupported length field L");
- return;
- }
-
- default:
- {
- assert (false && "unexpected length field");
- return;
- }
- }
-
- if (flags & LIBC_PRINTF_ARG_FLAG_SHARP)
- {
- if (value != 0 && specifier != 'u')
- {
- libc_printf_putchar (stream, '0');
-
- if (specifier == 'x')
- {
- libc_printf_putchar (stream, 'x');
- }
- else if (specifier == 'X')
- {
- libc_printf_putchar (stream, 'X');
- }
- else
- {
- assert (specifier == 'o');
- }
- }
- }
-
- uint32_t radix;
- const char *alphabet;
-
- switch (specifier)
- {
- case 'u':
- {
- alphabet = "0123456789";
- radix = 10;
- break;
- }
-
- case 'o':
- {
- alphabet = "01234567";
- radix = 8;
- break;
- }
-
- case 'x':
- {
- alphabet = "0123456789abcdef";
- radix = 16;
- break;
- }
-
- case 'X':
- {
- alphabet = "0123456789ABCDEF";
- radix = 16;
- break;
- }
-
- default:
- {
- assert (false && "unexpected type field");
- return;
- }
- }
-
- char str_buffer[ 32 ];
- const char *string_p = libc_printf_uint_to_string (value,
- str_buffer,
- sizeof (str_buffer),
- alphabet,
- radix);
-
- if (flags & LIBC_PRINTF_ARG_FLAG_PRINT_SIGN)
- {
- /* printing sign */
-
- libc_printf_putchar (stream, '+');
- if (width > 0)
- {
- width--;
- }
- }
- else if (flags & LIBC_PRINTF_ARG_FLAG_SPACE)
- {
- /* no sign and space flag, printing one space */
-
- libc_printf_putchar (stream, ' ');
- if (width > 0)
- {
- width--;
- }
- }
-
- libc_printf_justified_string_output (stream,
- string_p,
- width,
- flags & LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY,
- flags & LIBC_PRINTF_ARG_FLAG_ZERO_PADDING);
-} /* libc_printf_write_u_o_x_X */
-
-/**
- * vfprintf
- *
- * @return number of characters printed
- */
-int __attr_weak___
-vfprintf (FILE *stream, /**< stream pointer */
- const char *format, /**< format string */
- va_list args) /**< arguments */
-{
- va_list args_copy;
-
- va_copy (args_copy, args);
-
- const char *format_iter_p = format;
-
- while (*format_iter_p)
- {
- if (*format_iter_p != '%')
- {
- libc_printf_putchar (stream, *format_iter_p);
- }
- else
- {
- libc_printf_arg_flags_mask_t flags = 0;
- uint32_t width = 0;
- libc_printf_arg_length_type_t length = LIBC_PRINTF_ARG_LENGTH_TYPE_NONE;
-
- while (true)
- {
- format_iter_p++;
-
- if (*format_iter_p == '-')
- {
- flags |= LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY;
- }
- else if (*format_iter_p == '+')
- {
- flags |= LIBC_PRINTF_ARG_FLAG_PRINT_SIGN;
- }
- else if (*format_iter_p == ' ')
- {
- flags |= LIBC_PRINTF_ARG_FLAG_SPACE;
- }
- else if (*format_iter_p == '#')
- {
- flags |= LIBC_PRINTF_ARG_FLAG_SHARP;
- }
- else if (*format_iter_p == '0')
- {
- flags |= LIBC_PRINTF_ARG_FLAG_ZERO_PADDING;
- }
- else
- {
- break;
- }
- }
-
- if (*format_iter_p == '*')
- {
- assert (false && "unsupported width field *");
- }
-
- /* If there is a number, recognize it as field width. */
- while (*format_iter_p >= '0' && *format_iter_p <= '9')
- {
- width = width * 10u + (uint32_t) (*format_iter_p - '0');
-
- format_iter_p++;
- }
-
- if (*format_iter_p == '.')
- {
- assert (false && "unsupported precision field");
- }
-
- switch (*format_iter_p)
- {
- case 'h':
- {
- format_iter_p++;
- if (*format_iter_p == 'h')
- {
- format_iter_p++;
-
- length = LIBC_PRINTF_ARG_LENGTH_TYPE_HH;
- }
- else
- {
- length = LIBC_PRINTF_ARG_LENGTH_TYPE_H;
- }
- break;
- }
-
- case 'l':
- {
- format_iter_p++;
- if (*format_iter_p == 'l')
- {
- format_iter_p++;
-
- length = LIBC_PRINTF_ARG_LENGTH_TYPE_LL;
- }
- else
- {
- length = LIBC_PRINTF_ARG_LENGTH_TYPE_L;
- }
- break;
- }
-
- case 'j':
- {
- format_iter_p++;
- length = LIBC_PRINTF_ARG_LENGTH_TYPE_J;
- break;
- }
-
- case 'z':
- {
- format_iter_p++;
- length = LIBC_PRINTF_ARG_LENGTH_TYPE_Z;
- break;
- }
-
- case 't':
- {
- format_iter_p++;
- length = LIBC_PRINTF_ARG_LENGTH_TYPE_T;
- break;
- }
-
- case 'L':
- {
- format_iter_p++;
- length = LIBC_PRINTF_ARG_LENGTH_TYPE_HIGHL;
- break;
- }
- }
-
- switch (*format_iter_p)
- {
- case 'd':
- case 'i':
- {
- libc_printf_write_d_i (stream, &args_copy, flags, length, width);
- break;
- }
-
- case 'u':
- case 'o':
- case 'x':
- case 'X':
- {
- libc_printf_write_u_o_x_X (stream, *format_iter_p, &args_copy, flags, length, width);
- break;
- }
-
- case 'f':
- case 'F':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- case 'a':
- case 'A':
- {
- assert (false && "unsupported double type field");
- break;
- }
-
- case 'c':
- {
- if (length & LIBC_PRINTF_ARG_LENGTH_TYPE_L)
- {
- assert (false && "unsupported length field L");
- }
- else
- {
- char str[2] =
- {
- (char) va_arg (args_copy, int), /* char is promoted to int */
- '\0'
- };
-
- libc_printf_justified_string_output (stream,
- str,
- width,
- flags & LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY,
- flags & LIBC_PRINTF_ARG_FLAG_ZERO_PADDING);
- }
- break;
- }
-
- case 's':
- {
- if (length & LIBC_PRINTF_ARG_LENGTH_TYPE_L)
- {
- assert (false && "unsupported length field L");
- }
- else
- {
- char *str_p = va_arg (args_copy, char *);
-
- libc_printf_justified_string_output (stream,
- str_p,
- width,
- flags & LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY,
- flags & LIBC_PRINTF_ARG_FLAG_ZERO_PADDING);
- }
- break;
- }
-
- case 'p':
- {
- va_list args_copy2;
- va_copy (args_copy2, args_copy);
- void *value = va_arg (args_copy2, void *);
- va_end (args_copy2);
-
- if (value == NULL)
- {
- printf ("(nil)");
- }
- else
- {
- libc_printf_write_u_o_x_X (stream,
- 'x',
- &args_copy,
- flags | LIBC_PRINTF_ARG_FLAG_SHARP,
- LIBC_PRINTF_ARG_LENGTH_TYPE_Z,
- width);
- }
- break;
- }
-
- case 'n':
- {
- assert (false && "unsupported type field n");
- }
- }
- }
-
- format_iter_p++;
- }
-
- va_end (args_copy);
-
- return 0;
-} /* vfprintf */
-
-/**
- * fprintf
- *
- * @return number of characters printed
- */
-int __attr_weak___
-fprintf (FILE *stream, /**< stream pointer */
- const char *format, /**< format string */
- ...) /**< parameters' values */
-{
- va_list args;
-
- va_start (args, format);
-
- int ret = vfprintf (stream, format, args);
-
- va_end (args);
-
- return ret;
-} /* fprintf */
-
-/**
- * printf
- *
- * @return number of characters printed
- */
-int __attr_weak___
-printf (const char *format, /**< format string */
- ...) /**< parameters' values */
-{
- va_list args;
-
- va_start (args, format);
-
- int ret = vfprintf (stdout, format, args);
-
- va_end (args);
-
- return ret;
-} /* printf */
+++ /dev/null
-/* 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.
- */
-
-/**
- * Jerry libc's common functions implementation
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "jerry-libc-defs.h"
-
-/**
- * State of pseudo-random number generator
- */
-static uint32_t libc_random_gen_state[4] = { 1455997910, 1999515274, 1234451287, 1949149569 };
-
-/**
- * Standard file descriptors
- */
-FILE *stdin = (FILE *) 0;
-FILE *stdout = (FILE *) 1;
-FILE *stderr = (FILE *) 2;
-
-#ifdef __GNUC__
-/*
- * Making GCC not to replace:
- * - memcpy -> call to memcpy;
- * - memset -> call to memset;
- * - memmove -> call to memmove.
- */
-#define CALL_PRAGMA(x) _Pragma (#x)
-
-CALL_PRAGMA (GCC diagnostic push)
-CALL_PRAGMA (GCC diagnostic ignored "-Wpragmas")
-CALL_PRAGMA (GCC push_options)
-CALL_PRAGMA (GCC optimize ("-fno-tree-loop-distribute-patterns"))
-#endif /* __GNUC__ */
-
-/**
- * memset
- *
- * @return @a s
- */
-void * __attr_weak___ __attr_used___
-memset (void *s, /**< area to set values in */
- int c, /**< value to set */
- size_t n) /**< area size */
-{
- uint8_t *area_p = (uint8_t *) s;
- while (n--)
- {
- *area_p++ = (uint8_t) c;
- }
-
- return s;
-} /* memset */
-
-/**
- * memcmp
- *
- * @return 0, if areas are equal;
- * <0, if first area's content is lexicographically less, than second area's content;
- * >0, otherwise
- */
-int __attr_weak___
-memcmp (const void *s1, /**< first area */
- const void *s2, /**< second area */
- size_t n) /**< area size */
-{
- const uint8_t *area1_p = (uint8_t *) s1, *area2_p = (uint8_t *) s2;
- while (n--)
- {
- int diff = ((int) *area1_p++) - ((int) *area2_p++);
- if (diff)
- {
- return diff;
- }
- }
-
- return 0;
-} /* memcmp */
-
-/**
- * memcpy
- *
- * @return the dest pointer's value
- */
-void * __attr_weak___ __attr_used___
-memcpy (void *s1, /**< destination */
- const void *s2, /**< source */
- size_t n) /**< bytes number */
-{
- uint8_t *dst_p = (uint8_t *) s1;
- const uint8_t *src_p = (const uint8_t *) s2;
-
- /* Aligned fast case. */
- if (n >= 4 && !(((uintptr_t) s1) & 0x3) && !(((uintptr_t) s2) & 0x3))
- {
- size_t chunks = (n >> 2);
- uint32_t *u32_dst_p = (uint32_t *) dst_p;
- const uint32_t *u32_src_p = (const uint32_t *) src_p;
-
- do
- {
- *u32_dst_p++ = *u32_src_p++;
- }
- while (--chunks);
-
- n &= 0x3;
- dst_p = (uint8_t *) u32_dst_p;
- src_p = (const uint8_t *) u32_src_p;
- }
-
- while (n--)
- {
- *dst_p++ = *src_p++;
- }
-
- return s1;
-} /* memcpy */
-
-/**
- * memmove
- *
- * @return the dest pointer's value
- */
-void * __attr_weak___ __attr_used___
-memmove (void *s1, /**< destination */
- const void *s2, /**< source */
- size_t n) /**< bytes number */
-{
- uint8_t *dest_p;
- const uint8_t *src_p;
-
- if (s1 < s2)
- { /* from begin to end */
- dest_p = (uint8_t *) s1;
- src_p = (const uint8_t *) s2;
-
- while (n--)
- {
- *dest_p++ = *src_p++;
- }
- }
- else if (s1 > s2)
- { /* from end to begin */
- dest_p = ((uint8_t *) s1) + n - 1;
- src_p = ((const uint8_t *) s2) + n - 1;
-
- while (n--)
- {
- *dest_p-- = *src_p--;
- }
- }
-
- return s1;
-} /* memmove */
-
-#ifdef __GNUC__
-CALL_PRAGMA (GCC pop_options)
-CALL_PRAGMA (GCC diagnostic pop)
-#endif /* __GNUC__ */
-
-/**
- * Compare two strings.
- *
- * @return an integer less than, equal to, or greater than zero if s1 is found, respectively,
- * to be less than, to match, or be greater than s2.
- */
-int __attr_weak___
-strcmp (const char *s1, /**< first string */
- const char *s2) /**< second string */
-{
- while (1)
- {
- int c1 = (unsigned char) *s1++;
- int c2 = (unsigned char) *s2++;
- int diff = c1 - c2;
-
- if (!c1 || diff)
- {
- return diff;
- }
- }
-} /* strcmp */
-
-/**
- * Compare two strings.
- *
- * @return an integer less than, equal to, or greater than zero if the first n character of s1 is found, respectively,
- * to be less than, to match, or be greater than the first n character of s2.
- */
-int __attr_weak___
-strncmp (const char *s1, /**< first string */
- const char *s2, /**< second string */
- size_t n) /**< maximum number of characters to compare */
-{
- while (n--)
- {
- int c1 = (unsigned char) *s1++;
- int c2 = (unsigned char) *s2++;
- int diff = c1 - c2;
-
- if (!c1 || diff)
- {
- return diff;
- }
- }
-
- return 0;
-} /* strncmp */
-
-/**
- * Copy a string. At most n bytes of src are copied.
- *
- * Note:
- * If there is no null byte among the first n bytes of src, the string
- * placed in dest will not be null-terminated.
- *
- * @return a pointer to the destination string dest.
- */
-char * __attr_weak___ __attr_used___
-strncpy (char *dest, /**< destination string */
- const char *src, /**< source string */
- size_t n) /**< maximum number of characters to copy */
-{
- while (n--)
- {
- char c = *src++;
- *dest++ = c;
-
- if (!c)
- {
- break;
- }
- }
-
- return dest;
-} /* strncpy */
-
-/**
- * Calculate the length of a string.
- *
- * @return the length.
- */
-size_t __attr_weak___
-strlen (const char *s) /**< string */
-{
- size_t i = 0;
- while (s[i])
- {
- i++;
- }
-
- return i;
-} /* strlen */
-
-/**
- * Generate pseudo-random integer
- *
- * Note:
- * The function implements George Marsaglia's XorShift random number generator
- *
- * @return integer in range [0; RAND_MAX]
- */
-int __attr_weak___
-rand (void)
-{
- uint32_t intermediate = libc_random_gen_state[0] ^ (libc_random_gen_state[0] << 11);
- intermediate ^= intermediate >> 8;
-
- libc_random_gen_state[0] = libc_random_gen_state[1];
- libc_random_gen_state[1] = libc_random_gen_state[2];
- libc_random_gen_state[2] = libc_random_gen_state[3];
-
- libc_random_gen_state[3] ^= libc_random_gen_state[3] >> 19;
- libc_random_gen_state[3] ^= intermediate;
-
- return (int) (libc_random_gen_state[3] % (RAND_MAX + 1));
-} /* rand */
-
-/**
- * Initialize pseudo-random number generator with the specified seed value
- */
-void __attr_weak___
-srand (unsigned int seed) /**< new seed */
-{
- libc_random_gen_state[0] = (uint32_t) ((seed * 14316555781)
- + (seed * 1183186591)
- + (seed * 622729787)
- + (seed * 338294347));
-
- libc_random_gen_state[1] = 842502087;
- libc_random_gen_state[2] = 3579807591;
- libc_random_gen_state[3] = 273326509;
-} /* srand */
-
-/**
- * Convert a string to a long integer.
- *
- * The function first discards leading whitespace characters. Then takes an
- * optional sign followed by as many digits as possible and interprets them as a
- * numerical value. Additional characters after those that form the number are
- * ignored.
- *
- * Note:
- * If base is not 10, the behaviour is undefined.
- * If the value read is out-of-range, the behaviour is undefined.
- * The implementation never sets errno.
- *
- * @return the integer value of str.
- */
-long int __attr_weak___
-strtol (const char *nptr, /**< string representation of an integer number */
- char **endptr, /**< [out] the address of the first non-number character */
- int base) /**< numerical base or radix (MUST be 10) */
-{
- assert (base == 10);
- (void) base; /* Unused. */
-
- const char *str = nptr;
-
- /* Skip leading whitespaces. */
- while (*str == ' ' || *str == '\t' || *str == '\r' || *str == '\n')
- {
- str++;
- }
-
- bool digits = false;
- bool positive = true;
- long int num = 0;
-
- /* Process optional sign. */
- if (*str == '-')
- {
- positive = false;
- str++;
- }
- else if (*str == '+')
- {
- str++;
- }
-
- /* Process base-10 digits. */
- while (*str >= '0' && *str <= '9')
- {
- num = num * 10 + (*str - '0');
- digits = true;
- str++;
- }
-
- /* Set endptr and return result*/
- if (digits)
- {
- if (endptr)
- {
- *endptr = (char *) str;
- }
- return positive ? num : -num;
- }
- else
- {
- if (endptr)
- {
- *endptr = (char *) nptr;
- }
- return 0L;
- }
-} /* strtol */
+++ /dev/null
-/* 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.
- */
-
-#if defined (__x86_64__)
-#include "arch/x86-64.h"
-#elif defined (__i386__)
-#include "arch/x86-32.h"
-#elif defined (__ARM_ARCH_7A__)
-#include "arch/arm-v7.h"
-#else /* !__x86_64__ && !__i386__ && !__ARM_ARCH_7A__ */
-#error "Unsupported architecture"
-#endif /* __x86_64__ */
-
-#if defined (__linux__)
-.macro func _name
-.global \_name
-.type \_name, %function
-\_name:
-.endm
-.macro endfunc _name
-.size \_name, .-\_name
-.endm
-#elif defined (__APPLE__) && defined (__MACH__)
-.macro func _name
-.global \_name
-\_name:
-.endm
-.macro endfunc _name
-.endm
-#else /* !__linux && !(__APPLE__ && __MACH__) */
-#error "Unsupported OS"
-#endif /* __linux__ */
-
-func _start
- _START
-endfunc _start
-
-func syscall_0
- SYSCALL_0
-endfunc syscall_0
-
-func syscall_1
- SYSCALL_1
-endfunc syscall_1
-
-func syscall_2
- SYSCALL_2
-endfunc syscall_2
-
-func syscall_3
- SYSCALL_3
-endfunc syscall_3
-
-/**
- * setjmp (jmp_buf env)
- *
- * See also:
- * longjmp
- *
- * @return 0 - if returns from direct call,
- * nonzero - if returns after longjmp.
- */
-func setjmp
- _SETJMP
-endfunc setjmp
-
-/**
- * longjmp (jmp_buf env, int val)
- *
- * Note:
- * if val is not 0, then it would be returned from setjmp,
- * otherwise - 0 would be returned.
- *
- * See also:
- * setjmp
- */
-func longjmp
- _LONGJMP
-endfunc longjmp
+++ /dev/null
-/* 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.
- */
-
-/**
- * Jerry libc platform-specific functions posix implementation
- */
-
-#include <assert.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-
-#if defined (__linux__)
-#define SYSCALL_NO(NAME) __NR_ ## NAME
-#elif defined (__APPLE__) && defined (__MACH__)
-#define SYS_exit_group SYS_exit
-#define SYSCALL_NO(NAME) SYS_ ## NAME
-#else /* !__linux && !(__APPLE__ && __MACH__) */
-#error "Unsupported OS"
-#endif /* __linux__ */
-
-#include "jerry-libc-defs.h"
-
-long int syscall_0 (long int syscall_no);
-long int syscall_1 (long int syscall_no, long int arg1);
-long int syscall_2 (long int syscall_no, long int arg1, long int arg2);
-long int syscall_3 (long int syscall_no, long int arg1, long int arg2, long int arg3);
-
-/**
- * Exit - cause normal process termination with specified status code
- */
-void __attr_weak___ __attr_noreturn___ __attr_used___
-exit (int status) /**< status code */
-{
-#ifdef ENABLE_INIT_FINI
- libc_fini_array ();
-#endif /* ENABLE_INIT_FINI */
-
- syscall_1 (SYSCALL_NO (close), (long int) stdin);
- syscall_1 (SYSCALL_NO (close), (long int) stdout);
- syscall_1 (SYSCALL_NO (close), (long int) stderr);
-
- syscall_1 (SYSCALL_NO (exit_group), status);
-
- while (true)
- {
- /* unreachable */
- }
-} /* exit */
-
-/**
- * Abort current process, producing an abnormal program termination.
- * The function raises the SIGABRT signal.
- */
-void __attr_weak___ __attr_noreturn___ __attr_used___
-abort (void)
-{
- syscall_1 (SYSCALL_NO (close), (long int) stdin);
- syscall_1 (SYSCALL_NO (close), (long int) stdout);
- syscall_1 (SYSCALL_NO (close), (long int) stderr);
-
- raise (SIGABRT);
-
- while (true)
- {
- /* unreachable */
- }
-} /* abort */
-
-/**
- * Send a signal to the current process.
- *
- * @return 0 - upon successful completion,
- * non-zero value - otherwise.
- */
-int __attr_weak___ __attr_used___
-raise (int sig) /**< signal number */
-{
- return (int) syscall_2 (SYSCALL_NO (kill), syscall_0 (SYSCALL_NO (getpid)), sig);
-} /* raise */
-
-/**
- * fopen
- *
- * @return FILE pointer - upon successful completion,
- * NULL - otherwise.
- */
-FILE * __attr_weak___
-fopen (const char *path, /**< file path */
- const char *mode) /**< file open mode */
-{
- bool may_read = false;
- bool may_write = false;
- bool truncate = false;
- bool create_if_not_exist = false;
- bool position_at_end = false;
-
- assert (path != NULL && mode != NULL);
- assert (mode[1] == '+' || mode[1] == '\0');
-
- switch (mode[0])
- {
- case 'r':
- {
- may_read = true;
- may_write = (mode[1] == '+');
- break;
- }
- case 'w':
- {
- may_write = true;
- truncate = true;
- create_if_not_exist = true;
- may_read = (mode[1] == '+');
- break;
- }
- case 'a':
- {
- may_write = true;
- position_at_end = true;
- create_if_not_exist = true;
- if (mode[1] == '+')
- {
- assert (false && "unsupported mode a+");
- }
- break;
- }
- default:
- {
- assert (false && "unsupported mode");
- }
- }
-
- int flags = 0;
- int access = S_IRUSR | S_IWUSR;
- if (may_read && !may_write)
- {
- flags = O_RDONLY;
- }
- else if (!may_read && may_write)
- {
- flags = O_WRONLY;
- }
- else
- {
- assert (may_read && may_write);
-
- flags = O_RDWR;
- }
-
- if (truncate)
- {
- flags |= O_TRUNC;
- }
-
- if (create_if_not_exist)
- {
- flags |= O_CREAT;
- }
-
- if (position_at_end)
- {
- flags |= O_APPEND;
- }
-
- long int ret = syscall_3 (SYSCALL_NO (open), (long int) path, flags, access);
-
- return ((ret < 0) ? NULL : (void *) (uintptr_t) (ret));
-} /* fopen */
-
-/**
- * fclose
- *
- * @return 0 - upon successful completion,
- * non-zero value - otherwise.
- */
-int __attr_weak___
-fclose (FILE *fp) /**< stream pointer */
-{
- syscall_2 (SYSCALL_NO (close), (long int) fp, 0);
-
- return 0;
-} /* fclose */
-
-/**
- * fread
- *
- * @return number of elements read
- */
-size_t __attr_weak___
-fread (void *ptr, /**< address of buffer to read to */
- size_t size, /**< size of elements to read */
- size_t nmemb, /**< number of elements to read */
- FILE *stream) /**< stream pointer */
-{
- long int ret;
- size_t bytes_read = 0;
-
- if (size == 0)
- {
- return 0;
- }
-
- do
- {
- ret = syscall_3 (SYSCALL_NO (read),
- (long int) stream,
- (long int) ((uint8_t *) ptr + bytes_read),
- (long int) (size * nmemb - bytes_read));
-
- bytes_read += (size_t) ret;
- }
- while (bytes_read != size * nmemb && ret != 0);
-
- return bytes_read / size;
-} /* fread */
-
-/**
- * fwrite
- *
- * @return number of elements written
- */
-size_t __attr_weak___
-fwrite (const void *ptr, /**< data to write */
- size_t size, /**< size of elements to write */
- size_t nmemb, /**< number of elements */
- FILE *stream) /**< stream pointer */
-{
- size_t bytes_written = 0;
-
- if (size == 0)
- {
- return 0;
- }
-
- do
- {
- long int ret = syscall_3 (SYSCALL_NO (write),
- (long int) stream,
- (long int) ((uint8_t *) ptr + bytes_written),
- (long int) (size * nmemb - bytes_written));
-
- bytes_written += (size_t) ret;
- }
- while (bytes_written != size * nmemb);
-
- return bytes_written / size;
-} /* fwrite */
-
-/**
- * This function can get the time as well as a timezone.
- *
- * @return 0 if success, -1 otherwise
- */
-int __attr_weak___
-gettimeofday (void *tp, /**< struct timeval */
- void *tzp) /**< struct timezone */
-{
- return (int) syscall_2 (SYSCALL_NO (gettimeofday), (long int) tp, (long int) tzp);
-} /* gettimeofday */
# Source directories
file(GLOB SOURCE_LIBM *.c)
-add_library(${JERRY_LIBM_NAME} STATIC ${SOURCE_LIBM})
+add_library(${JERRY_LIBM_NAME} ${SOURCE_LIBM})
set_property(TARGET ${JERRY_LIBM_NAME}
PROPERTY COMPILE_FLAGS "${COMPILE_FLAGS_LIBM}")
set(ENABLE_LINK_MAP OFF CACHE BOOL "Enable generating a link map file?")
# Status messages
-message(STATUS "ENABLE_LINK_MAP " ${ENABLE_LINK_MAP})
+message(STATUS "ENABLE_LINK_MAP " ${ENABLE_LINK_MAP})
# Generate map file
if(ENABLE_LINK_MAP)
install(TARGETS ${JERRY_NAME} DESTINATION bin)
endmacro()
-if(JERRY_LIBC AND FEATURE_EXTERNAL_CONTEXT)
- MESSAGE(FATAL_ERROR "This configuration is not supported for jerry-main. Please build against your system libc to enable the external context.")
-endif()
-
# Jerry standalones
if(JERRY_CMDLINE)
jerry_create_executable("jerry" "main-unix.c" "cli.c")
* implementations.
*/
- #ifdef __GNUC__
+#ifdef __GNUC__
/*
* Note:
* This is nasty and dangerous. However, we only need the timeval structure
cli_print_prefix (help, length);
help += length;
- while (*help == ' ' && *help != 0)
+ while (*help == ' ')
{
help++;
}
*/
#include <assert.h>
+#include <stdlib.h>
#include <string.h>
#include "jerryscript.h"
*/
#define JERRY_BUFFER_SIZE (1048576)
+/**
+ * Maximum number of loaded literals
+ */
+#define JERRY_LITERAL_LENGTH (4096)
+
/**
* Standalone Jerry exit codes
*/
#define JERRY_STANDALONE_EXIT_CODE_OK (0)
#define JERRY_STANDALONE_EXIT_CODE_FAIL (1)
-static uint8_t input_buffer[ JERRY_BUFFER_SIZE ];
-static uint32_t output_buffer[ JERRY_BUFFER_SIZE / 4 ];
+static uint8_t input_buffer[JERRY_BUFFER_SIZE];
+static uint32_t output_buffer[JERRY_BUFFER_SIZE / 4];
+static jerry_char_t literal_buffer[JERRY_BUFFER_SIZE];
static const char *output_file_name_p = "js.snapshot";
+static jerry_length_t magic_string_lengths[JERRY_LITERAL_LENGTH];
+static const jerry_char_t *magic_string_items[JERRY_LITERAL_LENGTH];
/**
* Check whether JerryScript has a requested feature enabled or not. If not,
read_file (uint8_t *input_pos_p, /**< next position in the input buffer */
const char *file_name) /**< file name */
{
- FILE *file = fopen (file_name, "r");
+ FILE *file = fopen (file_name, "rb");
if (file == NULL)
{
return 0;
}
- printf ("Input file '%s' (%d bytes) loaded.\n", file_name, (int) bytes_read);
+ printf ("Input file '%s' (%lu bytes) loaded.\n", file_name, bytes_read);
return bytes_read;
} /* read_file */
static void
print_unhandled_exception (jerry_value_t error_value) /**< error value */
{
- assert (!jerry_value_has_error_flag (error_value));
+ assert (!jerry_value_is_error (error_value));
jerry_value_t err_str_val = jerry_value_to_string (error_value);
- if (jerry_value_has_error_flag (err_str_val))
+ if (jerry_value_is_error (err_str_val))
{
/* Avoid recursive error throws. */
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Snapshot error: [value cannot be converted to string]\n");
{
OPT_GENERATE_HELP,
OPT_GENERATE_STATIC,
- OPT_GENERATE_LITERAL_LIST,
- OPT_GENERATE_LITERAL_C,
OPT_GENERATE_SHOW_OP,
OPT_GENERATE_OUT,
+ OPT_IMPORT_LITERAL_LIST
} generate_opt_id_t;
/**
.help = "print this help and exit"),
CLI_OPT_DEF (.id = OPT_GENERATE_STATIC, .opt = "s", .longopt = "static",
.help = "generate static snapshot"),
- CLI_OPT_DEF (.id = OPT_GENERATE_LITERAL_LIST, .longopt = "save-literals-list-format",
+ CLI_OPT_DEF (.id = OPT_IMPORT_LITERAL_LIST, .longopt = "load-literals-list-format",
.meta = "FILE",
- .help = "export literals found in parsed JS input (in list format)"),
- CLI_OPT_DEF (.id = OPT_GENERATE_LITERAL_C, .longopt = "save-literals-c-format",
- .meta = "FILE",
- .help = "export literals found in parsed JS input (in C source format)"),
+ .help = "import literals from list format (for static snapshots)"),
CLI_OPT_DEF (.id = OPT_GENERATE_SHOW_OP, .longopt = "show-opcodes",
.help = "print generated opcodes"),
CLI_OPT_DEF (.id = OPT_GENERATE_OUT, .opt = "o", .meta="FILE",
.help = "specify output file name (default: js.snapshot)"),
CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE",
- .help = "input snapshot file")
+ .help = "input source file")
};
/**
{
(void) argc;
- bool is_save_literals_mode_in_c_format = false;
uint32_t snapshot_flags = 0;
jerry_init_flag_t flags = JERRY_INIT_EMPTY;
const char *file_name_p = NULL;
uint8_t *source_p = input_buffer;
size_t source_length = 0;
- const char *save_literals_file_name_p = NULL;
+ const char *literals_file_name_p = NULL;
cli_change_opts (cli_state_p, generate_opts);
snapshot_flags |= JERRY_SNAPSHOT_SAVE_STATIC;
break;
}
- case OPT_GENERATE_LITERAL_LIST:
- case OPT_GENERATE_LITERAL_C:
+ case OPT_IMPORT_LITERAL_LIST:
{
- if (save_literals_file_name_p != NULL)
- {
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: literal file name already specified");
- return JERRY_STANDALONE_EXIT_CODE_FAIL;
- }
-
- is_save_literals_mode_in_c_format = (id == OPT_GENERATE_LITERAL_C);
- save_literals_file_name_p = cli_consume_string (cli_state_p);
+ literals_file_name_p = cli_consume_string (cli_state_p);
break;
}
case OPT_GENERATE_SHOW_OP:
if (!jerry_is_valid_utf8_string (source_p, (jerry_size_t) source_length))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Input must be a valid UTF-8 string.\n");
+ jerry_cleanup ();
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
- jerry_value_t snapshot_result;
+ if (literals_file_name_p != NULL)
+ {
+ /* Import literal list */
+ uint8_t *sp_buffer_start_p = source_p + source_length + 1;
+ size_t sp_buffer_size = read_file (sp_buffer_start_p, literals_file_name_p);
+
+ if (sp_buffer_size > 0)
+ {
+ const char *sp_buffer_p = (const char *) sp_buffer_start_p;
+ uint32_t num_of_lit = 0;
+
+ do
+ {
+ char *sp_buffer_end_p = NULL;
+ jerry_length_t mstr_size = (jerry_length_t) strtol (sp_buffer_p, &sp_buffer_end_p, 10);
+ if (mstr_size > 0)
+ {
+ magic_string_items[num_of_lit] = (jerry_char_t *) (sp_buffer_end_p + 1);
+ magic_string_lengths[num_of_lit] = mstr_size;
+ num_of_lit++;
+ }
+ sp_buffer_p = sp_buffer_end_p + mstr_size + 1;
+ }
+ while ((size_t) (sp_buffer_p - (char *) sp_buffer_start_p) < sp_buffer_size);
+ if (num_of_lit > 0)
+ {
+ jerry_register_magic_strings (magic_string_items, num_of_lit,
+ magic_string_lengths);
+ }
+ }
+ }
+
+ jerry_value_t snapshot_result;
snapshot_result = jerry_generate_snapshot ((jerry_char_t *) file_name_p,
(size_t) strlen (file_name_p),
(jerry_char_t *) source_p,
output_buffer,
sizeof (output_buffer) / sizeof (uint32_t));
- if (jerry_value_has_error_flag (snapshot_result))
+ if (jerry_value_is_error (snapshot_result))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Generating snapshot failed!\n");
- jerry_value_clear_error_flag (&snapshot_result);
+ snapshot_result = jerry_get_value_from_error (snapshot_result, true);
print_unhandled_exception (snapshot_result);
jerry_release_value (snapshot_result);
+ jerry_cleanup ();
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
size_t snapshot_size = (size_t) jerry_get_number_value (snapshot_result);
jerry_release_value (snapshot_result);
- FILE *snapshot_file_p = fopen (output_file_name_p, "w");
+ FILE *snapshot_file_p = fopen (output_file_name_p, "wb");
if (snapshot_file_p == NULL)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Unable to write snapshot file: '%s'\n", output_file_name_p);
+ jerry_cleanup ();
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
printf ("Created snapshot file: '%s' (%lu bytes)\n", output_file_name_p, (unsigned long) snapshot_size);
- if (save_literals_file_name_p != NULL)
+ jerry_cleanup ();
+ return JERRY_STANDALONE_EXIT_CODE_OK;
+} /* process_generate */
+
+/**
+ * Literal dump command line option IDs
+ */
+typedef enum
+{
+ OPT_LITERAL_DUMP_HELP,
+ OPT_LITERAL_DUMP_FORMAT,
+ OPT_LITERAL_DUMP_OUT,
+} literal_dump_opt_id_t;
+
+/**
+ * Literal dump command line options
+ */
+static const cli_opt_t literal_dump_opts[] =
+{
+ CLI_OPT_DEF (.id = OPT_LITERAL_DUMP_HELP, .opt = "h", .longopt = "help",
+ .help = "print this help and exit"),
+ CLI_OPT_DEF (.id = OPT_LITERAL_DUMP_FORMAT, .longopt = "format",
+ .meta = "[c|list]",
+ .help = "specify output format (default: list)"),
+ CLI_OPT_DEF (.id = OPT_LITERAL_DUMP_OUT, .opt = "o",
+ .help = "specify output file name (default: literals.[h|list])"),
+ CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE(S)",
+ .help = "input snapshot files")
+};
+
+/**
+ * Process 'litdump' command.
+ *
+ * @return error code (0 - no error)
+ */
+static int
+process_literal_dump (cli_state_t *cli_state_p, /**< cli state */
+ int argc, /**< number of arguments */
+ char *prog_name_p) /**< program name */
+{
+ uint8_t *input_pos_p = input_buffer;
+
+ cli_change_opts (cli_state_p, literal_dump_opts);
+
+ JERRY_VLA (const uint32_t *, snapshot_buffers, argc);
+ JERRY_VLA (size_t, snapshot_buffer_sizes, argc);
+ uint32_t number_of_files = 0;
+ const char *literals_file_name_p = NULL;
+ bool is_c_format = false;
+
+ for (int id = cli_consume_option (cli_state_p); id != CLI_OPT_END; id = cli_consume_option (cli_state_p))
{
- const size_t literal_buffer_size = jerry_parse_and_save_literals ((jerry_char_t *) source_p,
- source_length,
- false,
- output_buffer,
- sizeof (output_buffer) / sizeof (uint32_t),
- is_save_literals_mode_in_c_format);
- if (literal_buffer_size == 0)
+ switch (id)
{
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Literal saving failed!\n");
- return JERRY_STANDALONE_EXIT_CODE_FAIL;
+ case OPT_LITERAL_DUMP_HELP:
+ {
+ cli_help (prog_name_p, "litdump", literal_dump_opts);
+ return JERRY_STANDALONE_EXIT_CODE_OK;
+ }
+ case OPT_LITERAL_DUMP_FORMAT:
+ {
+ const char *fromat_str_p = cli_consume_string (cli_state_p);
+ if (!strcmp ("c", fromat_str_p))
+ {
+ is_c_format = true;
+ }
+ else if (!strcmp ("list", fromat_str_p))
+ {
+ is_c_format = false;
+ }
+ else
+ {
+ jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Unsupported literal dump format.");
+ return JERRY_STANDALONE_EXIT_CODE_FAIL;
+ }
+ break;
+ }
+ case OPT_LITERAL_DUMP_OUT:
+ {
+ literals_file_name_p = cli_consume_string (cli_state_p);
+ break;
+ }
+ case CLI_OPT_DEFAULT:
+ {
+ const char *file_name_p = cli_consume_string (cli_state_p);
+
+ if (cli_state_p->error == NULL)
+ {
+ size_t size = read_file (input_pos_p, file_name_p);
+
+ if (size == 0)
+ {
+ return JERRY_STANDALONE_EXIT_CODE_FAIL;
+ }
+
+ snapshot_buffers[number_of_files] = (const uint32_t *) input_pos_p;
+ snapshot_buffer_sizes[number_of_files] = size;
+
+ number_of_files++;
+ const uintptr_t mask = sizeof (uint32_t) - 1;
+ input_pos_p = (uint8_t *) ((((uintptr_t) input_pos_p) + size + mask) & ~mask);
+ }
+ break;
+ }
+ default:
+ {
+ cli_state_p->error = "Internal error";
+ break;
+ }
}
+ }
+
+ if (check_cli_error (cli_state_p))
+ {
+ return JERRY_STANDALONE_EXIT_CODE_FAIL;
+ }
+
+ if (number_of_files < 1)
+ {
+ jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: at least one input file must be specified.\n");
+ return JERRY_STANDALONE_EXIT_CODE_FAIL;
+ }
- FILE *literal_file_p = fopen (save_literals_file_name_p, "w");
+ jerry_init (JERRY_INIT_EMPTY);
- if (literal_file_p == NULL)
+ size_t lit_buf_sz = 0;
+ if (number_of_files == 1)
+ {
+ lit_buf_sz = jerry_get_literals_from_snapshot (snapshot_buffers[0],
+ snapshot_buffer_sizes[0],
+ literal_buffer,
+ JERRY_BUFFER_SIZE,
+ is_c_format);
+ }
+ else
+ {
+ /* The input contains more than one input snapshot file, so we must merge them first. */
+ const char *error_p = NULL;
+ size_t merged_snapshot_size = jerry_merge_snapshots (snapshot_buffers,
+ snapshot_buffer_sizes,
+ number_of_files,
+ output_buffer,
+ JERRY_BUFFER_SIZE,
+ &error_p);
+
+ if (merged_snapshot_size == 0)
{
- jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Unable to write literal file: '%s'\n", save_literals_file_name_p);
+ jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", error_p);
+ jerry_cleanup ();
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
- fwrite (output_buffer, sizeof (uint8_t), literal_buffer_size, literal_file_p);
- fclose (literal_file_p);
+ printf ("Successfully merged the input snapshots (%lu bytes).\n", merged_snapshot_size);
- printf ("Created literal file: '%s' (%lu bytes)\n", save_literals_file_name_p, (unsigned long) literal_buffer_size);
+ lit_buf_sz = jerry_get_literals_from_snapshot (output_buffer,
+ merged_snapshot_size,
+ literal_buffer,
+ JERRY_BUFFER_SIZE,
+ is_c_format);
}
- return 0;
-} /* process_generate */
+ if (lit_buf_sz == 0)
+ {
+ jerry_port_log (JERRY_LOG_LEVEL_ERROR,
+ "Error: Literal saving failed! No literals were found in the input snapshot(s).\n");
+ jerry_cleanup ();
+ return JERRY_STANDALONE_EXIT_CODE_FAIL;
+ }
+
+ if (literals_file_name_p == NULL)
+ {
+ literals_file_name_p = is_c_format ? "literals.h" : "literals.list";
+ }
+
+ FILE *file_p = fopen (literals_file_name_p, "wb");
+
+ if (file_p == NULL)
+ {
+ jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: cannot open file: '%s'\n", literals_file_name_p);
+ jerry_cleanup ();
+ return JERRY_STANDALONE_EXIT_CODE_FAIL;
+ }
+
+ fwrite (literal_buffer, sizeof (uint8_t), lit_buf_sz, file_p);
+ fclose (file_p);
+
+ printf ("Literals are saved into '%s' (%lu bytes).\n", literals_file_name_p, lit_buf_sz);
+
+ jerry_cleanup ();
+ return JERRY_STANDALONE_EXIT_CODE_OK;
+} /* process_literal_dump */
/**
* Merge command line option IDs
int argc, /**< number of arguments */
char *prog_name_p) /**< program name */
{
- jerry_init (JERRY_INIT_EMPTY);
-
uint8_t *input_pos_p = input_buffer;
cli_change_opts (cli_state_p, merge_opts);
- const uint32_t *merge_buffers[argc];
- size_t merge_buffer_sizes[argc];
+ JERRY_VLA (const uint32_t *, merge_buffers, argc);
+ JERRY_VLA (size_t, merge_buffer_sizes, argc);
uint32_t number_of_files = 0;
for (int id = cli_consume_option (cli_state_p); id != CLI_OPT_END; id = cli_consume_option (cli_state_p))
if (number_of_files < 2)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: at least two input files must be passed.\n");
-
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
- const char *error_p;
- size_t size = jerry_merge_snapshots (merge_buffers,
- merge_buffer_sizes,
- number_of_files,
- output_buffer,
- JERRY_BUFFER_SIZE,
- &error_p);
+ jerry_init (JERRY_INIT_EMPTY);
+
+ const char *error_p = NULL;
+ size_t merged_snapshot_size = jerry_merge_snapshots (merge_buffers,
+ merge_buffer_sizes,
+ number_of_files,
+ output_buffer,
+ JERRY_BUFFER_SIZE,
+ &error_p);
- if (size == 0)
+ if (merged_snapshot_size == 0)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", error_p);
+ jerry_cleanup ();
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
- FILE *file_p = fopen (output_file_name_p, "w");
+ FILE *file_p = fopen (output_file_name_p, "wb");
- if (file_p != NULL)
- {
- fwrite (output_buffer, 1u, size, file_p);
- fclose (file_p);
- }
- else
+ if (file_p == NULL)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: cannot open file: '%s'\n", output_file_name_p);
+ jerry_cleanup ();
+ return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
+ fwrite (output_buffer, 1u, merged_snapshot_size, file_p);
+ fclose (file_p);
+
+ printf ("Merge is completed. Merged snapshot is saved into '%s' (%lu bytes).\n",
+ output_file_name_p,
+ merged_snapshot_size);
+
+ jerry_cleanup ();
return JERRY_STANDALONE_EXIT_CODE_OK;
} /* process_merge */
printf ("\nAvailable commands:\n"
" generate\n"
+ " litdump\n"
" merge\n"
"\nPassing -h or --help after a command displays its help.\n");
} /* print_commands */
{
return process_merge (&cli_state, argc, argv[0]);
}
+ else if (!strcmp ("litdump", command_p))
+ {
+ return process_literal_dump (&cli_state, argc, argv[0]);
+ }
else if (!strcmp ("generate", command_p))
{
return process_generate (&cli_state, argc, argv[0]);
read_file (const char *file_name,
size_t *out_size_p)
{
- FILE *file = fopen (file_name, "r");
+ FILE *file = fopen (file_name, "rb");
if (file == NULL)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to open file: %s\n", file_name);
{
ret_value = jerry_parse (NULL, 0, source_p, source_size, JERRY_PARSE_NO_OPTS);
- if (!jerry_value_has_error_flag (ret_value))
+ if (!jerry_value_is_error (ret_value))
{
jerry_value_t func_val = ret_value;
ret_value = jerry_run (func_val);
}
}
- if (jerry_value_has_error_flag (ret_value))
+ if (jerry_value_is_error (ret_value))
{
break;
}
int ret_code = JERRY_STANDALONE_EXIT_CODE_OK;
- if (jerry_value_has_error_flag (ret_value))
+ if (jerry_value_is_error (ret_value))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unhandled exception: Script Error!\n");
ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL;
#include <string.h>
#include "jerryscript.h"
+#include "jerryscript-ext/debugger.h"
#include "jerryscript-ext/handler.h"
#include "jerryscript-port.h"
#include "jerryscript-port-default.h"
}
else
{
- file = fopen (file_name, "r");
+ file = fopen (file_name, "rb");
if (file == NULL)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to open file: %s\n", file_name);
static void
print_unhandled_exception (jerry_value_t error_value) /**< error value */
{
- assert (!jerry_value_has_error_flag (error_value));
+ assert (!jerry_value_is_error (error_value));
jerry_char_t err_str_buf[256];
jerry_value_t backtrace_val = jerry_get_property (error_value, stack_str);
jerry_release_value (stack_str);
- if (!jerry_value_has_error_flag (backtrace_val)
+ if (!jerry_value_is_error (backtrace_val)
&& jerry_value_is_array (backtrace_val))
{
printf ("Exception backtrace:\n");
{
jerry_value_t item_val = jerry_get_property_by_index (backtrace_val, i);
- if (!jerry_value_has_error_flag (item_val)
+ if (!jerry_value_is_error (item_val)
&& jerry_value_is_string (item_val))
{
jerry_size_t str_size = jerry_get_string_size (item_val);
if (str_size >= 256)
{
- printf ("%3d: [Backtrace string too long]\n", i);
+ printf ("%3u: [Backtrace string too long]\n", i);
}
else
{
assert (string_end == str_size);
err_str_buf[string_end] = 0;
- printf ("%3d: %s\n", i, err_str_buf);
+ printf ("%3u: %s\n", i, err_str_buf);
}
}
{
jerry_value_t result_val = jerryx_handler_register_global ((const jerry_char_t *) name_p, handler_p);
- if (jerry_value_has_error_flag (result_val))
+ if (jerry_value_is_error (result_val))
{
jerry_port_log (JERRY_LOG_LEVEL_WARNING, "Warning: failed to register '%s' method.", name_p);
- jerry_value_clear_error_flag (&result_val);
+ result_val = jerry_get_value_from_error (result_val, true);
print_unhandled_exception (result_val);
}
size_t resource_name_size, /**< size of resource name */
const jerry_char_t *source_p, /**< source code */
size_t source_size, /**< source code size */
- void *user_p __attribute__((unused))) /**< user pointer */
+ void *user_p) /**< user pointer */
{
+ (void) user_p; /* unused */
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))
+ if (!jerry_value_is_error (ret_val))
{
jerry_value_t func_val = ret_val;
ret_val = jerry_run (func_val);
#ifdef JERRY_ENABLE_EXTERNAL_CONTEXT
/**
- * The alloc function passed to jerry_create_instance
+ * The alloc function passed to jerry_create_context
*/
static void *
-instance_alloc (size_t size,
- void *cb_data_p __attribute__((unused)))
+context_alloc (size_t size,
+ void *cb_data_p)
{
+ (void) cb_data_p; /* unused */
return malloc (size);
-} /* instance_alloc */
+} /* context_alloc */
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
+/**
+ * Inits the engine and the debugger
+ */
+static void
+init_engine (jerry_init_flag_t flags, /**< initialized flags for the engine */
+ bool debug_server, /**< enable the debugger init or not */
+ uint16_t debug_port) /**< the debugger port */
+{
+ jerry_init (flags);
+ if (debug_server)
+ {
+ jerryx_debugger_after_connect (jerryx_debugger_tcp_create (debug_port)
+ && jerryx_debugger_ws_create ());
+ }
+
+ register_js_function ("assert", jerryx_handler_assert);
+ register_js_function ("gc", jerryx_handler_gc);
+ register_js_function ("print", jerryx_handler_print);
+} /* init_engine */
+
int
main (int argc,
char **argv)
{
srand ((unsigned) jerry_port_get_current_time ());
- const char *file_names[argc];
+ JERRY_VLA (const char *, file_names, argc);
int files_counter = 0;
jerry_init_flag_t flags = JERRY_INIT_EMPTY;
- const char *exec_snapshot_file_names[argc];
- uint32_t exec_snapshot_file_indices[argc];
+ JERRY_VLA (const char *, exec_snapshot_file_names, argc);
+ JERRY_VLA (uint32_t, exec_snapshot_file_indices, argc);
int exec_snapshots_count = 0;
bool is_parse_only = false;
#ifdef JERRY_ENABLE_EXTERNAL_CONTEXT
- jerry_instance_t *instance_p = jerry_create_instance (512*1024, instance_alloc, NULL);
- jerry_port_default_set_instance (instance_p);
+ jerry_context_t *context_p = jerry_create_context (512*1024, context_alloc, NULL);
+ jerry_port_default_set_current_context (context_p);
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
- jerry_init (flags);
- if (start_debug_server)
- {
- jerry_debugger_init (debug_port);
- }
-
- register_js_function ("assert", jerryx_handler_assert);
- register_js_function ("gc", jerryx_handler_gc);
- register_js_function ("print", jerryx_handler_print);
+ init_engine (flags, start_debug_server, debug_port);
jerry_value_t ret_value = jerry_create_undefined ();
JERRY_SNAPSHOT_EXEC_COPY_DATA);
}
- if (jerry_value_has_error_flag (ret_value))
+ if (jerry_value_is_error (ret_value))
{
break;
}
}
}
- if (!jerry_value_has_error_flag (ret_value))
+ while (true)
{
- for (int i = 0; i < files_counter; i++)
- {
- size_t source_size;
- const jerry_char_t *source_p = (jerry_char_t *) read_file (file_names[i], &source_size);
- if (source_p == NULL)
+ if (!jerry_value_is_error (ret_value))
+ {
+ for (int i = 0; i < files_counter; i++)
{
- ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) "Source file load error");
- break;
- }
+ size_t source_size;
+ const jerry_char_t *source_p = (jerry_char_t *) read_file (file_names[i], &source_size);
- if (!jerry_is_valid_utf8_string (source_p, (jerry_size_t) source_size))
- {
- ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) ("Input must be a valid UTF-8 string."));
- break;
- }
+ if (source_p == NULL)
+ {
+ ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) "Source file load error");
+ break;
+ }
- ret_value = jerry_parse ((jerry_char_t *) file_names[i],
- strlen (file_names[i]),
- source_p,
- source_size,
- JERRY_PARSE_NO_OPTS);
+ if (!jerry_is_valid_utf8_string (source_p, (jerry_size_t) source_size))
+ {
+ ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) ("Input must be a valid UTF-8 string."));
+ break;
+ }
- if (!jerry_value_has_error_flag (ret_value) && !is_parse_only)
- {
- jerry_value_t func_val = ret_value;
- ret_value = jerry_run (func_val);
- jerry_release_value (func_val);
- }
+ ret_value = jerry_parse ((jerry_char_t *) file_names[i],
+ strlen (file_names[i]),
+ source_p,
+ source_size,
+ JERRY_PARSE_NO_OPTS);
- if (jerry_value_has_error_flag (ret_value))
- {
- break;
- }
+ if (!jerry_value_is_error (ret_value) && !is_parse_only)
+ {
+ jerry_value_t func_val = ret_value;
+ ret_value = jerry_run (func_val);
+ jerry_release_value (func_val);
+ }
- jerry_release_value (ret_value);
- ret_value = jerry_create_undefined ();
- }
- }
+ if (jerry_value_is_error (ret_value))
+ {
+ break;
+ }
- if (is_wait_mode)
- {
- is_repl_mode = false;
+ jerry_release_value (ret_value);
+ ret_value = jerry_create_undefined ();
+ }
+ }
- if (jerry_is_feature_enabled (JERRY_FEATURE_DEBUGGER))
+ if (is_wait_mode)
{
- while (true)
- {
- jerry_debugger_wait_for_source_status_t receive_status;
+ is_repl_mode = false;
- do
+ if (jerry_is_feature_enabled (JERRY_FEATURE_DEBUGGER))
+ {
+ while (true)
{
- jerry_value_t run_result;
+ jerry_debugger_wait_for_source_status_t receive_status;
- receive_status = jerry_debugger_wait_for_client_source (wait_for_source_callback,
- NULL,
- &run_result);
-
- if (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED)
+ do
{
- ret_value = jerry_create_error (JERRY_ERROR_COMMON,
- (jerry_char_t *) "Connection aborted before source arrived.");
+ jerry_value_t run_result;
+
+ receive_status = jerry_debugger_wait_for_client_source (wait_for_source_callback,
+ NULL,
+ &run_result);
+
+ if (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED)
+ {
+ ret_value = jerry_create_error (JERRY_ERROR_COMMON,
+ (jerry_char_t *) "Connection aborted before source arrived.");
+ }
+
+ if (receive_status == JERRY_DEBUGGER_SOURCE_END)
+ {
+ jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "No more client source.\n");
+ }
+
+ if (jerry_value_is_abort (run_result))
+ {
+ ret_value = jerry_acquire_value (run_result);
+ }
+
+ jerry_release_value (run_result);
}
+ while (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVED);
- if (receive_status == JERRY_DEBUGGER_SOURCE_END)
+ if (receive_status != JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED)
{
- jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "No more client source.\n");
+ break;
}
- jerry_release_value (run_result);
- }
- while (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVED);
+ init_engine (flags, true, debug_port);
- if (receive_status != JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED)
- {
- break;
+ ret_value = jerry_create_undefined ();
}
+ }
- jerry_cleanup ();
+ }
- jerry_init (flags);
- jerry_debugger_init (debug_port);
+ bool restart = false;
- register_js_function ("assert", jerryx_handler_assert);
- register_js_function ("gc", jerryx_handler_gc);
- register_js_function ("print", jerryx_handler_print);
+ if (jerry_is_feature_enabled (JERRY_FEATURE_DEBUGGER) && jerry_value_is_abort (ret_value))
+ {
+ jerry_value_t abort_value = jerry_get_value_from_error (ret_value, false);
+ if (jerry_value_is_string (abort_value))
+ {
+ static const char restart_str[] = "r353t";
- ret_value = jerry_create_undefined ();
+ jerry_value_t str_val = jerry_value_to_string (abort_value);
+ jerry_size_t str_size = jerry_get_string_size (str_val);
+
+ if (str_size == sizeof (restart_str) - 1)
+ {
+ JERRY_VLA (jerry_char_t, str_buf, str_size);
+ jerry_string_to_char_buffer (str_val, str_buf, str_size);
+ if (memcmp (restart_str, (char *) (str_buf), str_size) == 0)
+ {
+ jerry_release_value (ret_value);
+ restart = true;
+ }
+ }
+
+ jerry_release_value (str_val);
}
+
+ jerry_release_value (abort_value);
+ }
+
+ if (!restart)
+ {
+ break;
}
+ jerry_cleanup ();
+
+ init_engine (flags, true, debug_port);
+
+ ret_value = jerry_create_undefined ();
}
if (is_repl_mode)
if (len > 0)
{
+ if (!jerry_is_valid_utf8_string (buffer, (jerry_size_t) len))
+ {
+ jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Input must be a valid UTF-8 string.\n");
+ return JERRY_STANDALONE_EXIT_CODE_FAIL;
+ }
+
/* Evaluate the line */
- jerry_value_t ret_val_eval = jerry_eval (buffer, len, false);
+ jerry_value_t ret_val_eval = jerry_eval (buffer, len, JERRY_PARSE_NO_OPTS);
- if (!jerry_value_has_error_flag (ret_val_eval))
+ if (!jerry_value_is_error (ret_val_eval))
{
/* Print return value */
const jerry_value_t args[] = { ret_val_eval };
jerry_release_value (ret_val_eval);
ret_val_eval = jerry_run_all_enqueued_jobs ();
- if (jerry_value_has_error_flag (ret_val_eval))
+ if (jerry_value_is_error (ret_val_eval))
{
- jerry_value_clear_error_flag (&ret_val_eval);
+ ret_val_eval = jerry_get_value_from_error (ret_val_eval, true);
print_unhandled_exception (ret_val_eval);
}
}
else
{
- jerry_value_clear_error_flag (&ret_val_eval);
+ ret_val_eval = jerry_get_value_from_error (ret_val_eval, true);
print_unhandled_exception (ret_val_eval);
}
int ret_code = JERRY_STANDALONE_EXIT_CODE_OK;
- if (jerry_value_has_error_flag (ret_value))
+ if (jerry_value_is_error (ret_value))
{
- jerry_value_clear_error_flag (&ret_value);
+ ret_value = jerry_get_value_from_error (ret_value, true);
print_unhandled_exception (ret_value);
ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL;
ret_value = jerry_run_all_enqueued_jobs ();
- if (jerry_value_has_error_flag (ret_value))
+ if (jerry_value_is_error (ret_value))
{
- jerry_value_clear_error_flag (&ret_value);
+ ret_value = jerry_get_value_from_error (ret_value, true);
print_unhandled_exception (ret_value);
ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL;
}
jerry_cleanup ();
#ifdef JERRY_ENABLE_EXTERNAL_CONTEXT
- free (instance_p);
+ free (context_p);
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
return ret_code;
} /* main */
# (should only be necessary if we used compiler default libc but not checking that)
set(DEFINES_PORT_DEFAULT _BSD_SOURCE _DEFAULT_SOURCE)
+INCLUDE (CheckStructHasMember)
+# CHECK_STRUCT_HAS_MEMBER works by trying to compile some C code that accesses the
+# given field of the given struct. However, our default compiler options break this
+# C code, so turn a couple of them off for this.
+set(CMAKE_REQUIRED_FLAGS "-Wno-error=strict-prototypes -Wno-error=old-style-definition")
+# tm.tm_gmtoff is non-standard, so glibc doesn't expose it in c99 mode
+# (our default). Define some macros to expose it anyway.
+set(CMAKE_REQUIRED_DEFINITIONS "-D_BSD_SOURCE -D_DEFAULT_SOURCE")
+CHECK_STRUCT_HAS_MEMBER ("struct tm" tm_gmtoff time.h HAVE_TM_GMTOFF)
+if(HAVE_TM_GMTOFF)
+ set(DEFINES_PORT_DEFAULT ${DEFINES_PORT_DEFAULT} HAVE_TM_GMTOFF)
+endif()
+
+# Sleep function availability check
+INCLUDE (CheckIncludeFiles)
+CHECK_INCLUDE_FILES (time.h HAVE_TIME_H)
+CHECK_INCLUDE_FILES (unistd.h HAVE_UNISTD_H)
+if(HAVE_TIME_H)
+ set(DEFINES_PORT_DEFAULT ${DEFINES_PORT_DEFAULT} HAVE_TIME_H)
+elseif(HAVE_UNISTD_H)
+ set(DEFINES_PORT_DEFAULT ${DEFINES_PORT_DEFAULT} HAVE_UNISTD_H)
+endif()
+
# Default Jerry port implementation library variants:
# - default
# - default-minimal (no extra termination and log APIs)
foreach(JERRY_PORT_LIBRARY_NAME ${JERRY_PORT_DEFAULT_NAME} ${JERRY_PORT_DEFAULT_NAME}-minimal)
- add_library(${JERRY_PORT_LIBRARY_NAME} STATIC ${SOURCE_PORT_DEFAULT})
+ add_library(${JERRY_PORT_LIBRARY_NAME} ${SOURCE_PORT_DEFAULT})
target_include_directories(${JERRY_PORT_LIBRARY_NAME} PUBLIC ${INCLUDE_PORT_DEFAULT})
- target_include_directories(${JERRY_PORT_LIBRARY_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/jerry-core/include)
- target_include_directories(${JERRY_PORT_LIBRARY_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/jerry-ext/include)
+ target_include_directories(${JERRY_PORT_LIBRARY_NAME} PRIVATE ${INCLUDE_CORE_PUBLIC})
+ target_include_directories(${JERRY_PORT_LIBRARY_NAME} PRIVATE ${INCLUDE_EXT_PUBLIC})
target_compile_definitions(${JERRY_PORT_LIBRARY_NAME} PRIVATE ${DEFINES_PORT_DEFAULT})
target_link_libraries(${JERRY_PORT_LIBRARY_NAME} jerry-core) # FIXME: remove this dependency as soon as possible
endforeach()
* limitations under the License.
*/
+#ifdef HAVE_TM_GMTOFF
+#include <time.h>
+#endif /* HAVE_TM_GMTOFF */
#ifdef __GNUC__
#include <sys/time.h>
-#endif
+#endif /* __GNUC__ */
#include "jerryscript-port.h"
#include "jerryscript-port-default.h"
/**
- * Default implementation of jerry_port_get_time_zone. Uses 'gettimeofday' if
- * available on the system, does nothing otherwise.
+ * Default implementation of jerry_port_get_local_time_zone_adjustment. Uses the 'tm_gmtoff' field
+ * of 'struct tm' (a GNU extension) filled by 'localtime_r' if available on the
+ * system, does nothing otherwise.
*
- * @return true - if 'gettimeofday' is available and executed successfully,
- * false - otherwise.
+ * @return offset between UTC and local time at the given unix timestamp, if
+ * available. Otherwise, returns 0, assuming UTC time.
*/
-bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p) /**< [out] time zone structure to fill */
+double jerry_port_get_local_time_zone_adjustment (double unix_ms, /**< ms since unix epoch */
+ bool is_utc) /**< is the time above in UTC? */
{
-#ifdef __GNUC__
- struct timeval tv;
- struct timezone tz;
-
- /* gettimeofday may not fill tz, so zero-initializing */
- tz.tz_minuteswest = 0;
- tz.tz_dsttime = 0;
-
- if (gettimeofday (&tv, &tz) != 0)
+#ifdef HAVE_TM_GMTOFF
+ struct tm tm;
+ time_t now = (time_t) (unix_ms / 1000);
+ localtime_r (&now, &tm);
+ if (!is_utc)
{
- return false;
+ now -= tm.tm_gmtoff;
+ localtime_r (&now, &tm);
}
-
- tz_p->offset = tz.tz_minuteswest;
- tz_p->daylight_saving_time = tz.tz_dsttime > 0 ? 1 : 0;
-
- return true;
-#else /* !__GNUC__ */
- return false;
-#endif /* __GNUC__ */
-} /* jerry_port_get_time_zone */
+ return ((double) tm.tm_gmtoff) * 1000;
+#else /* !HAVE_TM_GMTOFF */
+ (void) unix_ms;
+ (void) is_utc;
+ return 0.0;
+#endif /* HAVE_TM_GMTOFF */
+} /* jerry_port_get_local_time_zone_adjustment */
/**
* Default implementation of jerry_port_get_current_time. Uses 'gettimeofday' if
#ifdef __GNUC__
struct timeval tv;
- if (gettimeofday (&tv, NULL) != 0)
+ if (gettimeofday (&tv, NULL) == 0)
{
- return 0.0;
+ return ((double) tv.tv_sec) * 1000.0 + ((double) tv.tv_usec) / 1000.0;
}
+#endif /* __GNUC__ */
- return ((double) tv.tv_sec) * 1000.0 + ((double) tv.tv_usec) / 1000.0;
-#else /* __!GNUC__ */
return 0.0;
-#endif /* __GNUC__ */
} /* jerry_port_get_current_time */
* limitations under the License.
*/
-#include "jerryscript-port.h"
-#include "jerryscript-port-default.h"
+#if !defined (_XOPEN_SOURCE) || _XOPEN_SOURCE < 500
+#undef _XOPEN_SOURCE
+/* Required macro for sleep functions (nanosleep or usleep) */
+#define _XOPEN_SOURCE 500
+#endif
#ifdef HAVE_TIME_H
#include <time.h>
#include <unistd.h>
#endif /* HAVE_TIME_H */
-#ifdef JERRY_DEBUGGER
-void jerry_port_sleep (uint32_t sleep_time)
+#include "jerryscript-port.h"
+#include "jerryscript-port-default.h"
+
+/**
+ * Default implementation of jerry_port_sleep. Uses 'nanosleep' or 'usleep' if
+ * available on the system, does nothing otherwise.
+ */
+void jerry_port_sleep (uint32_t sleep_time) /**< milliseconds to sleep */
{
#ifdef HAVE_TIME_H
- nanosleep (&(const struct timespec)
- {
- sleep_time / 1000, (sleep_time % 1000) * 1000000L /* Seconds, nanoseconds */
- }
- , NULL);
+ struct timespec sleep_timespec;
+ sleep_timespec.tv_sec = (time_t) sleep_time / 1000;
+ sleep_timespec.tv_nsec = ((long int) sleep_time % 1000) * 1000000L;
+
+ nanosleep (&sleep_timespec, NULL);
#elif defined (HAVE_UNISTD_H)
usleep ((useconds_t) sleep_time * 1000);
-#endif /* HAVE_TIME_H */
+#else
(void) sleep_time;
+#endif /* HAVE_TIME_H */
} /* jerry_port_sleep */
-#endif /* JERRY_DEBUGGER */
#include "jerryscript-port-default.h"
/**
- * Pointer to the current instance.
+ * Pointer to the current context.
* Note that it is a global variable, and is not a thread safe implementation.
*/
-static jerry_instance_t *current_instance_p = NULL;
+static jerry_context_t *current_context_p = NULL;
/**
- * Set the current_instance_p as the passed pointer.
+ * Set the current_context_p as the passed pointer.
*/
void
-jerry_port_default_set_instance (jerry_instance_t *instance_p) /**< points to the created instance */
+jerry_port_default_set_current_context (jerry_context_t *context_p) /**< points to the created context */
{
- current_instance_p = instance_p;
-} /* jerry_port_default_set_instance */
+ current_context_p = context_p;
+} /* jerry_port_default_set_current_context */
/**
- * Get the current instance.
+ * Get the current context.
*
- * @return the pointer to the current instance
+ * @return the pointer to the current context
*/
-jerry_instance_t *
-jerry_port_get_current_instance (void)
+jerry_context_t *
+jerry_port_get_current_context (void)
{
- return current_instance_p;
-} /* jerry_port_get_current_instance */
+ return current_context_p;
+} /* jerry_port_get_current_context */
* The "abort-on-fail" behaviour is only available if the port
* implementation library is compiled without the DISABLE_EXTRA_API macro.
*/
-void jerry_port_fatal (jerry_fatal_code_t code)
+void jerry_port_fatal (jerry_fatal_code_t code) /**< cause of error */
{
#ifndef DISABLE_EXTRA_API
if (code != 0
&& code != ERR_OUT_OF_MEMORY
- && jerry_port_default_is_abort_on_fail ())
+ && abort_on_fail)
{
abort ();
}
- else
- {
-#endif /* !DISABLE_EXTRA_API */
- exit (code);
-#ifndef DISABLE_EXTRA_API
- }
#endif /* !DISABLE_EXTRA_API */
+
+ exit ((int) code);
} /* jerry_port_fatal */
#include "jerryscript-port.h"
#include "jerryscript-port-default.h"
-#include "debugger.h"
+#include "jerryscript-debugger.h"
#ifndef DISABLE_EXTRA_API
#endif /* !DISABLE_EXTRA_API */
/**
- * Default implementation of jerry_port_log. Prints log message to a buffer
- * then prints the buffer to the standard error with 'fprintf' if message
- * level is less than or equal to the set log level.
- * Additionally, sends the message to the debugger client.
+ * Default implementation of jerry_port_log. Prints log message to the standard
+ * error with 'vfprintf' if message log level is less than or equal to the
+ * current log level.
+ *
+ * If debugger support is enabled, printing happens first to an in-memory buffer,
+ * which is then sent both to the standard error and to the debugger client.
*
* Note:
* Changing the log level from JERRY_LOG_LEVEL_ERROR is only possible if
* DISABLE_EXTRA_API macro.
*/
void
-jerry_port_log (jerry_log_level_t level, /**< log level */
+jerry_port_log (jerry_log_level_t level, /**< message log level */
const char *format, /**< format string */
...) /**< parameters */
{
va_list args;
va_start (args, format);
#ifdef JERRY_DEBUGGER
- char buffer[256];
- int length = 0;
- length = vsnprintf (buffer, 255, format, args);
- buffer[length] = '\0';
+ int length = vsnprintf (NULL, 0, format, args);
+ va_end (args);
+ va_start (args, format);
+
+ char buffer[length + 1];
+ vsnprintf (buffer, (size_t) length + 1, format, args);
+
fprintf (stderr, "%s", buffer);
- jerry_char_t *jbuffer = (jerry_char_t *) buffer;
- jerry_debugger_send_output (jbuffer, (jerry_size_t) length, (uint8_t) (level + 2));
+ jerry_debugger_send_log (level, (jerry_char_t *) buffer, (jerry_size_t) length);
#else /* If jerry-debugger isn't defined, libc is turned on */
vfprintf (stderr, format, args);
#endif /* JERRY_DEBUGGER */
#include "jerryscript-ext/handler.h"
+#ifdef JERRY_DEBUGGER
+
+#define DEBUG_BUFFER_SIZE (256)
+static char debug_buffer[DEBUG_BUFFER_SIZE];
+static int debug_buffer_index = 0;
+
+#endif /* JERRY_DEBUGGER */
+
/**
* Default implementation of jerryx_port_handler_print_char. Uses 'printf' to
* print a single character to standard output.
jerryx_port_handler_print_char (char c) /**< the character to print */
{
printf ("%c", c);
+
+#ifdef JERRY_DEBUGGER
+ debug_buffer[debug_buffer_index++] = c;
+
+ if ((debug_buffer_index == DEBUG_BUFFER_SIZE) || (c == '\n'))
+ {
+ jerry_debugger_send_output ((jerry_char_t *) debug_buffer, (jerry_size_t) debug_buffer_index);
+ debug_buffer_index = 0;
+ }
+#endif /* JERRY_DEBUGGER */
} /* jerryx_port_handler_print_char */
#ifndef JERRYSCRIPT_PORT_DEFAULT_H
#define JERRYSCRIPT_PORT_DEFAULT_H
+#include <stdbool.h>
+
#include "jerryscript.h"
#include "jerryscript-port.h"
-#include <stdbool.h>
-
#ifdef __cplusplus
extern "C"
{
jerry_log_level_t jerry_port_default_get_log_level (void);
void jerry_port_default_set_log_level (jerry_log_level_t level);
-void jerry_port_default_set_instance (jerry_instance_t *instance_p);
+void jerry_port_default_set_current_context (jerry_context_t *context_p);
/**
* @}
--- /dev/null
+# 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.
+
+sonar.projectName=JerryScript
+sonar.projectKey=jerryscript
+sonar.organization=jerryscript-project
+sonar.sources=jerry-core,jerry-ext,jerry-main,jerry-port
+sonar.cfamily.build-wrapper-output=bw-output
void jerry_resolve_error (jerry_value_t ret_value)
{
- if (jerry_value_has_error_flag (ret_value))
+ if (jerry_value_is_error (ret_value))
{
- jerry_value_clear_error_flag (&ret_value);
+ ret_value = jerry_get_value_from_error (ret_value, true);
jerry_value_t err_str_val = jerry_value_to_string (ret_value);
jerry_size_t err_str_size = jerry_get_string_size (err_str_val);
jerry_char_t *err_str_buf = (jerry_char_t *) balloc (err_str_size, NULL);
}
*p = '\0';
- jerry_value_t eval_ret = jerry_eval (buffer, str_total_length - 1, false);
+ jerry_value_t eval_ret = jerry_eval (buffer, str_total_length - 1, JERRY_PARSE_NO_OPTS);
- if (jerry_value_has_error_flag (eval_ret))
+ if (jerry_value_is_error (eval_ret))
{
jerry_resolve_error (eval_ret);
TCMD_RSP_ERROR (ctx, NULL);
} /* jerry_port_fatal */
/**
- * Curie BSP implementation of jerry_port_get_time_zone.
+ * Curie BSP implementation of jerry_port_get_local_time_zone_adjustment.
*/
-bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
+double jerry_port_get_local_time_zone_adjustment (double unix_ms, bool is_utc)
{
//EMPTY implementation
- tz_p->offset = 0;
- tz_p->daylight_saving_time = 0;
-
- return true;
-} /* jerry_port_get_time_zone */
+ return 0;
+} /* jerry_port_get_local_time_zone_adjustment */
/**
* Curie BSP implementation of jerry_port_get_current_time.
-DCMAKE_C_COMPILER_WORKS=TRUE \
-DENABLE_LTO=OFF \
-DENABLE_ALL_IN_ONE=ON \
- -DJERRY_LIBC=OFF \
-DJERRY_CMDLINE=OFF \
-DEXTERNAL_COMPILE_FLAGS="$(ESP_CFLAGS)" \
-DMEM_HEAP_SIZE_KB=$(JERRYHEAP)
wget https://github.com/esp8266/esp8266-wiki/raw/master/libs/libhal.a -O ../ESP8266_SDK/lib/libhal.a
# Perform all the necessary (JerryScript-independent) installation steps.
-install: install-apt-get-deps install-xtensa-kx106-gcc install-espressif-sdk
+install-noapt: install-xtensa-kx106-gcc install-espressif-sdk
+install: install-apt-get-deps install-noapt
## Targets for building ESP8266 with JerryScript.
jerry_release_value (global_obj_val);
jerry_release_value (prop_name_val);
- if (jerry_value_has_error_flag (res))
+ if (jerry_value_is_error (res))
{
printf ("!!! register_native_function failed: [%s]\r\n", name);
jerry_release_value (res);
} /* jerry_port_get_current_time */
/**
- * Dummy function to get the time zone.
+ * Dummy function to get the time zone adjustment.
*
- * @return true
+ * @return 0
*/
-bool
-jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
+double
+jerry_port_get_local_time_zone_adjustment (double unix_ms, bool is_utc)
{
/* We live in UTC. */
- tz_p->offset = 0;
- tz_p->daylight_saving_time = 0;
-
- return true;
-} /* jerry_port_get_time_zone */
+ return 0;
+} /* jerry_port_get_local_time_zone_adjustment */
{
jerry_value_t res = jerry_eval ((jerry_char_t *) source_p,
source_size,
- false);
- if (jerry_value_has_error_flag (res)) {
+ JERRY_PARSE_NO_OPTS);
+ if (jerry_value_is_error (res)) {
jerry_release_value (res);
return -1;
}
jerry_value_t sysloop_func = jerry_get_property (global_obj_val, prop_name_val);
jerry_release_value (prop_name_val);
- if (jerry_value_has_error_flag (sysloop_func)) {
+ if (jerry_value_is_error (sysloop_func)) {
printf ("Error: '%s' not defined!!!\r\n", fn_sys_loop_name);
jerry_release_value (sysloop_func);
jerry_release_value (global_obj_val);
jerry_release_value (sysloop_func);
jerry_release_value (global_obj_val);
- if (jerry_value_has_error_flag (res)) {
+ if (jerry_value_is_error (res)) {
jerry_release_value (res);
return -3;
}
+++ /dev/null
-# 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.
-
-# use TAB-8
-
-TARGET_LIST = k64f stm32f4 stm32f429i nucleo
-JERRYHEAP ?= 16
-
-ifneq ($(filter $(board), $(TARGET_LIST)),)
- TARGET = $(board)
-ifeq ($(TARGET), k64f)
- YOTTA_TARGET = frdm-k64f-gcc
- TARGET_DIR ?= /media/$(USER)/MBED
-else ifeq ($(TARGET), stm32f4)
- YOTTA_TARGET = stm32f4-disco-gcc
-else ifeq ($(TARGET), stm32f429i)
- YOTTA_TARGET = stm32f429i-disco-gcc
-else ifeq ($(TARGET), nucleo)
- YOTTA_TARGET = st-nucleo-f401re-gcc
- TARGET_DIR ?= /media/$(USER)/NODE_F401RE
-endif
-
-BUILD_DIR ?= build/mbed
-UPPERC_TARGET ?= $(shell echo $(TARGET) | tr a-z A-Z)
-COPYTARGET ?= targets/mbed/libjerry
-
-else
- $(error This board ($(board)) is not supported!)
-endif
-
-EXT_CFLAGS := -D__TARGET_MBED_$(UPPERC_TARGET)
-EXT_CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4
-EXT_CFLAGS += -Wno-error=format=
-
-EXT_PORT_DIR := ""
-
-.PHONY: jerry js2c yotta flash clean
-
-all: jerry js2c yotta
-
-jerry:
- mkdir -p $(COPYTARGET)
- mkdir -p $(BUILD_DIR)
- cmake -B$(BUILD_DIR) -H./ \
- -DCMAKE_SYSTEM_NAME=Mbed \
- -DCMAKE_SYSTEM_PROCESSOR=armv7l-hf \
- -DCMAKE_C_COMPILER=arm-none-eabi-gcc \
- -DCMAKE_C_COMPILER_WORKS=TRUE \
- -DENABLE_LTO=OFF \
- -DENABLE_ALL_IN_ONE=OFF \
- -DJERRY_LIBC=OFF \
- -DJERRY_CMDLINE=OFF \
- -DEXTERNAL_COMPILE_FLAGS="$(EXT_CFLAGS)" \
- -DMEM_HEAP_SIZE_KB=$(JERRYHEAP) \
-
- make -C$(BUILD_DIR) jerry-core
- make -C$(BUILD_DIR) jerry-libm
- cp $(BUILD_DIR)/lib/libjerry-core.a $(COPYTARGET)/libjerrycore.a
- cp $(BUILD_DIR)/lib/libjerry-libm.a $(COPYTARGET)/libjerrylibm.a
-
-js2c:
- cd targets/mbed; ../../tools/js2c.py;
-
-yotta:
- cd targets/mbed; \
- yotta target $(YOTTA_TARGET); \
- yotta build
-
-flash:
- ifndef TARGET_DIR
- st-flash write targets/mbed/build/$(YOTTA_TARGET)/source/jerry.bin 0x08000000
- else
- @if [ ! -d "${TARGET_DIR}" ] ; then \
- echo "The board not mounted at ${TARGET_DIR}"; \
- exit 1; \
- fi
- cp targets/mbed/build/$(YOTTA_TARGET)/source/jerry.bin \
- "$(TARGET_DIR)/."
- endif
- @echo "Wait till LED flashing stops..."
-
-clean:
- rm -rf $(COPYTARGET)
- rm -rf $(OUTPUT)
- rm -rf targets/mbed/build
+++ /dev/null
-# Copyright JS Foundation and other contributors, http://js.foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-# Default target for running the build test outside the Travis CI environment.
-all:
- $(MAKE) install
- $(MAKE) script
-
-
-## Targets for installing build dependencies of the Mbed JerryScript target.
-
-# Install tools via apt.
-install-apt-get-deps:
- sudo apt-get install -q -y ninja-build libffi-dev libssl-dev
-
-# Install yotta
-install-yotta:
- pyenv global 2.7.13 # force the python version to a newer one
- pip install --user "pyOpenSSL<17.5" # fix for failures with pyOpenSSL 17.5
- pip install --user yotta
-
-# Perform all the necessary (JerryScript-independent) installation steps.
-install: install-apt-get-deps install-yotta
-
-
-## Targets for building Mbed with JerryScript.
-
-# Build the firmware (Mbed with JerryScript).
-script:
- $(MAKE) -f targets/mbed/Makefile.mbed board=k64f
+++ /dev/null
-/* 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.
- */
-
-var check = 1;
-
-function blink ()
-{
- var blk = (check > 8) ? 1 : 0;
- led (0, blk);
- check = (check >= 10) ? 1 : check + 1;
-}
-
-print ("blink js OK");
+++ /dev/null
-/* 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.
- */
-
-function sysloop (ticknow)
-{
- blink ();
-}
-
-print ("main js OK");
+++ /dev/null
-{
- "name": "jerry",
- "version": "0.0.1",
- "bin": "./source",
- "private": true,
- "description": "JerryScript in mbed",
- "author": "",
- "license": "Apache-2.0",
- "dependencies": {
- "mbed-drivers": "^1.5.0"
- }
-}
+++ /dev/null
-This folder contains files to run JerryScript in mbed / for:
-
-* Freedom-K64F (k64)
-* Discovery-STM32F4 (stm32f4)
-* Discovery-STM32F429ZI (stm32f429i)
-* Nucleo-F401RE (nucleo)
-
-####Yotta
-You need to install yotta before proceeding. Please visit [Yotta docs page](http://yottadocs.mbed.com/#installing-on-linux).
-
-####Cross-compiler
-For cross-compilation the GCC 5.2.1 is suggested to be used. All the supported targets were tested with this version. If you don't have any GCC compiler installed, please visit [this](https://launchpad.net/gcc-arm-embedded/+download) page to download GCC 5.2.1.
-
-####How to build a target
-Navigate to your JerryScript root folder (after you cloned this repository into the targets folder) and use the following command:
-
-```
-make -f targets/mbed/Makefile.mbed board=$(TARGET)
-```
-Where the `$(TARGET)` is one of the following options: `k64f`, `stm32f4`, `stm32f429i` or `nucleo`.
-This command will create a new folder for your target and build the jerryscript and mbed OS into that folder.
-
-####How to build a completely new target
-If you want to build a new target (which is not available in this folder) you have to modify the makefile.
-You have to add the new board name to the `TARGET_LIST` and you have to add a new branch with the new `YOTTA_TARGET` and a new `TARGET_DIR` path (if it neccessary) to the if at the top in the Makefile (just as you see right now).
-There is a little code snippet:
-
-```
-ifeq ($(TARGET), k64f)
- YOTTA_TARGET = frdm-k64f-gcc
- TARGET_DIR ?= /media/$(USER)/MBED
-else ifeq ($(TARGET), stm32f4)
- YOTTA_TARGET =
-```
-
-Basically, you can create a new target in this way (If the mbed OS support your board).
-
-#####Let's get into the details!
-1. The next rule is the `jerry` rule. This rule builds the JerryScript and copy the output files into the target libjerry folder. Two files will be generated at `targets/mbed/libjerry`:
- * libjerrycore.a
- * libfdlibm.a
-
- You can run this rule with the following command:
- - `make -f targets/mbed/Makefile.mbed board=$(TARGET) jerry`
-
-2. The next rule is the `js2c`. This rule calls a `js2c.py` python script from the `jerryscript/targets/tools` and creates the JavaScript builtin file into the `targets/mbed/source/` folder. This file is the `jerry-targetjs.h`. You can run this rule with the follwoing command:
-
- - `make -f targets/mbed/Makefile.mbed board=$(TARGET) js2c`
-
-3. The last rule is the `yotta`. This rule sets the yotta target and install the mbed-drivers module, install the dependencies for the mbed OS and finaly creates the mbed binary file. The binary file will be genrated at `targets/mbed/build/$(YOTTA_TARGET)/source/jerry.bin`. You can run this rule with the following command:
-
- - `make -f targets/mbed/Makefile.mbed board=$(TARGET) yotta`
-
-4. Optional rule: `clean`. It removes the build folder from the mbed and jerry. You can run this rule with this command:
-
- - `make -f targets/mbed/Makefile.mbed board=$(TARGET) clean`
-
-#####Flashing
-When the build is finished you can flash the binary into your board if you want. In case of ST boards you have to install the `st-link` software. Please visit [this page](https://github.com/texane/stlink) to install STLink-v2.
-You can flash your binary into your board with the following command:
-```
-make -f targets/mbed/Makefile.mbed board=$(TARGET) flash
-```
-The flash rule grabs the binary and copies it to the mounted board or use the STLink-v2 to flash.
-When the status LED of the board stops blinking, press RESET button on the board to execute JerryScript led flashing sample program in js folder.
-
-###Note
-If you use an STM32F4 board your build will stop with missing header errors. To fix this error please visit to [this page](http://browser.sed.hu/blog/20160407/how-run-javascripts-jerryscript-mbed) and read about the fix in the `New target for STM32F4` block.
+++ /dev/null
-/* 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 <stdlib.h>
-#include <stdio.h>
-
-#include "jerry-core/include/jerryscript.h"
-#include "jerry_extapi.h"
-
-#include "native_mbed.h"
-
-#ifndef MIN
-#define MIN(A,B) ((A)<(B)?(A):(B))
-#endif
-
-//-----------------------------------------------------------------------------
-
-#define __UNSED__ __attribute__((unused))
-
-#define DECLARE_HANDLER(NAME) \
-static jerry_value_t \
-NAME ## _handler (const jerry_value_t func_value __UNSED__, \
- const jerry_value_t this_value __UNSED__, \
- const jerry_value_t args[], \
- const jerry_length_t args_cnt )
-
-#define REGISTER_HANDLER(NAME) \
- register_native_function ( # NAME, NAME ## _handler)
-
-//-----------------------------------------------------------------------------
-
-DECLARE_HANDLER(assert)
-{
- if (args_cnt == 1
- && jerry_value_is_boolean (args[0])
- && jerry_get_boolean_value (args[0]))
- {
- printf (">> Jerry assert true\r\n");
- return jerry_create_boolean (true);
- }
- printf ("ERROR: Script assertion failed\n");
- exit (JERRY_STANDALONE_EXIT_CODE_FAIL);
- return jerry_create_boolean (false);
-}
-
-DECLARE_HANDLER(led)
-{
- jerry_value_t ret_val;
-
- if (args_cnt < 2)
- {
- ret_val = jerry_create_boolean (false);
- printf ("Error: invalid arguments number!\r\n");
- return ret_val;
- }
-
- if (!(jerry_value_is_number (args[0])
- && jerry_value_is_number (args[1])))
- {
- ret_val = jerry_create_boolean (false);
- printf ("Error: arguments must be numbers!\r\n");
- return ret_val;
- }
-
- int port, value;
- port = (int) jerry_get_number_value (args[0]);
- value = (int) jerry_get_number_value (args[1]);
-
- if (port >= 0 && port <= 3)
- {
- native_led (port, value);
- ret_val = jerry_create_boolean (true);
- }
- else
- {
- ret_val = jerry_create_boolean (false);
- }
- return ret_val;
-}
-
-//-----------------------------------------------------------------------------
-
-static bool
-register_native_function (const char* name,
- jerry_external_handler_t handler)
-{
- jerry_value_t global_object_val = jerry_get_global_object ();
- jerry_value_t reg_function = jerry_create_external_function (handler);
-
- bool is_ok = true;
-
- if (!(jerry_value_is_function (reg_function)
- && jerry_value_is_constructor (reg_function)))
- {
- is_ok = false;
- printf ("Error: create_external_function failed !!!\r\n");
- jerry_release_value (global_object_val);
- jerry_release_value (reg_function);
- return is_ok;
- }
-
- if (jerry_value_has_error_flag (reg_function))
- {
- is_ok = false;
- printf ("Error: create_external_function has error flag! \n\r");
- jerry_release_value (global_object_val);
- jerry_release_value (reg_function);
- return is_ok;
- }
-
- jerry_value_t jerry_name = jerry_create_string ((jerry_char_t *) name);
-
- jerry_value_t set_result = jerry_set_property (global_object_val,
- jerry_name,
- reg_function);
-
-
- if (jerry_value_has_error_flag (set_result))
- {
- is_ok = false;
- printf ("Error: register_native_function failed: [%s]\r\n", name);
- }
-
- jerry_release_value (jerry_name);
- jerry_release_value (global_object_val);
- jerry_release_value (reg_function);
- jerry_release_value (set_result);
-
- return is_ok;
-}
-
-void js_register_functions (void)
-{
- REGISTER_HANDLER (assert);
- REGISTER_HANDLER (led);
-}
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __JERRY_EXTAPI_H__
-#define __JERRY_EXTAPI_H__
-
-#define JERRY_STANDALONE_EXIT_CODE_OK (0)
-#define JERRY_STANDALONE_EXIT_CODE_FAIL (1)
-
-void js_register_functions (void);
-
-#endif
+++ /dev/null
-/* 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 <stdlib.h>
-#include <stdio.h>
-
-#include "jerry-core/include/jerryscript.h"
-#include "jerry_extapi.h"
-#include "jerry_run.h"
-
-static const char* fn_sys_loop_name = "sysloop";
-
-int js_entry (const char *source_p, const size_t source_size)
-{
- const jerry_char_t *jerry_src = (const jerry_char_t *) source_p;
- jerry_init (JERRY_INIT_EMPTY);
- uint8_t ret_code = 0;
-
- js_register_functions ();
-
- jerry_value_t parsed_code = jerry_parse (NULL, 0, jerry_src, source_size, JERRY_PARSE_NO_OPTS);
-
- if (!jerry_value_has_error_flag (parsed_code))
- {
- jerry_value_t ret_value = jerry_run (parsed_code);
-
- if (jerry_value_has_error_flag (ret_value))
- {
- printf ("Error: ret_value has an error flag!\r\n");
- return ret_code = -1;
- }
-
- jerry_release_value (ret_value);
- }
- else
- {
- printf ("Error: jerry_parse failed!\r\n");
- ret_code = -1;
- }
-
- jerry_release_value (parsed_code);
-
- return ret_code;
-}
-
-int js_eval (const char *source_p, const size_t source_size)
-{
- int status = 0;
-
- jerry_value_t ret_val = jerry_eval ((jerry_char_t *) source_p,
- source_size,
- false);
-
- if (jerry_value_has_error_flag (ret_val))
- {
- printf ("Error: jerry_eval failed!\r\n");
- status = -1;
- }
-
- jerry_release_value (ret_val);
-
- return status;
-}
-
-int js_loop (uint32_t ticknow)
-{
- int status = 0;
- jerry_value_t global_obj = jerry_get_global_object ();
- jerry_value_t sys_name = jerry_create_string ((const jerry_char_t *) fn_sys_loop_name);
- jerry_value_t sysloop_func = jerry_get_property (global_obj, sys_name);
-
- jerry_release_value (sys_name);
-
- if (jerry_value_has_error_flag (sysloop_func))
- {
- printf ("Error: '%s' not defined!!!\r\n", fn_sys_loop_name);
- jerry_release_value (global_obj);
- jerry_release_value (sysloop_func);
- return -1;
- }
-
- if (!jerry_value_is_function (sysloop_func))
- {
- printf ("Error: '%s' is not a function!!!\r\n", fn_sys_loop_name);
- jerry_release_value (global_obj);
- jerry_release_value (sysloop_func);
- return -2;
- }
-
- jerry_value_t val_args[1];
- uint16_t val_argv = 1;
-
- val_args[0] = jerry_create_number (ticknow);
-
- jerry_value_t ret_val_sysloop = jerry_call_function (sysloop_func,
- global_obj,
- val_args,
- val_argv);
- if (jerry_value_has_error_flag (ret_val_sysloop))
- {
- status = -3;
- }
-
- jerry_release_value (global_obj);
- jerry_release_value (ret_val_sysloop);
- jerry_release_value (sysloop_func);
- jerry_release_value (val_args[0]);
-
- return status;
-}
-
-void js_exit (void)
-{
- jerry_cleanup ();
-}
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __JERRY_RUN_H__
-#define __JERRY_RUN_H__
-
-int js_entry (const char *source_p, const size_t source_size);
-int js_eval (const char *source_p, const size_t source_size);
-int js_loop (uint32_t ticknow);
-void js_exit (void);
-
-#endif
+++ /dev/null
-/* 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 "mbed-drivers/mbed.h"
-
-#include "jerry-core/include/jerryscript.h"
-#include "jerry-core/include/jerryscript-port.h"
-#include "jerry_run.h"
-
-#include "jerry-targetjs.h"
-
-static Serial pc (USBTX, USBRX); //tx, rx
-
-static int jerry_task_init (void)
-{
- srand ((unsigned) jerry_port_get_current_time ());
- int retcode;
-
- DECLARE_JS_CODES;
-
- /* run main.js */
- retcode = js_entry (js_codes[0].source, js_codes[0].length);
- if (retcode != 0)
- {
- printf ("js_entry failed code(%d) [%s]\r\n", retcode, js_codes[0].name);
- js_exit ();
- return -1;
- }
- /* run rest of the js files */
- for (int src = 1; js_codes[src].source; src++)
- {
- retcode = js_eval (js_codes[src].source, js_codes[src].length);
- if (retcode != 0)
- {
- printf ("js_eval failed code(%d) [%s]\r\n", retcode, js_codes[src].name);
- js_exit ();
- return -2;
- }
- }
- return 0;
-}
-
-static void jerry_loop (void)
-{
- static uint32_t _jcount = 0;
-
- js_loop (_jcount++);
-}
-
-void app_start (int, char**)
-{
- /* set 9600 baud rate for stdout */
- pc.baud (9600);
-
- printf ("\r\nJerryScript in mbed\r\n");
- printf ("Version: \t%d.%d\n\n", JERRY_API_MAJOR_VERSION, JERRY_API_MINOR_VERSION);
-
- if (jerry_task_init () == 0)
- {
- minar::Scheduler::postCallback(jerry_loop).period(minar::milliseconds(100));
- }
-}
+++ /dev/null
-# 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.
-
-# application name
-set(MBEDMODULE "jerry")
-
-# add include jerry-core
-set(LJCORE ${CMAKE_CURRENT_LIST_DIR}/../../../)
-include_directories(${LJCORE})
-
-# compile flags
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlittle-endian -mthumb -mcpu=cortex-m4" )
-
-# link jerryscript
-set(LJPATH ${CMAKE_CURRENT_LIST_DIR}/../libjerry)
-set(LJFILES "")
-set(LJFILES ${LJFILES} ${LJPATH}/libjerrylibm.a)
-set(LJFILES ${LJFILES} ${LJPATH}/libjerrycore.a)
-target_link_libraries(${MBEDMODULE} ${LJFILES})
+++ /dev/null
-/* 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 "mbed-drivers/mbed.h"
-
-#include "native_mbed.h"
-
-void native_led (int port, int val)
-{
- static const PinName portmap[] = { LED1, LED2, LED3, LED4 };
- static DigitalOut led (portmap[port]);
- led = val;
-}
+++ /dev/null
-/* Copyright JS Foundation and other contributors, http://js.foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __NATIVE_MBED_H__
-#define __NATIVE_MBED_H__
-
-void native_led (int port, int val);
-
-#endif /* !__NATIVE_MBED_H__ */
+++ /dev/null
-/* 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.
- */
-
-#define _BSD_SOURCE
-#include <stdarg.h>
-#include <stdlib.h>
-#include <sys/time.h>
-
-#include "jerry-core/include/jerryscript-port.h"
-
-#include "mbed-hal/us_ticker_api.h"
-
-/**
- * Provide log message implementation for the engine.
- */
-void
-jerry_port_log (jerry_log_level_t level, /**< log level */
- const char *format, /**< format string */
- ...) /**< parameters */
-{
- (void) level; /* ignore log level */
-
- va_list args;
- va_start (args, format);
- vfprintf (stderr, format, args);
- va_end (args);
-} /* jerry_port_log */
-
-/**
- * Implementation of jerry_port_fatal.
- */
-void
-jerry_port_fatal (jerry_fatal_code_t code) /**< fatal code enum item */
-{
- exit (code);
-} /* jerry_port_fatal */
-
-/**
- * Implementation of jerry_port_get_time_zone.
- *
- * @return true - if success
- */
-bool
-jerry_port_get_time_zone (jerry_time_zone_t *tz_p) /**< timezone pointer */
-{
- tz_p->offset = 0;
- tz_p->daylight_saving_time = 0;
- return true;
-} /* jerry_port_get_time_zone */
-
-/**
- * Implementation of jerry_port_get_current_time.
- *
- * @return current timer's counter value in milliseconds
- */
-double
-jerry_port_get_current_time (void)
-{
- /* Note: if the target has its own RTC, this value should be extended by the
- * RTC's one. */
- return (double) us_ticker_read () / 1000;
-} /* jerry_port_get_current_time */
install:
pip install --user mbed-cli
cd targets/mbedos5 && mbed deploy
+ pip install --user mbed-host-tests==1.4.2 # FIXME: mbed-host-tests 1.4.4 requires pyocd>=0.14.0, which cannot be satisfied for whatever reason
pip install --user -r targets/mbedos5/mbed-os/requirements.txt
jerry_value_t result = jerry_set_property_by_index(function_obj_p, id, args[0]);
- if (jerry_value_has_error_flag(result)) {
+ if (jerry_value_is_error(result)) {
jerry_release_value(result);
mbed::js::EventLoop::getInstance().getQueue().cancel(id);
jerry_value_t result = jerry_set_property_by_index(function_obj_p, id, args[0]);
- if (jerry_value_has_error_flag(result)) {
+ if (jerry_value_is_error(result)) {
jerry_release_value(result);
mbed::js::EventLoop::getInstance().getQueue().cancel(id);
jerry_value_t parsed_code = jerry_parse(NULL, 0, code, length, JERRY_PARSE_NO_OPTS);
- if (jerry_value_has_error_flag(parsed_code)) {
+ if (jerry_value_is_error(parsed_code)) {
LOG_PRINT_ALWAYS("jerry_parse failed [%s]\r\n", js_codes[src].name);
jerry_release_value(parsed_code);
jsmbed_js_exit();
jerry_value_t returned_value = jerry_run(parsed_code);
jerry_release_value(parsed_code);
- if (jerry_value_has_error_flag(returned_value)) {
+ if (jerry_value_is_error(returned_value)) {
LOG_PRINT_ALWAYS("jerry_run failed [%s]\r\n", js_codes[src].name);
jerry_release_value(returned_value);
jsmbed_js_exit();
extern uint32_t jsmbed_js_magic_string_count;
extern uint32_t jsmbed_js_magic_string_values[];
-extern const jerry_char_ptr_t jsmbed_js_magic_strings[];
+extern const jerry_char_t *jsmbed_js_magic_strings[];
extern const jerry_length_t jsmbed_js_magic_string_lengths[];
void jsmbed_js_load_magic_strings() {
return is_ok;
}
- if (jerry_value_has_error_flag(reg_function)) {
+ if (jerry_value_is_error(reg_function)) {
is_ok = false;
LOG_PRINT_ALWAYS("Error: jerry_create_external_function has error flag! \r\n");
jerry_release_value(global_object_val);
jerry_value_t set_result = jerry_set_property(global_object_val, jerry_name, reg_function);
- if (jerry_value_has_error_flag(set_result)) {
+ if (jerry_value_is_error(set_result)) {
is_ok = false;
LOG_PRINT_ALWAYS("Error: jerry_create_external_function failed: [%s]\r\n", name);
}
#endif /* JSMBED_OVERRIDE_JERRY_PORT_LOG */
/**
- * Implementation of jerry_port_get_time_zone.
+ * Implementation of jerry_port_get_local_time_zone_adjustment.
*
- * @return true - if success
+ * @return 0, as we live in UTC.
*/
-bool
-jerry_port_get_time_zone (jerry_time_zone_t *tz_p) /**< timezone pointer */
+double
+jerry_port_get_local_time_zone_adjustment (double unix_ms, bool is_utc)
{
- tz_p->offset = 0;
- tz_p->daylight_saving_time = 0;
- return true;
-} /* jerry_port_get_time_zone */
+ return 0;
+} /* jerry_port_get_local_time_zone_adjustment */
/**
* Implementation of jerry_port_get_current_time.
cmake/*
docs/*
-jerry-libc/*
jerry-libm/*
jerry-main/*
jerry-port/default/default-date.c
# See the License for the specific language governing permissions and
# limitations under the License.
"""
-Generate pins.js for a specified target, using target definitions from the
+Generate pins.cpp for a specified target, using target definitions from the
mbed OS source tree.
It's expecting to be run from the targets/mbedos5 directory.
import sys
import os
-from simpleeval import SimpleEval, DEFAULT_OPERATORS
from pycparserext.ext_c_parser import GnuCParser
-from pycparser import parse_file, c_ast, c_generator
+from pycparser import parse_file, c_ast
# import mbed tools
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'mbed-os'))
Visit a node.
"""
if node.declname in self.names:
- c_gen = c_generator.CGenerator()
- pins = {}
-
- operators = DEFAULT_OPERATORS
- operators[ast.BitOr] = lambda a, b: a | b
- operators[ast.LShift] = lambda a, b: a << b
- operators[ast.RShift] = lambda a, b: a << b
- evaluator = SimpleEval(DEFAULT_OPERATORS)
-
- for pin in node.type.values.enumerators:
- expr = c_gen.visit(pin.value)
-
- if "(int)" in expr:
- expr = expr.replace('(int)', '')
-
- if expr in pins:
- pins[pin.name] = pins[expr]
- else:
- pins[pin.name] = evaluator.eval(expr.strip())
-
- return pins
+ return [pin.name for pin in node.type.values.enumerators]
def enumerate_pins(c_source_file, include_dirs, definitions):
return visitor.visit(parsed_ast)
-def write_pins_to_files(pins, out_js_file, out_cpp_file):
+def write_pins_to_file(pins, pins_file, out_cpp_file):
"""
- Write the generated pins for a specified mbed board into the output JS and C++ files.
+ Write the generated pins for a specified mbed board into the output C++ file.
"""
- out_js = '\r\n'.join(['var %s = %s;' % pin for pin in pins])
- out_js_file.write(out_js)
+
+ include = '\n#include "../{}"'.format(pins_file)
count = '''
unsigned int jsmbed_js_magic_string_count = {};
'''.format(len(pins))
- lengths = ',\n '.join(str(len(pin[0])) for pin in pins)
+ lengths = ',\n '.join(str(len(pin)) for pin in pins)
lenghts_source = '''
unsigned int jsmbed_js_magic_string_lengths[] = {
%s
};
''' % lengths
- magic_values = ',\n '.join(str(pin[1]) for pin in pins)
+ magic_values = ',\n '.join(pins)
magic_source = '''
unsigned int jsmbed_js_magic_string_values[] = {
%s
};
''' % magic_values
- magic_strings = ',\n '.join('"' + pin[0] + '"' for pin in pins)
+ magic_strings = ',\n '.join('"' + pin + '"' for pin in pins)
magic_string_source = '''
const char * jsmbed_js_magic_strings[] = {
%s
};
''' % magic_strings
- out_cpp_file.write(LICENSE + count + lenghts_source + magic_source + magic_string_source)
+ out_cpp_file.write(LICENSE + include + count + lenghts_source + magic_source + magic_string_source)
def main():
sys.exit(1)
description = """
- Generate pins.js for a specified mbed board, using target definitions from the
+ Generate pins.cpp for a specified mbed board, using target definitions from the
mbed OS source tree.
"""
parser = argparse.ArgumentParser(description=description)
parser.add_argument('board', help='mbed board name')
- parser.add_argument('-o',
- help='Output JavaScript file (default: %(default)s)',
- default='js/pins.js',
- type=argparse.FileType('w'))
parser.add_argument('-c',
help='Output C++ file (default: %(default)s)',
default='source/pins.cpp',
pins = enumerate_pins(pins_file, ['./tools'] + list(includes), defines)
# first sort alphabetically, then by length.
- pins = [(x, pins[x]) for x in pins] # turn dict into tuples, which can be sorted
- pins = sorted(pins, key=lambda x: (len(x[0]), x[0].lower()))
+ pins = sorted(pins, key=lambda x: (len(x), x.lower()))
- write_pins_to_files(pins, args.o, args.c)
+ write_pins_to_file(pins, pins_file, args.c)
if __name__ == "__main__":
git clone https://bitbucket.org/nuttx/nuttx.git ../nuttx -b nuttx-7.22
# Perform all the necessary (JerryScript-independent) installation steps.
-install: install-apt-get-deps install-kconfig install-clone-nuttx
+install-noapt: install-kconfig install-clone-nuttx
+install: install-apt-get-deps install-noapt
## Targets for building NuttX with JerryScript.
# Build JerryScript.
script-build-jerryscript:
- tools/build.py --clean --toolchain cmake/toolchain_mcu_stm32f4.cmake --profile=es2015-subset --jerry-cmdline OFF --jerry-libc OFF --lto OFF --jerry-libm ON --all-in-one ON --mem-heap 70 --compile-flag='--sysroot=../nuttx'
+ tools/build.py --clean --toolchain cmake/toolchain_mcu_stm32f4.cmake --profile=es2015-subset --jerry-cmdline OFF --lto OFF --jerry-libm ON --all-in-one ON --mem-heap 70 --compile-flag='--sysroot=../nuttx'
# Link in the NuttX JerryScript target directory under the NuttX apps tree.
script-add-jerryscript-app:
--clean \
--lto=OFF \
--jerry-cmdline=OFF \
- --jerry-libc=OFF \
--jerry-libm=ON \
--all-in-one=ON \
--mem-heap=70 \
#include <stdlib.h>
#include "jerryscript.h"
+#include "jerryscript-ext/debugger.h"
#include "jerryscript-ext/handler.h"
#include "jerryscript-port.h"
#include "setjmp.h"
print_unhandled_exception (jerry_value_t error_value, /**< error value */
const jerry_char_t *source_p) /**< source_p */
{
- assert (jerry_value_has_error_flag (error_value));
+ assert (jerry_value_is_error (error_value));
- error_value = jerry_get_value_without_error_flag (error_value);
+ error_value = jerry_get_value_from_error (error_value, false);
jerry_value_t err_str_val = jerry_value_to_string (error_value);
jerry_size_t err_str_size = jerry_get_string_size (err_str_val);
jerry_char_t err_str_buf[256];
{
jerry_value_t result_val = jerryx_handler_register_global ((const jerry_char_t *) name_p, handler_p);
- if (jerry_value_has_error_flag (result_val))
+ if (jerry_value_is_error (result_val))
{
jerry_port_log (JERRY_LOG_LEVEL_WARNING, "Warning: failed to register '%s' method.", name_p);
}
if (start_debug_server)
{
- jerry_debugger_init (debug_port);
+ jerryx_debugger_after_connect (jerryx_debugger_tcp_create (debug_port)
+ && jerryx_debugger_ws_create ());
}
register_js_function ("assert", jerryx_handler_assert);
{
printf ("No input files, running a hello world demo:\n");
const jerry_char_t script[] = "var str = 'Hello World'; print(str + ' from JerryScript')";
- size_t script_size = strlen ((const char *) script);
- ret_value = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS);
+ ret_value = jerry_parse (NULL, 0, script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
- if (!jerry_value_has_error_flag (ret_value))
+ if (!jerry_value_is_error (ret_value))
{
ret_value = jerry_run (ret_value);
}
source_size,
JERRY_PARSE_NO_OPTS);
- if (!jerry_value_has_error_flag (ret_value))
+ if (!jerry_value_is_error (ret_value))
{
jerry_value_t func_val = ret_value;
ret_value = jerry_run (func_val);
jerry_release_value (func_val);
}
- if (jerry_value_has_error_flag (ret_value))
+ if (jerry_value_is_error (ret_value))
{
print_unhandled_exception (ret_value, source_p);
free ((void*) source_p);
int ret_code = JERRY_STANDALONE_EXIT_CODE_OK;
- if (jerry_value_has_error_flag (ret_value))
+ if (jerry_value_is_error (ret_value))
{
ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL;
}
ret_value = jerry_run_all_enqueued_jobs ();
- if (jerry_value_has_error_flag (ret_value))
+ if (jerry_value_is_error (ret_value))
{
ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL;
}
} /* jerry_port_log */
/**
- * Dummy function to get the time zone.
+ * Dummy function to get the time zone adjustment.
*
- * @return true
+ * @return 0
*/
-bool
-jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
+double
+jerry_port_get_local_time_zone_adjustment (double unix_ms, bool is_utc)
{
/* We live in UTC. */
- tz_p->offset = 0;
- tz_p->daylight_saving_time = 0;
-
- return true;
-} /* jerry_port_get_time_zone */
+ return 0;
+} /* jerry_port_get_local_time_zone_adjustment */
/**
* Dummy function to get the current time.
```
$ ./tools/build.py --toolchain cmake/toolchain_openwrt_mips.cmake \
- --jerry-libc OFF \
--lto OFF
```
-Currenlty the JerryScript libc does not supports the mips platform, that's why the `--jerry-libc OFF` argument
-is passed during build.
-
### 2. Copy the binary
After a successful build the `build/bin/jerry` binary file can be copied to the target device.
-DCMAKE_C_COMPILER_WORKS=TRUE \
-DENABLE_LTO=ON \
-DENABLE_ALL_IN_ONE=OFF \
- -DJERRY_LIBC=OFF \
-DJERRY_LIBM=OFF \
-DJERRY_CMDLINE=OFF \
-DFEATURE_PROFILE=minimal \
test.delay(250); \
";
- size_t script_size = strlen ((const char *) script);
-
- jerry_value_t eval_ret = jerry_eval (script, script_size, false);
+ jerry_value_t eval_ret = jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
/* Free JavaScript value, returned by eval */
jerry_release_value (eval_ret);
# default BOARD enviroment
BOARD ?= stm32f4discovery
+# LLVM/Clang-based toolchain
+TOOLCHAIN ?= llvm
+
# path to the RIOT base directory
RIOTBASE ?= $(CURDIR)/../RIOT
# path to the JERRYSCRIPT directory
# path to the binary directory
BINDIR ?= $(JERRYDIR)/targets/riot-stm32f4/bin/
-# Comment this out to disable code in RIOT that does safety checking
-# which is not needed in a production environment but helps in the
-# development process:
-CFLAGS += -DDEVELHELP
-
# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1
USEMODULE += shell_commands
# Add the jerry libs
-USEMODULE += libjerrycore libjerryport-minimal libjerryext
+USEMODULE += libjerry-core libjerry-port-default-minimal libjerry-ext
include $(RIOTBASE)/Makefile.include
# See the License for the specific language governing permissions and
# limitations under the License.
+# Build and output directories
BUILD_DIR ?= build/riotstm32f4
COPYTARGET ?= targets/riot-stm32f4/bin
+# JerryScript configuration
JERRYHEAP ?= 16
-EXT_CFLAGS := -D__TARGET_RIOT_STM32F4
+# To be defined on the command line of make if Clang is available via a
+# different name (e.g., clang-N.M)
+CC ?= clang
+
+# Cross-compilation settings for Clang
+EXT_CFLAGS := -target arm-none-eabi
EXT_CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4
-EXT_CFLAGS += -Wno-error=format=
+EXT_CFLAGS += -isystem /usr/arm-none-eabi/include
+EXT_CFLAGS += $(addprefix -isystem $(lastword $(sort $(wildcard /usr/lib/gcc/arm-none-eabi/*/))), include include-fixed)
+EXT_CFLAGS += -nostdinc
+
+# For ABI compatibility with RIOT-OS
+EXT_CFLAGS += -fshort-enums
+
.PHONY: libjerry riot-jerry flash clean
libjerry:
mkdir -p $(BUILD_DIR)
- mkdir -p $(COPYTARGET)
cmake -B$(BUILD_DIR) -H./ \
-DCMAKE_SYSTEM_NAME=RIOT \
-DCMAKE_SYSTEM_PROCESSOR=armv7l \
- -DCMAKE_C_COMPILER=arm-none-eabi-gcc \
+ -DCMAKE_C_COMPILER=$(CC) \
-DCMAKE_C_COMPILER_WORKS=TRUE \
-DENABLE_LTO=OFF \
-DENABLE_ALL_IN_ONE=OFF \
- -DJERRY_LIBC=OFF \
-DJERRY_LIBM=OFF \
-DJERRY_CMDLINE=OFF \
-DEXTERNAL_COMPILE_FLAGS="$(EXT_CFLAGS)" \
-DMEM_HEAP_SIZE_KB=$(JERRYHEAP)
-
make -C$(BUILD_DIR) jerry-core jerry-port-default-minimal jerry-ext
- cp $(BUILD_DIR)/lib/libjerry-core.a $(COPYTARGET)/libjerrycore.a
- cp $(BUILD_DIR)/lib/libjerry-port-default-minimal.a $(COPYTARGET)/libjerryport-minimal.a
- cp $(BUILD_DIR)/lib/libjerry-ext.a $(COPYTARGET)/libjerryext.a
+ mkdir -p $(COPYTARGET)
+ cp $(BUILD_DIR)/lib/libjerry-core.a $(COPYTARGET)
+ cp $(BUILD_DIR)/lib/libjerry-port-default-minimal.a $(COPYTARGET)
+ cp $(BUILD_DIR)/lib/libjerry-ext.a $(COPYTARGET)
riot-jerry: libjerry
make -f ./targets/riot-stm32f4/Makefile
# Install cross-compiler via apt.
install-apt-get-deps:
- sudo apt-get install -q -y gcc-arm-none-eabi
+ sudo apt-get install -q -y clang-3.9 gcc-arm-embedded gcc-multilib
# Fetch RIOT OS repository.
install-clone-riot:
- git clone git://github.com/RIOT-OS/RIOT.git ../RIOT -b 2017.10
+ git clone git://github.com/RIOT-OS/RIOT.git ../RIOT -b 2018.07
# Perform all the necessary (JerryScript-independent) installation steps.
-install: install-apt-get-deps install-clone-riot
+install-noapt: install-clone-riot
+install: install-apt-get-deps install-noapt
## Targets for building RIOT with JerryScript.
{
jerry_value_t result_val = jerryx_handler_register_global ((const jerry_char_t *) name_p, handler_p);
- if (jerry_value_has_error_flag (result_val))
+ if (jerry_value_is_error (result_val))
{
printf ("Warning: failed to register '%s' method.", name_p);
}
jerry_value_t ret_value = jerry_create_undefined ();
const jerry_char_t script[] = "print ('Hello, World!');";
- size_t script_size = strlen ((const char *) script);
printf ("This test run the following script code: [%s]\n\n", script);
/* Initialize engine */
register_js_function ("print", jerryx_handler_print);
/* Setup Global scope code */
- ret_value = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS);
+ ret_value = jerry_parse (NULL, 0, script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
- if (!jerry_value_has_error_flag (ret_value))
+ if (!jerry_value_is_error (ret_value))
{
/* Execute the parsed source code in the Global scope */
ret_value = jerry_run (ret_value);
int ret_code = JERRY_STANDALONE_EXIT_CODE_OK;
- if (jerry_value_has_error_flag (ret_value))
+ if (jerry_value_is_error (ret_value))
{
printf ("Script Error!");
cmake -B$(BUILD_DIR) -H./ \
-DENABLE_LTO=OFF \
-DENABLE_ALL_IN_ONE=OFF \
- -DJERRY_LIBC=OFF \
-DJERRY_CMDLINE=OFF \
-DEXTERNAL_COMPILE_FLAGS="$(EXT_CFLAGS)" \
-DMEM_HEAP_SIZE_KB=$(JERRYHEAP) \
```
$ sudo apt-add-repository -y "ppa:team-gcc-arm-embedded/ppa"
-$ sudo apt-get update
+$ sudo apt-get update
$ sudo apt-get install gcc-arm-embedded
$ git clone https://github.com/jerryscript-project/jerryscript.git jerryscript
$ cd jerryscript
--clean \
--lto=OFF \
--jerry-cmdline=OFF \
- --jerry-libc=OFF \
--all-in-one=OFF \
--mem-heap=70 \
--profile=es2015-subset \
TASH>>jerry
No input files, running a hello world demo:
Hello World from JerryScript
-```
\ No newline at end of file
+```
endif
ifeq ($(CONFIG_WINDOWS_NATIVE),y)
- BIN = ..\..\libapps$(LIBEXT)
+ BIN = $(APPDIR)\libapps$(LIBEXT)
else
ifeq ($(WINTOOL),y)
- BIN = ..\\..\\libapps$(LIBEXT)
+ BIN = $(APPDIR)\\libapps$(LIBEXT)
else
- BIN = ../../libapps$(LIBEXT)
+ BIN = $(APPDIR)/libapps$(LIBEXT)
endif
endif
#include <tinyara/fs/fs_utils.h>
#include "jerryscript.h"
+#include "jerryscript-ext/debugger.h"
#include "jerryscript-ext/handler.h"
#include "jerryscript-port.h"
#include "setjmp.h"
print_unhandled_exception (jerry_value_t error_value, /**< error value */
const jerry_char_t *source_p) /**< source_p */
{
- assert (jerry_value_has_error_flag (error_value));
+ assert (jerry_value_is_error (error_value));
- error_value = jerry_get_value_without_error_flag (error_value);
+ error_value = jerry_get_value_from_error (error_value, false);
jerry_value_t err_str_val = jerry_value_to_string (error_value);
jerry_size_t err_str_size = jerry_get_string_size (err_str_val);
jerry_char_t err_str_buf[256];
{
jerry_value_t result_val = jerryx_handler_register_global ((const jerry_char_t *) name_p, handler_p);
- if (jerry_value_has_error_flag (result_val))
+ if (jerry_value_is_error (result_val))
{
jerry_port_log (JERRY_LOG_LEVEL_WARNING, "Warning: failed to register '%s' method.", name_p);
}
if (start_debug_server)
{
- jerry_debugger_init (debug_port);
+ jerryx_debugger_after_connect (jerryx_debugger_tcp_create (debug_port)
+ && jerryx_debugger_ws_create ());
}
register_js_function ("assert", jerryx_handler_assert);
{
printf ("No input files, running a hello world demo:\n");
const jerry_char_t script[] = "var str = 'Hello World'; print(str + ' from JerryScript')";
- size_t script_size = strlen ((const char *) script);
- ret_value = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS);
+ ret_value = jerry_parse (NULL, 0, script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
- if (!jerry_value_has_error_flag (ret_value))
+ if (!jerry_value_is_error (ret_value))
{
ret_value = jerry_run (ret_value);
}
source_size,
JERRY_PARSE_NO_OPTS);
- if (!jerry_value_has_error_flag (ret_value))
+ if (!jerry_value_is_error (ret_value))
{
jerry_value_t func_val = ret_value;
ret_value = jerry_run (func_val);
jerry_release_value (func_val);
}
- if (jerry_value_has_error_flag (ret_value))
+ if (jerry_value_is_error (ret_value))
{
print_unhandled_exception (ret_value, source_p);
free ((void*) source_p);
int ret_code = JERRY_STANDALONE_EXIT_CODE_OK;
- if (jerry_value_has_error_flag (ret_value))
+ if (jerry_value_is_error (ret_value))
{
ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL;
}
} /* jerry_port_log */
/**
- * Dummy function to get the time zone.
+ * Dummy function to get the time zone adjustment.
*
- * @return true
+ * @return 0
*/
-bool
-jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
+double
+jerry_port_get_local_time_zone_adjustment (double unix_ms, bool is_utc)
{
/* We live in UTC. */
- tz_p->offset = 0;
- tz_p->daylight_saving_time = 0;
-
- return true;
-} /* jerry_port_get_time_zone */
+ return 0;
+} /* jerry_port_get_local_time_zone_adjustment */
/**
* Dummy function to get the current time.
LDFLAGS += -g
endif
-LDFLAAGS += --gc-sections
+LDFLAGS += --gc-sections
HOSTCC = gcc
HOSTINCLUDES = -I.
# 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 3.8)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(NONE)
${CMAKE_CURRENT_BINARY_DIR}/../obj/lib/libjerry-ext.a)
set_target_properties(jerry-ext PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}/../../jerry-ext/include)
-target_link_libraries(app jerry-core jerry-ext)
+target_link_libraries(app PUBLIC jerry-core jerry-ext)
zephyr_get_include_directories_for_lang_as_string(C includes)
zephyr_get_system_include_directories_for_lang_as_string(C system_includes)
COMMAND echo Z_CFLAGS=${system_includes} ${includes} ${definitions} ${options}
COMMAND echo NOSTDINC_FLAGS=${system_includes}
COMMAND echo ZEPHYRINCLUDE=${includes}
- COMMAND echo KBUILD_CFLAGS=${definitions}${options}
+ COMMAND echo KBUILD_CFLAGS=${definitions} ${options}
VERBATIM
USES_TERMINAL
)
# Install Zephyr SDK.
install-zephyr-sdk:
- wget https://github.com/zephyrproject-rtos/meta-zephyr-sdk/releases/download/0.9.2/zephyr-sdk-0.9.2-setup.run -O ../zephyr-sdk-0.9.2-setup.run
- sh ../zephyr-sdk-0.9.2-setup.run -- -y -d $(CURDIR)/../zephyr-sdk-0.9.2
- wget https://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.sh
- sudo sh cmake-3.8.2-Linux-x86_64.sh --prefix=/usr/local --exclude-subdir
+ wget https://github.com/zephyrproject-rtos/meta-zephyr-sdk/releases/download/0.9.3/zephyr-sdk-0.9.3-setup.run -O ../zephyr-sdk-0.9.3-setup.run
+ sh ../zephyr-sdk-0.9.3-setup.run -- -y -d $(CURDIR)/../zephyr-sdk-0.9.3
cmake --version
# Fetch Zephyr Project repository and install python dependencies.
-install-zephyr: install-apt-get-deps
- git clone https://github.com/zephyrproject-rtos/zephyr.git ../zephyr -b v1.10.0
+install-zephyr:
+ git clone https://github.com/zephyrproject-rtos/zephyr.git ../zephyr -b v1.13.0
+ pip3 install --user -U pip
+ pip3 install --user -U setuptools
+ # FIXME: It's temporary workaround to make Travis CI happy for Zephry v1.13.0.
+ pip3 install --user pyocd==0.12.0
pip3 install --user -r ../zephyr/scripts/requirements.txt
# Perform all the necessary (JerryScript-independent) installation steps.
-install: install-zephyr-sdk install-zephyr
+install-noapt: install-zephyr-sdk install-zephyr
+install: install-apt-get-deps install-noapt
## Targets for building Zephyr with JerryScript.
SHELL=bash
script:
export ZEPHYR_GCC_VARIANT=zephyr && \
- export ZEPHYR_SDK_INSTALL_DIR=$(CURDIR)/../zephyr-sdk-0.9.2 && \
+ export ZEPHYR_SDK_INSTALL_DIR=$(CURDIR)/../zephyr-sdk-0.9.3 && \
source ../zephyr/zephyr-env.sh && \
$(MAKE) -f ./targets/zephyr/Makefile.zephyr BOARD=arduino_101
-DCMAKE_C_COMPILER_WORKS=TRUE \
-DENABLE_LTO=OFF \
-DENABLE_ALL_IN_ONE=OFF \
- -DJERRY_LIBC=OFF \
-DJERRY_CMDLINE=OFF \
-DFEATURE_PROFILE=$(JERRYPROFILE) \
-DFEATURE_ERROR_MESSAGES=ON \
CONFIG_FLOAT=y
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_CONSOLE_HANDLER=y
-CONFIG_CONSOLE_HANDLER_SHELL=y
-CONFIG_ARC_INIT=n
-
} /* jerry_port_get_current_time */
/**
- * Dummy function to get the time zone.
+ * Dummy function to get the time zone adjustment.
*
- * @return true
+ * @return 0
*/
-bool
-jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
+double
+jerry_port_get_local_time_zone_adjustment (double unix_ms, bool is_utc)
{
/* We live in UTC. */
- tz_p->offset = 0;
- tz_p->daylight_saving_time = 0;
-
- return true;
-} /* jerry_port_get_time_zone */
+ return 0;
+} /* jerry_port_get_local_time_zone_adjustment */
/**
* Provide the implementation of jerryx_port_handler_print_char.
{
jerry_value_t result_val = jerryx_handler_register_global ((const jerry_char_t *) name_p, handler_p);
- if (jerry_value_has_error_flag (result_val))
+ if (jerry_value_is_error (result_val))
{
jerry_port_log (JERRY_LOG_LEVEL_WARNING, "Warning: failed to register '%s' method.", name_p);
}
ret_val = jerry_eval ((jerry_char_t *) source_buffer,
strlen (source_buffer),
- false);
+ JERRY_PARSE_NO_OPTS);
- if (jerry_value_has_error_flag (ret_val))
+ if (jerry_value_is_error (ret_val))
{
/* User-friendly error messages require at least "cp" JerryScript
profile. Include a message prefix in case "cp_minimal" profile
printf ("Error executing statement: ");
/* Clear error flag, otherwise print call below won't produce any
output. */
- jerry_value_clear_error_flag (&ret_val);
+ ret_val = jerry_get_value_from_error (ret_val, true);
}
- if (!jerry_value_has_error_flag (print_function))
+ if (!jerry_value_is_error (print_function))
{
jerry_value_t ret_val_print = jerry_call_function (print_function,
jerry_create_undefined (),
print_function = jerry_get_property (global_obj_val, print_func_name_val);
jerry_release_value (print_func_name_val);
jerry_release_value (global_obj_val);
- if (jerry_value_has_error_flag (print_function))
+ if (jerry_value_is_error (print_function))
{
printf ("Error: could not look up print function, expression results won't be printed\n");
}
step
next
s
+bt 1 2 t
+bt 1 2
+bt 0 3 t
bt
+bt 2
+bt 2 t
n
n
s
backtrace
+bt 4 4
+bt 600 919
+bt 3 500
+bt 42
+bt 4 3
c
Stopped at tests/debugger/do_backtrace.js:33 (in test() at line:30, col:1)
(jerry-debugger) s
Stopped at tests/debugger/do_backtrace.js:23 (in foo() at line:21, col:1)
+(jerry-debugger) bt 1 2 t
+Total number of frames: 3
+Frame 1: tests/debugger/do_backtrace.js:33 (in test() at line:30, col:1)
+(jerry-debugger) bt 1 2
+Frame 1: tests/debugger/do_backtrace.js:33 (in test() at line:30, col:1)
+(jerry-debugger) bt 0 3 t
+Total number of frames: 3
+Frame 0: tests/debugger/do_backtrace.js:23 (in foo() at line:21, col:1)
+Frame 1: tests/debugger/do_backtrace.js:33 (in test() at line:30, col:1)
+Frame 2: tests/debugger/do_backtrace.js:40
(jerry-debugger) bt
Frame 0: tests/debugger/do_backtrace.js:23 (in foo() at line:21, col:1)
Frame 1: tests/debugger/do_backtrace.js:33 (in test() at line:30, col:1)
Frame 2: tests/debugger/do_backtrace.js:40
+(jerry-debugger) bt 2
+Frame 0: tests/debugger/do_backtrace.js:23 (in foo() at line:21, col:1)
+Frame 1: tests/debugger/do_backtrace.js:33 (in test() at line:30, col:1)
+(jerry-debugger) bt 2 t
+Total number of frames: 3
+Frame 0: tests/debugger/do_backtrace.js:23 (in foo() at line:21, col:1)
+Frame 1: tests/debugger/do_backtrace.js:33 (in test() at line:30, col:1)
(jerry-debugger) n
out: function foo
Stopped at tests/debugger/do_backtrace.js:24 (in foo() at line:21, col:1)
Frame 1: tests/debugger/do_backtrace.js:25 (in foo() at line:21, col:1)
Frame 2: tests/debugger/do_backtrace.js:33 (in test() at line:30, col:1)
Frame 3: tests/debugger/do_backtrace.js:40
+(jerry-debugger) bt 4 4
+(jerry-debugger) bt 600 919
+(jerry-debugger) bt 3 500
+Frame 3: tests/debugger/do_backtrace.js:40
+(jerry-debugger) bt 42
+Frame 0: tests/debugger/do_backtrace.js:18 (in f4() at line:17, col:1)
+Frame 1: tests/debugger/do_backtrace.js:25 (in foo() at line:21, col:1)
+Frame 2: tests/debugger/do_backtrace.js:33 (in test() at line:30, col:1)
+Frame 3: tests/debugger/do_backtrace.js:40
+(jerry-debugger) bt 4 3
+Error: Start depth needs to be lower than or equal to max depth
(jerry-debugger) c
out: function f4
out: var cat
Stopped at breakpoint:1 tests/debugger/do_break.js:51
(jerry-debugger) delete 1
+Breakpoint 1 deleted
(jerry-debugger) list
=== Active breakpoints ===
2: tests/debugger/do_break.js:36 (in test() at line:20, col:1)
Breakpoint 1 at tests/debugger/do_delete.js:17
(jerry-debugger) b do_delete.js:21
No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint at do_delete.js:21
+Pending breakpoint 2 at do_delete.js:21
(jerry-debugger) b do_delete.js:19
Breakpoint 3 at tests/debugger/do_delete.js:19
(jerry-debugger) b do_delete.js:18
=== Pending breakpoints ===
2: do_delete.js:21 (pending)
(jerry-debugger) delete 2
+Pending breakpoint 2 deleted
(jerry-debugger) delete 3
+Breakpoint 3 deleted
(jerry-debugger) list
=== Active breakpoints ===
1: tests/debugger/do_delete.js:17
Breakpoint 3 at tests/debugger/do_delete_all.js:21 (in delete_test() at line:20, col:1)
(jerry-debugger) b do_delete_all:350
No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint at do_delete_all:350
+Pending breakpoint 4 at do_delete_all:350
(jerry-debugger) b do_delete_all:37
No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint at do_delete_all:37
+Pending breakpoint 5 at do_delete_all:37
(jerry-debugger) list
=== Active breakpoints ===
1: tests/debugger/do_delete_all.js:17
--- /dev/null
+eval_at 0
+eval_at 0 b
+n
+eval_at 0 b
+b do_eval_at.js:20
+n
+scopes
+eval_at 0 b
+eval_at 1 b
+eval_at 0 b=20
+eval_at 1 b=100
+n
+eval_at 0 a
+scopes
+eval_at 0 b
+eval_at -1 b
+eval_at 65536 b
+eval_at b
+eval_at 200
+c
--- /dev/null
+Connecting to: localhost:5001
+Stopped at tests/debugger/do_eval_at.js:15
+(jerry-debugger) eval_at 0
+undefined
+(jerry-debugger) eval_at 0 b
+undefined
+(jerry-debugger) n
+Stopped at tests/debugger/do_eval_at.js:23
+(jerry-debugger) eval_at 0 b
+2
+(jerry-debugger) b do_eval_at.js:20
+Breakpoint 1 at tests/debugger/do_eval_at.js:20 (in f() at line:17, col:1)
+(jerry-debugger) n
+Stopped at breakpoint:1 tests/debugger/do_eval_at.js:20 (in f() at line:17, col:1)
+(jerry-debugger) scopes
+level | type
+0 | local
+1 | global
+(jerry-debugger) eval_at 0 b
+6
+(jerry-debugger) eval_at 1 b
+2
+(jerry-debugger) eval_at 0 b=20
+20
+(jerry-debugger) eval_at 1 b=100
+100
+(jerry-debugger) n
+Stopped at tests/debugger/do_eval_at.js:25
+(jerry-debugger) eval_at 0 a
+23
+(jerry-debugger) scopes
+level | type
+0 | global
+(jerry-debugger) eval_at 0 b
+100
+(jerry-debugger) eval_at -1 b
+Error: Invalid scope chain index: -1 (must be between 0 and 65535)
+(jerry-debugger) eval_at 65536 b
+Error: Invalid scope chain index: 65536 (must be between 0 and 65535)
+(jerry-debugger) eval_at b
+Error: invalid literal for int() with base 10: 'b'
+(jerry-debugger) eval_at 200
+Uncaught exception: Error
+(jerry-debugger) c
--- /dev/null
+// 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.
+
+var b = 2;
+
+function f(a)
+{
+ var b = 6;
+ return a + b;
+}
+
+var a = f(3);
+
+null;
Documented commands (type help <topic>):
========================================
-abort bt display exception list next source
-b c dump f memstats quit src
-backtrace continue e finish ms s step
-break delete eval help n scroll throw
+abort c e finish n s step
+b continue eval help next scopes throw
+backtrace delete eval_at list quit scroll variables
+break display exception memstats res source
+bt dump f ms restart src
(jerry-debugger) quit
Stopped at tests/debugger/do_pending_breakpoints.js:15
(jerry-debugger) break :1
No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint at :1
+Pending breakpoint 1 at :1
(jerry-debugger) break f
No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint at f()
+Pending breakpoint 2 at f()
(jerry-debugger) list
=== Pending breakpoints ===
1: :1 (pending)
--- /dev/null
+Connecting to: localhost:5001
+Stopped at tests/debugger/do_print.js:15
+(jerry-debugger) c
+out: Hello world!
+out: A [ ] 110 null true undefined
+out:
+out: [A
+out: B C
+out: D E
+out: F
+out: G]
+out: 1: Az élet gyönyörű.
+out: 2: Az élet gyönyörű.
+out: 3: Az élet gyönyörű.
+out: 4: Az élet gyönyörű.
+out: 5: Az élet gyönyörű.
+out: 6: Az élet gyönyörű.
+out: 7: Az élet gyönyörű.
+out: 8: Az élet gyönyörű.
+out: 9: Az élet gyönyörű.
+out: 10: Az élet gyönyörű.
+out: 11: Az élet gyönyörű.
+out: 12: Az élet gyönyörű.
+out: 13: Az élet gyönyörű.
+out: 14: Az élet gyönyörű.
+out: 15: Az élet gyönyörű.
+out: 16: Az élet gyönyörű.
+out: 17: Az élet gyönyörű.
+out: 18: Az élet gyönyörű.
+out: 19: Az élet gyönyörű.
+out: 20: Az élet gyönyörű.
+out: 21: Az élet gyönyörű.
+out: 22: Az élet gyönyörű.
+out: 23: Az élet gyönyörű.
+out: 24: Az élet gyönyörű.
+out: 25: Az élet gyönyörű.
+out: 26: Az élet gyönyörű.
+out: 27: Az élet gyönyörű.
+out: 28: Az élet gyönyörű.
+out: 29: Az élet gyönyörű.
+out: 30: Az élet gyönyörű.
+out: 31: Az élet gyönyörű.
+out: 32: Az élet gyönyörű.
+out: 33: Az élet gyönyörű.
+out: 34: Az élet gyönyörű.
+out: 35: Az élet gyönyörű.
+out: 36: Az élet gyönyörű.
+out: 37: Az élet gyönyörű.
+out: 38: Az élet gyönyörű.
+out: 39: Az élet gyönyörű.
+out: 40: Az élet gyönyörű.
+out: 41: Az élet gyönyörű.
+out: 42: Az élet gyönyörű.
+out: 43: Az élet gyönyörű.
+out: 44: Az élet gyönyörű.
+out: 45: Az élet gyönyörű.
+out: 46: Az élet gyönyörű.
+out: 47: Az élet gyönyörű.
+out: 48: Az élet gyönyörű.
+out: 49: Az élet gyönyörű.
+out: 50: Az élet gyönyörű.
+out: 51: Az élet gyönyörű.
+out: 52: Az élet gyönyörű.
+out: 53: Az élet gyönyörű.
+out: 54: Az élet gyönyörű.
+out: 55: Az élet gyönyörű.
+out: 56: Az élet gyönyörű.
+out: 57: Az élet gyönyörű.
+out: 58: Az élet gyönyörű.
+out: 59: Az élet gyönyörű.
+out: 60: Az élet gyönyörű.
+out: 61: Az élet gyönyörű.
+out: 62: Az élet gyönyörű.
+out: 63: Az élet gyönyörű.
+out: 64: Az élet gyönyörű.
+out: 65: Az élet gyönyörű.
+out: 66: Az élet gyönyörű.
+out: 67: Az élet gyönyörű.
+out: 68: Az élet gyönyörű.
+out: 69: Az élet gyönyörű.
+out: 70: Az élet gyönyörű.
+out: 71: Az élet gyönyörű.
+out: 72: Az élet gyönyörű.
+out: 73: Az élet gyönyörű.
+out: 74: Az élet gyönyörű.
+out: 75: Az élet gyönyörű.
+out: 76: Az élet gyönyörű.
+out: 77: Az élet gyönyörű.
+out: 78: Az élet gyönyörű.
+out: 79: Az élet gyönyörű.
+out: 80: Az élet gyönyörű.
+out: 81: Az élet gyönyörű.
+out: 82: Az élet gyönyörű.
+out: 83: Az élet gyönyörű.
+out: 84: Az élet gyönyörű.
+out: 85: Az élet gyönyörű.
+out: 86: Az élet gyönyörű.
+out: 87: Az élet gyönyörű.
+out: 88: Az élet gyönyörű.
+out: 89: Az élet gyönyörű.
+out: 90: Az élet gyönyörű.
+out: 91: Az élet gyönyörű.
+out: 92: Az élet gyönyörű.
+out: 93: Az élet gyönyörű.
+out: 94: Az élet gyönyörű.
+out: 95: Az élet gyönyörű.
+out: 96: Az élet gyönyörű.
+out: 97: Az élet gyönyörű.
+out: 98: Az élet gyönyörű.
+out: 99: Az élet gyönyörű.
+out: 100: Az élet gyönyörű.
+out:
--- /dev/null
+// 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.
+
+print("Hello world!");
+print("A", "[", "", "]", 1.1e2, null, true, undefined);
+print();
+print("[A\nB", "C\nD", "E\nF\nG]");
+
+var s = "";
+
+for (i = 1; i <= 100; i++) {
+ /* Translated from hungarian: life is beautiful */
+ s += i + ": Az élet gyönyörű.\n";
+}
+
+/* Long string with non-ascii characters. */
+print(s);
--- /dev/null
+n
+n
+n
+restart
--- /dev/null
+Connecting to: localhost:5001
+Stopped at tests/debugger/do_restart.js:23
+(jerry-debugger) n
+Stopped at tests/debugger/do_restart.js:24
+(jerry-debugger) n
+out: foo
+Stopped at tests/debugger/do_restart.js:25
+(jerry-debugger) n
+out: bar
+Stopped at tests/debugger/do_restart.js:24
+(jerry-debugger) restart
+Connecting to: localhost:5001
+Stopped at tests/debugger/do_restart.js:23
+(jerry-debugger) continue
+out: foo
+out: bar
+out: foo
+out: bar
--- /dev/null
+// 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.
+
+function foo() {
+ print("foo");
+}
+
+function bar() {
+ print("bar");
+}
+
+for (var i = 0; i < 2; i++) {
+ foo();
+ bar();
+}
--- /dev/null
+scopes
+b do_scopes.js:22
+c
+scopes
+c
+scopes
+b do_scopes.js:28
+c
+scopes
+b do_scopes.js:31
+c
+scopes
+b do_scopes.js:33
+c
+scopes
+b do_scopes.js:35
+c
+scopes
+c
--- /dev/null
+Connecting to: localhost:5001
+Stopped at tests/debugger/do_scopes.js:15
+(jerry-debugger) scopes
+level | type
+0 | global
+(jerry-debugger) b do_scopes.js:22
+Breakpoint 1 at tests/debugger/do_scopes.js:22 (in f() at line:17, col:1)
+(jerry-debugger) c
+Exception throw detected (to disable automatic stop type exception 0)
+Exception hint: error
+Stopped at tests/debugger/do_scopes.js:19 (in f() at line:17, col:1)
+(jerry-debugger) scopes
+level | type
+0 | local
+1 | global
+(jerry-debugger) c
+Stopped at breakpoint:1 tests/debugger/do_scopes.js:22 (in f() at line:17, col:1)
+(jerry-debugger) scopes
+level | type
+0 | catch
+1 | local
+2 | global
+(jerry-debugger) b do_scopes.js:28
+Breakpoint 2 at tests/debugger/do_scopes.js:28 (in function() at line:27, col:4)
+(jerry-debugger) c
+Stopped at breakpoint:2 tests/debugger/do_scopes.js:28 (in function() at line:27, col:4)
+(jerry-debugger) scopes
+level | type
+0 | local
+1 | closure
+2 | global
+(jerry-debugger) b do_scopes.js:31
+Breakpoint 3 at tests/debugger/do_scopes.js:31 (in function() at line:27, col:4)
+(jerry-debugger) c
+Stopped at breakpoint:3 tests/debugger/do_scopes.js:31 (in function() at line:27, col:4)
+(jerry-debugger) scopes
+level | type
+0 | with
+1 | local
+2 | closure
+3 | global
+(jerry-debugger) b do_scopes.js:33
+Breakpoint 4 at tests/debugger/do_scopes.js:33 (in function() at line:27, col:4)
+(jerry-debugger) c
+Stopped at breakpoint:4 tests/debugger/do_scopes.js:33 (in function() at line:27, col:4)
+(jerry-debugger) scopes
+level | type
+0 | with
+1 | with
+2 | local
+3 | closure
+4 | global
+(jerry-debugger) b do_scopes.js:35
+Breakpoint 5 at tests/debugger/do_scopes.js:35 (in function() at line:27, col:4)
+(jerry-debugger) c
+Stopped at breakpoint:5 tests/debugger/do_scopes.js:35 (in function() at line:27, col:4)
+(jerry-debugger) scopes
+level | type
+0 | with
+1 | local
+2 | closure
+3 | global
+(jerry-debugger) c
--- /dev/null
+// 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.
+
+var c = 4;
+
+function f() {
+ try {
+ throw "error";
+ }
+ catch (err) {
+ var c = 10;
+ }
+
+ var z = true;
+ var g = 0;
+ (function() {
+ var a = [1,2,3]
+ a.y = "abc";
+ with (a) {
+ var h = [4,5,6]
+ with (h) {
+ h.d = "dfg"
+ }
+ a.d = g + c;
+ }
+ })();
+}
+
+f();
+
--- /dev/null
+scopes
+variables
+variables 1
+variables 0
+b tests/debugger/do_variables.js:20
+c
+scopes
+variables 0
+variables 1
+variables 2
+b tests/debugger/do_variables.js:30
+c
+scopes
+variables 1
+variables 0
+b tests/debugger/do_variables.js:33
+c
+c
+scopes
+variables 0
+variables 1
+b tests/debugger/do_variables.js:50
+c
+scopes
+variables 0
+variables 1
+variables 2
+c
--- /dev/null
+Connecting to: localhost:5001
+Stopped at tests/debugger/do_variables.js:15
+(jerry-debugger) scopes
+level | type
+0 | global
+(jerry-debugger) variables
+name | type | value
+f | Function |
+addX | Function |
+z | undefined | undefined
+c | undefined | undefined
+print | Function |
+gc | Function |
+assert | Function |
+(jerry-debugger) variables 1
+name | type | value
+(jerry-debugger) variables 0
+name | type | value
+f | Function |
+addX | Function |
+z | undefined | undefined
+c | undefined | undefined
+print | Function |
+gc | Function |
+assert | Function |
+(jerry-debugger) b tests/debugger/do_variables.js:20
+Breakpoint 1 at tests/debugger/do_variables.js:20 (in function() at line:19, col:10)
+(jerry-debugger) c
+Stopped at breakpoint:1 tests/debugger/do_variables.js:20 (in function() at line:19, col:10)
+(jerry-debugger) scopes
+level | type
+0 | local
+1 | closure
+2 | global
+(jerry-debugger) variables 0
+name | type | value
+n | Number | 9
+b | undefined | undefined
+(jerry-debugger) variables 1
+name | type | value
+x | Number | 3
+(jerry-debugger) variables 2
+name | type | value
+addThree | Function |
+f | Function |
+addX | Function |
+z | Number | 5
+c | Number | 4
+print | Function |
+gc | Function |
+assert | Function |
+(jerry-debugger) b tests/debugger/do_variables.js:30
+Breakpoint 2 at tests/debugger/do_variables.js:30 (in f() at line:28, col:1)
+(jerry-debugger) c
+Stopped at breakpoint:2 tests/debugger/do_variables.js:30 (in f() at line:28, col:1)
+(jerry-debugger) scopes
+level | type
+0 | local
+1 | global
+(jerry-debugger) variables 1
+name | type | value
+d | Number | 12
+addThree | Function |
+f | Function |
+addX | Function |
+z | Number | 5
+c | Number | 4
+print | Function |
+gc | Function |
+assert | Function |
+(jerry-debugger) variables 0
+name | type | value
+b | undefined | undefined
+x | undefined | undefined
+user | undefined | undefined
+m | undefined | undefined
+c | undefined | undefined
+(jerry-debugger) b tests/debugger/do_variables.js:33
+Breakpoint 3 at tests/debugger/do_variables.js:33 (in f() at line:28, col:1)
+(jerry-debugger) c
+Exception throw detected (to disable automatic stop type exception 0)
+Exception hint: error
+Stopped at breakpoint:2 tests/debugger/do_variables.js:30 (in f() at line:28, col:1)
+(jerry-debugger) c
+Stopped at breakpoint:3 tests/debugger/do_variables.js:33 (in f() at line:28, col:1)
+(jerry-debugger) scopes
+level | type
+0 | catch
+1 | local
+2 | global
+(jerry-debugger) variables 0
+name | type | value
+err | String | error
+(jerry-debugger) variables 1
+name | type | value
+b | undefined | undefined
+x | undefined | undefined
+user | undefined | undefined
+m | undefined | undefined
+c | undefined | undefined
+(jerry-debugger) b tests/debugger/do_variables.js:50
+Breakpoint 4 at tests/debugger/do_variables.js:50 (in function() at line:46, col:4)
+(jerry-debugger) c
+Stopped at breakpoint:4 tests/debugger/do_variables.js:50 (in function() at line:46, col:4)
+(jerry-debugger) scopes
+level | type
+0 | with
+1 | local
+2 | closure
+3 | global
+(jerry-debugger) variables 0
+name | type | value
+y | String | abc
+2 | Number | 3
+1 | Number | 2
+0 | Number | 1
+(jerry-debugger) variables 1
+name | type | value
+h | undefined | undefined
+a | Array | [1,2,3]
+(jerry-debugger) variables 2
+name | type | value
+b | Number | 10
+x | Boolean | true
+user | Object | [object Object]
+m | Null | null
+c | Number | 10
+(jerry-debugger) c
--- /dev/null
+// 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.
+
+var c = 4;
+var z = 5;
+
+function addX(x) {
+ return function(n) {
+ var b = 2;
+ return n + x;
+ }
+}
+
+addThree = addX(3);
+d = addThree(c+z);
+
+function f() {
+ try {
+ throw "error";
+ }
+ catch (err) {
+ var c = 10;
+ }
+
+ var m = null;
+
+ var user = {
+ name: "John",
+ age: 30
+ };
+
+ var x = true;
+ var b = 10;
+
+ (function() {
+ var a = [1,2,3]
+ a.y = "abc";
+ with (a) {
+ var h = [4,5,6]
+ with (h) {
+ h.d = "dfg"
+ }
+ a.d = x;
+ }
+ })();
+}
+
+f();
+
--- /dev/null
+// 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.
+
+var a = null;
+var c = a instanceof Object;
+assert (!c);
+++ /dev/null
-// 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.
-
-var catched = false;
-
-function f1()
-{
- var arguments = 1;
-}
-
-try
-{
- f1();
-} catch (e)
-{
- assert (e === CompactProfileError);
-
- catched = true;
-}
-
-assert(catched);
-
-catched = false;
-
-function f2()
-{
- var a = arguments;
-}
-
-try
-{
- f2();
-} catch (e)
-{
- assert (e === CompactProfileError);
-
- catched = true;
-}
-
-assert(catched);
-
-catched = false;
-
-try
-{
- eval('abc');
-} catch (e)
-{
- assert (e === CompactProfileError);
-
- catched = true;
-}
-
-assert(catched);
-
-catched = false;
-
-try
-{
- Function('abc');
-} catch (e)
-{
- assert (e === CompactProfileError);
-
- catched = true;
-}
-
-assert(catched);
-
-catched = false;
-
-try
-{
- new Function('abc');
-} catch (e)
-{
- assert (e === CompactProfileError);
-
- catched = true;
-}
-
-assert(catched);
-
-catched = false;
-
-try
-{
- var a = Date.now();
-} catch (e)
-{
- assert (e === CompactProfileError);
-
- catched = true;
-}
-
-assert(catched);
catch (e) {
assert (e instanceof ReferenceError);
}
+
+assert (0.1 + 0.2 != 0.3);
assert ((1152921504606846976).toString() === "1152921504606847000")
assert (1.797693134862315808e+308 === Infinity);
+
+assert (9999999999999999 == 10000000000000000);
assert (d.getDay() == 4);
assert (d.getUTCDay() == 4);
assert (d.getHours() == 12);
-// FIXME: Missing timezone adjustment.
-//assert (d.getUTCHours() == (12 + d.getTimezoneOffset() / 60));
+assert (d.getUTCHours() == (12 + d.getTimezoneOffset() / 60));
assert (d.getMinutes() == 13);
assert (d.getUTCMinutes() == 13);
assert (d.getSeconds() == 14);
assert (d.getUTCDate() == 9);
assert (d.getDay() == 4);
assert (d.getUTCDay() == 4);
-// FIXME: Missing timezone adjustment.
-//assert (d.getHours() == 12);
-//assert (d.getUTCHours() == (12 + d.getTimezoneOffset() / 60));
+assert (d.getHours() == Math.floor(12 - 1.5 + d.getTimezoneOffset() / 60));
+assert (d.getUTCHours() == Math.floor(12 - 1.5));
assert (d.getMinutes() == 43);
assert (d.getUTCMinutes() == 43);
assert (d.getSeconds() == 14);
assert (d.getUTCDate() == 1);
assert (d.getDay() == 4);
assert (d.getUTCDay() == 4);
-// FIXME: Missing timezone adjustment.
-// assert (d.getHours() == 0 - (d.getTimezoneOffset() / 60));
+assert (d.getHours() == 0 - (d.getTimezoneOffset() / 60));
assert (d.getUTCHours() == 0);
assert (d.getMinutes() == 0);
assert (d.getUTCMinutes() == 0);
assert (d.getUTCMilliseconds() == 1);
/* 15.9.5.34 Date.prototype.setHours (hour [, min [, sec [, ms ] ] ] ) */
-// FIXME: Missing timezone adjustment.
-//d.setTime(0);
-//assert (d.setHours(1) == hour + d.getTimezoneOffset() * 60000);
-//assert (d.getHours() == 1);
-//d.setTime(0);
-//assert (d.setHours(1, 1) == hour + min + d.getTimezoneOffset() * 60000);
-//assert (d.getHours() == 1);
-//assert (d.getMinutes() == 1);
-//d.setTime(0);
-//assert (d.setHours(1, 1, 1) == hour + min + sec + d.getTimezoneOffset() * 60000);
-//assert (d.getHours() == 1);
-//assert (d.getMinutes() == 1);
-//assert (d.getSeconds() == 1);
-//d.setTime(0);
-//assert (d.setHours(1, 1, 1, 1) == hour + min + sec + ms + d.getTimezoneOffset() * 60000);
-//assert (d.getHours() == 1);
-//assert (d.getMinutes() == 1);
-//assert (d.getSeconds() == 1);
-//assert (d.getMilliseconds() == 1);
+d.setTime(0);
+assert (d.setHours(1) == hour + d.getTimezoneOffset() * 60000);
+assert (d.getHours() == 1);
+d.setTime(0);
+assert (d.setHours(1, 1) == hour + min + d.getTimezoneOffset() * 60000);
+assert (d.getHours() == 1);
+assert (d.getMinutes() == 1);
+d.setTime(0);
+assert (d.setHours(1, 1, 1) == hour + min + sec + d.getTimezoneOffset() * 60000);
+assert (d.getHours() == 1);
+assert (d.getMinutes() == 1);
+assert (d.getSeconds() == 1);
+d.setTime(0);
+assert (d.setHours(1, 1, 1, 1) == hour + min + sec + ms + d.getTimezoneOffset() * 60000);
+assert (d.getHours() == 1);
+assert (d.getMinutes() == 1);
+assert (d.getSeconds() == 1);
+assert (d.getMilliseconds() == 1);
/* 15.9.5.35 Date.prototype.setUTCHours (hour [, min [, sec [, ms ] ] ] ) */
d.setTime(0);
assert((7 != 2) == true);
var num = 0;
-//var obj = new String("0");
+var obj = new String("0");
var str = "0";
var b = false;
assert(num === num);
-//assert(obj === obj);
+assert(obj === obj);
assert(str === str);
-//assert((num === obj) == false);
+assert((num === obj) == false);
assert((num === str) == false);
-//assert((obj === str) == false);
-//assert((null === undefined) == false);
-//assert((obj === null) == false);
-//assert((obj === undefined) == false);
+assert((obj === str) == false);
+assert((null === undefined) == false);
+assert((obj === null) == false);
+assert((obj === undefined) == false);
--- /dev/null
+// 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.
+
+var arrow_is_available = false;
+
+try {
+ assert (eval ("(f => 5) ()") === 5);
+ arrow_is_available = true;
+} catch (e) {
+ assert (e instanceof SyntaxError);
+}
+
+var array1 = [5, 12, 0, 8, 130, 44];
+
+function bigger_than_10 (element) {
+ return element > 10;
+}
+
+assert (array1.find (bigger_than_10) === 12);
+
+function less_than_0 (element) {
+ if (element == 0) {
+ throw new Error ("zero");
+ }
+ return element < 0;
+}
+
+try {
+ array1.find (less_than_0);
+ assert (false);
+} catch (e) {
+ assert (e instanceof Error);
+ assert (e.message === "zero");
+}
+
+var inventory = [
+ {name: 'apples', quantity: 2},
+ {name: 'bananas', quantity: 0},
+ {name: 'cherries', quantity: 5}
+];
+
+function isCherries (fruit) {
+ return fruit.name === 'cherries';
+}
+
+assert (JSON.stringify (inventory.find (isCherries)) === '{"name":"cherries","quantity":5}');
+
+if (arrow_is_available) {
+ assert (eval ("inventory.find (fruit => fruit.name === 'bananas')") === inventory[1]);
+}
+
+/* Test the callback function arguments */
+var src_array = [4, 6, 8, 12];
+var array_index = 0;
+
+function isPrime (element, index, array) {
+ assert (array_index++ === index);
+ assert (array === src_array)
+ assert (element === array[index]);
+
+ var start = 2;
+ while (start <= Math.sqrt (element)) {
+ if (element % start++ < 1) {
+ return false;
+ }
+ }
+ return element > 1;
+}
+
+assert (src_array.find (isPrime) === undefined);
+
+src_array = [4, 5, 8, 12];
+array_index = 0;
+assert (src_array.find (isPrime) === 5);
+
+
+// Checking behavior when unable to get length
+var obj = {};
+Object.defineProperty (obj, 'length', { 'get' : function () { throw new ReferenceError ("foo"); } });
+obj.find = Array.prototype.find;
+
+try {
+ obj.find ();
+ assert (false);
+} catch (e) {
+ assert (e.message === "foo");
+ assert (e instanceof ReferenceError);
+}
+
+var data = { 0: 1, 2: -3, 3: "string" }
+assert (Array.prototype.find.call (data, function (e) { return e < 5; }) === undefined);
+
+// Checking behavior when unable to get element
+var obj = {}
+obj.length = 1;
+Object.defineProperty (obj, '0', { 'get' : function () { throw new ReferenceError ("foo"); } });
+obj.find = Array.prototype.find
+
+try {
+ obj.find (function () { return undefined; });
+ assert (false);
+} catch (e) {
+ assert (e.message === "foo");
+ assert (e instanceof ReferenceError);
+}
+
+// Checking behavior when the first argument is not a callback
+var array = [1, 2, 3];
+
+try {
+ array.find (5);
+ assert (false);
+} catch (e) {
+ assert (e instanceof TypeError);
+}
+
+// Checking behavior when the first argument does not exist
+try {
+ array.find ();
+ assert (false);
+} catch (e) {
+ assert (e instanceof TypeError);
+}
+
+// Checking behavior when the there are more than 2 arguments
+assert (array.find (function (e) { return e < 2 }, {}, 8, 4, 5, 6, 6) === 1);
--- /dev/null
+/* 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.
+ */
+
+var g = Array.bind (0, 1, 2, 3)
+g.prototype = Array.prototype;
+
+class C extends g {}
+
+class D extends C {
+ constructor () {
+ super (4, 5);
+ }
+}
+
+var d = new D;
+assert (Object.getPrototypeOf (d) == D.prototype);
--- /dev/null
+/* 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.
+ */
+
+ function isInstanceofArray (instance) {
+ assert (instance instanceof C);
+ assert (instance instanceof B);
+ assert (instance instanceof A);
+ assert (instance instanceof Array);
+ }
+
+ class A extends Array {
+ f () {
+ return 5;
+ }
+ }
+
+ class B extends A {
+ g () {
+ return eval ("eval ('super.f ()')");
+ }
+ }
+
+ class C extends B {
+ h () {
+ return eval ('super.g ()');
+ }
+ }
+
+ var c = new C (1, 2, 3, 4, 5, 6);
+
+ isInstanceofArray (c);
+ c.push (7);
+ assert (c.length === 7);
+ assert (c.f () === 5);
+ assert (c.g () === 5);
+ assert (c.h () === 5);
+
+/* TODO: Enable these tests after Symbol has been implemented
+ // Test built-in Array prototype methods
+ var mapped = c.map ((x) => x * 2);
+ isInstanceofArray (mapped);
+
+ for (var i = 0; i < mapped.length; i++) {
+ assert (mapped[i] == c[i] * 2);
+ }
+
+ var concated = c.concat (c);
+ isInstanceofArray (concated);
+
+ for (var i = 0; i < concated.length; i++) {
+ assert (concated[i] == c[i % (concated.length / 2)]);
+ }
+
+ var sliced = c.slice (c);
+ isInstanceofArray (sliced);
+
+ for (var i = 0; i < sliced.length; i++) {
+ assert (sliced[i] == c[i]);
+ }
+
+ var filtered = c.filter ((x) => x > 100);
+ isInstanceofArray (sliced);
+ assert (filtered.length === 0);
+
+ var spliced = c.splice (c.length - 1);
+ isInstanceofArray (spliced);
+ assert (spliced.length === 1);
+ assert (spliced[0] === 7);
+
+ c.constructor = 5;
+
+ try {
+ mapped = c.map ((x) => x * 2);
+ assert (false);
+ } catch (e) {
+ assert (e instanceof TypeError);
+ }
+
+ try {
+ concated = c.concat (c);
+ assert (false);
+ } catch (e) {
+ assert (e instanceof TypeError);
+ }
+
+ try {
+ sliced = c.slice (c);
+ assert (false);
+ } catch (e) {
+ assert (e instanceof TypeError);
+ }
+
+ try {
+ filtered = c.filter ((x) => x > 100);
+ assert (false);
+ } catch (e) {
+ assert (e instanceof TypeError);
+ }
+
+ try {
+ spliced = c.splice (0);
+ assert (false);
+ } catch (e) {
+ assert (e instanceof TypeError);
+ }
+*/
--- /dev/null
+/* 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.
+ */
+
+ function isInstanceofTypedArray (instance) {
+ assert (instance instanceof C);
+ assert (instance instanceof B);
+ assert (instance instanceof A);
+ assert (instance instanceof Uint8Array);
+ }
+
+ class A extends Uint8Array {
+ f () {
+ return 5;
+ }
+ }
+
+ class B extends A {
+ g () {
+ return super.f ();
+ }
+ }
+
+ class C extends B {
+ h () {
+ return super.g ();
+ }
+ }
+
+ var c = new C ([1, 2, 3, 4, 5, 6]);
+
+ isInstanceofTypedArray (c);
+ assert (c.length === 6);
+ assert (c.f () === 5)
+ assert (c.g () === 5)
+ assert (c.h () === 5)
+
+/* TODO: Enable these tests after Symbol has been implemented
+ var mapped = c.map ((x) => x * 2);
+ isInstanceofTypedArray (mapped);
+
+ for (var i = 0; i < mapped.length; i++) {
+ assert (mapped[i] == c[i] * 2);
+ }
+
+ var filtered = c.filter ((x) => x > 100);
+ isInstanceofTypedArray (filtered);
+ assert (filtered.length === 0);
+
+ c.constructor = 5;
+
+ try {
+ mapped = c.map ((x) => x * 2);
+ assert (false);
+ } catch (e) {
+ assert (e instanceof TypeError)
+ }
+
+ try {
+ filtered = c.filter ((x) => x > 100);
+ assert (false);
+ } catch (e) {
+ assert (e instanceof TypeError)
+ }
+*/
--- /dev/null
+/* 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.
+ */
+
+class Animal {
+ constructor (name) {
+ this.name = name;
+ }
+
+ hello () {
+ return "Hello I am " + this.name;
+ }
+
+ static speak () {
+ return "Animals roar.";
+ }
+
+ static explain () {
+ return "I can walk,";
+ }
+
+ whoAmI () {
+ return "I am an Animal.";
+ }
+
+ breath () {
+ return "I am breathing.";
+ }
+
+ get myName () {
+ return this.name;
+ }
+
+ set rename (name) {
+ this.name = name;
+ }
+}
+
+class Dog extends Animal {
+ constructor (name, barks) {
+ super (name);
+ this.barks = barks;
+ }
+
+ hello () {
+ return super.hello () + " and I can " + (this.barks ? "bark" : "not bark");
+ }
+
+ whoAmI () {
+ return "I am a Dog.";
+ }
+
+ static speak () {
+ return "Dogs bark.";
+ }
+
+ static explain () {
+ return super.explain () + " jump,";
+ }
+
+ bark () {
+ return this.barks ? "Woof" : "----";
+ }
+}
+
+class Doge extends Dog {
+ constructor (name, barks, awesomeness) {
+ super (name, barks);
+ this.awesomeness = awesomeness;
+ }
+
+ hello () {
+ return super.hello () + " and I'm " + (this.awesomeness > 9000 ? "super awesome" : "awesome") + ".";
+ }
+
+ whoAmI ( ) {
+ return "I am a Doge.";
+ }
+
+ static speak () {
+ return "Doges wow.";
+ }
+
+ static explain () {
+ return super.explain () + " dance.";
+ }
+}
+
+var doge = new Doge ("doggoe", true, 10000);
+assert (doge.name === "doggoe");
+doge.rename = "doggo";
+assert (doge.myName === "doggo");
+assert (doge.barks === true);
+assert (doge.awesomeness === 10000);
+assert (doge.hello () === "Hello I am doggo and I can bark and I'm super awesome.");
+assert (doge.whoAmI () === "I am a Doge.");
+assert (doge.breath () === "I am breathing.");
+assert (doge.bark () === "Woof");
+assert (Doge.speak () === "Doges wow.");
+assert (Doge.explain () === "I can walk, jump, dance.");
+assert (doge instanceof Animal);
+assert (doge instanceof Dog);
+assert (doge instanceof Doge);
+assert (Dog.prototype.constructor === Dog)
+assert (Doge.prototype.constructor === Doge)
--- /dev/null
+/* 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.
+ */
+
+ class A extends Array {
+ constructor () {
+ return null;
+ }
+ }
+
+ class B extends A { }
+
+ try {
+ new B;
+ assert (false);
+ } catch (e) {
+ assert (e instanceof TypeError);
+ }
--- /dev/null
+/* 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.
+ */
+
+ class A extends Array {
+ constructor () {
+ assert (false);
+ return null;
+ }
+ }
+
+ class B extends A {
+ constructor () {
+ return { o : 10 };
+ }
+ }
+
+ var b = new B;
+ assert (b.o === 10);
--- /dev/null
+/* 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.
+ */
+
+ class A extends Array {
+ constructor (a, b, c) {
+ eval ("eval ('super (a, b, c)')");
+ eval ("eval ('this.f = 5;')");
+ assert (this.h ()()() === 5);
+
+ return { o : 4 };
+ }
+
+ g () {
+ return function () {
+ return 5;
+ }
+ }
+ }
+
+ class B extends A {
+ constructor (a, b, c) {
+ eval ("eval ('super (a, b, c)')");
+ assert (this.f === undefined)
+ assert (this.o === 4)
+ this.k = 5;
+ return { o : 7 };
+ }
+
+ h () {
+ return super["g"];
+ }
+ }
+
+ var b = new B (1, 2, 3, 4);
+ assert (b.k === undefined);
+ assert (b.o === 7);
+ assert (b.h === undefined);
+ assert (b.g === undefined);
--- /dev/null
+/* 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.
+ */
+
+ class C extends Array {
+ constructor (a, b) {
+ var a = eval ('super (arguments);');
+ }
+ }
+
+ class D extends C {
+ constructor () {
+ var a = eval ("eval ('super (1, 2);')");
+ return
+ }
+ }
+
+ var d = new D;
+ assert (JSON.stringify (d) === '[{"0":1,"1":2}]');
+ assert (d + "" === "[object Arguments]");
+ assert (d.length === 1);
--- /dev/null
+/* 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.
+ */
+
+class A {
+ constructor () {
+ this.a = 5;
+ }
+
+ f () {
+ return 10;
+ }
+
+ super () {
+ this.super = 10;
+ return 15;
+ }
+}
+
+class B extends A {
+ constructor () {
+ super ();
+ assert (super.f === A.prototype.f);
+ super.f = 8;
+ assert (this.f === 8);
+ assert (super.f === A.prototype.f);
+
+ assert (this.a === 5);
+ super.a = 10;
+ assert (this.a === 10);
+
+ assert (super.super () === 15);
+ assert (this.super === 10);
+ super.super = 20;
+ assert (this.super === 20);
+ assert (super.super () === 15);
+ }
+}
+
+var b = new B;
+assert (b.f === 8);
+assert (b.a === 10);
--- /dev/null
+/* 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.
+ */
+
+ class A extends Array {
+ constructor () {
+ super ();
+ return;
+ }
+ };
+
+ var a = new A;
+ assert (a.length === 0);
+ assert (a instanceof Array);
+ assert (a instanceof A);
+ assert (JSON.stringify (a) === "[]");
--- /dev/null
+/* 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.
+ */
+
+ class C {
+ static a () {
+ return 5;
+ }
+ }
+
+ class D extends C {
+ constructor () {
+ super ();
+ }
+ }
+
+ assert (D.a () === 5);
+
+ C.a = function () {
+ return 6;
+ }
+
+ assert (D.a () === 6);
+
+ C = 5;
+
+ assert (D.a () === 6);
--- /dev/null
+/* 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.
+ */
+
+class A extends Array {
+ constructor (a, b, c) {
+ super (a, b);
+ this.f = 5;
+ }
+}
+
+class B extends A { }
+
+var b = new B (1, 2, 3, 4);
+assert (b.f === 5);
+assert (b.length === 2);
--- /dev/null
+/* 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.
+ */
+
+ class A extends Array {
+ constructor (a, b, c) {
+ super (a, b);
+ this.f = 5;
+ }
+ }
+
+ class B extends A {
+ constructor (a, b, c) {
+ super (a, b);
+ this.g = super.f;
+ this.h = this.f;
+ }
+ }
+
+ var b = new B (1, 2, 3, 4);
+ assert (b.g === undefined);
+ assert (b.h === 5);
+ assert (b.length === 2);
--- /dev/null
+/* 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.
+ */
+
+ class A extends Array {
+ constructor (a, b, c) {
+ eval ("eval ('super (a, b, c)')");
+ eval ("eval ('this.f = 5;')");
+ }
+ }
+
+ class B extends A { }
+
+ var b = new B (1, 2, 3, 4);
+ assert (b.f === 5);
+ assert (b.length === 3);
--- /dev/null
+/* 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.
+ */
+
+ class A extends Array {
+ constructor (a, b, c, d, e) {
+ eval ("eval ('super (a, b, c)')");
+ this.a = 6;
+ return new String ("foo");
+ }
+
+ f () {
+ return 5;
+ }
+ }
+
+ class B extends A {
+ constructor (a, b, c, d) {
+ eval ("eval ('super (a, b, c, d)')");
+ assert (super.f () === 5);
+ }
+ }
+
+ var a = new B (1, 2, 3, 4, 5, 6);
+ assert (a.a === undefined);
+ assert (a[0] + a[1] + a[2] === "foo");
--- /dev/null
+/* 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.
+ */
+
+ class C extends Array {
+ constructor () {
+ var a = eval ('super (1, 2); 5');
+ assert (a === 5);
+ }
+ }
+
+ class D extends C {
+ constructor () {
+ var a = eval ("eval ('super (1, 2); 3')");
+ assert (a === 3);
+ }
+ }
+
+ var d = new D;
+
+ assert (JSON.stringify (d) === "[1,2]");
--- /dev/null
+/* 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.
+ */
+
+ var A = Array;
+ var order = 0;
+
+ function f () {
+ order++;
+
+ return function () {
+ return A;
+ }
+ }
+
+ var B = class extends f ()() {
+ constructor () {
+ assert (++order === 2);
+ eval ("eval ('super (1, 2, 3, 4)')");
+ try {
+ super (1, 2, 3, 4, 5)
+ assert (false);
+ } catch (e) {
+ assert (e instanceof ReferenceError)
+ }
+
+ assert (this.g ()()()() === 10);
+ assert (eval ("eval ('this.g ()')()")()() === 10);
+ assert (eval ("eval ('this.g ()')")()()() === 10);
+ assert (eval ("eval ('this.g ()()()')")() === 10);
+ assert (eval ("eval ('this.g')")()()()() === 10);
+ this.push (5);
+ assert (this.length === 5)
+ eval ('this.push (6)');
+ assert (this.length === 6);
+ eval ("eval ('this.push (7)')");
+ this.j = 6;
+ return;
+ }
+ }
+
+ var C = class extends B {
+ g () {
+ return function () {
+ return () => {
+ return 10;
+ }
+ }
+ }
+ }
+
+ var D = class D extends C {
+ constructor () {
+ super ();
+ this.k = 5;
+ return
+ }
+
+ g () {
+ return eval ('super["g"]');
+ }
+ }
+
+ assert (order === 1);
+
+ var d = new D;
+ assert (d.length === 7);
+ assert (d.k === 5);
+ assert (d.j === 6);
+ assert (d instanceof D);
+ assert (d instanceof C);
+ assert (d instanceof B);
+ assert (d instanceof f ()());
+ assert (JSON.stringify (d) === "[1,2,3,4,5,6,7]");
--- /dev/null
+/* 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.
+ */
+
+ var order = 0;
+
+ try {
+ var A = class extends null {
+ constructor () {
+ order++;
+ }
+ }
+
+ new A;
+ } catch (e) {
+ assert (order === 1);
+ assert (e instanceof ReferenceError);
+ }
--- /dev/null
+/* 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.
+ */
+
+function must_throw (str) {
+ try {
+ eval ("switch (1) { default: " + str + "}");
+ assert (false);
+ } catch (e) { }
+
+ try {
+ eval (str);
+ assert (false);
+ }
+ catch (e) { }
+
+ try {
+ eval ("'use strict'; switch (1) { default: " + str + "}");
+ assert (false);
+ } catch (e) { }
+
+ try {
+ eval ("'use strict'; " + str);
+ assert (false);
+ } catch (e) { }
+}
+
+class A {
+ constructor (a) {
+ this.a = a;
+ }
+
+ f () {
+ return 5;
+ }
+}
+
+must_throw ("class B extends 5 + 6 + 5 { constructor (a, b) { super (a) } }");
+
+must_throw ("class B extends null { constructor () { super () } }; new B");
+
+must_throw ("var o = { a : 5 }; \
+ class B extends Object.keys (o)[0] { constructor (a, b) { super (a) } } \
+ var b = new B (1, 2);");
+
+must_throw ("class B extends A { constructor (a, b) { this.b = b} } \
+ var b = new B (1, 2);");
+
+must_throw ("class B extends A { constructor (a, b) { super.f () } } \
+ var b = new B (1, 2);");
+
+must_throw ("class B extends A { constructor (a, b) { eval ('this.b = b') } } \
+ var b = new B (1, 2);");
+
+must_throw ("class B extends A { constructor (a, b) { eval ('super.f ()') } } \
+ var b = new B (1, 2);");
+
+must_throw ("class B extends A { constructor (a, b) { super (a); super (a); } } \
+ var b = new B (1, 2);");
+
+must_throw ("class B extends A { constructor (a, b) { eval ('super (a)'); eval ('super (a)'); } } \
+ var b = new B (1, 2);");
+
+must_throw ("class B extends A { constructor (a, b) { super (a) } g () { super (a) } } \
+ var b = new B (1, 2);");
+
+must_throw ("class B extends A { constructor (a, b) { super (a) } g () { eval ('super (a)') } } \
+ var b = new B (1, 2); \
+ b.g ();");
+
+must_throw ("class B extends A { constructor (a, b) { super (a) } g () { return function () { return super.f () } } } \
+ var b = new B (1, 2); \
+ b.g ()();");
+
+must_throw ("class B extends A { constructor (a, b) { super (a) } \
+ g () { return function () { return eval ('super.f ()') } } } \
+ var b = new B (1, 2); \
+ b.g ()();");
+
+must_throw ("class B extends A { constructor (a, b) { super (a) } \
+ g () { return function () { return eval (\"eval ('super.f ();')\") } } } \
+ var b = new B (1, 2); \
+ b.g ()();");
+
+must_throw ("class A extends Array { constructor () { return 5; } }; new A");
+
+must_throw ("class A extends Array { constructor () { return undefined; } }; new A");
+
+must_throw ("class B extends undefined { }; new B;");
+
+must_throw ("var A = class extends Array { . }");
+
+must_throw ("class Array extends Array { }");
+
+must_throw ("class A extends A { }");
+
+must_throw ("class A extends { constructor () { super () } }");
+
+class B extends A {
+ constructor (a, b) {
+ super (a);
+ assert (super.f () === 5);
+ }
+
+ g () {
+ return () => {
+ return super.f ();
+ }
+ }
+
+ h () {
+ return () => {
+ return () => {
+ return eval ('super.f ()');
+ }
+ }
+ }
+}
+
+var b = new B (1, 2);
+assert (b.g ()() === 5);
+assert (b.h ()()() === 5);
--- /dev/null
+/* 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.
+ */
+
+var calculatorMixin = Base => class extends Base {
+ f () {
+ return 1;
+ }
+};
+
+var randomizerMixin = Base => class extends Base {
+ g () {
+ return 2;
+ }
+};
+
+class A {
+ constructor () { }
+}
+
+class B extends calculatorMixin (randomizerMixin (A)) {
+
+}
+
+var b = new B ();
+assert (b.f () === 1)
+assert (b.g () === 2);
--- /dev/null
+/* 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.
+ */
+
+ order = 0;
+
+ var Mixin1 = (superclass) => class extends superclass {
+ foo () {
+ assert (order++ == 1)
+ if (super.foo) {
+ super.foo ();
+ }
+ }
+ };
+
+ var Mixin2 = (superclass) => class extends superclass {
+ foo () {
+ assert (order++ == 2)
+ if (super.foo) {
+ assert (super.foo () === 5);
+ }
+ }
+ };
+
+ class S {
+ foo () {
+ assert (order++ == 3)
+ return 5;
+ }
+ }
+
+ class C extends Mixin1 (Mixin2 (S)) {
+ foo () {
+ assert (order++ == 0)
+ super.foo ();
+ }
+ }
+
+ new C ().foo ()
--- /dev/null
+/* 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.
+ */
+
+function must_throw(str) {
+ try {
+ eval("switch (1) { default: " + str + "}");
+ assert(false);
+ } catch (e) {
+ }
+
+ try {
+ eval(str);
+ assert(false);
+ }
+ catch (e) {
+ }
+
+ must_throw_strict(str);
+}
+
+function must_throw_strict(str) {
+ try {
+ eval ("'use strict'; switch (1) { default: " + str + "}");
+ assert (false);
+ } catch (e) {
+ }
+
+ try {
+ eval("'use strict'; " + str);
+ assert(false);
+ } catch (e) {
+ }
+}
+
+must_throw("class {}");
+must_throw("class class {}");
+must_throw("class A { constructor() {} this.a = 5 }");
+must_throw("class A { constructor() {} constructor() {} }");
+must_throw("class A { static prototype() {} }");
+must_throw("class A { get constructor() {} }");
+must_throw("class A { set constructor() {} }");
+must_throw("class A {}; A()");
+must_throw("class X {}; var o = {}; Object.defineProperty(o, 'p', { get: X, set: X }); o.p;");
+must_throw("var a = new A; class A {};");
+must_throw("class A { g\\u0065t e() {} }");
+must_throw('class A { "static" e() {} }');
+
+assert(eval("class A {}") === undefined);
+assert(eval("var a = class A {}") === undefined);
+assert(eval("var a = class {}") === undefined);
+assert(eval("class A { ; ; ; ;;;;;;;;;;;; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;; }") === undefined);
+assert(eval('class A {"constructor"() {} }') === undefined);
+assert(isNaN (eval('switch(1) { default: (class A{} % 1) }')));
+
+class B {
+}
+
+var b = new B;
+assert(typeof B === "function");
+assert(typeof b === "object");
+
+class C {
+ c1() {
+ return 5;
+ }
+
+ c2() {
+ return this._c;
+ }
+ 3() {
+ return 3;
+ }
+}
+
+var c = new C;
+assert (c.c1() === 5);
+assert (c.c2() === undefined);
+assert (c["3"]() === 3);
+
+class D {
+ constructor(d) {
+ this._d = d;
+ }
+
+ d1() {
+ return this._d;
+ }
+}
+var d = new D(5);
+assert(d.d1() === 5);
+
+class E {
+ constructor(e) {
+ this._e = e;
+ }
+
+ get e() {
+ return this._e;
+ }
+
+ set e(e) {
+ this._e = e;
+ }
+}
+var e = new E (5);
+assert (e.e === 5);
+e.e = 10;
+assert (e.e === 10);
+
+var F = class ClassF {
+ constructor(f) {
+ this._f = f;
+ }
+
+ static f1() {
+ return this;
+ }
+
+ static f2() {
+ return this._f;
+ }
+
+ static f3(a, b) {
+ return a + b;
+ }
+
+ static constructor(a) {
+ return a;
+ }
+
+ static static(a) {
+ return a;
+ }
+
+ static 2 (a) {
+ return 2 * a;
+ }
+}
+
+var f = new F(5);
+
+assert (f.f1 === undefined);
+assert (f.f2 === undefined);
+assert (F.f1() === F);
+assert (F.f2() === undefined);
+assert (F.f3(1, 1) === 2);
+assert (F.constructor(5) === 5);
+assert (F.static(5) === 5);
+assert (F["2"](5) === 10);
+
+var G = class {
+ static set a(a) {
+ this._a = a;
+ }
+ static get a() {
+ return this._a;
+ }
+ static set 1(a) {
+ this._a = a;
+ }
+ static get 1() {
+ return this._a;
+ }
+
+ static set constructor(a) {
+ this._a = a;
+ }
+ static get constructor() {
+ return this._a;
+ }
+
+ static g1() {
+ return 5;
+ }
+
+ static g1() {
+ return 10;
+ }
+}
+
+G.a = 10;
+assert (G.a === 10);
+assert (G.g1() === 10);
+G["1"] = 20;
+assert (G["1"] === 20);
+G.constructor = 30;
+assert (G.constructor === 30);
--- /dev/null
+// 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.
+
+var local = 0;
+
+switch(0) { /* This switch forces a pre-scanner run. */
+default:
+
+ function f(a = (5, local = 6),
+ b = ((5 + function(a = 6) { return a }() * 3)),
+ c,
+ d = true ? 1 : 2)
+ {
+ return "" + a + ", " + b + ", " + c + ", " + d;
+ }
+
+ assert(f() === "6, 23, undefined, 1");
+ assert(local === 6);
+
+ var obj = {
+ f: function(a = [10,,20],
+ b,
+ c = Math.cos(0),
+ d)
+ {
+ return "" + a + ", " + b + ", " + c + ", " + d;
+ }
+ };
+
+ assert(obj.f() === "10,,20, undefined, 1, undefined");
+
+ function g(a, b = (local = 7)) { }
+
+ local = 0;
+ g();
+ assert(local === 7);
+
+ local = 0;
+ g(0);
+ assert(local === 7);
+
+ local = 0;
+ g(0, undefined);
+ assert(local === 7);
+
+ local = 0;
+ g(0, null);
+ assert(local === 0);
+
+ local = 0;
+ g(0, false);
+ assert(local === 0);
+ break;
+}
+
+function CheckSyntaxError(str)
+{
+ try {
+ eval(str);
+ assert(false);
+ } catch (e) {
+ assert(e instanceof SyntaxError);
+ }
+}
+
+CheckSyntaxError('function x(a += 5) {}');
+CheckSyntaxError('function x(a =, b) {}');
+CheckSyntaxError('function x(a = (b) {}');
+CheckSyntaxError('function x(a, a = 5) {}');
+CheckSyntaxError('function x(a = 5, a) {}');
--- /dev/null
+/* 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.
+ */
+
+var m = new Map();
+assert(m.size == 0);
+assert(m.set(1, 1) === m);
+assert(m.has(1));
+assert(m.size == 1);
+
+assert(m.set(undefined, 123) === m);
+assert(m.size == 2);
+assert(m.has(undefined));
+assert(m.get(undefined) === 123);
+
+assert(m.set(null, 456) === m);
+assert(m.size == 3);
+assert(m.has(null));
+assert(m.get(null) === 456);
+
+assert(m.set("strItem", { x:789 }) === m);
+assert(m.size == 4);
+assert(m.has("str" + "Item"));
+assert(m.get("st" + "rItem").x === 789);
+
+assert(m.set(12.25, 12.25) === m);
+assert(m.size == 5);
+assert(m.has(12 + (function() { return 0.25 })()));
+assert(m.get(13 - (function() { return 0.75 })()) === 12.25);
+
+assert(m.delete(1))
+assert(m.size == 4);
+assert(!m.has(1));
+assert(m.get(1) === undefined);
+
+assert(!m.delete(2));
+
+assert(m.delete(12 + (function() { return 0.25 })()));
+assert(m.size == 3);
+assert(!m.has(12.25));
+assert(m.get(12.25) === undefined);
+
+assert(m.delete("strI" + "tem"))
+assert(m.delete(undefined))
+assert(m.size == 1);
+
+assert(m.delete(null))
+assert(m.size == 0);
+
+m.set(1,1)
+m.set(2,2)
+m.set(3,3)
+m.set(1,7)
+m.set(1,8)
+m.set(2,7)
+m.set(2,8)
+m.set(3,7)
+m.set(3,8)
+
+assert(m.size == 3);
+assert(m.get(1) === 8);
+assert(m.get(2) === 8);
+assert(m.get(3) === 8);
--- /dev/null
+// 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.
+
+function member_str() {
+ return "member";
+}
+
+switch (true) {
+default:
+ var obj = {
+ ["val" + "ue"]: 0,
+ set[member_str()](x) {
+ // Multiple statements.
+ this.value = x + 4;
+ this.value += 2;
+ },
+ get[member_str() ? member_str() : ""]() {
+ // Multiple statements.
+ this.value = this.value + 1;
+ return this.value;
+ },
+ get
+ [1 + 2]
+ ()
+ {
+ return 3;
+ },
+ [false ? member_str()
+ : ""]
+ :8
+ }
+}
+
+obj["member"] = 10;
+assert(obj.member === 17);
+assert(obj.member === 18);
+
+assert(obj[3] === 3);
+assert(obj["3"] === 3);
+
+assert(obj[""] === 8);
--- /dev/null
+// 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.
+
+/* Test object literals. */
+
+var local = 0;
+
+function f(x)
+{
+ return x + "et";
+}
+
+var o = {
+ a: 5,
+ [
+ "pr" +
+ "op"] : 6,
+
+ [f
+ ("g")
+ ]
+ : 7,
+
+ [f(
+ "s"
+ ) ]: 8,
+
+ get [f
+ ("res")
+ ]
+ () { return 9 },
+
+ set
+ [f("res")](
+ value) { local = value },
+};
+
+assert(o.a === 5);
+assert(o.prop === 6);
+assert(o.get === 7);
+assert(o.set === 8);
+
+local = 0;
+o.reset = 10;
+assert(local === 10);
+assert(o.reset === 9);
+
+/* Test classes. */
+
+function fxy() {
+ return "xy";
+}
+
+class C {
+ [fxy()] () {
+ return 6;
+ }
+
+ static [fxy()]() {
+ return 7;
+ }
+
+ get ["a" + 1]() {
+ return 8;
+ }
+
+ set ["a" + 1](x) {
+ local = x;
+ }
+
+ static get ["a" + 1]() {
+ return 10;
+ }
+
+ static set ["a" + 1](x) {
+ local = x;
+ }
+};
+
+var c = new C;
+assert(c.xy() === 6);
+assert(C.xy() === 7);
+
+local = 0;
+c.a1 = 9;
+assert(local === 9);
+assert(c.a1 === 8);
+
+local = 0;
+C.a1 = 11;
+assert(local === 11);
+assert(C.a1 === 10);
+
+class D {
+ [(() => "const" + "ructor")()] (arg) {
+ this.a = arg;
+ }
+}
+
+var d = new D;
+assert(d.a === undefined);
+d.constructor(7);
+assert(d.a === 7);
+
+class E {
+ get ["_constructor_".substring(1,12)]() {
+ return this.a;
+ }
+}
+
+var e = new E;
+assert(e.constructor === undefined);
+e.a = 8;
+assert(e.constructor === 8);
+
+function throw_error(snippet)
+{
+ try {
+ eval(snippet);
+ assert(false);
+ } catch (e) {
+ assert(e instanceof TypeError);
+ }
+}
+
+throw_error("new class { static ['proto' + 'type'] () {} }");
+throw_error("new class { static get ['proto' + 'type'] () {} }");
+throw_error("new class { static set ['proto' + 'type'] (x) {} }");
--- /dev/null
+// 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.
+
+switch (1) {
+default:
+ var o = {
+ value: 10,
+ func() {
+ return 234 + this.value;
+ },
+ ["a" + "b"]() {
+ return 456 - this.value;
+ }
+ }
+}
+
+assert(o.func() === 244);
+assert(o.ab() === 446);
+
+switch (1) {
+default:
+ var ab = 5;
+ var cd = 6;
+ o = {
+ ab,
+ cd: 8,
+ cd
+ }
+}
+
+assert(o.ab === 5);
+assert(o.cd === 6);
+
+function exception_expected(str) {
+ try {
+ eval(str);
+ assert(false);
+ } catch (e) {
+ assert(e instanceof SyntaxError);
+ }
+}
+
+// These forms are invalid.
+exception_expected('({ true })');
+exception_expected('({ 13 })');
+exception_expected('({ "x" })');
+
+switch (1) {
+default:
+ // These forms are valid.
+ ({ true: true });
+ ({ 13: 13 });
+ ({ "x": "x" });
+}
--- /dev/null
+// 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.
+
+try {
+ // By default bound functions always support new operator.
+ // However, arrow functions must throw an error even in this case.
+
+ var f = (() => 1).bind();
+
+ new f;
+
+ assert(false);
+} catch (e) {
+ assert(e instanceof TypeError);
+}
--- /dev/null
+// 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.
+
+(new Int8Array(0)).filter(parseInt)
--- /dev/null
+// 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.
+
+var a = eval("Object.prototype[1] = 0;\
+ Promise.all()")
+a.catch(function(err) {
+ assert(err instanceof TypeError);
+});
--- /dev/null
+// 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.
+
+Object.prototype[1] = 0;
+Promise.race([]);
--- /dev/null
+// 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.
+
+Object.setPrototypeOf(Math, Int32Array);
+for (var i = 0; i < 200; i++) {
+ Promise.race([, [,] % {}]).then();
+}
--- /dev/null
+// 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.
+
+Object.defineProperty(Array.prototype, 0, {set: function() {var $ = $()}});
+Promise.all([0]);
--- /dev/null
+// 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.
+
+Object.defineProperty(Array.prototype, 0, {set: function() {throw "MyError"}});
+Promise.all([0]);
--- /dev/null
+// 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.
+
+// This test case should not throw an error anymore.
+Object.defineProperty(Object.prototype, 0, {'get': function() { throw $ }});
+Promise.all();
--- /dev/null
+// 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.
+
+// Original issue
+Object.defineProperty(Object.prototype, 6, {});
+Promise.all([0]);
+
+// Variant 2
+Object.defineProperty(Object.prototype, 2, {});
+Promise.all([0]);
+
+// Variant 3
+Object.defineProperty(Object.prototype, 3, {});
+Promise.all([0]);
+
+// Variant 4
+Object.defineProperty(Object.prototype, 4, {});
+Promise.all([0]);
+
+// Variant 5
+Object.defineProperty(Object.prototype, 5, {});
+Promise.all([0]);
+
+// Variant 7
+Object.defineProperty(Object.prototype, 7, {});
+Promise.all([0]);
+
+// Variant 8
+Object.defineProperty(Object.prototype, 8, {});
+Promise.all([0]);
--- /dev/null
+// 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.
+
+for (/a/ in a => { }, a => { }, a => { }) throw 1
--- /dev/null
+// 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.
+
+function f(a,b,c) {
+ var args = Array.prototype.slice.call(arguments, 3);
+ assert (typeof args.splice === "function");
+}
+f();
--- /dev/null
+// 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.
+
+Object.defineProperty ( Array.prototype , 0 , { set : function ( ) { throw "MyError" } } ) ;
+Promise.all ( [ "2015-01-01" ] ) ;
--- /dev/null
+// 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.
+
+
+Object.defineProperty( Array.prototype, 0, { set : function ( ) { throw "MyError" } } );
+Promise.all( [ .86456 ] ) ;
--- /dev/null
+/* 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.
+ */
+
+var a = new Int32Array([1, 2, 3, 4, 5]);
+assert(a.fill(0).toString() === '0,0,0,0,0');
+assert(a.toString() === '0,0,0,0,0');
+assert(a.fill(1, 3).toString() === '0,0,0,1,1');
+assert(a.toString() === '0,0,0,1,1');
+assert(a.fill(2, 1, 3).toString() === '0,2,2,1,1');
+assert(a.toString() === '0,2,2,1,1');
+assert(a.fill(3, -3).toString() === '0,2,3,3,3');
+assert(a.toString() === '0,2,3,3,3');
+assert(a.fill(4, -3, -1).toString() === '0,2,4,4,3');
+assert(a.toString() === '0,2,4,4,3');
+assert(a.fill(5, 3, 2).toString() === '0,2,4,4,3');
+assert(a.toString() === '0,2,4,4,3');
+assert(a.fill(6, -2, -3).toString() === '0,2,4,4,3');
+assert(a.toString() === '0,2,4,4,3');
+assert(a.fill(7, 4, 1).toString() === '0,2,4,4,3');
+assert(a.toString() === '0,2,4,4,3');
+assert(a.fill(8, -1, -4).toString() === '0,2,4,4,3');
+assert(a.toString() === '0,2,4,4,3');
+assert(a.fill(9, 1).fill(10, 1).toString() === '0,10,10,10,10');
+assert(a.toString() === '0,10,10,10,10');
+assert(a.fill(11, 0, 4).fill(12, 1, 2).toString() === '11,12,11,11,10');
+assert(a.toString() === '11,12,11,11,10');
+assert(a.fill(13, 999, 1000).fill(14, -1000, -999).toString() === '11,12,11,11,10');
+assert(a.toString() === '11,12,11,11,10');
+assert(a.fill(14, 0, 0).toString() === '11,12,11,11,10');
+assert(a.toString() === '11,12,11,11,10');
+assert(a.fill(15, a.length, a.length).toString() === '11,12,11,11,10');
+assert(a.toString() === '11,12,11,11,10');
+assert(a.fill(NaN).toString() === '0,0,0,0,0'); // NaN gets coerced into an integer.
+assert(a.toString() === '0,0,0,0,0');
+assert(a.fill({ valueOf: () => 16 }).toString() === '16,16,16,16,16');
+assert(a.toString() === '16,16,16,16,16');
+
+var b = new Uint8Array();
+assert(b.fill(1).toString() === '');
+assert(b.toString() === '');
+assert(b.fill(2, 0, 0).toString() === '');
+assert(b.toString() === '');
+assert(b.fill(3, b.length, b.length).toString() === '');
+assert(b.toString() === '');
+
+var c = new Uint8Array([0]);
+assert(c.fill(256).toString() === '0');
+assert(c.toString() === '0');
+assert(c.fill(257).toString() === '1');
+assert(c.toString() === '1');
+
+try {
+ c.fill({});
+} catch (e) {
+ assert(e instanceof TypeError);
+ assert(c.toString() === '1');
+}
+
+var d = new Float32Array([0]);
+assert(d.fill(NaN).toString() === 'NaN');
+assert(d.toString() === 'NaN');
+
+var ab = new ArrayBuffer(4);
+var e = new Uint8Array(ab);
+assert(e.fill(0).toString() === '0,0,0,0');
+
+var f = new Uint32Array(ab);
+assert(f.fill(1).toString() === '1');
+assert(e.toString() === '1,0,0,0');
+
+var g = new Uint8Array(ab, 1, 2);
+assert(g.toString() === '0,0');
+assert(g.fill(2).toString() === '2,2');
+assert(e.toString() === '1,2,2,0');
+assert(g.fill(3, -1).toString() === '2,3');
+assert(e.toString() === '1,2,3,0');
+assert(g.fill(4, 0, 2).toString() === '4,4');
+assert(e.toString() === '1,4,4,0');
+assert(g.fill(5, 0, 999).toString() === '5,5');
+assert(e.toString() === '1,5,5,0');
+assert(g.fill(6, -999, 999).toString() === '6,6');
+assert(e.toString() === '1,6,6,0');
+assert(g.fill(7, -999, 0).toString() === '6,6');
+assert(e.toString() === '1,6,6,0');
+
+var ab2 = new ArrayBuffer(4);
+var h = new Uint8Array(ab2);
+var i = new Uint16Array(ab2, 0, 1);
+assert(i.fill(1).toString() === '1');
+assert(h.toString() === '1,0,0,0');
+var j = new Uint16Array(ab2, 2, 1);
+assert(j.fill(1).toString() === '1');
+assert(h.toString() === '1,0,1,0');
--- /dev/null
+// 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.
+
+var arrow_is_available = false;
+
+try {
+ assert (eval ("(f => 5) ()") === 5);
+ arrow_is_available = true;
+} catch (e) {
+ assert (e instanceof SyntaxError);
+}
+
+var typedArrayTypes = [Int8Array,
+ Uint8Array,
+ Uint8ClampedArray,
+ Int16Array,
+ Uint16Array,
+ Int32Array,
+ Uint32Array,
+ Float32Array,
+ Float64Array];
+
+
+typedArrayTypes.forEach (function (TypedArray) {
+
+ var array1 = new TypedArray ([5, 12, 0, 8, 120, 44]);
+
+ function bigger_than_10 (element) {
+ return element > 10;
+ }
+
+ assert (array1.find (bigger_than_10) === 12);
+
+ function less_than_0 (element) {
+ if (element == 0) {
+ throw new Error ("zero");
+ }
+ return element < 0;
+ }
+
+ try {
+ array1.find (less_than_0);
+ assert (false);
+ } catch (e) {
+ assert (e instanceof Error);
+ assert (e.message === "zero");
+ }
+
+ if (arrow_is_available) {
+ assert (eval ("array1.find (e => e > 100)") === 120);
+ }
+
+ /* Test the callback function arguments */
+ var src_array = new TypedArray ([4, 6, 8, 12]);
+ var array_index = 0;
+
+ function isPrime (element, index, array) {
+ assert (array_index++ === index);
+ assert (array === src_array)
+ assert (element === array[index]);
+
+ var start = 2;
+ while (start <= Math.sqrt (element)) {
+ if (element % start++ < 1) {
+ return false;
+ }
+ }
+ return element > 1;
+ }
+
+ assert (src_array.find (isPrime) === undefined);
+
+ src_array = new TypedArray ([4, 5, 8, 12]);
+ array_index = 0;
+ assert (src_array.find (isPrime) === 5);
+
+ // Checking behavior when the given object is not %TypedArray%
+ try {
+ TypedArray.prototype.find.call (5);
+ assert (false);
+ } catch (e) {
+ assert (e instanceof TypeError);
+ }
+
+ // Checking behavior when the first argument is not a callback
+ var array = new TypedArray ([1, 2, 3]);
+
+ try {
+ array.find (5);
+ assert (false);
+ } catch (e) {
+ assert (e instanceof TypeError);
+ }
+
+ // Checking behavior when the first argument is not exists
+ try {
+ array.find ();
+ assert (false);
+ } catch (e) {
+ assert (e instanceof TypeError);
+ }
+
+ // Checking behavior when the there are more than 2 arguments
+ assert (array.find (function (e) { return e < 2 }, {}, 8, 4, 5, 6, 6) === 1);
+})
--- /dev/null
+/* 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.
+ */
+
+var float_array = new Float32Array([1.125, 5.5, -1.25, -0.0]);
+var int_array = new Int8Array([3, 2, 1, 100, -30]);
+var uint_array = new Uint8Array([3, 2, 1, 100, -30]);
+var empty_array = new Uint32Array();
+
+assert(float_array.join() === float_array.toString());
+assert(int_array.join('-') === "3-2-1-100--30");
+assert(uint_array.join('=') === "3=2=1=100=226");
+assert(empty_array.join('_') === "");
--- /dev/null
+/* 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.
+ */
+
+var a = new Int32Array([1, 2, 3, 4, 5]);
+var b = new Int32Array(5);
+
+try {
+ a.set(b, 123456);
+ assert(1 === 0); // Should not get here.
+} catch (e) {
+ assert(e instanceof RangeError);
+}
+
+b.set(a);
+assert(b.join() === '1,2,3,4,5');
+try {
+ b.set(a, 1);
+ assert(1 === 0); // Should not get here.
+} catch (e) {
+ assert(e instanceof RangeError);
+}
+
+b.set(new Int32Array([99, 98]), 2);
+assert(b.join() === '1,2,99,98,5');
+
+b.set(new Int32Array([99, 98, 97]), 2);
+assert(b.join() === '1,2,99,98,97');
+
+try {
+ b.set(new Int32Array([99, 98, 97, 96]), 2);
+ assert(1 === 0); // Should not get here.
+} catch (e) {
+ assert(e instanceof RangeError);
+}
+
+try {
+ b.set([101, 102, 103, 104], 4);
+ assert(1 === 0); // Should not get here.
+} catch (e) {
+ assert(e instanceof RangeError);
+}
+
+// ab = [ 0, 1, 2, 3, 4, 5, 6, 7 ]
+// a1 = [ ^, ^, ^, ^, ^, ^, ^, ^ ]
+// a2 = [ ^, ^, ^, ^ ]
+var ab = new ArrayBuffer(8);
+var a1 = new Uint8Array(ab);
+for (var i = 0; i < a1.length; i += 1) {
+ a1.set([i], i);
+}
+
+var a2 = new Uint8Array(ab, 4);
+a1.set(a2, 2);
+assert(a1.join() === '0,1,4,5,6,7,6,7');
+assert(a2.join() === '6,7,6,7');
+
+var a3 = new Uint32Array(ab, 4);
+a1.set(a3, 2);
+assert(a1.join() === '0,1,6,5,6,7,6,7');
+assert(a3.join() === '117835526');
+
+var a4 = new Uint8Array(ab, 0, 4);
+a1.set(a4, 2);
+assert(a1.join() === '0,1,0,1,6,5,6,7');
+assert(a4.join() === '0,1,0,1');
+
+var a5 = new Uint32Array(ab, 4, 1);
+a1.set(a5, 2);
+assert(a1.join() === '0,1,6,1,6,5,6,7');
+assert(a5.join() === '117835014');
+
+var c = new Int32Array([0xFFFFFFFF]);
+var d = new Uint8Array(4);
+d.set(c);
+assert(d.join() === '255,0,0,0');
+
+var e = new Float32Array([3.33]);
+var f = new Uint8Array(1);
+f.set(e);
+assert(f.join() === '3');
+e.set(f);
+assert(e.join() === '3');
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Default sorting behavior.
+var a = Uint8Array.from([4, 1, 3, 5, 4, 2]);
+assert(a.sort().toString() === '1,2,3,4,4,5');
+assert(a.toString() === '1,2,3,4,4,5');
+
+// Views into typedarrays should be properly sorted.
+var b = Uint8Array.from([2, 1, 4, 3, 0]);
+assert(b.subarray(2, 4).sort().toString() === '3,4');
+assert(b.toString() === '2,1,3,4,0');
+
+// Empty typedarrays should be able to be "sorted".
+var c = Uint8Array.from([]);
+assert(c.sort().toString() === '');
+
+// Infinity should be supported.
+var d = Float32Array.from([Infinity, 3, 2, 1, -Infinity]);
+assert(d.sort().toString() === '-Infinity,1,2,3,Infinity');
+
+// +0 and -0 should be properly sorted.
+var e = Float32Array.from([1, 0, -0, -1]);
+assert(e.sort().toString() === '-1,0,0,1');
+
+// NaN should be supported and always at the end.
+var f = Float32Array.from([NaN, 0, 1, -1, -Infinity, Infinity, NaN]);
+assert(f.sort().toString() === '-Infinity,-1,0,1,Infinity,NaN,NaN');
+
+// The element size of the view should be sorted properly.
+var ab = new ArrayBuffer(4);
+var g = new Uint32Array(ab);
+var h = new Uint8Array(ab);
+h.set([0xFF, 0, 0xFF, 0]);
+assert(h.toString() === '255,0,255,0');
+assert(g.toString() === '16711935');
+assert(h.subarray(0, 2).sort().toString() === '0,255');
+assert(h.subarray(2, 4).sort().toString() === '0,255');
+assert(g.toString() === '4278255360');
+assert(g.sort().toString() === '4278255360');
+assert(h.toString() === '0,255,0,255');
+
+// Comparator argument should be callable.
+var i = Uint8Array.from([1, 2, 3]);
+try {
+ i.sort({});
+ assert(false);
+} catch (e) {
+ assert(e instanceof TypeError);
+}
+
+// Comparator function returns a Number.
+i.sort(function (lhs, rhs) {
+ return rhs - lhs;
+});
+assert(i.toString() === '3,2,1');
+
+// Comparator function returns a non-Number type that coerces to a Number.
+i.sort(function (lhs, rhs) {
+ return { valueOf: function() { return rhs - lhs; } };
+});
+assert(i.toString() === '3,2,1');
--- /dev/null
+/* 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.
+ */
+
+var a = new Int32Array([1, 2, 3, 4, 5]);
+assert(a.subarray().toString() === '1,2,3,4,5');
+assert(a.subarray(3).toString() === '4,5');
+assert(a.subarray(1, 3).toString() === '2,3');
+assert(a.subarray(-3).toString() === '3,4,5');
+assert(a.subarray(-3, -1).toString() === '3,4');
+assert(a.subarray(3, 2).toString() === '');
+assert(a.subarray(-2, -3).toString() === '');
+assert(a.subarray(4, 1).toString() === '');
+assert(a.subarray(-1, -4).toString() === '');
+assert(a.subarray(1).subarray(1).toString() === '3,4,5');
+assert(a.subarray(1, 4).subarray(1, 2).toString() === '3');
+
+var b = new Uint8Array([]);
+assert(b.subarray(123456, -123456).toString() === '');
+assert(b.subarray().subarray().toString() === '');
+
+var ab = new ArrayBuffer(28);
+var tmp = new Int32Array(ab);
+tmp.set([0, 1, 2, 3, 4, 5, 0]);
+var c = new Int32Array(ab, 4, 5);
+assert(c.toString() === '1,2,3,4,5');
+assert(c.subarray().toString() === '1,2,3,4,5');
+assert(c.subarray(3).toString() === '4,5');
+assert(c.subarray(1, 3).toString() === '2,3');
+assert(c.subarray(-3).toString() === '3,4,5');
+assert(c.subarray(-3, -1).toString() === '3,4');
+assert(c.subarray(3, 2).toString() === '');
+assert(c.subarray(-2, -3).toString() === '');
+assert(c.subarray(4, 1).toString() === '');
+assert(c.subarray(-1, -4).toString() === '');
+assert(c.subarray(1).subarray(1).toString() === '3,4,5');
+assert(c.subarray(1, 4).subarray(1, 2).toString() === '3');
--- /dev/null
+/* 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.
+ */
+
+var float_array = new Float32Array([1.125, 5.5, -1.25, -0.0]);
+var int_array = new Int8Array([3, 2, 1, 100, -30])
+var uint_array = new Uint8Array([3, 2, 1, 100, -30])
+var empty_array = new Uint32Array();
+
+assert(float_array.toString() === "1.125,5.5,-1.25,0");
+assert(int_array.toString() === "3,2,1,100,-30");
+assert(uint_array.toString() === "3,2,1,100,226");
+assert(empty_array.toString() === "");
--- /dev/null
+// 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.
+
+function throw_error(snippet)
+{
+ try
+ {
+ eval(snippet);
+ assert (false);
+ }
+ catch (e)
+ {
+ assert (e instanceof SyntaxError);
+ }
+}
+
+function throw_error_strict(snippet)
+{
+ 'use strict'
+
+ try
+ {
+ eval(snippet);
+ assert (false);
+ }
+ catch (e)
+ {
+ assert (e instanceof SyntaxError);
+ }
+}
+
+// These should be failed in ECMA-262 v5.1
+throw_error_strict("({a:1, a:2})");
+throw_error("({a:1, get a() { return 1 }})");
+throw_error("({get a() {return undefined}, get a() {return undefined}})");
+throw_error("({ get 1() {}, 1:1 })");
+++ /dev/null
-// 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.
-
-var a = {a:1, get a() {return 1}}
+++ /dev/null
-// 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.
-
-var a = {get a() {return undefined}, get a() {return undefined}}
+++ /dev/null
-// 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.
-
-"use strict"
-
-var a = {a:1, a:2};
--- /dev/null
+// 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.
+
+
+new RegExp().compile("\\1\\");
--- /dev/null
+// 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.
+
+Object.defineProperty(Object.prototype, 0, {'get': function() { throw $ }});
+/**
+ * The below line is added becase the patch #2526 introduces internal properties for promises.
+ * The Reference Error this issue produced can still be reproduced by calling this line.
+ * The reason it was present before is that Promise's 0th property was Promise which could be modified
+ * with the above line, and the engine getting that property for internal purposes got the `throw $` instead.
+ * Thanks to internal properties, it can't be modified anymore from JS side, therefore Promise won't trigger the error.
+ * To keep this issue's output as it was before, the `Array.prototype[0];` line is added.
+ */
+Array.prototype[0];
+Promise.all();
--- /dev/null
+// 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.
+
+Object.defineProperty(Array.prototype, 0, { get : function () { throw $; } });
+Promise.race([ , this]).then(Error);
--- /dev/null
+// 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.
+
+var expr = "Dummy value";
+
+var f = function expr() {
+ assert(expr === f);
+ expr = 6;
+ assert(expr === f);
+ assert(!(delete expr));
+ assert(expr === f);
+}
+
+f();
+
+f = function expr() {
+ assert(expr === undefined);
+ var expr = 6;
+ assert(expr === 6);
+}
+
+f();
+
+var f = function expr() {
+ assert(expr === f);
+ eval("var expr = 8");
+ assert(expr === 8);
+}
+
+f();
+
+var f = function expr(i) {
+ assert(expr === f);
+
+ if (i > 0) {
+ expr(i - 1);
+ }
+}
+
+f(10);
assert ( isNaN (Math.pow (0.0 /* any number */, NaN)) );
assert ( Math.pow (NaN, 0.0) === 1.0 );
-// assert ( Math.pow (NaN, -0.0) === 1.0 );
+assert ( Math.pow (NaN, -0.0) === 1.0 );
assert ( isNaN (Math.pow (NaN, 1.0 /* any non-zero number */)) );
assert ( Math.pow (2.0, Infinity) === Infinity );
assert ( Math.pow (2.0, -Infinity) === 0.0 );
assert ( Math.pow (-Infinity, 3.0) === -Infinity );
assert ( Math.pow (-Infinity, 2.0) === Infinity );
assert ( Math.pow (-Infinity, 2.5) === Infinity );
-// assert ( Math.pow (-Infinity, -3.0) === -0.0 );
+assert ( Math.pow (-Infinity, -3.0) === -0.0 );
assert ( Math.pow (-Infinity, -2.0) === 0.0 );
assert ( Math.pow (-Infinity, -2.5) === 0.0 );
assert ( Math.pow (0.0, 1.2) === 0.0 );
assert ( Math.pow (0.0, -1.2) === Infinity );
-// assert ( Math.pow (-0.0, 3.0) === -0.0 );
-// assert ( Math.pow (-0.0, 2.0) === 0.0 );
-// assert ( Math.pow (-0.0, 2.5) === 0.0 );
-// assert ( Math.pow (-0.0, -3.0) === -Infinity );
-// assert ( Math.pow (-0.0, -2.0) === Infinity );
-// assert ( Math.pow (-0.0, -2.5) === Infinity );
+assert ( Math.pow (-0.0, 3.0) === -0.0 );
+assert ( Math.pow (-0.0, 2.0) === 0.0 );
+assert ( Math.pow (-0.0, 2.5) === 0.0 );
+assert ( Math.pow (-0.0, -3.0) === -Infinity );
+assert ( Math.pow (-0.0, -2.0) === Infinity );
+assert ( Math.pow (-0.0, -2.5) === Infinity );
assert ( isNaN (Math.pow (-3, 2.5)) );
assert(Math.pow (-2, 2) === 4);
// Test non-object argument
try {
- Object.getOwnPrototypeNames("hello");
+ Object.getOwnPropertyNames("hello");
assert (false);
} catch (e) {
assert (e instanceof TypeError);
+++ /dev/null
-// 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.
-
-try
-{
- // This should be failed in ECMA-262 v5.1
- eval("({ get 1() {}, 1:1 })");
- assert (false);
-}
-catch (e)
-{
- assert (e instanceof SyntaxError);
-}
--- /dev/null
+// 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.
+
+switch (true) {
+default:
+ var obj = {
+ value: 0,
+ set
+ member
+ (x)
+ {
+ // Multiple statements.
+ this.value = x + 4;
+ this.value += 2;
+ },
+ get"member"() {
+ // Multiple statements.
+ this.value = this.value + 1;
+ return this.value;
+ },
+ get 3() {
+ return 3;
+ }
+ }
+}
+
+obj["member"] = 10;
+assert(obj.member === 17);
+assert(obj.member === 18);
+
+assert(obj[3] === 3);
+assert(obj["3"] === 3);
--- /dev/null
+// 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.
+
+/* String which is 32 bytes long. */
+var str = "'\\t' +'\\t' +'\\t'+'\\t'+'\\t'+'\\t'+";
+
+for (var i = 0; i < 10; i++) {
+ str = str + str;
+}
+
+str = "(function() { return " + str + "1 })";
+
+/* Eat memory. */
+var array = [];
+
+try
+{
+ for (var i = 0; i < 90; i++)
+ {
+ array[i] = eval(str);
+ }
+ assert (false);
+}
+catch (err)
+{
+ array = null;
+ assert (err === null);
+}
--- /dev/null
+// 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.
+
+'\
+'
+++ /dev/null
-// 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.
-
-'\
-'
--- /dev/null
+// 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.
+
+
+try {
+ ((new RegExp("[\\u0")).exec("u"));
+ assert (false);
+} catch (e) {
+ assert (e instanceof SyntaxError);
+}
+
+try {
+ ((new RegExp("[\\x0")).exec("x"));
+ assert (false);
+} catch (e) {
+ assert (e instanceof SyntaxError);
+}
--- /dev/null
+// 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.
+
+
+try {
+ (new RegExp("[\\u0020")).exec("u");
+ assert (false);
+} catch (e) {
+ assert (e instanceof SyntaxError);
+}
+
+try {
+ (new RegExp("[\\x20")).exec("x");
+ assert (false);
+} catch (e) {
+ assert (e instanceof SyntaxError);
+}
--- /dev/null
+// 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.
+
+try {
+ "[]{83}".match("(?=){12,8}");
+ assert (false);
+} catch (e) {
+ assert (e instanceof SyntaxError);
+}
--- /dev/null
+// 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.
+
+Math in Number
--- /dev/null
+// 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.
+
+// This issue was triggered when show opcodes was enabled at compile
+// time but not enabled in runtime. A memory leak was created.
+
+function f()
+{
+ var \u0042 = true;
+};
--- /dev/null
+// 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.
+
+// Wrong byte codes were dumped for this function when show opcodes had been enabled
+
+function abc(a,b) {
+ var c = 6;
+ return arguments[0] + b + c;
+}
+
+abc(1, 2);
--- /dev/null
+// 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.
+
+// Must be a success.
+eval('g\\u0065t: break get')
+
+try {
+ // Must be a fail.
+ eval('({ g\\u0065t a() {} })')
+ assert(false);
+} catch (e) {
+ assert(e instanceof SyntaxError);
+}
+
+// Must be a success.
+eval('({ g\\u0065t: 5 })')
--- /dev/null
+// 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.
+
+var src = "var a = 0; while(a) { switch(a) {" ;
+for (var i = 0; i < 4000; i++)
+ src += "-Infinity" + i + "\u00a0\u00a01.2e3";
+src += "\udc00%f0%90%80%80\udc00";
+print(src);
--- /dev/null
+// 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.
+
+var src = "";
+for (var i = 0; i < 4000; i++)
+ src += "\udc00%f0%90%80%80\udc00";
+src += "} }";
+print(src);
--- /dev/null
+// 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.
+
+var src = "";
+for (var i = 0; i < 4000; i++)
+ src += 4 + i + ": a += a += a; break; ";
+ src += "\\
+\
";
+print(src);
--- /dev/null
+/* 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.
+ */
+function fn(x) {
+ switch (x) {
+ case 1: { return }
+ }
+}
+
+new Function("switch(1) { default: { return }}")
--- /dev/null
+// 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.
+
+Object.defineProperty(Object.prototype, "", {});
+assert(JSON.stringify() === undefined)
--- /dev/null
+// 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.
+
+try {
+ eval(".5.");
+ assert(false);
+} catch(e) {
+ assert(e instanceof SyntaxError);
+}
--- /dev/null
+// 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.
+
+var x = [0];
+assert (x == x);
+assert (x == !x);
+assert (Array(3) == ",,");
+
+assert ([] + [] == "");
+assert ([] + {} == "[object Object]");
+assert (eval ("{} + []") == 0);
+assert (isNaN (eval ("{} + {}")));
+assert ({} + [] == "[object Object]");
+assert ({} + {} == "[object Object][object Object]");
+
+assert ((! + [] + [] + ![]) === "truefalse");
--- /dev/null
+// Copyright JS Foundation and other contributors, http://js.foundation\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+//\r
+// http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+\r
+// This test file should use CR-LF styled line endings to test if everything is\r
+// parsed correctly\r
+\r
+\r
+var value =\r
+ 5;\r
+\r
+assert (value === 5);\r
set(TARGET_NAME unit-${TARGET_NAME})
add_executable(${TARGET_NAME} ${SOURCE_UNIT_TEST_MAIN})
- set_property(TARGET ${TARGET_NAME}
- PROPERTY LINK_FLAGS "${LINKER_FLAGS_COMMON}")
-
+ target_include_directories(${TARGET_NAME} PRIVATE ${INCLUDE_CORE_PRIVATE})
+ set_property(TARGET ${TARGET_NAME} PROPERTY LINK_FLAGS "${LINKER_FLAGS_COMMON}")
+ set_property(TARGET ${TARGET_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
target_link_libraries(${TARGET_NAME} jerry-core jerry-port-default-minimal)
add_dependencies(unittests-core ${TARGET_NAME})
JERRY_UNUSED (args_count);
jerry_value_t value = jerry_create_string ((jerry_char_t *) "Abort run!");
- jerry_value_set_abort_flag (&value);
+ value = jerry_create_abort_from_value (value, true);
return value;
} /* callback_func */
jerry_value_t callback_name = jerry_create_string ((jerry_char_t *) "callback");
jerry_value_t func = jerry_create_external_function (callback_func);
jerry_value_t res = jerry_set_property (global, callback_name, func);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
jerry_release_value (res);
jerry_release_value (func);
jerry_release_value (callback_name);
jerry_release_value (global);
- const char *inf_loop_code_src_p = ("while(true) {\n"
- " with ({}) {\n"
- " try {\n"
- " callback();\n"
- " } catch (e) {\n"
- " } finally {\n"
- " }\n"
- " }\n"
- "}");
+ const jerry_char_t inf_loop_code_src1[] = TEST_STRING_LITERAL (
+ "while(true) {\n"
+ " with ({}) {\n"
+ " try {\n"
+ " callback();\n"
+ " } catch (e) {\n"
+ " } finally {\n"
+ " }\n"
+ " }\n"
+ "}"
+ );
jerry_value_t parsed_code_val = jerry_parse (NULL,
0,
- (jerry_char_t *) inf_loop_code_src_p,
- strlen (inf_loop_code_src_p),
+ inf_loop_code_src1,
+ sizeof (inf_loop_code_src1) - 1,
JERRY_PARSE_NO_OPTS);
- TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
+ TEST_ASSERT (!jerry_value_is_error (parsed_code_val));
res = jerry_run (parsed_code_val);
- TEST_ASSERT (jerry_value_has_abort_flag (res));
+ TEST_ASSERT (jerry_value_is_abort (res));
jerry_release_value (res);
jerry_release_value (parsed_code_val);
- inf_loop_code_src_p = ("function f() {"
- " while(true) {\n"
- " with ({}) {\n"
- " try {\n"
- " callback();\n"
- " } catch (e) {\n"
- " } finally {\n"
- " }\n"
- " }\n"
- " }"
- "}\n"
- "function g() {\n"
- " for (a in { x:5 })\n"
- " f();\n"
- "}\n"
- "\n"
- "with({})\n"
- " f();\n");
+ const jerry_char_t inf_loop_code_src2[] = TEST_STRING_LITERAL (
+ "function f() {"
+ " while(true) {\n"
+ " with ({}) {\n"
+ " try {\n"
+ " callback();\n"
+ " } catch (e) {\n"
+ " } finally {\n"
+ " }\n"
+ " }\n"
+ " }"
+ "}\n"
+ "function g() {\n"
+ " for (a in { x:5 })\n"
+ " f();\n"
+ "}\n"
+ "\n"
+ "with({})\n"
+ " f();\n"
+ );
parsed_code_val = jerry_parse (NULL,
0,
- (jerry_char_t *) inf_loop_code_src_p,
- strlen (inf_loop_code_src_p),
+ inf_loop_code_src2,
+ sizeof (inf_loop_code_src2) - 1,
JERRY_PARSE_NO_OPTS);
- TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
+ TEST_ASSERT (!jerry_value_is_error (parsed_code_val));
res = jerry_run (parsed_code_val);
- TEST_ASSERT (jerry_value_has_abort_flag (res));
+ TEST_ASSERT (jerry_value_is_abort (res));
jerry_release_value (res);
jerry_release_value (parsed_code_val);
/* Test flag overwrites. */
jerry_value_t value = jerry_create_string ((jerry_char_t *) "Error description");
- TEST_ASSERT (!jerry_value_has_abort_flag (value));
- TEST_ASSERT (!jerry_value_has_error_flag (value));
+ TEST_ASSERT (!jerry_value_is_abort (value));
+ TEST_ASSERT (!jerry_value_is_error (value));
- jerry_value_set_abort_flag (&value);
- TEST_ASSERT (jerry_value_has_abort_flag (value));
- TEST_ASSERT (jerry_value_has_error_flag (value));
+ value = jerry_create_abort_from_value (value, true);
+ TEST_ASSERT (jerry_value_is_abort (value));
+ TEST_ASSERT (jerry_value_is_error (value));
- jerry_value_set_error_flag (&value);
- TEST_ASSERT (!jerry_value_has_abort_flag (value));
- TEST_ASSERT (jerry_value_has_error_flag (value));
+ value = jerry_create_error_from_value (value, true);
+ TEST_ASSERT (!jerry_value_is_abort (value));
+ TEST_ASSERT (jerry_value_is_error (value));
- jerry_value_set_abort_flag (&value);
- TEST_ASSERT (jerry_value_has_abort_flag (value));
- TEST_ASSERT (jerry_value_has_error_flag (value));
+ value = jerry_create_abort_from_value (value, true);
+ TEST_ASSERT (jerry_value_is_abort (value));
+ TEST_ASSERT (jerry_value_is_error (value));
jerry_release_value (value);
for (size_t idx = 0; idx < sizeof (errors) / sizeof (errors[0]); idx++)
{
jerry_value_t error_obj = jerry_create_error (errors[idx], (const jerry_char_t *)"test");
- TEST_ASSERT (jerry_value_has_error_flag (error_obj));
+ TEST_ASSERT (jerry_value_is_error (error_obj));
TEST_ASSERT (jerry_get_error_type (error_obj) == errors[idx]);
- jerry_value_clear_error_flag (&error_obj);
+ error_obj = jerry_get_value_from_error (error_obj, true);
TEST_ASSERT (jerry_get_error_type (error_obj) == errors[idx]);
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jerryscript.h"
+
+#include "test-common.h"
+
+int
+main (void)
+{
+ TEST_INIT ();
+
+ jerry_init (JERRY_INIT_EMPTY);
+
+ /* Test: init property descriptor */
+ jerry_property_descriptor_t prop_desc;
+ jerry_init_property_descriptor_fields (&prop_desc);
+ TEST_ASSERT (prop_desc.is_value_defined == false);
+ TEST_ASSERT (jerry_value_is_undefined (prop_desc.value));
+ TEST_ASSERT (prop_desc.is_writable_defined == false);
+ TEST_ASSERT (prop_desc.is_writable == false);
+ TEST_ASSERT (prop_desc.is_enumerable_defined == false);
+ TEST_ASSERT (prop_desc.is_enumerable == false);
+ TEST_ASSERT (prop_desc.is_configurable_defined == false);
+ TEST_ASSERT (prop_desc.is_configurable == false);
+ TEST_ASSERT (prop_desc.is_get_defined == false);
+ TEST_ASSERT (jerry_value_is_undefined (prop_desc.getter));
+ TEST_ASSERT (prop_desc.is_set_defined == false);
+ TEST_ASSERT (jerry_value_is_undefined (prop_desc.setter));
+
+ /* Test: define own properties */
+ jerry_value_t global_obj_val = jerry_get_global_object ();
+ jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "my_defined_property");
+ prop_desc.is_value_defined = true;
+ prop_desc.value = jerry_acquire_value (prop_name);
+ jerry_value_t res = jerry_define_own_property (global_obj_val, prop_name, &prop_desc);
+ TEST_ASSERT (!jerry_value_is_error (res));
+ TEST_ASSERT (jerry_value_is_boolean (res));
+ TEST_ASSERT (jerry_get_boolean_value (res));
+ jerry_release_value (res);
+ jerry_free_property_descriptor_fields (&prop_desc);
+
+ /* Test: get own property descriptor */
+ bool is_ok = jerry_get_own_property_descriptor (global_obj_val, prop_name, &prop_desc);
+ TEST_ASSERT (is_ok);
+ TEST_ASSERT (prop_desc.is_value_defined == true);
+ TEST_ASSERT (jerry_value_is_string (prop_desc.value));
+ TEST_ASSERT (prop_desc.is_writable == false);
+ TEST_ASSERT (prop_desc.is_enumerable == false);
+ TEST_ASSERT (prop_desc.is_configurable == false);
+ TEST_ASSERT (prop_desc.is_get_defined == false);
+ TEST_ASSERT (jerry_value_is_undefined (prop_desc.getter));
+ TEST_ASSERT (prop_desc.is_set_defined == false);
+ TEST_ASSERT (jerry_value_is_undefined (prop_desc.setter));
+ jerry_release_value (prop_name);
+ jerry_free_property_descriptor_fields (&prop_desc);
+
+ jerry_release_value (global_obj_val);
+ jerry_cleanup ();
+
+ return 0;
+} /* main */
#include "jerryscript.h"
#include "test-common.h"
+static void
+compare_str (jerry_value_t value, const jerry_char_t *str_p, size_t str_len)
+{
+ jerry_size_t size = jerry_get_string_size (value);
+ JERRY_ASSERT (str_len == size);
+ JERRY_VLA (jerry_char_t, str_buff, size);
+ jerry_string_to_utf8_char_buffer (value, str_buff, size);
+ JERRY_ASSERT (!memcmp (str_p, str_buff, str_len));
+} /* compare_str */
+
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t obj_val = jerry_create_object ();
- jerry_value_set_error_flag (&obj_val);
+ obj_val = jerry_create_error_from_value (obj_val, true);
jerry_value_t err_val = jerry_acquire_value (obj_val);
- jerry_value_clear_error_flag (&obj_val);
- jerry_release_value (obj_val);
+ obj_val = jerry_get_value_from_error (err_val, true);
+ JERRY_ASSERT (obj_val != err_val);
jerry_release_value (err_val);
+ jerry_release_value (obj_val);
+
+ const jerry_char_t pterodactylus[] = "Pterodactylus";
+ const size_t pterodactylus_size = sizeof (pterodactylus) - 1;
+
+ jerry_value_t str = jerry_create_string (pterodactylus);
+ jerry_value_t error = jerry_create_error_from_value (str, true);
+ str = jerry_get_value_from_error (error, true);
+
+ compare_str (str, pterodactylus, pterodactylus_size);
+ jerry_release_value (str);
+
+ str = jerry_create_string (pterodactylus);
+ error = jerry_create_error_from_value (str, false);
+ jerry_release_value (str);
+ str = jerry_get_value_from_error (error, true);
+
+ compare_str (str, pterodactylus, pterodactylus_size);
+ jerry_release_value (str);
+
+ str = jerry_create_string (pterodactylus);
+ error = jerry_create_abort_from_value (str, true);
+ str = jerry_get_value_from_error (error, true);
+
+ compare_str (str, pterodactylus, pterodactylus_size);
+ jerry_release_value (str);
+
+ str = jerry_create_string (pterodactylus);
+ error = jerry_create_abort_from_value (str, false);
+ jerry_release_value (str);
+ str = jerry_get_value_from_error (error, true);
+
+ compare_str (str, pterodactylus, pterodactylus_size);
+ jerry_release_value (str);
+
+ str = jerry_create_string (pterodactylus);
+ error = jerry_create_error_from_value (str, true);
+ error = jerry_create_abort_from_value (error, true);
+ JERRY_ASSERT (jerry_value_is_abort (error));
+ str = jerry_get_value_from_error (error, true);
+
+ compare_str (str, pterodactylus, pterodactylus_size);
+ jerry_release_value (str);
+
+ str = jerry_create_string (pterodactylus);
+ error = jerry_create_error_from_value (str, true);
+ jerry_value_t error2 = jerry_create_abort_from_value (error, false);
+ JERRY_ASSERT (jerry_value_is_abort (error2));
+ jerry_release_value (error);
+ str = jerry_get_value_from_error (error2, true);
+
+ compare_str (str, pterodactylus, pterodactylus_size);
+ jerry_release_value (str);
+
+ double test_num = 3.1415926;
+ jerry_value_t num = jerry_create_number (test_num);
+ jerry_value_t num2 = jerry_create_error_from_value (num, false);
+ JERRY_ASSERT (jerry_value_is_error (num2));
+ jerry_release_value (num);
+ num2 = jerry_get_value_from_error (num2, true);
+ JERRY_ASSERT (jerry_get_number_value (num2) == test_num);
+ jerry_release_value (num2);
+
+ num = jerry_create_number (test_num);
+ num2 = jerry_create_error_from_value (num, true);
+ JERRY_ASSERT (jerry_value_is_error (num2));
+ num2 = jerry_get_value_from_error (num2, true);
+ JERRY_ASSERT (jerry_get_number_value (num2) == test_num);
+ jerry_release_value (num2);
+
+ num = jerry_create_number (test_num);
+ num2 = jerry_create_error_from_value (num, false);
+ JERRY_ASSERT (jerry_value_is_error (num2));
+ jerry_release_value (num);
+ jerry_value_t num3 = jerry_create_error_from_value (num2, false);
+ JERRY_ASSERT (jerry_value_is_error (num3));
+ jerry_release_value (num2);
+ num2 = jerry_get_value_from_error (num3, true);
+ JERRY_ASSERT (jerry_get_number_value (num2) == test_num);
+ jerry_release_value (num2);
+
+ num = jerry_create_number (test_num);
+ num2 = jerry_create_error_from_value (num, true);
+ JERRY_ASSERT (jerry_value_is_error (num2));
+ num3 = jerry_create_error_from_value (num2, true);
+ JERRY_ASSERT (jerry_value_is_error (num3));
+ num2 = jerry_get_value_from_error (num3, true);
+ JERRY_ASSERT (jerry_get_number_value (num2) == test_num);
+ jerry_release_value (num2);
+
+ num = jerry_create_number (test_num);
+ error = jerry_create_abort_from_value (num, true);
+ JERRY_ASSERT (jerry_value_is_abort (error));
+ num2 = jerry_create_error_from_value (error, true);
+ JERRY_ASSERT (jerry_value_is_error (num2));
+ num = jerry_get_value_from_error (num2, true);
+ JERRY_ASSERT (jerry_get_number_value (num) == test_num);
+ jerry_release_value (num);
+
+ num = jerry_create_number (test_num);
+ error = jerry_create_abort_from_value (num, false);
+ jerry_release_value (num);
+ JERRY_ASSERT (jerry_value_is_abort (error));
+ num2 = jerry_create_error_from_value (error, true);
+ JERRY_ASSERT (jerry_value_is_error (num2));
+ num = jerry_get_value_from_error (num2, true);
+ JERRY_ASSERT (jerry_get_number_value (num) == test_num);
+ jerry_release_value (num);
+
+ num = jerry_create_number (test_num);
+ error = jerry_create_abort_from_value (num, true);
+ JERRY_ASSERT (jerry_value_is_abort (error));
+ num2 = jerry_create_error_from_value (error, false);
+ jerry_release_value (error);
+ JERRY_ASSERT (jerry_value_is_error (num2));
+ num = jerry_get_value_from_error (num2, true);
+ JERRY_ASSERT (jerry_get_number_value (num) == test_num);
+ jerry_release_value (num);
+
+ num = jerry_create_number (test_num);
+ error = jerry_create_abort_from_value (num, false);
+ jerry_release_value (num);
+ JERRY_ASSERT (jerry_value_is_abort (error));
+ num2 = jerry_create_error_from_value (error, false);
+ jerry_release_value (error);
+ JERRY_ASSERT (jerry_value_is_error (num2));
+ num = jerry_get_value_from_error (num2, true);
+ JERRY_ASSERT (jerry_get_number_value (num) == test_num);
+ jerry_release_value (num);
+
+ jerry_value_t value = jerry_create_number (42);
+ value = jerry_get_value_from_error (value, true);
+ jerry_release_value (value);
+
+ value = jerry_create_number (42);
+ jerry_value_t value2 = jerry_get_value_from_error (value, false);
+ jerry_release_value (value);
+ jerry_release_value (value2);
+
+ value = jerry_create_number (42);
+ error = jerry_create_error_from_value (value, true);
+ error = jerry_create_error_from_value (error, true);
+ jerry_release_value (error);
+
+ value = jerry_create_number (42);
+ error = jerry_create_abort_from_value (value, true);
+ error = jerry_create_abort_from_value (error, true);
+ jerry_release_value (error);
+
+ value = jerry_create_number (42);
+ error = jerry_create_error_from_value (value, true);
+ error2 = jerry_create_error_from_value (error, false);
+ jerry_release_value (error);
+ jerry_release_value (error2);
+
+ value = jerry_create_number (42);
+ error = jerry_create_abort_from_value (value, true);
+ error2 = jerry_create_abort_from_value (error, false);
+ jerry_release_value (error);
+ jerry_release_value (error2);
jerry_cleanup ();
} /* main */
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jerryscript.h"
+
+#include "test-common.h"
+
+static bool
+strict_equals (jerry_value_t a, /**< the first string to compare */
+ jerry_value_t b) /**< the second string to compare */
+{
+ const jerry_char_t is_equal_src[] = "var isEqual = function(a, b) { return (a === b); }; isEqual";
+ jerry_value_t is_equal_fn_val = jerry_eval (is_equal_src, sizeof (is_equal_src) - 1, JERRY_PARSE_NO_OPTS);
+ TEST_ASSERT (!jerry_value_is_error (is_equal_fn_val));
+ jerry_value_t args[2] = {a, b};
+ jerry_value_t res = jerry_call_function (is_equal_fn_val, jerry_create_undefined (), args, 2);
+ TEST_ASSERT (!jerry_value_is_error (res));
+ TEST_ASSERT (jerry_value_is_boolean (res));
+ bool is_strict_equal = jerry_get_boolean_value (res);
+ jerry_release_value (res);
+ jerry_release_value (is_equal_fn_val);
+ return is_strict_equal;
+} /* strict_equals */
+
+int
+main (void)
+{
+ jerry_size_t sz, utf8_sz, cesu8_sz;
+ jerry_length_t cesu8_length, utf8_length;
+ jerry_value_t args[2];
+
+ TEST_INIT ();
+ jerry_init (JERRY_INIT_EMPTY);
+
+ /* Test corner case for jerry_string_to_char_buffer */
+ args[0] = jerry_create_string ((jerry_char_t *) "");
+ sz = jerry_get_string_size (args[0]);
+ TEST_ASSERT (sz == 0);
+ jerry_release_value (args[0]);
+
+ /* Test create_jerry_string_from_utf8 with 4-byte long unicode sequences,
+ * test string: 'str: {DESERET CAPITAL LETTER LONG I}'
+ */
+ args[0] = jerry_create_string_from_utf8 ((jerry_char_t *) "\x73\x74\x72\x3a \xf0\x90\x90\x80");
+ args[1] = jerry_create_string ((jerry_char_t *) "\x73\x74\x72\x3a \xed\xa0\x81\xed\xb0\x80");
+
+ /* These sizes must be equal */
+ utf8_sz = jerry_get_string_size (args[0]);
+ cesu8_sz = jerry_get_string_size (args[1]);
+
+ char string_from_utf8[utf8_sz];
+ char string_from_cesu8[cesu8_sz];
+
+ jerry_string_to_char_buffer (args[0], (jerry_char_t *) string_from_utf8, utf8_sz);
+ jerry_string_to_char_buffer (args[1], (jerry_char_t *) string_from_cesu8, cesu8_sz);
+
+ TEST_ASSERT (utf8_sz == cesu8_sz);
+
+ TEST_ASSERT (!strncmp (string_from_utf8, string_from_cesu8, utf8_sz));
+ jerry_release_value (args[0]);
+ jerry_release_value (args[1]);
+
+ /* Test jerry_string_to_utf8_char_buffer, test string: 'str: {DESERET CAPITAL LETTER LONG I}' */
+ args[0] = jerry_create_string_from_utf8 ((jerry_char_t *) "\x73\x74\x72\x3a \xf0\x90\x90\x80");
+ args[1] = jerry_create_string ((jerry_char_t *) "\x73\x74\x72\x3a \xed\xa0\x81\xed\xb0\x80");
+
+ /* Test that the strings are equal / ensure hashes are equal */
+ TEST_ASSERT (strict_equals (args[0], args[1]));
+
+ /* These sizes must be equal */
+ utf8_sz = jerry_get_utf8_string_size (args[0]);
+ cesu8_sz = jerry_get_utf8_string_size (args[1]);
+
+ TEST_ASSERT (utf8_sz == cesu8_sz);
+
+ char string_from_utf8_string[utf8_sz];
+ char string_from_cesu8_string[cesu8_sz];
+
+ jerry_string_to_utf8_char_buffer (args[0], (jerry_char_t *) string_from_utf8_string, utf8_sz);
+ jerry_string_to_utf8_char_buffer (args[1], (jerry_char_t *) string_from_cesu8_string, cesu8_sz);
+
+ TEST_ASSERT (!strncmp (string_from_utf8_string, string_from_cesu8_string, utf8_sz));
+ jerry_release_value (args[0]);
+ jerry_release_value (args[1]);
+
+ /* Test string: 'str: {MATHEMATICAL FRAKTUR SMALL F}{MATHEMATICAL FRAKTUR SMALL G}' */
+ args[0] = jerry_create_string_from_utf8 ((jerry_char_t *) "\x73\x74\x72\x3a \xf0\x9d\x94\xa3 \xf0\x9d\x94\xa4");
+
+ cesu8_length = jerry_get_string_length (args[0]);
+ utf8_length = jerry_get_utf8_string_length (args[0]);
+
+ cesu8_sz = jerry_get_string_size (args[0]);
+ utf8_sz = jerry_get_utf8_string_size (args[0]);
+
+ TEST_ASSERT (cesu8_length == 10 && utf8_length == 8);
+ TEST_ASSERT (cesu8_sz != utf8_sz);
+ TEST_ASSERT (utf8_sz == 14 && cesu8_sz == 18);
+
+ char test_string[utf8_sz];
+
+ TEST_ASSERT (jerry_string_to_utf8_char_buffer (args[0], (jerry_char_t *) test_string, utf8_sz) == 14);
+ TEST_ASSERT (!strncmp (test_string, "\x73\x74\x72\x3a \xf0\x9d\x94\xa3 \xf0\x9d\x94\xa4", utf8_sz));
+
+ sz = jerry_substring_to_utf8_char_buffer (args[0], 0, utf8_length, (jerry_char_t *) test_string, utf8_sz);
+ TEST_ASSERT (sz == 14);
+ TEST_ASSERT (!strncmp (test_string, "\x73\x74\x72\x3a \xf0\x9d\x94\xa3 \xf0\x9d\x94\xa4", sz));
+
+ sz = jerry_substring_to_utf8_char_buffer (args[0], 0, utf8_length + 1, (jerry_char_t *) test_string, utf8_sz);
+ TEST_ASSERT (sz == 14);
+ TEST_ASSERT (!strncmp (test_string, "\x73\x74\x72\x3a \xf0\x9d\x94\xa3 \xf0\x9d\x94\xa4", sz));
+
+ sz = jerry_substring_to_utf8_char_buffer (args[0], utf8_length, 0, (jerry_char_t *) test_string, utf8_sz);
+ TEST_ASSERT (sz == 0);
+
+ sz = jerry_substring_to_utf8_char_buffer (args[0], 0, utf8_length, (jerry_char_t *) test_string, utf8_sz - 1);
+ TEST_ASSERT (sz == 10);
+ TEST_ASSERT (!strncmp (test_string, "\x73\x74\x72\x3a \xf0\x9d\x94\xa3 ", sz));
+
+ sz = jerry_substring_to_utf8_char_buffer (args[0], 0, utf8_length - 1, (jerry_char_t *) test_string, utf8_sz);
+ TEST_ASSERT (sz == 10);
+ TEST_ASSERT (!strncmp (test_string, "\x73\x74\x72\x3a \xf0\x9d\x94\xa3 ", sz));
+
+ sz = jerry_substring_to_utf8_char_buffer (args[0],
+ utf8_length - 2,
+ utf8_length - 1,
+ (jerry_char_t *) test_string,
+ utf8_sz);
+ TEST_ASSERT (sz == 1);
+ TEST_ASSERT (!strncmp (test_string, " ", sz));
+
+ sz = jerry_substring_to_utf8_char_buffer (args[0],
+ utf8_length - 3,
+ utf8_length - 2,
+ (jerry_char_t *) test_string,
+ utf8_sz);
+ TEST_ASSERT (sz == 4);
+ TEST_ASSERT (!strncmp (test_string, "\xf0\x9d\x94\xa3", sz));
+
+ jerry_release_value (args[0]);
+
+ /* Test string: 'str: {DESERET CAPITAL LETTER LONG I}' */
+ args[0] = jerry_create_string ((jerry_char_t *) "\x73\x74\x72\x3a \xed\xa0\x81\xed\xb0\x80");
+
+ cesu8_length = jerry_get_string_length (args[0]);
+ utf8_length = jerry_get_utf8_string_length (args[0]);
+
+ cesu8_sz = jerry_get_string_size (args[0]);
+ utf8_sz = jerry_get_utf8_string_size (args[0]);
+
+ TEST_ASSERT (cesu8_length == 7 && utf8_length == 6);
+ TEST_ASSERT (cesu8_sz != utf8_sz);
+ TEST_ASSERT (utf8_sz == 9 && cesu8_sz == 11);
+
+ jerry_release_value (args[0]);
+
+ /* Test string: 'price: 10{EURO SIGN}' */
+ args[0] = jerry_create_string_from_utf8 ((jerry_char_t *) "\x70\x72\x69\x63\x65\x3a \x31\x30\xe2\x82\xac");
+
+ cesu8_length = jerry_get_string_length (args[0]);
+ utf8_length = jerry_get_utf8_string_length (args[0]);
+
+ cesu8_sz = jerry_get_string_size (args[0]);
+ utf8_sz = jerry_get_utf8_string_size (args[0]);
+
+ TEST_ASSERT (cesu8_length == utf8_length);
+ TEST_ASSERT (cesu8_length == 10);
+ TEST_ASSERT (cesu8_sz == utf8_sz);
+ TEST_ASSERT (utf8_sz == 12);
+ jerry_release_value (args[0]);
+
+ /* Test string: '3' */
+ {
+ jerry_value_t test_str = jerry_create_string ((const jerry_char_t *) "3");
+ char result_string[1] = { 'E' };
+ jerry_size_t copied_utf8 = jerry_substring_to_utf8_char_buffer (test_str,
+ 0,
+ 1,
+ (jerry_char_t *) result_string,
+ sizeof (result_string));
+ TEST_ASSERT (copied_utf8 == 1);
+ TEST_ASSERT (result_string[0] == '3');
+
+ result_string[0] = 'E';
+ jerry_size_t copied = jerry_substring_to_char_buffer (test_str,
+ 0,
+ 1,
+ (jerry_char_t *) result_string,
+ sizeof (result_string));
+ TEST_ASSERT (copied == 1);
+ TEST_ASSERT (result_string[0] == '3');
+
+ jerry_release_value (test_str);
+ }
+
+ /* Test jerry_substring_to_char_buffer */
+ args[0] = jerry_create_string ((jerry_char_t *) "an ascii string");
+
+ /* Buffer size */
+ cesu8_sz = 5;
+
+ char substring[cesu8_sz];
+ sz = jerry_substring_to_char_buffer (args[0], 3, 8, (jerry_char_t *) substring, cesu8_sz);
+ TEST_ASSERT (sz == 5);
+ TEST_ASSERT (!strncmp (substring, "ascii", sz));
+
+ /* Buffer size is 5, substring length is 11 => copied only the first 5 char */
+ sz = jerry_substring_to_char_buffer (args[0], 0, 11, (jerry_char_t *) substring, cesu8_sz);
+
+ TEST_ASSERT (sz == 5);
+ TEST_ASSERT (!strncmp (substring, "an as", sz));
+
+ /* Position of the first character is greater than the string length */
+ sz = jerry_substring_to_char_buffer (args[0], 16, 21, (jerry_char_t *) substring, cesu8_sz);
+ TEST_ASSERT (sz == 0);
+
+ sz = jerry_substring_to_char_buffer (args[0], 14, 15, (jerry_char_t *) substring, cesu8_sz);
+ TEST_ASSERT (sz == 1);
+ TEST_ASSERT (!strncmp (substring, "g", sz));
+
+ sz = jerry_substring_to_char_buffer (args[0], 0, 1, (jerry_char_t *) substring, cesu8_sz);
+ TEST_ASSERT (sz == 1);
+ TEST_ASSERT (!strncmp (substring, "a", sz));
+
+ cesu8_length = jerry_get_string_length (args[0]);
+ cesu8_sz = jerry_get_string_size (args[0]);
+ TEST_ASSERT (cesu8_length == 15);
+ TEST_ASSERT (cesu8_length == cesu8_sz);
+
+ sz = jerry_substring_to_char_buffer (args[0], 0, cesu8_length, (jerry_char_t *) substring, cesu8_sz);
+ TEST_ASSERT (sz = 15);
+ TEST_ASSERT (!strncmp (substring, "an ascii string", sz));
+
+ jerry_release_value (args[0]);
+
+ /* Test jerry_substring_to_char_buffer: '0101' */
+ args[0] = jerry_create_string ((jerry_char_t *) "0101");
+ cesu8_sz = jerry_get_string_size (args[0]);
+
+ char number_substring[cesu8_sz];
+
+ sz = jerry_substring_to_char_buffer (args[0], 1, 3, (jerry_char_t *) number_substring, cesu8_sz);
+ TEST_ASSERT (sz == 2);
+ TEST_ASSERT (!strncmp (number_substring, "10", sz));
+
+ jerry_release_value (args[0]);
+
+ /* Test jerry_substring_to_char_buffer: 'str: {greek zero sign}' */
+ args[0] = jerry_create_string ((jerry_char_t *) "\x73\x74\x72\x3a \xed\xa0\x80\xed\xb6\x8a");
+ cesu8_sz = jerry_get_string_size (args[0]);
+ cesu8_length = jerry_get_string_length (args[0]);
+ TEST_ASSERT (cesu8_sz == 11);
+ TEST_ASSERT (cesu8_length = 7);
+
+ char supl_substring[cesu8_sz];
+
+ sz = jerry_substring_to_char_buffer (args[0], 0, cesu8_length, (jerry_char_t *) supl_substring, cesu8_sz);
+ TEST_ASSERT (sz == 11);
+ TEST_ASSERT (!strncmp (supl_substring, "\x73\x74\x72\x3a \xed\xa0\x80\xed\xb6\x8a", sz));
+
+ /* Decrease the buffer size => the low surrogate char will not fit into the buffer */
+ cesu8_sz -= 1;
+ sz = jerry_substring_to_char_buffer (args[0], 0, cesu8_length, (jerry_char_t *) supl_substring, cesu8_sz);
+ TEST_ASSERT (sz == 8);
+ TEST_ASSERT (!strncmp (supl_substring, "\x73\x74\x72\x3a \xed\xa0\x80", sz));
+
+ sz = jerry_substring_to_char_buffer (args[0],
+ cesu8_length - 1,
+ cesu8_length,
+ (jerry_char_t *) supl_substring,
+ cesu8_sz);
+ TEST_ASSERT (sz == 3);
+ TEST_ASSERT (!strncmp (supl_substring, "\xed\xb6\x8a", sz));
+
+ sz = jerry_substring_to_char_buffer (args[0],
+ cesu8_length - 2,
+ cesu8_length - 1,
+ (jerry_char_t *) supl_substring,
+ cesu8_sz);
+ TEST_ASSERT (sz == 3);
+ TEST_ASSERT (!strncmp (supl_substring, "\xed\xa0\x80", sz));
+
+ jerry_release_value (args[0]);
+
+ jerry_cleanup ();
+
+ return 0;
+} /* main */
jerry_init (JERRY_INIT_EMPTY);
- jerry_char_t test_eval_function[] = "function demo(a) { return a + 1; }; demo";
+ const jerry_char_t test_eval_function[] = "function demo(a) { return a + 1; }; demo";
test_entry_t entries[] =
{
ENTRY (JERRY_TYPE_OBJECT, jerry_create_object ()),
ENTRY (JERRY_TYPE_OBJECT, jerry_create_array (10)),
- ENTRY (JERRY_TYPE_OBJECT, jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t *) "error")),
+ ENTRY (JERRY_TYPE_ERROR, jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t *) "error")),
ENTRY (JERRY_TYPE_NULL, jerry_create_null ()),
- ENTRY (JERRY_TYPE_FUNCTION, jerry_eval (test_eval_function, strlen ((char *) test_eval_function), false)),
+ ENTRY (JERRY_TYPE_FUNCTION, jerry_eval (test_eval_function,
+ sizeof (test_eval_function) - 1,
+ JERRY_PARSE_NO_OPTS)),
ENTRY (JERRY_TYPE_FUNCTION, jerry_create_external_function (test_ext_function)),
ENTRY (JERRY_TYPE_STRING, jerry_create_string (test_eval_function)),
#include "test-common.h"
-const char *test_source = (
- "function assert (arg) { "
- " if (!arg) { "
- " throw Error('Assert failed');"
- " } "
- "} "
- "this.t = 1; "
- "function f () { "
- "return this.t; "
- "} "
- "this.foo = f; "
- "this.bar = function (a) { "
- "return a + t; "
- "}; "
- "function A () { "
- "this.t = 12; "
- "} "
- "this.A = A; "
- "this.a = new A (); "
- "function call_external () { "
- " return this.external ('1', true); "
- "} "
- "function call_throw_test() { "
- " var catched = false; "
- " try { "
- " this.throw_test(); "
- " } catch (e) { "
- " catched = true; "
- " assert(e.name == 'TypeError'); "
- " assert(e.message == 'error'); "
- " } "
- " assert(catched); "
- "} "
- "function throw_reference_error() { "
- " throw new ReferenceError ();"
- "} "
- "p = {'alpha':32, 'bravo':false, 'charlie':{}, 'delta':123.45, 'echo':'foobar'};"
- "np = {}; Object.defineProperty (np, 'foxtrot', { "
- "get: function() { throw 'error'; }, enumerable: true }) "
- );
+const jerry_char_t test_source[] = TEST_STRING_LITERAL (
+ "function assert (arg) { "
+ " if (!arg) { "
+ " throw Error('Assert failed');"
+ " } "
+ "} "
+ "this.t = 1; "
+ "function f () { "
+ "return this.t; "
+ "} "
+ "this.foo = f; "
+ "this.bar = function (a) { "
+ "return a + t; "
+ "}; "
+ "function A () { "
+ "this.t = 12; "
+ "} "
+ "this.A = A; "
+ "this.a = new A (); "
+ "function call_external () { "
+ " return this.external ('1', true); "
+ "} "
+ "function call_throw_test() { "
+ " var catched = false; "
+ " try { "
+ " this.throw_test(); "
+ " } catch (e) { "
+ " catched = true; "
+ " assert(e.name == 'TypeError'); "
+ " assert(e.message == 'error'); "
+ " } "
+ " assert(catched); "
+ "} "
+ "function throw_reference_error() { "
+ " throw new ReferenceError ();"
+ "} "
+ "p = {'alpha':32, 'bravo':false, 'charlie':{}, 'delta':123.45, 'echo':'foobar'};"
+ "np = {}; Object.defineProperty (np, 'foxtrot', { "
+ "get: function() { throw 'error'; }, enumerable: true }) "
+);
bool test_api_is_free_callback_was_called = false;
#undef JERRY_MAGIC_STRING_DEF
};
-const jerry_char_ptr_t magic_string_items[] =
+const jerry_char_t *magic_string_items[] =
{
#define JERRY_MAGIC_STRING_DEF(NAME, STRING) \
- (const jerry_char_ptr_t) jerry_magic_string_ex_ ## NAME,
+ (const jerry_char_t *) jerry_magic_string_ex_ ## NAME,
JERRY_MAGIC_STRING_ITEMS
return jerry_run_simple ((const jerry_char_t *) script_p, script_size, JERRY_INIT_EMPTY);
} /* test_run_simple */
-static bool
-strict_equals (jerry_value_t a,
- jerry_value_t b)
-{
- bool is_strict_equal;
- const char *is_equal_src;
- jerry_value_t args[2];
- jerry_value_t is_equal_fn_val;
- jerry_value_t res;
-
- is_equal_src = "var isEqual = function(a, b) { return (a === b); }; isEqual";
- is_equal_fn_val = jerry_eval ((jerry_char_t *) is_equal_src, strlen (is_equal_src), false);
- TEST_ASSERT (!jerry_value_has_error_flag (is_equal_fn_val));
- args[0] = a;
- args[1] = b;
- res = jerry_call_function (is_equal_fn_val, jerry_create_undefined (), args, 2);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
- TEST_ASSERT (jerry_value_is_boolean (res));
- is_strict_equal = jerry_get_boolean_value (res);
- jerry_release_value (res);
- jerry_release_value (is_equal_fn_val);
- return is_strict_equal;
-} /* strict_equals */
-
int
main (void)
{
TEST_INIT ();
bool is_ok;
- jerry_size_t sz, utf8_sz, cesu8_sz;
- jerry_length_t cesu8_length, utf8_length;
+ jerry_size_t sz, cesu8_sz;
+ jerry_length_t cesu8_length;
jerry_value_t val_t, val_foo, val_bar, val_A, val_A_prototype, val_a, val_a_foo, val_value_field, val_p, val_np;
jerry_value_t val_call_external;
jerry_value_t global_obj_val, obj_val;
parsed_code_val = jerry_parse (NULL,
0,
- (jerry_char_t *) test_source,
- strlen (test_source),
+ test_source,
+ sizeof (test_source) - 1,
JERRY_PARSE_NO_OPTS);
- TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
+ TEST_ASSERT (!jerry_value_is_error (parsed_code_val));
res = jerry_run (parsed_code_val);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
jerry_release_value (res);
jerry_release_value (parsed_code_val);
global_obj_val = jerry_get_global_object ();
- /* Test corner case for jerry_string_to_char_buffer */
- args[0] = jerry_create_string ((jerry_char_t *) "");
- sz = jerry_get_string_size (args[0]);
- TEST_ASSERT (sz == 0);
- jerry_release_value (args[0]);
-
- /* Test create_jerry_string_from_utf8 with 4-byte long unicode sequences,
- * test string: 'str: {DESERET CAPITAL LETTER LONG I}'
- */
- args[0] = jerry_create_string_from_utf8 ((jerry_char_t *) "\x73\x74\x72\x3a \xf0\x90\x90\x80");
- args[1] = jerry_create_string ((jerry_char_t *) "\x73\x74\x72\x3a \xed\xa0\x81\xed\xb0\x80");
-
- /* These sizes must be equal */
- utf8_sz = jerry_get_string_size (args[0]);
- cesu8_sz = jerry_get_string_size (args[1]);
-
- char string_from_utf8[utf8_sz];
- char string_from_cesu8[cesu8_sz];
-
- jerry_string_to_char_buffer (args[0], (jerry_char_t *) string_from_utf8, utf8_sz);
- jerry_string_to_char_buffer (args[1], (jerry_char_t *) string_from_cesu8, cesu8_sz);
-
- TEST_ASSERT (utf8_sz == cesu8_sz);
- TEST_ASSERT (!strncmp (string_from_utf8, string_from_cesu8, utf8_sz));
- jerry_release_value (args[0]);
- jerry_release_value (args[1]);
-
- /* Test jerry_string_to_utf8_char_buffer, test string: 'str: {DESERET CAPITAL LETTER LONG I}' */
- args[0] = jerry_create_string_from_utf8 ((jerry_char_t *) "\x73\x74\x72\x3a \xf0\x90\x90\x80");
- args[1] = jerry_create_string ((jerry_char_t *) "\x73\x74\x72\x3a \xed\xa0\x81\xed\xb0\x80");
-
- /* Test that the strings are equal / ensure hashes are equal */
- TEST_ASSERT (strict_equals (args[0], args[1]));
-
- /* These sizes must be equal */
- utf8_sz = jerry_get_utf8_string_size (args[0]);
- cesu8_sz = jerry_get_utf8_string_size (args[1]);
-
- TEST_ASSERT (utf8_sz == cesu8_sz);
-
- char string_from_utf8_string[utf8_sz];
- char string_from_cesu8_string[cesu8_sz];
-
- jerry_string_to_utf8_char_buffer (args[0], (jerry_char_t *) string_from_utf8_string, utf8_sz);
- jerry_string_to_utf8_char_buffer (args[1], (jerry_char_t *) string_from_cesu8_string, cesu8_sz);
-
- TEST_ASSERT (!strncmp (string_from_utf8_string, string_from_cesu8_string, utf8_sz));
- jerry_release_value (args[0]);
- jerry_release_value (args[1]);
-
- /* Test string: 'str: {MATHEMATICAL FRAKTUR SMALL F}{MATHEMATICAL FRAKTUR SMALL G}' */
- args[0] = jerry_create_string_from_utf8 ((jerry_char_t *) "\x73\x74\x72\x3a \xf0\x9d\x94\xa3 \xf0\x9d\x94\xa4");
-
- cesu8_length = jerry_get_string_length (args[0]);
- utf8_length = jerry_get_utf8_string_length (args[0]);
-
- cesu8_sz = jerry_get_string_size (args[0]);
- utf8_sz = jerry_get_utf8_string_size (args[0]);
-
- TEST_ASSERT (cesu8_length == 10 && utf8_length == 8);
- TEST_ASSERT (cesu8_sz != utf8_sz);
- TEST_ASSERT (utf8_sz == 14 && cesu8_sz == 18);
-
- char test_string[utf8_sz];
-
- TEST_ASSERT (jerry_string_to_utf8_char_buffer (args[0], (jerry_char_t *) test_string, utf8_sz) == 14);
- TEST_ASSERT (!strncmp (test_string, "\x73\x74\x72\x3a \xf0\x9d\x94\xa3 \xf0\x9d\x94\xa4", utf8_sz));
-
- sz = jerry_substring_to_utf8_char_buffer (args[0], 0, utf8_length, (jerry_char_t *) test_string, utf8_sz);
- TEST_ASSERT (sz == 14);
- TEST_ASSERT (!strncmp (test_string, "\x73\x74\x72\x3a \xf0\x9d\x94\xa3 \xf0\x9d\x94\xa4", sz));
-
- sz = jerry_substring_to_utf8_char_buffer (args[0], 0, utf8_length + 1, (jerry_char_t *) test_string, utf8_sz);
- TEST_ASSERT (sz == 14);
- TEST_ASSERT (!strncmp (test_string, "\x73\x74\x72\x3a \xf0\x9d\x94\xa3 \xf0\x9d\x94\xa4", sz));
-
- sz = jerry_substring_to_utf8_char_buffer (args[0], utf8_length, 0, (jerry_char_t *) test_string, utf8_sz);
- TEST_ASSERT (sz == 0);
-
- sz = jerry_substring_to_utf8_char_buffer (args[0], 0, utf8_length, (jerry_char_t *) test_string, utf8_sz - 1);
- TEST_ASSERT (sz == 10);
- TEST_ASSERT (!strncmp (test_string, "\x73\x74\x72\x3a \xf0\x9d\x94\xa3 ", sz));
-
- sz = jerry_substring_to_utf8_char_buffer (args[0], 0, utf8_length - 1, (jerry_char_t *) test_string, utf8_sz);
- TEST_ASSERT (sz == 10);
- TEST_ASSERT (!strncmp (test_string, "\x73\x74\x72\x3a \xf0\x9d\x94\xa3 ", sz));
-
- sz = jerry_substring_to_utf8_char_buffer (args[0],
- utf8_length - 2,
- utf8_length - 1,
- (jerry_char_t *) test_string,
- utf8_sz);
- TEST_ASSERT (sz == 1);
- TEST_ASSERT (!strncmp (test_string, " ", sz));
-
- sz = jerry_substring_to_utf8_char_buffer (args[0],
- utf8_length - 3,
- utf8_length - 2,
- (jerry_char_t *) test_string,
- utf8_sz);
- TEST_ASSERT (sz == 4);
- TEST_ASSERT (!strncmp (test_string, "\xf0\x9d\x94\xa3", sz));
-
- jerry_release_value (args[0]);
-
- /* Test string: 'str: {DESERET CAPITAL LETTER LONG I}' */
- args[0] = jerry_create_string ((jerry_char_t *) "\x73\x74\x72\x3a \xed\xa0\x81\xed\xb0\x80");
-
- cesu8_length = jerry_get_string_length (args[0]);
- utf8_length = jerry_get_utf8_string_length (args[0]);
-
- cesu8_sz = jerry_get_string_size (args[0]);
- utf8_sz = jerry_get_utf8_string_size (args[0]);
-
- TEST_ASSERT (cesu8_length == 7 && utf8_length == 6);
- TEST_ASSERT (cesu8_sz != utf8_sz);
- TEST_ASSERT (utf8_sz == 9 && cesu8_sz == 11);
-
- jerry_release_value (args[0]);
-
- /* Test string: 'price: 10{EURO SIGN}' */
- args[0] = jerry_create_string_from_utf8 ((jerry_char_t *) "\x70\x72\x69\x63\x65\x3a \x31\x30\xe2\x82\xac");
-
- cesu8_length = jerry_get_string_length (args[0]);
- utf8_length = jerry_get_utf8_string_length (args[0]);
-
- cesu8_sz = jerry_get_string_size (args[0]);
- utf8_sz = jerry_get_utf8_string_size (args[0]);
-
- TEST_ASSERT (cesu8_length == utf8_length);
- TEST_ASSERT (cesu8_length == 10);
- TEST_ASSERT (cesu8_sz == utf8_sz);
- TEST_ASSERT (utf8_sz == 12);
- jerry_release_value (args[0]);
-
- /* Test jerry_substring_to_char_buffer */
- args[0] = jerry_create_string ((jerry_char_t *) "an ascii string");
-
- /* Buffer size */
- cesu8_sz = 5;
-
- char substring[cesu8_sz];
- sz = jerry_substring_to_char_buffer (args[0], 3, 8, (jerry_char_t *) substring, cesu8_sz);
- TEST_ASSERT (sz == 5);
- TEST_ASSERT (!strncmp (substring, "ascii", sz));
-
- /* Buffer size is 5, substring length is 11 => copied only the first 5 char */
- sz = jerry_substring_to_char_buffer (args[0], 0, 11, (jerry_char_t *) substring, cesu8_sz);
-
- TEST_ASSERT (sz == 5);
- TEST_ASSERT (!strncmp (substring, "an as", sz));
-
- /* Position of the first character is greater than the string length */
- sz = jerry_substring_to_char_buffer (args[0], 16, 21, (jerry_char_t *) substring, cesu8_sz);
- TEST_ASSERT (sz == 0);
-
- sz = jerry_substring_to_char_buffer (args[0], 14, 15, (jerry_char_t *) substring, cesu8_sz);
- TEST_ASSERT (sz == 1);
- TEST_ASSERT (!strncmp (substring, "g", sz));
-
- sz = jerry_substring_to_char_buffer (args[0], 0, 1, (jerry_char_t *) substring, cesu8_sz);
- TEST_ASSERT (sz == 1);
- TEST_ASSERT (!strncmp (substring, "a", sz));
-
- cesu8_length = jerry_get_string_length (args[0]);
- cesu8_sz = jerry_get_string_size (args[0]);
- TEST_ASSERT (cesu8_length == 15);
- TEST_ASSERT (cesu8_length == cesu8_sz);
-
- sz = jerry_substring_to_char_buffer (args[0], 0, cesu8_length, (jerry_char_t *) substring, cesu8_sz);
- TEST_ASSERT (sz = 15);
- TEST_ASSERT (!strncmp (substring, "an ascii string", sz));
-
- jerry_release_value (args[0]);
-
- /* Test jerry_substring_to_char_buffer: '0101' */
- args[0] = jerry_create_string ((jerry_char_t *) "0101");
- cesu8_sz = jerry_get_string_size (args[0]);
-
- char number_substring[cesu8_sz];
-
- sz = jerry_substring_to_char_buffer (args[0], 1, 3, (jerry_char_t *) number_substring, cesu8_sz);
- TEST_ASSERT (sz == 2);
- TEST_ASSERT (!strncmp (number_substring, "10", sz));
-
- jerry_release_value (args[0]);
-
- /* Test jerry_substring_to_char_buffer: 'str: {greek zero sign}' */
- args[0] = jerry_create_string ((jerry_char_t *) "\x73\x74\x72\x3a \xed\xa0\x80\xed\xb6\x8a");
- cesu8_sz = jerry_get_string_size (args[0]);
- cesu8_length = jerry_get_string_length (args[0]);
- TEST_ASSERT (cesu8_sz == 11);
- TEST_ASSERT (cesu8_length = 7);
-
- char supl_substring[cesu8_sz];
-
- sz = jerry_substring_to_char_buffer (args[0], 0, cesu8_length, (jerry_char_t *) supl_substring, cesu8_sz);
- TEST_ASSERT (sz == 11);
- TEST_ASSERT (!strncmp (supl_substring, "\x73\x74\x72\x3a \xed\xa0\x80\xed\xb6\x8a", sz));
-
- /* Decrease the buffer size => the low surrogate char will not fit into the buffer */
- cesu8_sz -= 1;
- sz = jerry_substring_to_char_buffer (args[0], 0, cesu8_length, (jerry_char_t *) supl_substring, cesu8_sz);
- TEST_ASSERT (sz == 8);
- TEST_ASSERT (!strncmp (supl_substring, "\x73\x74\x72\x3a \xed\xa0\x80", sz));
-
- sz = jerry_substring_to_char_buffer (args[0],
- cesu8_length - 1,
- cesu8_length,
- (jerry_char_t *) supl_substring,
- cesu8_sz);
- TEST_ASSERT (sz == 3);
- TEST_ASSERT (!strncmp (supl_substring, "\xed\xb6\x8a", sz));
-
- sz = jerry_substring_to_char_buffer (args[0],
- cesu8_length - 2,
- cesu8_length - 1,
- (jerry_char_t *) supl_substring,
- cesu8_sz);
- TEST_ASSERT (sz == 3);
- TEST_ASSERT (!strncmp (supl_substring, "\xed\xa0\x80", sz));
-
- jerry_release_value (args[0]);
-
/* Get global.boo (non-existing field) */
val_t = get_property (global_obj_val, "boo");
- TEST_ASSERT (!jerry_value_has_error_flag (val_t));
+ TEST_ASSERT (!jerry_value_is_error (val_t));
TEST_ASSERT (jerry_value_is_undefined (val_t));
/* Get global.t */
val_t = get_property (global_obj_val, "t");
- TEST_ASSERT (!jerry_value_has_error_flag (val_t));
+ TEST_ASSERT (!jerry_value_is_error (val_t));
TEST_ASSERT (jerry_value_is_number (val_t)
&& jerry_get_number_value (val_t) == 1.0);
jerry_release_value (val_t);
/* Get global.foo */
val_foo = get_property (global_obj_val, "foo");
- TEST_ASSERT (!jerry_value_has_error_flag (val_foo));
+ TEST_ASSERT (!jerry_value_is_error (val_foo));
TEST_ASSERT (jerry_value_is_object (val_foo));
/* Call foo (4, 2) */
args[0] = jerry_create_number (4);
args[1] = jerry_create_number (2);
res = jerry_call_function (val_foo, jerry_create_undefined (), args, 2);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_number (res)
&& jerry_get_number_value (res) == 1.0);
jerry_release_value (res);
/* Get global.bar */
val_bar = get_property (global_obj_val, "bar");
- TEST_ASSERT (!jerry_value_has_error_flag (val_bar));
+ TEST_ASSERT (!jerry_value_is_error (val_bar));
TEST_ASSERT (jerry_value_is_object (val_bar));
/* Call bar (4, 2) */
res = jerry_call_function (val_bar, jerry_create_undefined (), args, 2);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_number (res)
&& jerry_get_number_value (res) == 5.0);
jerry_release_value (res);
jerry_release_value (args[0]);
args[0] = jerry_create_string ((jerry_char_t *) "abcd");
res = set_property (global_obj_val, "t", args[0]);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_get_boolean_value (res));
jerry_release_value (res);
/* Call foo (4, 2) */
res = jerry_call_function (val_foo, jerry_create_undefined (), args, 2);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_string (res));
sz = jerry_get_string_size (res);
TEST_ASSERT (sz == 4);
/* Get global.A */
val_A = get_property (global_obj_val, "A");
- TEST_ASSERT (!jerry_value_has_error_flag (val_A));
+ TEST_ASSERT (!jerry_value_is_error (val_A));
TEST_ASSERT (jerry_value_is_object (val_A));
/* Get A.prototype */
is_ok = jerry_value_is_constructor (val_A);
TEST_ASSERT (is_ok);
val_A_prototype = get_property (val_A, "prototype");
- TEST_ASSERT (!jerry_value_has_error_flag (val_A_prototype));
+ TEST_ASSERT (!jerry_value_is_error (val_A_prototype));
TEST_ASSERT (jerry_value_is_object (val_A_prototype));
jerry_release_value (val_A);
/* Set A.prototype.foo = global.foo */
res = set_property (val_A_prototype, "foo", val_foo);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_get_boolean_value (res));
jerry_release_value (res);
jerry_release_value (val_A_prototype);
/* Get global.a */
val_a = get_property (global_obj_val, "a");
- TEST_ASSERT (!jerry_value_has_error_flag (val_a));
+ TEST_ASSERT (!jerry_value_is_error (val_a));
TEST_ASSERT (jerry_value_is_object (val_a));
/* Get a.t */
res = get_property (val_a, "t");
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_number (res)
&& jerry_get_number_value (res) == 12.0);
jerry_release_value (res);
/* Get a.foo */
val_a_foo = get_property (val_a, "foo");
- TEST_ASSERT (!jerry_value_has_error_flag (val_a_foo));
+ TEST_ASSERT (!jerry_value_is_error (val_a_foo));
TEST_ASSERT (jerry_value_is_object (val_a_foo));
/* Call a.foo () */
res = jerry_call_function (val_a_foo, val_a, NULL, 0);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_number (res)
&& jerry_get_number_value (res) == 12.0);
jerry_release_value (res);
&& jerry_value_is_constructor (external_func_val));
res = set_property (global_obj_val, "external", external_func_val);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_get_boolean_value (res));
jerry_release_value (external_func_val);
/* Call 'call_external' function that should call external function created above */
val_call_external = get_property (global_obj_val, "call_external");
- TEST_ASSERT (!jerry_value_has_error_flag (val_call_external));
+ TEST_ASSERT (!jerry_value_is_error (val_call_external));
TEST_ASSERT (jerry_value_is_object (val_call_external));
res = jerry_call_function (val_call_external, global_obj_val, NULL, 0);
jerry_release_value (val_call_external);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_string (res));
sz = jerry_get_string_size (res);
TEST_ASSERT (sz == 19);
&& jerry_value_is_constructor (external_construct_val));
res = set_property (global_obj_val, "external_construct", external_construct_val);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_get_boolean_value (res));
jerry_release_value (res);
/* Call external function created above, as constructor */
args[0] = jerry_create_boolean (true);
res = jerry_construct_object (external_construct_val, args, 1);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_object (res));
val_value_field = get_property (res, "value_field");
/* Get 'value_field' of constructed object */
- TEST_ASSERT (!jerry_value_has_error_flag (val_value_field));
+ TEST_ASSERT (!jerry_value_is_error (val_value_field));
TEST_ASSERT (jerry_value_is_boolean (val_value_field)
&& jerry_get_boolean_value (val_value_field));
jerry_release_value (val_value_field);
TEST_ASSERT (jerry_value_is_function (throw_test_handler_val));
res = set_property (global_obj_val, "throw_test", throw_test_handler_val);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_get_boolean_value (res));
jerry_release_value (res);
jerry_release_value (throw_test_handler_val);
val_t = get_property (global_obj_val, "call_throw_test");
- TEST_ASSERT (!jerry_value_has_error_flag (val_t));
+ TEST_ASSERT (!jerry_value_is_error (val_t));
TEST_ASSERT (jerry_value_is_object (val_t));
res = jerry_call_function (val_t, global_obj_val, NULL, 0);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
jerry_release_value (val_t);
jerry_release_value (res);
/* Test: Unhandled exception in called function */
val_t = get_property (global_obj_val, "throw_reference_error");
- TEST_ASSERT (!jerry_value_has_error_flag (val_t));
+ TEST_ASSERT (!jerry_value_is_error (val_t));
TEST_ASSERT (jerry_value_is_object (val_t));
res = jerry_call_function (val_t, global_obj_val, NULL, 0);
- TEST_ASSERT (jerry_value_has_error_flag (res));
+ TEST_ASSERT (jerry_value_is_error (res));
jerry_release_value (val_t);
/* 'res' should contain exception object */
+ res = jerry_get_value_from_error (res, true);
TEST_ASSERT (jerry_value_is_object (res));
jerry_release_value (res);
/* Test: Call of non-function */
obj_val = jerry_create_object ();
res = jerry_call_function (obj_val, global_obj_val, NULL, 0);
- TEST_ASSERT (jerry_value_has_error_flag (res));
+ TEST_ASSERT (jerry_value_is_error (res));
/* 'res' should contain exception object */
+ res = jerry_get_value_from_error (res, true);
TEST_ASSERT (jerry_value_is_object (res));
jerry_release_value (res);
/* Test: Unhandled exception in function called, as constructor */
val_t = get_property (global_obj_val, "throw_reference_error");
- TEST_ASSERT (!jerry_value_has_error_flag (val_t));
+ TEST_ASSERT (!jerry_value_is_error (val_t));
TEST_ASSERT (jerry_value_is_object (val_t));
res = jerry_construct_object (val_t, NULL, 0);
- TEST_ASSERT (jerry_value_has_error_flag (res));
+ TEST_ASSERT (jerry_value_is_error (res));
jerry_release_value (val_t);
/* 'res' should contain exception object */
+ res = jerry_get_value_from_error (res, true);
TEST_ASSERT (jerry_value_is_object (res));
jerry_release_value (res);
/* Test: Call of non-function as constructor */
obj_val = jerry_create_object ();
res = jerry_construct_object (obj_val, NULL, 0);
- TEST_ASSERT (jerry_value_has_error_flag (res));
+ TEST_ASSERT (jerry_value_is_error (res));
/* 'res' should contain exception object */
+ res = jerry_get_value_from_error (res, true);
TEST_ASSERT (jerry_value_is_object (res));
jerry_release_value (res);
jerry_release_value (v_und);
jerry_release_value (array_obj_val);
- /* Test: init property descriptor */
- jerry_property_descriptor_t prop_desc;
- jerry_init_property_descriptor_fields (&prop_desc);
- TEST_ASSERT (prop_desc.is_value_defined == false);
- TEST_ASSERT (jerry_value_is_undefined (prop_desc.value));
- TEST_ASSERT (prop_desc.is_writable_defined == false);
- TEST_ASSERT (prop_desc.is_writable == false);
- TEST_ASSERT (prop_desc.is_enumerable_defined == false);
- TEST_ASSERT (prop_desc.is_enumerable == false);
- TEST_ASSERT (prop_desc.is_configurable_defined == false);
- TEST_ASSERT (prop_desc.is_configurable == false);
- TEST_ASSERT (prop_desc.is_get_defined == false);
- TEST_ASSERT (jerry_value_is_undefined (prop_desc.getter));
- TEST_ASSERT (prop_desc.is_set_defined == false);
- TEST_ASSERT (jerry_value_is_undefined (prop_desc.setter));
-
- /* Test: define own properties */
- jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "my_defined_property");
- prop_desc.is_value_defined = true;
- prop_desc.value = jerry_acquire_value (prop_name);
- res = jerry_define_own_property (global_obj_val, prop_name, &prop_desc);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
- TEST_ASSERT (jerry_value_is_boolean (res));
- TEST_ASSERT (jerry_get_boolean_value (res));
- jerry_release_value (res);
- jerry_free_property_descriptor_fields (&prop_desc);
-
- /* Test: get own property descriptor */
- is_ok = jerry_get_own_property_descriptor (global_obj_val, prop_name, &prop_desc);
- TEST_ASSERT (is_ok);
- TEST_ASSERT (prop_desc.is_value_defined == true);
- TEST_ASSERT (jerry_value_is_string (prop_desc.value));
- TEST_ASSERT (prop_desc.is_writable == false);
- TEST_ASSERT (prop_desc.is_enumerable == false);
- TEST_ASSERT (prop_desc.is_configurable == false);
- TEST_ASSERT (prop_desc.is_get_defined == false);
- TEST_ASSERT (jerry_value_is_undefined (prop_desc.getter));
- TEST_ASSERT (prop_desc.is_set_defined == false);
- TEST_ASSERT (jerry_value_is_undefined (prop_desc.setter));
- jerry_release_value (prop_name);
- jerry_free_property_descriptor_fields (&prop_desc);
-
/* Test: object keys */
res = jerry_get_object_keys (global_obj_val);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_array (res));
jerry_release_value (res);
/* Test: jerry_value_to_primitive */
- obj_val = jerry_eval ((jerry_char_t *) "new String ('hello')", 20, false);
- TEST_ASSERT (!jerry_value_has_error_flag (obj_val));
+ obj_val = jerry_eval ((jerry_char_t *) "new String ('hello')", 20, JERRY_PARSE_NO_OPTS);
+ TEST_ASSERT (!jerry_value_is_error (obj_val));
TEST_ASSERT (jerry_value_is_object (obj_val));
TEST_ASSERT (!jerry_value_is_string (obj_val));
prim_val = jerry_value_to_primitive (obj_val);
- TEST_ASSERT (!jerry_value_has_error_flag (prim_val));
+ TEST_ASSERT (!jerry_value_is_error (prim_val));
TEST_ASSERT (jerry_value_is_string (prim_val));
jerry_release_value (prim_val);
/* Test: jerry_get_prototype */
proto_val = jerry_get_prototype (obj_val);
- TEST_ASSERT (!jerry_value_has_error_flag (proto_val));
+ TEST_ASSERT (!jerry_value_is_error (proto_val));
TEST_ASSERT (jerry_value_is_object (proto_val));
jerry_release_value (obj_val);
/* Test: jerry_set_prototype */
obj_val = jerry_create_object ();
res = jerry_set_prototype (obj_val, jerry_create_null ());
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_boolean (res));
TEST_ASSERT (jerry_get_boolean_value (res));
res = jerry_set_prototype (obj_val, jerry_create_object ());
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_boolean (res));
TEST_ASSERT (jerry_get_boolean_value (res));
proto_val = jerry_get_prototype (obj_val);
- TEST_ASSERT (!jerry_value_has_error_flag (proto_val));
+ TEST_ASSERT (!jerry_value_is_error (proto_val));
TEST_ASSERT (jerry_value_is_object (proto_val));
jerry_release_value (proto_val);
jerry_release_value (obj_val);
/* Test: eval */
- const char *eval_code_src_p = "(function () { return 123; })";
- val_t = jerry_eval ((jerry_char_t *) eval_code_src_p, strlen (eval_code_src_p), true);
- TEST_ASSERT (!jerry_value_has_error_flag (val_t));
+ const jerry_char_t eval_code_src1[] = "(function () { return 123; })";
+ val_t = jerry_eval (eval_code_src1, sizeof (eval_code_src1) - 1, JERRY_PARSE_STRICT_MODE);
+ TEST_ASSERT (!jerry_value_is_error (val_t));
TEST_ASSERT (jerry_value_is_object (val_t));
TEST_ASSERT (jerry_value_is_function (val_t));
res = jerry_call_function (val_t, jerry_create_undefined (), NULL, 0);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_number (res)
&& jerry_get_number_value (res) == 123.0);
jerry_release_value (res);
jerry_release_value (global_obj_val);
/* Test: run gc. */
- jerry_gc ();
+ jerry_gc (JERRY_GC_SEVERITY_LOW);
/* Test: spaces */
- eval_code_src_p = "\x0a \x0b \x0c \xc2\xa0 \xe2\x80\xa8 \xe2\x80\xa9 \xef\xbb\xbf 4321";
- val_t = jerry_eval ((jerry_char_t *) eval_code_src_p, strlen (eval_code_src_p), true);
- TEST_ASSERT (!jerry_value_has_error_flag (val_t));
+ const jerry_char_t eval_code_src2[] = "\x0a \x0b \x0c \xc2\xa0 \xe2\x80\xa8 \xe2\x80\xa9 \xef\xbb\xbf 4321";
+ val_t = jerry_eval (eval_code_src2, sizeof (eval_code_src2) - 1, JERRY_PARSE_STRICT_MODE);
+ TEST_ASSERT (!jerry_value_is_error (val_t));
TEST_ASSERT (jerry_value_is_number (val_t)
&& jerry_get_number_value (val_t) == 4321.0);
jerry_release_value (val_t);
jerry_release_value (val_t);
/* Test: create function */
- const char *func_resource = "unknown";
- const char *func_arg_list = "a , b,c";
- const char *func_src = " return 5 + a+\nb+c";
-
- jerry_value_t func_val = jerry_parse_function ((const jerry_char_t *) func_resource,
- strlen (func_resource),
- (const jerry_char_t *) func_arg_list,
- strlen (func_arg_list),
- (const jerry_char_t *) func_src,
- strlen (func_src),
+ const jerry_char_t func_resource[] = "unknown";
+ const jerry_char_t func_arg_list[] = "a , b,c";
+ const jerry_char_t func_src[] = " return 5 + a+\nb+c";
+
+ jerry_value_t func_val = jerry_parse_function (func_resource,
+ sizeof (func_resource) - 1,
+ func_arg_list,
+ sizeof (func_arg_list) - 1,
+ func_src,
+ sizeof (func_src) - 1,
JERRY_PARSE_NO_OPTS);
- TEST_ASSERT (!jerry_value_has_error_flag (func_val));
+ TEST_ASSERT (!jerry_value_is_error (func_val));
jerry_value_t func_args[3] =
{
TEST_ASSERT (test_api_is_free_callback_was_called);
- /* Test: jerry_get_value_without_error_flag */
+ /* Test: jerry_get_value_from_error */
{
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t num_val = jerry_create_number (123);
- jerry_value_set_error_flag (&num_val);
- TEST_ASSERT (jerry_value_has_error_flag (num_val));
- jerry_value_t num2_val = jerry_get_value_without_error_flag (num_val);
- TEST_ASSERT (!jerry_value_has_error_flag (num2_val));
+ num_val = jerry_create_error_from_value (num_val, true);
+ TEST_ASSERT (jerry_value_is_error (num_val));
+ jerry_value_t num2_val = jerry_get_value_from_error (num_val, false);
+ TEST_ASSERT (jerry_value_is_error (num_val));
+ TEST_ASSERT (!jerry_value_is_error (num2_val));
double num = jerry_get_number_value (num2_val);
TEST_ASSERT (num == 123);
- jerry_release_value (num_val);
+ num2_val = jerry_get_value_from_error (num_val, true);
+ TEST_ASSERT (!jerry_value_is_error (num2_val));
+ num = jerry_get_number_value (num2_val);
+ TEST_ASSERT (num == 123);
jerry_release_value (num2_val);
jerry_cleanup ();
}
{
jerry_init (JERRY_INIT_SHOW_OPCODES);
- const char *parser_err_src_p = "b = 'hello';\nvar a = (;";
+ const jerry_char_t parser_err_src[] = "b = 'hello';\nvar a = (;";
parsed_code_val = jerry_parse (NULL,
0,
- (jerry_char_t *) parser_err_src_p,
- strlen (parser_err_src_p),
+ parser_err_src,
+ sizeof (parser_err_src) - 1,
JERRY_PARSE_NO_OPTS);
- TEST_ASSERT (jerry_value_has_error_flag (parsed_code_val));
- jerry_value_clear_error_flag (&parsed_code_val);
+ TEST_ASSERT (jerry_value_is_error (parsed_code_val));
+ parsed_code_val = jerry_get_value_from_error (parsed_code_val, true);
jerry_value_t err_str_val = jerry_value_to_string (parsed_code_val);
jerry_size_t err_str_size = jerry_get_string_size (err_str_val);
jerry_char_t err_str_buf[256];
/* External Magic String */
jerry_init (JERRY_INIT_SHOW_OPCODES);
- uint32_t num_magic_string_items = (uint32_t) (sizeof (magic_string_items) / sizeof (jerry_char_ptr_t));
+ uint32_t num_magic_string_items = (uint32_t) (sizeof (magic_string_items) / sizeof (jerry_char_t *));
jerry_register_magic_strings (magic_string_items,
num_magic_string_items,
magic_string_lengths);
- const char *ms_code_src_p = "var global = {}; var console = [1]; var process = 1;";
+ const jerry_char_t ms_code_src[] = "var global = {}; var console = [1]; var process = 1;";
parsed_code_val = jerry_parse (NULL,
0,
- (jerry_char_t *) ms_code_src_p,
- strlen (ms_code_src_p),
+ ms_code_src,
+ sizeof (ms_code_src) - 1,
JERRY_PARSE_NO_OPTS);
- TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
+ TEST_ASSERT (!jerry_value_is_error (parsed_code_val));
res = jerry_run (parsed_code_val);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
jerry_release_value (res);
jerry_release_value (parsed_code_val);
jerry_release_value (args[0]);
- const char *test_magic_str_access_src_p = "'console'.charAt(6) == 'e'";
- res = jerry_eval ((const jerry_char_t *) test_magic_str_access_src_p,
- strlen (test_magic_str_access_src_p),
- false);
+ const jerry_char_t test_magic_str_access_src[] = "'console'.charAt(6) == 'e'";
+ res = jerry_eval (test_magic_str_access_src,
+ sizeof (test_magic_str_access_src) - 1,
+ JERRY_PARSE_NO_OPTS);
TEST_ASSERT (jerry_value_is_boolean (res));
TEST_ASSERT (jerry_get_boolean_value (res) == true);
{
/*json parser check*/
- char data_check[]="John";
+ const char data_check[]="John";
jerry_value_t key = jerry_create_string ((const jerry_char_t *) "name");
- 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);
+ const jerry_char_t data[] = "{\"name\": \"John\", \"age\": 5}";
+ jerry_value_t parsed_json = jerry_json_parse (data, sizeof (data) - 1);
jerry_value_t has_prop_js = jerry_has_property (parsed_json, key);
TEST_ASSERT (jerry_get_boolean_value (has_prop_js));
jerry_release_value (has_prop_js);
jerry_value_t parsed_data = jerry_get_property (parsed_json, key);
TEST_ASSERT (jerry_value_is_string (parsed_data)== true);
- jerry_size_t buff_size = (jerry_size_t) jerry_get_string_length (parsed_data);
char buff[jerry_get_string_length (parsed_data)];
- jerry_char_t *buff_p = (jerry_char_t *) buff;
- jerry_string_to_char_buffer (parsed_data, buff_p, buff_size);
+ jerry_size_t buff_size = (jerry_size_t) jerry_get_string_length (parsed_data);
+ jerry_string_to_char_buffer (parsed_data, (jerry_char_t *) buff, buff_size);
buff[buff_size] = '\0';
- TEST_ASSERT (strcmp ((const char *) data_check, (const char *) buff) == false);
+ TEST_ASSERT (strcmp (data_check, buff) == false);
jerry_release_value (parsed_json);
jerry_release_value (key);
jerry_release_value (parsed_data);
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);
+ jerry_value_t stringified = jerry_json_stringify (obj);
TEST_ASSERT (jerry_value_is_string (stringified));
char buff[jerry_get_string_length (stringified)];
jerry_string_to_char_buffer (stringified, (jerry_char_t *) buff,
TEST_ASSERT (false);
} /* assert_handler */
-/**
- * Checks whether global object has arraybuffer.
- */
-static bool
-arraybuffer_is_available (void)
-{
- jerry_value_t global_obj_val = jerry_get_global_object ();
- jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "ArrayBuffer");
-
- jerry_value_t prop_value = jerry_has_property (global_obj_val, prop_name);
- bool has_prop = jerry_get_boolean_value (prop_value);
-
- jerry_release_value (global_obj_val);
- jerry_release_value (prop_name);
- jerry_release_value (prop_value);
-
- return has_prop;
-} /* arraybuffer_is_available */
-
/**
* Test ArrayBuffer 'read' api call with various offset values.
*/
static void
test_read_with_offset (uint8_t offset) /**< offset for buffer read. */
{
- const char *eval_arraybuffer_src_p = ("var array = new Uint8Array (15);"
- "for (var i = 0; i < array.length; i++) { array[i] = i * 2; };"
- "array.buffer");
- jerry_value_t arraybuffer = jerry_eval ((jerry_char_t *) eval_arraybuffer_src_p,
- strlen (eval_arraybuffer_src_p),
- true);
-
- TEST_ASSERT (!jerry_value_has_error_flag (arraybuffer));
+ const jerry_char_t eval_arraybuffer_src[] = TEST_STRING_LITERAL (
+ "var array = new Uint8Array (15);"
+ "for (var i = 0; i < array.length; i++) { array[i] = i * 2; };"
+ "array.buffer"
+ );
+ jerry_value_t arraybuffer = jerry_eval (eval_arraybuffer_src,
+ sizeof (eval_arraybuffer_src) - 1,
+ JERRY_PARSE_STRICT_MODE);
+
+ TEST_ASSERT (!jerry_value_is_error (arraybuffer));
TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == 15);
jerry_release_value (offset_val);
}
- const char *eval_arraybuffer_src_p = "var array = new Uint8Array (15); array.buffer";
- jerry_value_t arraybuffer = jerry_eval ((jerry_char_t *) eval_arraybuffer_src_p,
- strlen (eval_arraybuffer_src_p),
- true);
+ const jerry_char_t eval_arraybuffer_src[] = "var array = new Uint8Array (15); array.buffer";
+ jerry_value_t arraybuffer = jerry_eval (eval_arraybuffer_src,
+ sizeof (eval_arraybuffer_src) - 1,
+ JERRY_PARSE_STRICT_MODE);
- TEST_ASSERT (!jerry_value_has_error_flag (arraybuffer));
+ TEST_ASSERT (!jerry_value_is_error (arraybuffer));
TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == 15);
jerry_length_t copied = jerry_arraybuffer_write (arraybuffer, offset, buffer, 20);
TEST_ASSERT (copied == (jerry_length_t)(15 - offset));
- const char *eval_test_arraybuffer_p = (
- "for (var i = 0; i < offset; i++)"
- "{"
- " assert (array[i] == 0, 'offset check for: ' + i + ' was: ' + array[i] + ' should be: 0');"
- "};"
- "for (var i = offset; i < array.length; i++)"
- "{"
- " var expected = (i - offset) * 3;"
- " assert (array[i] == expected, 'calc check for: ' + i + ' was: ' + array[i] + ' should be: ' + expected);"
- "};"
- "assert (array[15] === undefined, 'ArrayBuffer out of bounds index should return undefined value');");
- jerry_value_t res = jerry_eval ((jerry_char_t *) eval_test_arraybuffer_p,
- strlen (eval_test_arraybuffer_p),
- true);
+ const jerry_char_t eval_test_arraybuffer[] = TEST_STRING_LITERAL (
+ "for (var i = 0; i < offset; i++)"
+ "{"
+ " assert (array[i] == 0, 'offset check for: ' + i + ' was: ' + array[i] + ' should be: 0');"
+ "};"
+ "for (var i = offset; i < array.length; i++)"
+ "{"
+ " var expected = (i - offset) * 3;"
+ " assert (array[i] == expected, 'calc check for: ' + i + ' was: ' + array[i] + ' should be: ' + expected);"
+ "};"
+ "assert (array[15] === undefined, 'ArrayBuffer out of bounds index should return undefined value');"
+ );
+ jerry_value_t res = jerry_eval (eval_test_arraybuffer,
+ sizeof (eval_test_arraybuffer) - 1,
+ JERRY_PARSE_STRICT_MODE);
jerry_release_value (res);
jerry_release_value (arraybuffer);
} /* test_write_with_offset */
{
jerry_init (JERRY_INIT_EMPTY);
- if (!arraybuffer_is_available ())
+ if (!jerry_is_feature_enabled (JERRY_FEATURE_TYPEDARRAY))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "ArrayBuffer is disabled!\n");
jerry_cleanup ();
/* Test array buffer queries */
{
- const char *eval_arraybuffer_src_p = "new ArrayBuffer (10)";
- jerry_value_t eval_arraybuffer = jerry_eval ((jerry_char_t *) eval_arraybuffer_src_p,
- strlen (eval_arraybuffer_src_p),
- true);
- TEST_ASSERT (!jerry_value_has_error_flag (eval_arraybuffer));
+ const jerry_char_t eval_arraybuffer_src[] = "new ArrayBuffer (10)";
+ jerry_value_t eval_arraybuffer = jerry_eval (eval_arraybuffer_src,
+ sizeof (eval_arraybuffer_src) - 1,
+ JERRY_PARSE_STRICT_MODE);
+ TEST_ASSERT (!jerry_value_is_error (eval_arraybuffer));
TEST_ASSERT (jerry_value_is_arraybuffer (eval_arraybuffer));
TEST_ASSERT (jerry_get_arraybuffer_byte_length (eval_arraybuffer) == 10);
jerry_release_value (eval_arraybuffer);
{
const uint32_t length = 15;
jerry_value_t arraybuffer = jerry_create_arraybuffer (length);
- TEST_ASSERT (!jerry_value_has_error_flag (arraybuffer));
+ TEST_ASSERT (!jerry_value_is_error (arraybuffer));
TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length);
jerry_release_value (arraybuffer);
{
const uint32_t length = 0;
jerry_value_t arraybuffer = jerry_create_arraybuffer (length);
- TEST_ASSERT (!jerry_value_has_error_flag (arraybuffer));
+ TEST_ASSERT (!jerry_value_is_error (arraybuffer));
TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length);
{
const uint32_t length = 0;
jerry_value_t arraybuffer = jerry_create_arraybuffer (length);
- TEST_ASSERT (!jerry_value_has_error_flag (arraybuffer));
+ TEST_ASSERT (!jerry_value_is_error (arraybuffer));
TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length);
jerry_release_value (input_buffer);
}
- const char *eval_arraybuffer_src_p = (
+ const jerry_char_t eval_arraybuffer_src[] = TEST_STRING_LITERAL (
"var array = new Uint8Array(input_buffer);"
"for (var i = 0; i < array.length; i++)"
"{"
" array[i] = i * 2;"
"};"
- "array.buffer");
- jerry_value_t buffer = jerry_eval ((jerry_char_t *) eval_arraybuffer_src_p,
- strlen (eval_arraybuffer_src_p),
- true);
+ "array.buffer"
+ );
+ jerry_value_t buffer = jerry_eval (eval_arraybuffer_src,
+ sizeof (eval_arraybuffer_src) - 1,
+ JERRY_PARSE_STRICT_MODE);
- TEST_ASSERT (!jerry_value_has_error_flag (buffer));
+ TEST_ASSERT (!jerry_value_is_error (buffer));
TEST_ASSERT (jerry_value_is_arraybuffer (buffer));
TEST_ASSERT (jerry_get_arraybuffer_byte_length (buffer) == 20);
jerry_release_value (buffer);
- const char *eval_test_arraybuffer_p = (
+ const jerry_char_t eval_test_arraybuffer[] = TEST_STRING_LITERAL (
"var sum = 0;"
"for (var i = 0; i < array.length; i++)"
"{"
" assert(array[i] == expected, 'Array at index ' + i + ' was: ' + array[i] + ' should be: ' + expected);"
" sum += array[i]"
"};"
- "sum");
- jerry_value_t res = jerry_eval ((jerry_char_t *) eval_test_arraybuffer_p,
- strlen (eval_test_arraybuffer_p),
- true);
+ "sum"
+ );
+ jerry_value_t res = jerry_eval (eval_test_arraybuffer,
+ sizeof (eval_test_arraybuffer) - 1,
+ JERRY_PARSE_STRICT_MODE);
TEST_ASSERT (jerry_value_is_number (res));
TEST_ASSERT (jerry_get_number_value (res) == sum);
jerry_release_value (res);
/* Test ArrayBuffer external with invalid arguments */
{
jerry_value_t input_buffer = jerry_create_arraybuffer_external (0, NULL, NULL);
- TEST_ASSERT (jerry_value_has_error_flag (input_buffer));
+ TEST_ASSERT (jerry_value_is_error (input_buffer));
TEST_ASSERT (jerry_get_error_type (input_buffer) == JERRY_ERROR_RANGE);
jerry_release_value (input_buffer);
}
jerry_cleanup ();
TEST_ASSERT (callback_called == true);
+
+ return 0;
} /* main */
(const jerry_char_t *) source_p,
strlen (source_p),
JERRY_PARSE_NO_OPTS);
- TEST_ASSERT (!jerry_value_has_error_flag (code));
+ TEST_ASSERT (!jerry_value_is_error (code));
jerry_value_t result = jerry_run (code);
jerry_release_value (code);
jerry_value_t value = jerry_get_property_by_index (array, index);
- TEST_ASSERT (!jerry_value_has_error_flag (value)
+ TEST_ASSERT (!jerry_value_is_error (value)
&& jerry_value_is_string (value));
TEST_ASSERT (jerry_get_string_size (value) == len);
TEST_ASSERT (memcmp (buf, str, len) == 0);
} /* compare */
-int
-main (void)
+static void
+test_get_backtrace_api_call (void)
{
- TEST_INIT ();
-
- TEST_ASSERT (jerry_is_feature_enabled (JERRY_FEATURE_LINE_INFO));
-
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t global = jerry_get_global_object ();
jerry_value_t func = jerry_create_external_function (backtrace_handler);
jerry_value_t name = jerry_create_string ((const jerry_char_t *) "backtrace");
jerry_value_t result = jerry_set_property (global, name, func);
- TEST_ASSERT (!jerry_value_has_error_flag (result));
+ TEST_ASSERT (!jerry_value_is_error (result));
jerry_release_value (result);
jerry_release_value (name);
jerry_value_t backtrace = run ("something.js", source);
- TEST_ASSERT (!jerry_value_has_error_flag (backtrace)
+ TEST_ASSERT (!jerry_value_is_error (backtrace)
&& jerry_value_is_array (backtrace));
TEST_ASSERT (jerry_get_array_length (backtrace) == 4);
backtrace = run ("something_else.js", source);
- TEST_ASSERT (!jerry_value_has_error_flag (backtrace)
+ TEST_ASSERT (!jerry_value_is_error (backtrace)
&& jerry_value_is_array (backtrace));
TEST_ASSERT (jerry_get_array_length (backtrace) == 2);
jerry_release_value (backtrace);
jerry_cleanup ();
+} /* test_get_backtrace_api_call */
+static void
+test_exception_backtrace (void)
+{
jerry_init (JERRY_INIT_EMPTY);
- source = ("function f() {\n"
- " undef_reference;\n"
- "}\n"
- "\n"
- "function g() {\n"
- " return f();\n"
- "}\n"
- "\n"
- "g();\n");
+ const char *source = ("function f() {\n"
+ " undef_reference;\n"
+ "}\n"
+ "\n"
+ "function g() {\n"
+ " return f();\n"
+ "}\n"
+ "\n"
+ "g();\n");
jerry_value_t error = run ("bad.js", source);
- TEST_ASSERT (jerry_value_has_error_flag (error));
+ TEST_ASSERT (jerry_value_is_error (error));
- jerry_value_clear_error_flag (&error);
+ error = jerry_get_value_from_error (error, true);
TEST_ASSERT (jerry_value_is_object (error));
- name = jerry_create_string ((const jerry_char_t *) "stack");
- backtrace = jerry_get_property (error, name);
+ jerry_value_t name = jerry_create_string ((const jerry_char_t *) "stack");
+ jerry_value_t backtrace = jerry_get_property (error, name);
jerry_release_value (name);
jerry_release_value (error);
- TEST_ASSERT (!jerry_value_has_error_flag (backtrace)
+ TEST_ASSERT (!jerry_value_is_error (backtrace)
&& jerry_value_is_array (backtrace));
TEST_ASSERT (jerry_get_array_length (backtrace) == 3);
jerry_release_value (backtrace);
jerry_cleanup ();
+} /* test_exception_backtrace */
+
+static void
+test_large_line_count (void)
+{
+ jerry_init (JERRY_INIT_EMPTY);
+
+ const char *source = ("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+ "g();\n");
+
+ jerry_value_t error = run ("bad.js", source);
+
+ TEST_ASSERT (jerry_value_is_error (error));
+
+ error = jerry_get_value_from_error (error, true);
+
+ TEST_ASSERT (jerry_value_is_object (error));
+
+ jerry_value_t name = jerry_create_string ((const jerry_char_t *) "stack");
+ jerry_value_t backtrace = jerry_get_property (error, name);
+
+ jerry_release_value (name);
+ jerry_release_value (error);
+
+ TEST_ASSERT (!jerry_value_is_error (backtrace)
+ && jerry_value_is_array (backtrace));
+
+ TEST_ASSERT (jerry_get_array_length (backtrace) == 1);
+
+ compare (backtrace, 0, "bad.js:385");
+
+ jerry_release_value (backtrace);
+
+ jerry_cleanup ();
+} /* test_large_line_count */
+
+int
+main (void)
+{
+ TEST_INIT ();
+
+ TEST_ASSERT (jerry_is_feature_enabled (JERRY_FEATURE_LINE_INFO));
+
+ test_get_backtrace_api_call ();
+ test_exception_backtrace ();
+ test_large_line_count ();
return 0;
} /* main */
#define TEST_ASSERT(x) \
do \
{ \
- if (unlikely (!(x))) \
+ if (JERRY_UNLIKELY (!(x))) \
{ \
jerry_port_log (JERRY_LOG_LEVEL_ERROR, \
"TEST: Assertion '%s' failed at %s(%s):%lu.\n", \
srand ((unsigned) jerry_port_get_current_time ()); \
} while (0)
+/**
+ * Dummy macro to enable the breaking of long string literals into multiple
+ * substrings on separate lines. (Style checker doesn't allow it without putting
+ * the whole literal into parentheses but the compiler warns about parenthesized
+ * string constants.)
+ */
+#define TEST_STRING_LITERAL(x) x
+
#endif /* !TEST_COMMON_H */
int countdown = 6;
jerry_set_vm_exec_stop_callback (vm_exec_stop_callback, &countdown, 16);
- const char *inf_loop_code_src_p = "while(true) {}";
+ const jerry_char_t inf_loop_code_src1[] = "while(true) {}";
jerry_value_t parsed_code_val = jerry_parse (NULL,
0,
- (jerry_char_t *) inf_loop_code_src_p,
- strlen (inf_loop_code_src_p),
+ inf_loop_code_src1,
+ sizeof (inf_loop_code_src1) - 1,
JERRY_PARSE_NO_OPTS);
- TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
+ TEST_ASSERT (!jerry_value_is_error (parsed_code_val));
jerry_value_t res = jerry_run (parsed_code_val);
TEST_ASSERT (countdown == 0);
- TEST_ASSERT (jerry_value_has_error_flag (res));
+ TEST_ASSERT (jerry_value_is_error (res));
jerry_release_value (res);
jerry_release_value (parsed_code_val);
/* We keep the callback function, only the countdown is reset. */
countdown = 6;
- inf_loop_code_src_p = ("function f() { while (true) ; }\n"
- "try { f(); } catch(e) {}");
+ const jerry_char_t inf_loop_code_src2[] = TEST_STRING_LITERAL (
+ "function f() { while (true) ; }\n"
+ "try { f(); } catch(e) {}"
+ );
parsed_code_val = jerry_parse (NULL,
0,
- (jerry_char_t *) inf_loop_code_src_p,
- strlen (inf_loop_code_src_p),
+ inf_loop_code_src2,
+ sizeof (inf_loop_code_src2) - 1,
JERRY_PARSE_NO_OPTS);
- TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
+ TEST_ASSERT (!jerry_value_is_error (parsed_code_val));
res = jerry_run (parsed_code_val);
TEST_ASSERT (countdown == 0);
/* The result must have an error flag which proves that
* the error is thrown again inside the catch block. */
- TEST_ASSERT (jerry_value_has_error_flag (res));
+ TEST_ASSERT (jerry_value_is_error (res));
jerry_release_value (res);
jerry_release_value (parsed_code_val);
{
return 0;
}
- const char *test_source = (
- "var a = 'hello';"
- "var b = 'world';"
- "var c = a + ' ' + b;"
- );
+ const jerry_char_t test_source[] = TEST_STRING_LITERAL (
+ "var a = 'hello';"
+ "var b = 'world';"
+ "var c = a + ' ' + b;"
+ );
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t parsed_code_val = jerry_parse (NULL,
0,
- (jerry_char_t *) test_source,
- strlen (test_source),
+ test_source,
+ sizeof (test_source) - 1,
JERRY_PARSE_NO_OPTS);
- TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
+ TEST_ASSERT (!jerry_value_is_error (parsed_code_val));
jerry_value_t res = jerry_run (parsed_code_val);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
jerry_heap_stats_t stats;
memset (&stats, 0, sizeof (stats));
.free_cb = free_test_data
};
-static const char *strict_equal_source = "var x = function(a, b) {return a === b;}; x";
+static const jerry_char_t strict_equal_source[] = "var x = function(a, b) {return a === b;}; x";
static bool
find_test_object_by_data (const jerry_value_t candidate,
jerry_value_t *args_p = (jerry_value_t *) context_p;
jerry_value_t result = jerry_has_property (candidate, args_p[0]);
- bool has_property = (!jerry_value_has_error_flag (result) && jerry_get_boolean_value (result));
+ bool has_property = (!jerry_value_is_error (result) && jerry_get_boolean_value (result));
/* If the object has the desired property, store a new reference to it in args_p[1]. */
if (has_property)
/* Render strict-equal as a function. */
jerry_value_t parse_result = jerry_parse (NULL,
0,
- (jerry_char_t *) strict_equal_source,
- strlen (strict_equal_source),
+ strict_equal_source,
+ sizeof (strict_equal_source) - 1,
JERRY_PARSE_STRICT_MODE);
- TEST_ASSERT (!jerry_value_has_error_flag (parse_result));
+ TEST_ASSERT (!jerry_value_is_error (parse_result));
jerry_value_t strict_equal = jerry_run (parse_result);
- TEST_ASSERT (!jerry_value_has_error_flag (strict_equal));
+ TEST_ASSERT (!jerry_value_is_error (strict_equal));
jerry_release_value (parse_result);
/* Create an object and associate some native data with it. */
jerry_release_value (object);
/* Collect garbage. */
- jerry_gc ();
+ jerry_gc (JERRY_GC_SEVERITY_LOW);
/* Attempt to retrieve the object by its native pointer again. */
TEST_ASSERT (!jerry_objects_foreach_by_native_info (&test_info, find_test_object_by_data, &found_object));
jerry_release_value (args[1]);
/* Collect garbage. */
- jerry_gc ();
+ jerry_gc (JERRY_GC_SEVERITY_LOW);
/* Attempt to retrieve the object by the presence of its property again. */
args[0] = property_name;
#include "test-common.h"
-const char *test_source = (
- "var p1 = create_promise1();"
- "var p2 = create_promise2();"
- "p1.then(function(x) { "
- " assert(x==='resolved'); "
- "}); "
- "p2.catch(function(x) { "
- " assert(x==='rejected'); "
- "}); "
- );
+static const jerry_char_t test_source[] = TEST_STRING_LITERAL (
+ "var p1 = create_promise1();"
+ "var p2 = create_promise2();"
+ "p1.then(function(x) { "
+ " assert(x==='resolved'); "
+ "}); "
+ "p2.catch(function(x) { "
+ " assert(x==='rejected'); "
+ "}); "
+);
static int count_in_assert = 0;
static jerry_value_t my_promise1;
static jerry_value_t my_promise2;
-const jerry_char_t s1[] = "resolved";
-const jerry_char_t s2[] = "rejected";
+static const jerry_char_t s1[] = "resolved";
+static const jerry_char_t s2[] = "rejected";
static jerry_value_t
create_promise1_handler (const jerry_value_t func_obj_val, /**< function object */
jerry_release_value (result_val);
} /* register_js_function */
-/**
- * Checks whether global object has promise.
- */
-static bool
-promise_is_available (void)
-{
- jerry_value_t global_obj_val = jerry_get_global_object ();
- jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "Promise");
-
- jerry_value_t prop_value = jerry_has_property (global_obj_val, prop_name);
- bool has_prop = jerry_get_boolean_value (prop_value);
-
- jerry_release_value (global_obj_val);
- jerry_release_value (prop_name);
- jerry_release_value (prop_value);
-
- return has_prop;
-} /* promise_is_available */
-
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
- if (!promise_is_available ())
+ if (!jerry_is_feature_enabled (JERRY_FEATURE_PROMISE))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Promise is disabled!\n");
jerry_cleanup ();
jerry_value_t parsed_code_val = jerry_parse (NULL,
0,
- (jerry_char_t *) test_source,
- strlen (test_source),
+ test_source,
+ sizeof (test_source) - 1,
JERRY_PARSE_NO_OPTS);
- TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
+ TEST_ASSERT (!jerry_value_is_error (parsed_code_val));
jerry_value_t res = jerry_run (parsed_code_val);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
jerry_release_value (res);
jerry_release_value (parsed_code_val);
/* Run the jobqueue. */
res = jerry_run_all_enqueued_jobs ();
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (count_in_assert == 2);
jerry_release_value (my_promise1);
jerry_release_value (str_reject);
jerry_cleanup ();
+
+ return 0;
} /* main */
--- /dev/null
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jerryscript.h"
+
+#include "test-common.h"
+
+int
+main (void)
+{
+ TEST_INIT ();
+ jerry_init (JERRY_INIT_EMPTY);
+
+ jerry_value_t global_obj_val = jerry_get_global_object ();
+
+ jerry_char_t pattern[] = "[^.]+";
+ jerry_regexp_flags_t flags = JERRY_REGEXP_FLAG_GLOBAL | JERRY_REGEXP_FLAG_MULTILINE;
+ jerry_value_t regex_obj = jerry_create_regexp (pattern, flags);
+ TEST_ASSERT (jerry_value_is_object (regex_obj));
+
+ const jerry_char_t func_resource[] = "unknown";
+ const jerry_char_t func_arg_list[] = "regex";
+ const jerry_char_t func_src[] = "return [regex.exec('something.domain.com'), regex.multiline, regex.global];";
+ jerry_value_t func_val = jerry_parse_function (func_resource,
+ sizeof (func_resource) - 1,
+ func_arg_list,
+ sizeof (func_arg_list) - 1,
+ func_src,
+ sizeof (func_src) - 1,
+ JERRY_PARSE_NO_OPTS);
+
+ jerry_value_t res = jerry_call_function (func_val, global_obj_val, ®ex_obj, 1);
+ jerry_value_t regex_res = jerry_get_property_by_index (res, 0);
+ jerry_value_t regex_res_str = jerry_get_property_by_index (regex_res, 0);
+ jerry_value_t is_multiline = jerry_get_property_by_index (res, 1);
+ jerry_value_t is_global = jerry_get_property_by_index (res, 2);
+
+ jerry_size_t str_size = jerry_get_string_size (regex_res_str);
+ jerry_char_t res_buff[str_size];
+ jerry_size_t res_size = jerry_string_to_char_buffer (regex_res_str, res_buff, str_size);
+
+ const char expected_result[] = "something";
+ TEST_ASSERT (res_size == (sizeof (expected_result) - 1));
+ TEST_ASSERT (strncmp (expected_result, (const char *) res_buff, res_size) == 0);
+ TEST_ASSERT (jerry_get_boolean_value (is_multiline));
+ TEST_ASSERT (jerry_get_boolean_value (is_global));
+
+ jerry_release_value (regex_obj);
+ jerry_release_value (res);
+ jerry_release_value (func_val);
+ jerry_release_value (regex_res);
+ jerry_release_value (regex_res_str);
+ jerry_release_value (is_multiline);
+ jerry_release_value (is_global);
+ jerry_release_value (global_obj_val);
+
+ jerry_cleanup ();
+ return 0;
+} /* main */
*/
#define SNAPSHOT_BUFFER_SIZE (256)
+/**
+ * Maximum size of literal buffer
+ */
+#define LITERAL_BUFFER_SIZE (256)
+
/**
* Magic strings
*/
-static const jerry_char_ptr_t magic_strings[] =
+static const jerry_char_t *magic_strings[] =
{
- (const jerry_char_ptr_t) " ",
- (const jerry_char_ptr_t) "a",
- (const jerry_char_ptr_t) "b",
- (const jerry_char_ptr_t) "c",
- (const jerry_char_ptr_t) "from",
- (const jerry_char_ptr_t) "func",
- (const jerry_char_ptr_t) "string",
- (const jerry_char_ptr_t) "snapshot"
+ (const jerry_char_t *) " ",
+ (const jerry_char_t *) "a",
+ (const jerry_char_t *) "b",
+ (const jerry_char_t *) "c",
+ (const jerry_char_t *) "from",
+ (const jerry_char_t *) "func",
+ (const jerry_char_t *) "string",
+ (const jerry_char_t *) "snapshot"
};
/**
const jerry_init_flag_t flags = JERRY_INIT_EMPTY;
static uint32_t function_snapshot_buffer[SNAPSHOT_BUFFER_SIZE];
- const char *args_p = "a, b";
- const char *code_to_snapshot_p = "return a + b";
+ const jerry_char_t func_args[] = "a, b";
+ const jerry_char_t code_to_snapshot[] = "return a + b";
jerry_init (flags);
jerry_value_t generate_result;
generate_result = jerry_generate_function_snapshot (NULL,
0,
- (const jerry_char_t *) code_to_snapshot_p,
- strlen (code_to_snapshot_p),
- (jerry_char_t *) args_p,
- strlen (args_p),
+ code_to_snapshot,
+ sizeof (code_to_snapshot) - 1,
+ func_args,
+ sizeof (func_args) - 1,
0,
function_snapshot_buffer,
SNAPSHOT_BUFFER_SIZE);
- TEST_ASSERT (!jerry_value_has_error_flag (generate_result)
+ TEST_ASSERT (!jerry_value_is_error (generate_result)
&& jerry_value_is_number (generate_result));
size_t function_snapshot_size = (size_t) jerry_get_number_value (generate_result);
0,
0);
- TEST_ASSERT (!jerry_value_has_error_flag (function_obj));
+ TEST_ASSERT (!jerry_value_is_error (function_obj));
TEST_ASSERT (jerry_value_is_function (function_obj));
jerry_value_t this_val = jerry_create_undefined ();
jerry_value_t res = jerry_call_function (function_obj, this_val, args, 2);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_number (res));
double num = jerry_get_number_value (res);
TEST_ASSERT (num == 3);
{
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t res = jerry_exec_snapshot (snapshot_p, snapshot_size, 0, exec_snapshot_flags);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_number (res));
double raw_value = jerry_get_number_value (res);
TEST_ASSERT (raw_value == 15);
{
static uint32_t arguments_snapshot_buffer[SNAPSHOT_BUFFER_SIZE];
- const char *code_to_snapshot_p = ("function f(a,b,c) {"
- " arguments[0]++;"
- " arguments[1]++;"
- " arguments[2]++;"
- " return a + b + c;"
- "}"
- "f(3,4,5);");
+ const jerry_char_t code_to_snapshot[] = TEST_STRING_LITERAL (
+ "function f(a,b,c) {"
+ " arguments[0]++;"
+ " arguments[1]++;"
+ " arguments[2]++;"
+ " return a + b + c;"
+ "}"
+ "f(3,4,5);"
+ );
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t generate_result;
generate_result = jerry_generate_snapshot (NULL,
0,
- (jerry_char_t *) code_to_snapshot_p,
- strlen (code_to_snapshot_p),
+ code_to_snapshot,
+ sizeof (code_to_snapshot) - 1,
0,
arguments_snapshot_buffer,
SNAPSHOT_BUFFER_SIZE);
- TEST_ASSERT (!jerry_value_has_error_flag (generate_result)
+ TEST_ASSERT (!jerry_value_is_error (generate_result)
&& jerry_value_is_number (generate_result));
size_t snapshot_size = (size_t) jerry_get_number_value (generate_result);
jerry_value_t res = jerry_exec_snapshot (snapshot_p, snapshot_size, 0, exec_snapshot_flags);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_value_is_string (res));
jerry_size_t sz = jerry_get_string_size (res);
TEST_ASSERT (sz == 20);
if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE)
&& jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_EXEC))
{
- const char *code_to_snapshot_p = "(function () { return 'string from snapshot'; }) ();";
+ const jerry_char_t code_to_snapshot[] = "(function () { return 'string from snapshot'; }) ();";
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t generate_result;
generate_result = jerry_generate_snapshot (NULL,
0,
- (const jerry_char_t *) code_to_snapshot_p,
- strlen (code_to_snapshot_p),
+ code_to_snapshot,
+ sizeof (code_to_snapshot) - 1,
0,
snapshot_buffer,
SNAPSHOT_BUFFER_SIZE);
- TEST_ASSERT (!jerry_value_has_error_flag (generate_result)
+ TEST_ASSERT (!jerry_value_is_error (generate_result)
&& jerry_value_is_number (generate_result));
size_t snapshot_size = (size_t) jerry_get_number_value (generate_result);
/* Check the snapshot data. Unused bytes should be filled with zeroes */
const uint8_t expected_data[] =
{
- 0x4A, 0x52, 0x52, 0x59, 0x0C, 0x00, 0x00, 0x00,
+ 0x4A, 0x52, 0x52, 0x59, 0x14, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00,
- 0x28, 0x00, 0xB7, 0x46, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0xB8, 0x46, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x01, 0x00, 0x21, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x00,
0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x14, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE)
&& jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_EXEC))
{
- const char *code_to_snapshot_p = ("function func(a, b, c) {"
- " c = 'snapshot';"
- " return arguments[0] + ' ' + b + ' ' + arguments[2];"
- "};"
- "func('string', 'from');");
+ const jerry_char_t code_to_snapshot[] = TEST_STRING_LITERAL (
+ "function func(a, b, c) {"
+ " c = 'snapshot';"
+ " return arguments[0] + ' ' + b + ' ' + arguments[2];"
+ "};"
+ "func('string', 'from');"
+ );
jerry_init (JERRY_INIT_EMPTY);
jerry_register_magic_strings (magic_strings,
jerry_value_t generate_result;
generate_result = jerry_generate_snapshot (NULL,
0,
- (jerry_char_t *) code_to_snapshot_p,
- strlen (code_to_snapshot_p),
+ code_to_snapshot,
+ sizeof (code_to_snapshot) - 1,
JERRY_SNAPSHOT_SAVE_STATIC,
snapshot_buffer,
SNAPSHOT_BUFFER_SIZE);
- TEST_ASSERT (!jerry_value_has_error_flag (generate_result)
+ TEST_ASSERT (!jerry_value_is_error (generate_result)
&& jerry_value_is_number (generate_result));
size_t snapshot_size = (size_t) jerry_get_number_value (generate_result);
/* Static snapshots are not supported by default. */
jerry_value_t exec_result = jerry_exec_snapshot (snapshot_buffer, snapshot_size, 0, 0);
- TEST_ASSERT (jerry_value_has_error_flag (exec_result));
+ TEST_ASSERT (jerry_value_is_error (exec_result));
jerry_release_value (exec_result);
jerry_cleanup ();
size_t snapshot_sizes[2];
static uint32_t merged_snapshot_buffer[SNAPSHOT_BUFFER_SIZE];
- const char *code_to_snapshot_p = "123";
+ const jerry_char_t code_to_snapshot1[] = "var a = 'hello'; 123";
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t generate_result;
generate_result = jerry_generate_snapshot (NULL,
0,
- (const jerry_char_t *) code_to_snapshot_p,
- strlen (code_to_snapshot_p),
+ code_to_snapshot1,
+ sizeof (code_to_snapshot1) - 1,
0,
snapshot_buffer_0,
SNAPSHOT_BUFFER_SIZE);
- TEST_ASSERT (!jerry_value_has_error_flag (generate_result)
+ TEST_ASSERT (!jerry_value_is_error (generate_result)
&& jerry_value_is_number (generate_result));
snapshot_sizes[0] = (size_t) jerry_get_number_value (generate_result);
jerry_cleanup ();
- code_to_snapshot_p = "456";
+ const jerry_char_t code_to_snapshot2[] = "var b = 'hello'; 456";
jerry_init (JERRY_INIT_EMPTY);
generate_result = jerry_generate_snapshot (NULL,
0,
- (const jerry_char_t *) code_to_snapshot_p,
- strlen (code_to_snapshot_p),
+ code_to_snapshot2,
+ sizeof (code_to_snapshot2) - 1,
0,
snapshot_buffer_1,
SNAPSHOT_BUFFER_SIZE);
- TEST_ASSERT (!jerry_value_has_error_flag (generate_result)
+ TEST_ASSERT (!jerry_value_is_error (generate_result)
&& jerry_value_is_number (generate_result));
snapshot_sizes[1] = (size_t) jerry_get_number_value (generate_result);
snapshot_buffers[0] = snapshot_buffer_0;
snapshot_buffers[1] = snapshot_buffer_1;
+ static uint32_t snapshot_buffer_0_bck[SNAPSHOT_BUFFER_SIZE];
+ static uint32_t snapshot_buffer_1_bck[SNAPSHOT_BUFFER_SIZE];
+
+ memcpy (snapshot_buffer_0_bck, snapshot_buffer_0, SNAPSHOT_BUFFER_SIZE);
+ memcpy (snapshot_buffer_1_bck, snapshot_buffer_1, SNAPSHOT_BUFFER_SIZE);
+
size_t merged_size = jerry_merge_snapshots (snapshot_buffers,
snapshot_sizes,
2,
jerry_cleanup ();
+ TEST_ASSERT (0 == memcmp (snapshot_buffer_0_bck, snapshot_buffer_0, SNAPSHOT_BUFFER_SIZE));
+ TEST_ASSERT (0 == memcmp (snapshot_buffer_1_bck, snapshot_buffer_1, SNAPSHOT_BUFFER_SIZE));
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t res = jerry_exec_snapshot (merged_snapshot_buffer, merged_size, 0, 0);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_get_number_value (res) == 123);
jerry_release_value (res);
res = jerry_exec_snapshot (merged_snapshot_buffer, merged_size, 1, 0);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (jerry_get_number_value (res) == 456);
jerry_release_value (res);
/* C format generation */
jerry_init (JERRY_INIT_EMPTY);
- static uint32_t literal_buffer_c[SNAPSHOT_BUFFER_SIZE];
- static const char *code_for_c_format_p = "var object = { aa:'fo o', Bb:'max', aaa:'xzy0' };";
+ static jerry_char_t literal_buffer_c[LITERAL_BUFFER_SIZE];
+ static uint32_t literal_snapshot_buffer[SNAPSHOT_BUFFER_SIZE];
+ static const jerry_char_t code_for_c_format[] = "var object = { aa:'fo o', Bb:'max', aaa:'xzy0' };";
- size_t literal_sizes_c_format = jerry_parse_and_save_literals ((jerry_char_t *) code_for_c_format_p,
- strlen (code_for_c_format_p),
- false,
- literal_buffer_c,
- SNAPSHOT_BUFFER_SIZE,
- true);
- TEST_ASSERT (literal_sizes_c_format == 203);
+ jerry_value_t generate_result;
+ generate_result = jerry_generate_snapshot (NULL,
+ 0,
+ code_for_c_format,
+ sizeof (code_for_c_format) - 1,
+ 0,
+ literal_snapshot_buffer,
+ SNAPSHOT_BUFFER_SIZE);
+
+ TEST_ASSERT (!jerry_value_is_error (generate_result)
+ && jerry_value_is_number (generate_result));
+
+ size_t snapshot_size = (size_t) jerry_get_number_value (generate_result);
+ jerry_release_value (generate_result);
+ TEST_ASSERT (snapshot_size == 120);
+
+ const size_t lit_c_buf_sz = jerry_get_literals_from_snapshot (literal_snapshot_buffer,
+ snapshot_size,
+ literal_buffer_c,
+ LITERAL_BUFFER_SIZE,
+ true);
+ TEST_ASSERT (lit_c_buf_sz == 200);
static const char *expected_c_format = (
"jerry_length_t literal_count = 4;\n\n"
- "jerry_char_ptr_t literals[4] =\n"
+ "jerry_char_t *literals[4] =\n"
"{\n"
" \"Bb\",\n"
" \"aa\",\n"
"};\n"
);
- TEST_ASSERT (!strncmp ((char *) literal_buffer_c, expected_c_format, literal_sizes_c_format));
- jerry_cleanup ();
+ TEST_ASSERT (!strncmp ((char *) literal_buffer_c, expected_c_format, lit_c_buf_sz));
/* List format generation */
- jerry_init (JERRY_INIT_EMPTY);
-
- static uint32_t literal_buffer_list[SNAPSHOT_BUFFER_SIZE];
- static const char *code_for_list_format_p = "var obj = { a:'aa', bb:'Bb' };";
-
- size_t literal_sizes_list_format = jerry_parse_and_save_literals ((jerry_char_t *) code_for_list_format_p,
- strlen (code_for_list_format_p),
- false,
- literal_buffer_list,
- SNAPSHOT_BUFFER_SIZE,
- false);
-
- TEST_ASSERT (literal_sizes_list_format == 25);
- TEST_ASSERT (!strncmp ((char *) literal_buffer_list, "1 a\n2 Bb\n2 aa\n2 bb\n3 obj\n", literal_sizes_list_format));
+ static jerry_char_t literal_buffer_list[LITERAL_BUFFER_SIZE];
+ const size_t lit_list_buf_sz = jerry_get_literals_from_snapshot (literal_snapshot_buffer,
+ snapshot_size,
+ literal_buffer_list,
+ LITERAL_BUFFER_SIZE,
+ false);
+
+ TEST_ASSERT (lit_list_buf_sz == 30);
+ TEST_ASSERT (!strncmp ((char *) literal_buffer_list, "2 Bb\n2 aa\n3 aaa\n4 fo o\n4 xzy0\n", lit_list_buf_sz));
jerry_cleanup ();
}
}
} /* assert_handler */
-/**
- * Checks whether global object has typedarray.
- */
-static bool
-typedarray_is_available (void)
-{
- jerry_value_t global_obj_val = jerry_get_global_object ();
- jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "Int8Array");
-
- jerry_value_t prop_value = jerry_has_property (global_obj_val, prop_name);
- bool has_prop = jerry_get_boolean_value (prop_value);
-
- jerry_release_value (global_obj_val);
- jerry_release_value (prop_name);
- jerry_release_value (prop_value);
-
- return has_prop;
-} /* typedarray_is_available */
-
/**
* Do simple TypedArray property validation.
*/
jerry_length_t element_count, /**< expected element count */
jerry_length_t bytes_per_element) /**< bytes per element for the given type */
{
- TEST_ASSERT (!jerry_value_has_error_flag (typedarray));
+ TEST_ASSERT (!jerry_value_is_error (typedarray));
TEST_ASSERT (jerry_value_is_typedarray (typedarray));
TEST_ASSERT (jerry_get_typedarray_type (typedarray) == typedarray_type);
TEST_ASSERT (jerry_get_typedarray_length (typedarray) == element_count);
{
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) test_entries[i].constructor_name);
jerry_value_t prop_value = jerry_get_property (global_obj_val, prop_name);
- TEST_ASSERT (!jerry_value_has_error_flag (prop_value));
+ TEST_ASSERT (!jerry_value_is_error (prop_value));
jerry_value_t length_arg = jerry_create_number (test_entries[i].element_count);
jerry_value_t typedarray = jerry_construct_object (prop_value, &length_arg, 1);
arraybuffer,
offset,
element_count);
- TEST_ASSERT (!jerry_value_has_error_flag (typedarray));
+ TEST_ASSERT (!jerry_value_is_error (typedarray));
jerry_release_value (js_offset);
jerry_release_value (js_element_count);
register_js_value ("array", typedarray);
- const char *eval_src_p = (
+ const jerry_char_t eval_src[] = TEST_STRING_LITERAL (
"assert (array.length == expected_length,"
" 'expected length: ' + expected_length + ' got: ' + array.length);"
"assert (array.byteOffset == expected_offset);"
- "array[0] = 0x11223344;");
- jerry_value_t result = jerry_eval ((jerry_char_t *) eval_src_p,
- strlen (eval_src_p),
- true);
- TEST_ASSERT (!jerry_value_has_error_flag (result));
+ "array[0] = 0x11223344;"
+ );
+ jerry_value_t result = jerry_eval (eval_src,
+ sizeof (eval_src) - 1,
+ JERRY_PARSE_STRICT_MODE);
+ TEST_ASSERT (!jerry_value_is_error (result));
jerry_release_value (result);
{
}
} /* test_typedarray_complex_creation */
+/**
+ * Test get/set/delete property by index.
+ */
+static void test_property_by_index (test_entry_t test_entries[])
+{
+ int test_int_numbers[5] = {-5, -70, 13, 0, 56};
+ double test_double_numbers[5] = {-83.153, -35.15, 0, 13.1, 89.8975};
+ uint8_t test_uint_numbers[5] = {83, 15, 36, 0, 43};
+
+ for (uint32_t i = 0; test_entries[i].constructor_name != NULL; i++)
+ {
+ jerry_value_t test_number;
+ uint32_t test_numbers_length = sizeof (test_int_numbers) / sizeof (int);
+ jerry_value_t typedarray = jerry_create_typedarray (test_entries[i].typedarray_type, test_numbers_length);
+ jerry_typedarray_type_t type = jerry_get_typedarray_type (typedarray);
+
+ jerry_value_t set_result;
+ jerry_value_t get_result;
+
+ switch (type)
+ {
+ case JERRY_TYPEDARRAY_INT8:
+ case JERRY_TYPEDARRAY_INT16:
+ case JERRY_TYPEDARRAY_INT32:
+ {
+ for (uint8_t j = 0; j < test_numbers_length; j++)
+ {
+ test_number = jerry_create_number (test_int_numbers[j]);
+ TEST_ASSERT (!jerry_delete_property_by_index (typedarray, j));
+ set_result = jerry_set_property_by_index (typedarray, j, test_number);
+ get_result = jerry_get_property_by_index (typedarray, j);
+
+ TEST_ASSERT (jerry_value_is_boolean (set_result));
+ TEST_ASSERT (jerry_get_boolean_value (set_result));
+ TEST_ASSERT (!jerry_delete_property_by_index (typedarray, j));
+ TEST_ASSERT (jerry_get_number_value (get_result) == test_int_numbers[j]);
+
+ jerry_release_value (test_number);
+ jerry_release_value (set_result);
+ jerry_release_value (get_result);
+ }
+ break;
+ }
+ case JERRY_TYPEDARRAY_FLOAT32:
+ case JERRY_TYPEDARRAY_FLOAT64:
+ {
+ for (uint8_t j = 0; j < test_numbers_length; j++)
+ {
+ test_number = jerry_create_number (test_double_numbers[j]);
+ TEST_ASSERT (!jerry_delete_property_by_index (typedarray, j));
+ set_result = jerry_set_property_by_index (typedarray, j, test_number);
+ get_result = jerry_get_property_by_index (typedarray, j);
+
+ TEST_ASSERT (jerry_value_is_boolean (set_result));
+ TEST_ASSERT (jerry_get_boolean_value (set_result));
+ TEST_ASSERT (!jerry_delete_property_by_index (typedarray, j));
+
+ double epsilon = pow (10, -5);
+ double get_abs = fabs (jerry_get_number_value (get_result) - test_double_numbers[j]);
+ TEST_ASSERT (get_abs < epsilon);
+
+ jerry_release_value (test_number);
+ jerry_release_value (set_result);
+ jerry_release_value (get_result);
+
+ /* Testing positive and negative infinity */
+ for (uint8_t k = 0; k < 2; k++)
+ {
+ jerry_value_t inf = jerry_create_number_infinity (k);
+ jerry_value_t set_inf = jerry_set_property_by_index (typedarray, 0, inf);
+ TEST_ASSERT (jerry_value_is_boolean (set_inf));
+ TEST_ASSERT (jerry_get_boolean_value (set_inf));
+ jerry_value_t get_inf = jerry_get_property_by_index (typedarray, 0);
+ TEST_ASSERT (isinf (jerry_get_number_value (get_inf)));
+
+ jerry_release_value (inf);
+ jerry_release_value (set_inf);
+ jerry_release_value (get_inf);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ for (uint8_t j = 0; j < test_numbers_length; j++)
+ {
+ test_number = jerry_create_number (test_uint_numbers[j]);
+ TEST_ASSERT (!jerry_delete_property_by_index (typedarray, j));
+ set_result = jerry_set_property_by_index (typedarray, j, test_number);
+ get_result = jerry_get_property_by_index (typedarray, j);
+
+ TEST_ASSERT (jerry_value_is_boolean (set_result));
+ TEST_ASSERT (jerry_get_boolean_value (set_result));
+ TEST_ASSERT (!jerry_delete_property_by_index (typedarray, j));
+ TEST_ASSERT (jerry_get_number_value (get_result) == test_uint_numbers[j]);
+
+ jerry_release_value (test_number);
+ jerry_release_value (set_result);
+ jerry_release_value (get_result);
+ }
+ break;
+ }
+ }
+
+ jerry_value_t set_undefined = jerry_set_property_by_index (typedarray, 100, jerry_create_number (50));
+ TEST_ASSERT (jerry_value_is_error (set_undefined));
+ jerry_value_t get_undefined = jerry_get_property_by_index (typedarray, 100);
+ TEST_ASSERT (jerry_value_is_undefined (get_undefined));
+
+ jerry_release_value (set_undefined);
+ jerry_release_value (get_undefined);
+ jerry_release_value (typedarray);
+ }
+} /* test_property_by_index */
+
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
- if (!typedarray_is_available ())
+ if (!jerry_is_feature_enabled (JERRY_FEATURE_TYPEDARRAY))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "TypedArray is disabled!\n");
jerry_cleanup ();
}
/* Check read and to write */
- const char *eval_src_p = (
+ const jerry_char_t eval_src[] = TEST_STRING_LITERAL (
"assert (array.length == expected_length, 'expected length: ' + expected_length + ' got: ' + array.length);"
"for (var i = 0; i < array.length; i++)"
"{"
" assert (array[i] == expected_value);"
" array[i] = i;"
- "};");
- jerry_value_t result = jerry_eval ((jerry_char_t *) eval_src_p,
- strlen (eval_src_p),
- true);
+ "};"
+ );
+ jerry_value_t result = jerry_eval (eval_src,
+ sizeof (eval_src) - 1,
+ JERRY_PARSE_STRICT_MODE);
- TEST_ASSERT (!jerry_value_has_error_flag (result));
+ TEST_ASSERT (!jerry_value_is_error (result));
jerry_release_value (result);
/* Check write results */
test_typedarray_complex_creation (test_entries, false);
test_typedarray_complex_creation (test_entries, true);
+ test_property_by_index (test_entries);
+
/* test invalid things */
{
jerry_value_t values[] =
jerry_length_t offset = 22;
jerry_length_t byte_count = 23;
jerry_value_t error = jerry_get_typedarray_buffer (values[idx], &offset, &byte_count);
- TEST_ASSERT (jerry_value_has_error_flag (error));
+ TEST_ASSERT (jerry_value_is_error (error));
TEST_ASSERT (offset == 22);
TEST_ASSERT (byte_count == 23);
jerry_release_value (error);
if (!jerry_value_is_arraybuffer (values[idx]))
{
jerry_value_t error = jerry_create_typedarray_for_arraybuffer (JERRY_TYPEDARRAY_UINT8, values[idx]);
- TEST_ASSERT (jerry_value_has_error_flag (error));
+ TEST_ASSERT (jerry_value_is_error (error));
jerry_release_value (error);
}
}
jerry_cleanup ();
+
+ return 0;
} /* main */
# file names that will be generated. This allows the definition of proper
# dependencies between the MarkDown files and the generated sources.
execute_process(
- COMMAND ${GEN_DOCTEST} --dry -d ${CMAKE_CURRENT_SOURCE_DIR} ${DOC_FILES}
+ COMMAND ${GEN_DOCTEST} --dry -d ${CMAKE_CURRENT_BINARY_DIR} ${DOC_FILES}
OUTPUT_VARIABLE DOCTEST_OUTPUT
RESULT_VARIABLE GEN_DOCTEST_RESULT
)
# Add custom command to run doctest generator if any of the MarkDown sources
# changes.
add_custom_command(
- COMMAND ${GEN_DOCTEST} -d ${CMAKE_CURRENT_SOURCE_DIR} ${DOC_FILES}
+ COMMAND ${GEN_DOCTEST} -d ${CMAKE_CURRENT_BINARY_DIR} ${DOC_FILES}
DEPENDS ${GEN_DOCTEST} ${DOC_FILES}
OUTPUT ${DOCTEST_COMPILE} ${DOCTEST_LINK} ${DOCTEST_RUN}
COMMENT "Generating doctests"
)
+# Add custom target to trigger the custom command above. Targets below can/must
+# depend on this one so that the custom command gets executed only once.
+add_custom_target(all-doc-files DEPENDS ${DOCTEST_COMPILE} ${DOCTEST_LINK} ${DOCTEST_RUN})
+
# Process compile-only doctests: add them to a dummy library
# (named libcompile-doc-tests.a) to trigger compilation.
if(NOT ("${DOCTEST_COMPILE}" STREQUAL ""))
- add_library(compile-doc-tests STATIC ${DOCTEST_COMPILE})
+ add_library(compile-doc-tests ${DOCTEST_COMPILE})
+ add_dependencies(compile-doc-tests all-doc-files)
target_link_libraries(compile-doc-tests jerry-ext jerry-core jerry-port-default-minimal)
set_property(TARGET compile-doc-tests APPEND_STRING PROPERTY COMPILE_FLAGS "${COMPILE_FLAGS_DOCTEST}")
endif()
set(TARGET_NAME ${NAME_PREFIX}-${TARGET_NAME})
add_executable(${TARGET_NAME} ${DOCTEST_NAME})
+ add_dependencies(${TARGET_NAME} all-doc-files)
set_property(TARGET ${TARGET_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS "${COMPILE_FLAGS_DOCTEST}")
set_property(TARGET ${TARGET_NAME} PROPERTY LINK_FLAGS "${LINKER_FLAGS_COMMON}")
+ set_property(TARGET ${TARGET_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
target_link_libraries(${TARGET_NAME} jerry-ext jerry-core jerry-port-default-minimal)
endforeach()
endmacro()
set(TARGET_NAME unit-${TARGET_NAME})
add_executable(${TARGET_NAME} ${SOURCE_UNIT_TEST_EXT})
- set_property(TARGET ${TARGET_NAME}
- PROPERTY LINK_FLAGS "${LINKER_FLAGS_COMMON}")
+ set_property(TARGET ${TARGET_NAME} PROPERTY LINK_FLAGS "${LINKER_FLAGS_COMMON}")
+ set_property(TARGET ${TARGET_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
target_link_libraries(${TARGET_NAME} jerry-ext jerry-core jerry-port-default-minimal)
add_executable(${JERRYX_MODULE_UNITTEST_NAME} ${JERRYX_MODULE_UNIT_TEST_SOURCES})
set_property(TARGET ${JERRYX_MODULE_UNITTEST_NAME} PROPERTY LINK_FLAGS "${LINKER_FLAGS_COMMON}")
+set_property(TARGET ${JERRYX_MODULE_UNITTEST_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
target_link_libraries(${JERRYX_MODULE_UNITTEST_NAME} jerry-ext jerry-core jerry-port-default-minimal)
target_include_directories(${JERRYX_MODULE_UNITTEST_NAME} PRIVATE ${INCLUDE_UNIT_EXT})
" return x === y ? 1 : 0;"
"}) ();";
+/* Make sure the result of a module load is removed from the cache. */
+const char eval_string6[] =
+"(function() {"
+" var x = require('cache-check');"
+" clear_require_cache('cache-check');"
+" var y = require('cache-check');"
+" return x !== y ? 1 : 0;"
+"}) ();";
+
+/* Make sure the entire cache is cleared. */
+const char eval_string7[] =
+"(function() {"
+" var x = require('cache-check');"
+" clear_require_cache(undefined);"
+" var y = require('cache-check');"
+" return x !== y ? 1 : 0;"
+"}) ();";
+
/*
* Define a resolver for a module named "differently-handled-module" to check that custom resolvers work.
*/
&cache_check_resolver
};
+static jerry_value_t
+handle_clear_require_cache (const jerry_value_t js_function,
+ const jerry_value_t this_val,
+ const jerry_value_t args_p[],
+ const jerry_length_t args_count)
+{
+ (void) js_function;
+ (void) this_val;
+ (void) args_count;
+
+ TEST_ASSERT (args_count == 1);
+ jerryx_module_clear_cache (args_p[0], resolvers, 3);
+
+ return 0;
+} /* handle_clear_require_cache */
+
static jerry_value_t
handle_require (const jerry_value_t js_function,
const jerry_value_t this_val,
static void
assert_number (jerry_value_t js_value, double expected_result)
{
- TEST_ASSERT (!jerry_value_has_error_flag (js_value));
+ TEST_ASSERT (!jerry_value_is_error (js_value));
TEST_ASSERT (jerry_get_number_value (js_value) == expected_result);
} /* assert_number */
static void
eval_one (const char *the_string, double expected_result)
{
- jerry_value_t js_eval_result = jerry_eval ((const jerry_char_t *) the_string, strlen (the_string), true);
+ jerry_value_t js_eval_result = jerry_eval ((const jerry_char_t *) the_string,
+ strlen (the_string),
+ JERRY_PARSE_STRICT_MODE);
assert_number (js_eval_result, expected_result);
jerry_release_value (js_eval_result);
} /* eval_one */
jerry_init (JERRY_INIT_EMPTY);
js_global = jerry_get_global_object ();
+
js_function = jerry_create_external_function (handle_require);
js_property_name = jerry_create_string ((const jerry_char_t *) "require");
jerry_set_property (js_global, js_property_name, js_function);
+ jerry_release_value (js_property_name);
+ jerry_release_value (js_function);
+
+ js_function = jerry_create_external_function (handle_clear_require_cache);
+ js_property_name = jerry_create_string ((const jerry_char_t *) "clear_require_cache");
+ jerry_set_property (js_global, js_property_name, js_function);
+ jerry_release_value (js_property_name);
+ jerry_release_value (js_function);
+
+ jerry_release_value (js_global);
eval_one (eval_string1, 42);
eval_one (eval_string2, 29);
eval_one (eval_string3, 1);
eval_one (eval_string4, 1);
eval_one (eval_string5, 1);
-
- jerry_release_value (js_property_name);
- jerry_release_value (js_function);
- jerry_release_value (js_global);
+ eval_one (eval_string6, 1);
+ eval_one (eval_string7, 1);
jerry_cleanup ();
} /* main */
} \
} while (0)
+#define TEST_STRING_LITERAL(x) x
+
#endif /* !TEST_COMMON_H */
* Unit test for jerry-ext/args.
*/
+#include <string.h>
#include "jerryscript.h"
#include "jerryscript-ext/arg.h"
#include "test-common.h"
-#include <string.h>
-#include <jerryscript-ext/arg.h>
-
-const char *test_source = (
- "var arg1 = true;"
- "var arg2 = 10.5;"
- "var arg3 = 'abc';"
- "var arg4 = function foo() {};"
- "test_validator1(arg1, arg2, arg3, arg4);"
- "arg1 = new Boolean(true);"
- "arg3 = new String('abc');"
- "test_validator1(arg1, arg2, arg3);"
- "test_validator1(arg1, arg2, '');"
- "arg2 = new Number(10.5);"
- "test_validator1(arg1, arg2, arg3);"
- "test_validator1(arg1, 10.5, 'abcdef');"
- "var obj_a = new MyObjectA();"
- "var obj_b = new MyObjectB();"
- "test_validator2.call(obj_a, 5);"
- "test_validator2.call(obj_b, 5);"
- "test_validator2.call(obj_a, 1);"
- "var obj1 = {prop1:true, prop2:'1.5'};"
- "test_validator_prop1(obj1);"
- "test_validator_prop2(obj1);"
- "test_validator_prop2();"
- "var obj2 = {prop1:true};"
- "Object.defineProperty(obj2, 'prop2', {"
- " get: function() { throw new TypeError('prop2 error') }"
- "});"
- "test_validator_prop3(obj2);"
- "test_validator_int1(-1000, 1000, 128, -1000, 1000, -127,"
- " -1000, 4294967297, 65536, -2200000000, 4294967297, -2147483647);"
- "test_validator_int2(-1.5, -1.5, -1.5, 1.5, 1.5, 1.5, Infinity, -Infinity, 300.5, 300.5);"
- "test_validator_int3(NaN);"
- "var arr = [1, 2];"
- "test_validator_array1(arr);"
- "test_validator_array1();"
- "test_validator_array2(arr);"
- );
+static const jerry_char_t test_source[] = TEST_STRING_LITERAL (
+ "var arg1 = true;"
+ "var arg2 = 10.5;"
+ "var arg3 = 'abc';"
+ "var arg4 = function foo() {};"
+ "test_validator1(arg1, arg2, arg3, arg4);"
+ "arg1 = new Boolean(true);"
+ "arg3 = new String('abc');"
+ "test_validator1(arg1, arg2, arg3);"
+ "test_validator1(arg1, arg2, '');"
+ "arg2 = new Number(10.5);"
+ "test_validator1(arg1, arg2, arg3);"
+ "test_validator1(arg1, 10.5, 'abcdef');"
+ "var obj_a = new MyObjectA();"
+ "var obj_b = new MyObjectB();"
+ "test_validator2.call(obj_a, 5);"
+ "test_validator2.call(obj_b, 5);"
+ "test_validator2.call(obj_a, 1);"
+ "var obj1 = {prop1:true, prop2:'1.5'};"
+ "test_validator_prop1(obj1);"
+ "test_validator_prop2(obj1);"
+ "test_validator_prop2();"
+ "var obj2 = {prop1:true};"
+ "Object.defineProperty(obj2, 'prop2', {"
+ " get: function() { throw new TypeError('prop2 error') }"
+ "});"
+ "test_validator_prop3(obj2);"
+ "test_validator_int1(-1000, 1000, 128, -1000, 1000, -127,"
+ " -1000, 4294967297, 65536, -2200000000, 4294967297, -2147483647);"
+ "test_validator_int2(-1.5, -1.5, -1.5, 1.5, 1.5, 1.5, Infinity, -Infinity, 300.5, 300.5);"
+ "test_validator_int3(NaN);"
+ "var arr = [1, 2];"
+ "test_validator_array1(arr);"
+ "test_validator_array1();"
+ "test_validator_array2(arr);"
+);
static const jerry_object_native_info_t thing_a_info =
{
if (validator1_count == 0)
{
- TEST_ASSERT (!jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (!jerry_value_is_error (is_ok));
TEST_ASSERT (arg1);
TEST_ASSERT (arg2 == 10.5);
TEST_ASSERT (strcmp (arg3, "abc") == 0);
}
else if (validator1_count == 1)
{
- TEST_ASSERT (!jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (!jerry_value_is_error (is_ok));
TEST_ASSERT (arg1);
TEST_ASSERT (arg2 == 10.5);
TEST_ASSERT (strcmp (arg3, "abc") == 0);
}
else if (validator1_count == 2)
{
- TEST_ASSERT (!jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (!jerry_value_is_error (is_ok));
TEST_ASSERT (arg1);
TEST_ASSERT (arg2 == 10.5);
TEST_ASSERT (strcmp (arg3, "") == 0);
}
else
{
- TEST_ASSERT (jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (jerry_value_is_error (is_ok));
}
jerry_release_value (is_ok);
jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);
jerry_value_t to_number = jerry_value_to_number (js_arg);
- if (jerry_value_has_error_flag (to_number))
+ if (jerry_value_is_error (to_number))
{
jerry_release_value (to_number);
if (validator2_count == 0)
{
- TEST_ASSERT (!jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (!jerry_value_is_error (is_ok));
TEST_ASSERT (thing_p == &my_thing_a);
TEST_ASSERT (thing_p->x == 1);
}
else
{
- TEST_ASSERT (jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (jerry_value_is_error (is_ok));
}
jerry_release_value (is_ok);
mapping,
ARRAY_SIZE (mapping));
- TEST_ASSERT (!jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (!jerry_value_is_error (is_ok));
TEST_ASSERT (native1);
TEST_ASSERT (native2 == 1.5);
TEST_ASSERT (native3 == 3);
jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, mapping, ARRAY_SIZE (mapping));
- TEST_ASSERT (!jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (!jerry_value_is_error (is_ok));
if (validator_prop_count == 1)
{
mapping,
ARRAY_SIZE (mapping));
- TEST_ASSERT (jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (jerry_value_is_error (is_ok));
TEST_ASSERT (!native1);
TEST_ASSERT (native2);
mapping,
ARRAY_SIZE (mapping));
- TEST_ASSERT (!jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (!jerry_value_is_error (is_ok));
TEST_ASSERT (num0 == 0);
TEST_ASSERT (num1 == 255);
TEST_ASSERT (num2 == 128);
mapping,
ARRAY_SIZE (mapping));
- TEST_ASSERT (jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (jerry_value_is_error (is_ok));
TEST_ASSERT (num0 == -2);
TEST_ASSERT (num1 == -2);
TEST_ASSERT (num2 == -1);
mapping,
ARRAY_SIZE (mapping));
- TEST_ASSERT (jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (jerry_value_is_error (is_ok));
jerry_release_value (is_ok);
validator_int_count++;
jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, mapping, ARRAY_SIZE (mapping));
- TEST_ASSERT (!jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (!jerry_value_is_error (is_ok));
if (validator_array_count == 0)
{
jerry_value_t is_ok = jerryx_arg_transform_array (args_p[0], item_mapping, ARRAY_SIZE (item_mapping));
- TEST_ASSERT (jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (jerry_value_is_error (is_ok));
TEST_ASSERT (native1 == 1);
TEST_ASSERT (!native2);
/* test string: 'str: {DESERET CAPITAL LETTER LONG I}' */
jerry_value_t str = jerry_create_string ((jerry_char_t *) "\x73\x74\x72\x3a \xed\xa0\x81\xed\xb0\x80");
char expect_utf8_buf[] = "\x73\x74\x72\x3a \xf0\x90\x90\x80";
- size_t buf_len = strlen (expect_utf8_buf);
+ size_t buf_len = sizeof (expect_utf8_buf) - 1;
char buf[buf_len+1];
jerryx_arg_t mapping[] =
mapping,
ARRAY_SIZE (mapping));
- TEST_ASSERT (!jerry_value_has_error_flag (is_ok));
+ TEST_ASSERT (!jerry_value_is_error (is_ok));
TEST_ASSERT (!strcmp (buf, expect_utf8_buf));
jerry_release_value (str);
jerry_value_t parsed_code_val = jerry_parse (NULL,
0,
- (jerry_char_t *) test_source,
- strlen (test_source),
+ test_source,
+ sizeof (test_source) - 1,
JERRY_PARSE_NO_OPTS);
- TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
+ TEST_ASSERT (!jerry_value_is_error (parsed_code_val));
jerry_value_t res = jerry_run (parsed_code_val);
- TEST_ASSERT (!jerry_value_has_error_flag (res));
+ TEST_ASSERT (!jerry_value_is_error (res));
TEST_ASSERT (validator1_count == 5);
TEST_ASSERT (validator2_count == 3);
TEST_ASSERT (validator_prop_count == 4);
native_free_cb_call_count = 0;
test_autorelease_val ();
- jerry_gc ();
+ jerry_gc (JERRY_GC_SEVERITY_HIGH);
TEST_ASSERT (native_free_cb_call_count == 1);
jerry_cleanup ();
jerry_value_t module = jerryx_module_resolve (module_name, &resolver, 1);
jerry_release_value (module_name);
- TEST_ASSERT (jerry_value_has_error_flag (module));
+ TEST_ASSERT (jerry_value_is_error (module));
/* Retrieve the error message. */
+ module = jerry_get_value_from_error (module, true);
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "message");
jerry_value_t prop = jerry_get_property (module, prop_name);
set(TARGET_NAME unit-${TARGET_NAME})
add_executable(${TARGET_NAME} ${SOURCE_UNIT_TEST_MAIN})
- set_property(TARGET ${TARGET_NAME}
- PROPERTY LINK_FLAGS "${LINKER_FLAGS_COMMON}")
+ set_property(TARGET ${TARGET_NAME} PROPERTY LINK_FLAGS "${LINKER_FLAGS_COMMON}")
+ set_property(TARGET ${TARGET_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
target_link_libraries(${TARGET_NAME} jerry-libm)
- if(JERRY_LIBC)
- target_link_libraries(${TARGET_NAME} jerry-libc)
- endif()
add_dependencies(unittests-libm ${TARGET_NAME})
endforeach()
import sys
import settings
-BUILD_DIR = os.path.join(settings.PROJECT_DIR, 'build')
-
-DEFAULT_PROFILE = 'es5.1'
-
def default_toolchain():
(sysname, _, _, _, machine) = os.uname()
toolchain = os.path.join(settings.PROJECT_DIR,
devhelp_preparser = argparse.ArgumentParser(add_help=False)
devhelp_preparser.add_argument('--devhelp', action='store_true', default=False,
help='show help with all options '
- '(including those, which are useful for developers only)')
+ '(including those, which are useful for developers only)')
devhelp_arguments, args = devhelp_preparser.parse_known_args()
if devhelp_arguments.devhelp:
def devhelp(helpstring):
return helpstring if devhelp_arguments.devhelp else argparse.SUPPRESS
- parser = argparse.ArgumentParser(parents=[devhelp_preparser])
- parser.add_argument('--all-in-one', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help='all-in-one build (%(choices)s; default: %(default)s)')
- parser.add_argument('--builddir', metavar='DIR', action='store', default=BUILD_DIR,
- help='specify output directory (default: %(default)s)')
- parser.add_argument('--clean', action='store_true', default=False, help='clean build')
- parser.add_argument('--cmake-param', metavar='OPT', action='append', default=[],
- help='add custom argument to CMake')
- parser.add_argument('--compile-flag', metavar='OPT', action='append', default=[],
- help='add custom compile flag')
- parser.add_argument('--cpointer-32bit', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help='enable 32 bit compressed pointers (%(choices)s; default: %(default)s)')
- parser.add_argument('--debug', action='store_const', const='Debug', default='MinSizeRel', dest='build_type',
- help='debug build')
- parser.add_argument('--doctests', action='store_const', const='ON', default='OFF',
- help='build doctests')
- parser.add_argument('--error-messages', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help='enable error messages (%(choices)s; default: %(default)s)')
- parser.add_argument('--external-context', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help='enable external context (%(choices)s; default: %(default)s)')
- parser.add_argument('-j', '--jobs', metavar='N', action='store', type=int, default=multiprocessing.cpu_count() + 1,
- help='Allowed N build jobs at once (default: %(default)s)')
- parser.add_argument('--jerry-cmdline', metavar='X', choices=['ON', 'OFF'], default='ON', type=str.upper,
- help='build jerry command line tool (%(choices)s; default: %(default)s)')
- parser.add_argument('--jerry-cmdline-snapshot', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help='build snapshot command line tool (%(choices)s; default: %(default)s)')
- parser.add_argument('--jerry-debugger', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help='enable the jerry debugger (%(choices)s; default: %(default)s)')
- parser.add_argument('--jerry-ext', metavar='X', choices=['ON', 'OFF'], default='ON', type=str.upper,
- help='build jerry-ext (default: %(default)s)')
- parser.add_argument('--jerry-libc', metavar='X', choices=['ON', 'OFF'], default='ON', type=str.upper,
- help='build and use jerry-libc (%(choices)s; default: %(default)s)')
- parser.add_argument('--jerry-libm', metavar='X', choices=['ON', 'OFF'], default='ON', type=str.upper,
- help='build and use jerry-libm (%(choices)s; default: %(default)s)')
- parser.add_argument('--jerry-port-default', metavar='X', choices=['ON', 'OFF'], default='ON', type=str.upper,
- help='build default jerry port implementation (%(choices)s; default: %(default)s)')
- parser.add_argument('--js-parser', metavar='X', choices=['ON', 'OFF'], default='ON', type=str.upper,
- help='enable js-parser (%(choices)s; default: %(default)s)')
- parser.add_argument('--line-info', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help='provide line info (%(choices)s; default: %(default)s)')
- parser.add_argument('--link-lib', metavar='OPT', action='append', default=[],
- help='add custom library to be linked')
- parser.add_argument('--linker-flag', metavar='OPT', action='append', default=[],
- help='add custom linker flag')
- parser.add_argument('--lto', metavar='X', choices=['ON', 'OFF'], default='ON', type=str.upper,
- help='enable link-time optimizations (%(choices)s; default: %(default)s)')
- parser.add_argument('--mem-heap', metavar='SIZE', action='store', type=int, default=512,
- help='size of memory heap, in kilobytes (default: %(default)s)')
- parser.add_argument('--profile', metavar='FILE', action='store', default=DEFAULT_PROFILE,
- help='specify profile file (default: %(default)s)')
- parser.add_argument('--snapshot-exec', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help='enable executing snapshot files (%(choices)s; default: %(default)s)')
- parser.add_argument('--snapshot-save', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help='enable saving snapshot files (%(choices)s; default: %(default)s)')
- parser.add_argument('--system-allocator', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help='enable system allocator (%(choices)s; default: %(default)s)')
- parser.add_argument('--static-link', metavar='X', choices=['ON', 'OFF'], default='ON', type=str.upper,
- help='enable static linking of binaries (%(choices)s; default: %(default)s)')
- parser.add_argument('--strip', metavar='X', choices=['ON', 'OFF'], default='ON', type=str.upper,
- help='strip release binaries (%(choices)s; default: %(default)s)')
- parser.add_argument('--toolchain', metavar='FILE', action='store', default=default_toolchain(),
- help='add toolchain file (default: %(default)s)')
- parser.add_argument('--unittests', action='store_const', const='ON', default='OFF',
- help='build unittests')
- parser.add_argument('-v', '--verbose', action='store_const', const='ON', default='OFF',
- help='increase verbosity')
- parser.add_argument('--vm-exec-stop', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help='enable VM execution stopping (%(choices)s; default: %(default)s)')
-
- devgroup = parser.add_argument_group('developer options')
- devgroup.add_argument('--jerry-cmdline-test', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help=devhelp('build test version of the jerry command line tool '
- '(%(choices)s; default: %(default)s)'))
- devgroup.add_argument('--link-map', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help=devhelp('enable the generation of a link map file for jerry command line tool '
- '(%(choices)s; default: %(default)s)'))
- devgroup.add_argument('--mem-stats', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help=devhelp('enable memory statistics (%(choices)s; default: %(default)s)'))
- devgroup.add_argument('--mem-stress-test', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help=devhelp('enable mem-stress test (%(choices)s; default: %(default)s)'))
- devgroup.add_argument('--regexp-strict-mode', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help=devhelp('enable regexp strict mode (%(choices)s; default: %(default)s)'))
- devgroup.add_argument('--show-opcodes', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help=devhelp('enable parser byte-code dumps (%(choices)s; default: %(default)s)'))
- devgroup.add_argument('--show-regexp-opcodes', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help=devhelp('enable regexp byte-code dumps (%(choices)s; default: %(default)s)'))
- devgroup.add_argument('--valgrind', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help=devhelp('enable Valgrind support (%(choices)s; default: %(default)s)'))
- devgroup.add_argument('--valgrind-freya', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
- help=devhelp('enable Valgrind-Freya support (%(choices)s; default: %(default)s)'))
+ parser = argparse.ArgumentParser(parents=[devhelp_preparser], epilog="""
+ This tool is a thin wrapper around cmake and make to help build the
+ project easily. All the real build logic is in the CMakeLists.txt files.
+ For most of the options, the defaults are also defined there.
+ """)
+
+ buildgrp = parser.add_argument_group('general build options')
+ buildgrp.add_argument('--builddir', metavar='DIR', default=os.path.join(settings.PROJECT_DIR, 'build'),
+ help='specify build directory (default: %(default)s)')
+ buildgrp.add_argument('--clean', action='store_true', default=False,
+ help='clean build')
+ buildgrp.add_argument('--cmake-param', metavar='OPT', action='append', default=[],
+ help='add custom argument to CMake')
+ buildgrp.add_argument('--compile-flag', metavar='OPT', action='append', default=[],
+ help='add custom compile flag')
+ buildgrp.add_argument('--debug', action='store_const', const='Debug', dest='build_type',
+ help='debug build')
+ buildgrp.add_argument('--install', metavar='DIR', nargs='?', default=None, const=False,
+ help='install after build (default: don\'t install; '
+ 'default directory if install: OS-specific)')
+ buildgrp.add_argument('-j', '--jobs', metavar='N', type=int, default=multiprocessing.cpu_count() + 1,
+ help='number of parallel build jobs (default: %(default)s)')
+ buildgrp.add_argument('--link-lib', metavar='OPT', action='append', default=[],
+ help='add custom library to be linked')
+ buildgrp.add_argument('--linker-flag', metavar='OPT', action='append', default=[],
+ help='add custom linker flag')
+ buildgrp.add_argument('--lto', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable link-time optimizations (%(choices)s)')
+ buildgrp.add_argument('--shared-libs', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable building of shared libraries (%(choices)s)')
+ buildgrp.add_argument('--strip', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='strip release binaries (%(choices)s)')
+ buildgrp.add_argument('--toolchain', metavar='FILE', default=default_toolchain(),
+ help='specify toolchain file (default: %(default)s)')
+ buildgrp.add_argument('-v', '--verbose', action='store_const', const='ON',
+ help='increase verbosity')
+
+ compgrp = parser.add_argument_group('optional components')
+ compgrp.add_argument('--doctests', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help=devhelp('build doctests (%(choices)s)'))
+ compgrp.add_argument('--jerry-cmdline', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='build jerry command line tool (%(choices)s)')
+ compgrp.add_argument('--jerry-cmdline-snapshot', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='build snapshot command line tool (%(choices)s)')
+ compgrp.add_argument('--jerry-cmdline-test', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help=devhelp('build test version of the jerry command line tool (%(choices)s)'))
+ compgrp.add_argument('--jerry-ext', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='build jerry-ext (%(choices)s)')
+ compgrp.add_argument('--jerry-libm', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='build and use jerry-libm (%(choices)s)')
+ compgrp.add_argument('--jerry-port-default', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='build default jerry port implementation (%(choices)s)')
+ compgrp.add_argument('--unittests', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help=devhelp('build unittests (%(choices)s)'))
+
+ coregrp = parser.add_argument_group('jerry-core options')
+ coregrp.add_argument('--all-in-one', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='all-in-one build (%(choices)s)')
+ coregrp.add_argument('--cpointer-32bit', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable 32 bit compressed pointers (%(choices)s)')
+ coregrp.add_argument('--error-messages', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable error messages (%(choices)s)')
+ coregrp.add_argument('--external-context', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable external context (%(choices)s)')
+ coregrp.add_argument('--jerry-debugger', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable the jerry debugger (%(choices)s)')
+ coregrp.add_argument('--js-parser', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable js-parser (%(choices)s)')
+ coregrp.add_argument('--line-info', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='provide line info (%(choices)s)')
+ coregrp.add_argument('--logging', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable logging (%(choices)s)')
+ coregrp.add_argument('--mem-heap', metavar='SIZE', type=int,
+ help='size of memory heap (in kilobytes)')
+ coregrp.add_argument('--mem-stats', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help=devhelp('enable memory statistics (%(choices)s)'))
+ coregrp.add_argument('--mem-stress-test', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help=devhelp('enable mem-stress test (%(choices)s)'))
+ coregrp.add_argument('--profile', metavar='FILE',
+ help='specify profile file')
+ coregrp.add_argument('--regexp-strict-mode', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help=devhelp('enable regexp strict mode (%(choices)s)'))
+ coregrp.add_argument('--show-opcodes', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help=devhelp('enable parser byte-code dumps (%(choices)s)'))
+ coregrp.add_argument('--show-regexp-opcodes', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help=devhelp('enable regexp byte-code dumps (%(choices)s)'))
+ coregrp.add_argument('--snapshot-exec', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable executing snapshot files (%(choices)s)')
+ coregrp.add_argument('--snapshot-save', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable saving snapshot files (%(choices)s)')
+ coregrp.add_argument('--system-allocator', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable system allocator (%(choices)s)')
+ coregrp.add_argument('--valgrind', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help=devhelp('enable Valgrind support (%(choices)s)'))
+ coregrp.add_argument('--vm-exec-stop', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable VM execution stopping (%(choices)s)')
+
+ maingrp = parser.add_argument_group('jerry-main options')
+ maingrp.add_argument('--link-map', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help=devhelp('enable the generation of link map for jerry command line tool (%(choices)s)'))
arguments = parser.parse_args(args)
if arguments.devhelp:
def generate_build_options(arguments):
build_options = []
- build_options.append('-DENABLE_ALL_IN_ONE=%s' % arguments.all_in_one)
- build_options.append('-DCMAKE_BUILD_TYPE=%s' % arguments.build_type)
- build_options.append('-DEXTERNAL_COMPILE_FLAGS=' + ' '.join(arguments.compile_flag))
- build_options.append('-DFEATURE_CPOINTER_32_BIT=%s' % arguments.cpointer_32bit)
- build_options.append('-DFEATURE_ERROR_MESSAGES=%s' % arguments.error_messages)
- build_options.append('-DFEATURE_LINE_INFO=%s' % arguments.line_info)
- build_options.append('-DJERRY_CMDLINE=%s' % arguments.jerry_cmdline)
- build_options.append('-DJERRY_CMDLINE_TEST=%s' % arguments.jerry_cmdline_test)
- build_options.append('-DJERRY_CMDLINE_SNAPSHOT=%s' % arguments.jerry_cmdline_snapshot)
- build_options.append('-DJERRY_PORT_DEFAULT=%s' % arguments.jerry_port_default)
- build_options.append('-DJERRY_EXT=%s' % arguments.jerry_ext)
- build_options.append('-DJERRY_LIBC=%s' % arguments.jerry_libc)
- build_options.append('-DJERRY_LIBM=%s' % arguments.jerry_libm)
- build_options.append('-DFEATURE_JS_PARSER=%s' % arguments.js_parser)
- build_options.append('-DEXTERNAL_LINK_LIBS=' + ' '.join(arguments.link_lib))
- build_options.append('-DEXTERNAL_LINKER_FLAGS=' + ' '.join(arguments.linker_flag))
- build_options.append('-DENABLE_LTO=%s' % arguments.lto)
- build_options.append('-DMEM_HEAP_SIZE_KB=%d' % arguments.mem_heap)
-
- build_options.append('-DFEATURE_PROFILE=%s' % arguments.profile)
- build_options.append('-DFEATURE_DEBUGGER=%s' % arguments.jerry_debugger)
- build_options.append('-DFEATURE_EXTERNAL_CONTEXT=%s' % arguments.external_context)
- build_options.append('-DFEATURE_SNAPSHOT_EXEC=%s' % arguments.snapshot_exec)
- build_options.append('-DFEATURE_SNAPSHOT_SAVE=%s' % arguments.snapshot_save)
- build_options.append('-DFEATURE_SYSTEM_ALLOCATOR=%s' % arguments.system_allocator)
- build_options.append('-DENABLE_STATIC_LINK=%s' % arguments.static_link)
- build_options.append('-DENABLE_STRIP=%s' % arguments.strip)
- build_options.append('-DFEATURE_VM_EXEC_STOP=%s' % arguments.vm_exec_stop)
-
- if arguments.toolchain:
- build_options.append('-DCMAKE_TOOLCHAIN_FILE=%s' % arguments.toolchain)
-
- build_options.append('-DUNITTESTS=%s' % arguments.unittests)
- build_options.append('-DDOCTESTS=%s' % arguments.doctests)
- build_options.append('-DCMAKE_VERBOSE_MAKEFILE=%s' % arguments.verbose)
-
- # developer options
- build_options.append('-DENABLE_LINK_MAP=%s' % arguments.link_map)
- build_options.append('-DFEATURE_MEM_STATS=%s' % arguments.mem_stats)
- build_options.append('-DFEATURE_MEM_STRESS_TEST=%s' % arguments.mem_stress_test)
- build_options.append('-DFEATURE_PARSER_DUMP=%s' % arguments.show_opcodes)
- build_options.append('-DFEATURE_REGEXP_STRICT_MODE=%s' % arguments.regexp_strict_mode)
- build_options.append('-DFEATURE_REGEXP_DUMP=%s' % arguments.show_regexp_opcodes)
- build_options.append('-DFEATURE_VALGRIND=%s' % arguments.valgrind)
- build_options.append('-DFEATURE_VALGRIND_FREYA=%s' % arguments.valgrind_freya)
-
- build_options.extend(arguments.cmake_param)
+ def build_options_append(cmakeopt, cliarg):
+ if cliarg:
+ build_options.append('-D%s=%s' % (cmakeopt, cliarg))
+
+ # general build options
+ build_options_append('CMAKE_BUILD_TYPE', arguments.build_type)
+ build_options_append('EXTERNAL_COMPILE_FLAGS', ' '.join(arguments.compile_flag))
+ build_options_append('EXTERNAL_LINK_LIBS', ' '.join(arguments.link_lib))
+ build_options_append('EXTERNAL_LINKER_FLAGS', ' '.join(arguments.linker_flag))
+ build_options_append('ENABLE_LTO', arguments.lto)
+ build_options_append('BUILD_SHARED_LIBS', arguments.shared_libs)
+ build_options_append('ENABLE_STRIP', arguments.strip)
+ build_options_append('CMAKE_TOOLCHAIN_FILE', arguments.toolchain)
+ build_options_append('CMAKE_VERBOSE_MAKEFILE', arguments.verbose)
+
+ # optional components
+ build_options_append('DOCTESTS', arguments.doctests)
+ build_options_append('JERRY_CMDLINE', arguments.jerry_cmdline)
+ build_options_append('JERRY_CMDLINE_SNAPSHOT', arguments.jerry_cmdline_snapshot)
+ build_options_append('JERRY_CMDLINE_TEST', arguments.jerry_cmdline_test)
+ build_options_append('JERRY_EXT', arguments.jerry_ext)
+ build_options_append('JERRY_LIBM', arguments.jerry_libm)
+ build_options_append('JERRY_PORT_DEFAULT', arguments.jerry_port_default)
+ build_options_append('UNITTESTS', arguments.unittests)
+
+ # jerry-core options
+ build_options_append('ENABLE_ALL_IN_ONE', arguments.all_in_one)
+ build_options_append('FEATURE_CPOINTER_32_BIT', arguments.cpointer_32bit)
+ build_options_append('FEATURE_ERROR_MESSAGES', arguments.error_messages)
+ build_options_append('FEATURE_EXTERNAL_CONTEXT', arguments.external_context)
+ build_options_append('FEATURE_DEBUGGER', arguments.jerry_debugger)
+ build_options_append('FEATURE_JS_PARSER', arguments.js_parser)
+ build_options_append('FEATURE_LINE_INFO', arguments.line_info)
+ build_options_append('FEATURE_LOGGING', arguments.logging)
+ build_options_append('MEM_HEAP_SIZE_KB', arguments.mem_heap)
+ build_options_append('FEATURE_MEM_STATS', arguments.mem_stats)
+ build_options_append('FEATURE_MEM_STRESS_TEST', arguments.mem_stress_test)
+ build_options_append('FEATURE_PROFILE', arguments.profile)
+ build_options_append('FEATURE_REGEXP_STRICT_MODE', arguments.regexp_strict_mode)
+ build_options_append('FEATURE_PARSER_DUMP', arguments.show_opcodes)
+ build_options_append('FEATURE_REGEXP_DUMP', arguments.show_regexp_opcodes)
+ build_options_append('FEATURE_SNAPSHOT_EXEC', arguments.snapshot_exec)
+ build_options_append('FEATURE_SNAPSHOT_SAVE', arguments.snapshot_save)
+ build_options_append('FEATURE_SYSTEM_ALLOCATOR', arguments.system_allocator)
+ build_options_append('FEATURE_VALGRIND', arguments.valgrind)
+ build_options_append('FEATURE_VM_EXEC_STOP', arguments.vm_exec_stop)
+
+ # jerry-main options
+ build_options_append('ENABLE_LINK_MAP', arguments.link_map)
+
+ # general build options (final step)
+ if arguments.cmake_param:
+ build_options.extend(arguments.cmake_param)
return build_options
if not os.path.exists(arguments.builddir):
os.makedirs(arguments.builddir)
-def configure_build(arguments):
+def configure_jerry(arguments):
configure_output_dir(arguments)
build_options = generate_build_options(arguments)
cmake_cmd = ['cmake', '-B' + arguments.builddir, '-H' + settings.PROJECT_DIR]
+
+ if arguments.install:
+ cmake_cmd.append('-DCMAKE_INSTALL_PREFIX=%s' % arguments.install)
+
cmake_cmd.extend(build_options)
return subprocess.call(cmake_cmd)
-def build_jerry(arguments):
- return subprocess.call(['make', '--no-print-directory', '-j', str(arguments.jobs), '-C', arguments.builddir])
+def make_jerry(arguments, target=None):
+ make_cmd = ['make', '--no-print-directory', '-j', str(arguments.jobs), '-C', arguments.builddir]
+
+ if target:
+ make_cmd.append(target)
+
+ return subprocess.call(make_cmd)
def print_result(ret):
print('=' * 30)
def main():
arguments = get_arguments()
- ret = configure_build(arguments)
+
+ ret = configure_jerry(arguments)
if not ret:
- ret = build_jerry(arguments)
+ ret = make_jerry(arguments)
+
+ if not ret and arguments.install is not None:
+ ret = make_jerry(arguments, 'install')
print_result(ret)
sys.exit(ret)
# limitations under the License.
if [[ "$OSTYPE" == "linux"* ]]; then
- CPPCHECK_JOBS=${CPPCHECK_JOBS:=$(nproc)}
+ CPPCHECK_JOBS=${CPPCHECK_JOBS:=$(nproc)}
elif [[ "$OSTYPE" == "darwin"* ]]; then
- CPPCHECK_JOBS=${CPPCHECK_JOBS:=$(sysctl -n hw.ncpu)}
+ CPPCHECK_JOBS=${CPPCHECK_JOBS:=$(sysctl -n hw.ncpu)}
else
- CPPCHECK_JOBS=${CPPCHECK_JOBS:=1}
+ CPPCHECK_JOBS=${CPPCHECK_JOBS:=1}
fi
JERRY_CORE_DIRS=`find jerry-core -type d`
JERRY_EXT_DIRS=`find jerry-ext -type d`
JERRY_PORT_DIRS=`find jerry-port -type d`
-JERRY_LIBC_DIRS=`find jerry-libc -type d`
JERRY_LIBM_DIRS=`find jerry-libm -type d`
INCLUDE_DIRS=()
-for DIR in $JERRY_CORE_DIRS $JERRY_EXT_DIRS $JERRY_PORT_DIRS $JERRY_LIBC_DIRS $JERRY_LIBM_DIRS
+for DIR in $JERRY_CORE_DIRS $JERRY_EXT_DIRS $JERRY_PORT_DIRS $JERRY_LIBM_DIRS
do
- INCLUDE_DIRS=("${INCLUDE_DIRS[@]}" "-I$DIR")
+ INCLUDE_DIRS=("${INCLUDE_DIRS[@]}" "-I$DIR")
done
cppcheck -j$CPPCHECK_JOBS --force \
- --language=c --std=c99 \
- --enable=warning,style,performance,portability,information \
- --template="{file}:{line}: {severity}({id}): {message}" \
- --error-exitcode=1 \
- --exitcode-suppressions=tools/cppcheck/suppressions-list \
- --suppressions-list=tools/cppcheck/suppressions-list \
- "${INCLUDE_DIRS[@]}" \
- jerry-core jerry-ext jerry-port jerry-libc jerry-libm jerry-main tests/unit-*
+ --language=c --std=c99 \
+ --quiet \
+ --enable=warning,style,performance,portability,information \
+ --template="{file}:{line}: {severity}({id}): {message}" \
+ --error-exitcode=1 \
+ --exitcode-suppressions=tools/cppcheck/suppressions-list \
+ --suppressions-list=tools/cppcheck/suppressions-list \
+ "${INCLUDE_DIRS[@]}" \
+ jerry-core jerry-ext jerry-port jerry-libm jerry-main tests/unit-*
# See the License for the specific language governing permissions and
# limitations under the License.
-echo -n "Generating documentation with doxygen ..."
-DOXYGEN_WARNINGS=$((doxygen > /dev/null) 2>&1)
-echo " finished"
-
-if [ -n "$DOXYGEN_WARNINGS" ]
+doxygen 2>&1 >/dev/null | head -n 1000 | tee doxygen.log
+if [ -s doxygen.log ]
then
- echo "$DOXYGEN_WARNINGS"
- exit 1
+ EXIT=1
+else
+ EXIT=0
fi
+rm -f doxygen.log
+exit $EXIT
from __future__ import print_function
+import io
import os
import re
import sys
'cmake',
'jerry-core',
'jerry-ext',
- 'jerry-libc',
'jerry-libm',
'jerry-main',
'jerry-port',
for fname in files:
if any(fname.endswith(ext) for ext in EXTENSIONS):
fpath = os.path.join(root, fname)
- with open(fpath) as curr_file:
+ with io.open(fpath, 'r', errors='ignore') as curr_file:
if not LICENSE.search(curr_file.read()):
print('%s: incorrect license' % fpath)
is_ok = False
cp $MAGIC_STRINGS_INC_H $MAGIC_STRINGS_TEMP
$MAGIC_STRINGS_GEN
-diff -q $MAGIC_STRINGS_INC_H $MAGIC_STRINGS_TEMP
DIFF_RESULT=$?
-mv $MAGIC_STRINGS_TEMP $MAGIC_STRINGS_INC_H
-if [ $DIFF_RESULT -ne 0 ]
+if [ $DIFF_RESULT -eq 0 ]
then
- echo -e "\e[1;33m$MAGIC_STRINGS_INC_H must be re-generated. Run $MAGIC_STRINGS_GEN\e[0m"
+ diff -q $MAGIC_STRINGS_INC_H $MAGIC_STRINGS_TEMP
+ DIFF_RESULT=$?
+ if [ $DIFF_RESULT -ne 0 ]
+ then
+ echo -e "\e[1;33m$MAGIC_STRINGS_INC_H must be re-generated. Run $MAGIC_STRINGS_GEN\e[0m"
+ fi
fi
+mv $MAGIC_STRINGS_TEMP $MAGIC_STRINGS_INC_H
exit $DIFF_RESULT
--- /dev/null
+#!/bin/bash
+
+# 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.
+
+if [[ "${TRAVIS_REPO_SLUG}" == "jerryscript-project/jerryscript"
+ && ${TRAVIS_BRANCH} == "master"
+ && ${TRAVIS_EVENT_TYPE} == "push" ]]
+then
+ git fetch --unshallow
+ build-wrapper-linux-x86-64 --out-dir bw-output \
+ ./tools/build.py --error-messages=on \
+ --jerry-cmdline-snapshot=on \
+ --jerry-debugger=on \
+ --line-info=on \
+ --mem-stats=on \
+ --profile=es2015-subset \
+ --snapshot-save=on \
+ --snapshot-exec=on \
+ --valgrind=on \
+ --vm-exec-stop=on
+ sonar-scanner -Dsonar.projectVersion="${TRAVIS_COMMIT}"
+else
+ # SonarQube analysis works only on the master branch.
+ # Ensure the build works with the options used for the analysis.
+ ./tools/build.py --error-messages=on \
+ --jerry-cmdline-snapshot=on \
+ --jerry-debugger=on \
+ --line-info=on \
+ --mem-stats=on \
+ --profile=es2015-subset \
+ --snapshot-save=on \
+ --snapshot-exec=on \
+ --valgrind=on \
+ --vm-exec-stop=on
+fi
JERRY_CORE_FILES=`find ./jerry-core -name "*.c" -or -name "*.h"`
JERRY_EXT_FILES=`find ./jerry-ext -name "*.c" -or -name "*.h"`
JERRY_PORT_FILES=`find ./jerry-port -name "*.c" -or -name "*.h"`
-JERRY_LIBC_FILES=`find ./jerry-libc -name "*.c" -or -name "*.h"`
JERRY_LIBM_FILES=`find ./jerry-libm -name "*.c" -or -name "*.h"`
JERRY_MAIN_FILES=`find ./jerry-main -name "*.c" -or -name "*.h"`
UNIT_TEST_FILES=`find ./tests/unit-* -name "*.c" -or -name "*.h"`
vera++ -r tools/vera++ -p jerry \
-e --no-duplicate \
- $MANUAL_CHECK_FILES $JERRY_CORE_FILES $JERRY_EXT_FILES $JERRY_PORT_FILES $JERRY_LIBC_FILES $JERRY_LIBM_FILES $JERRY_MAIN_FILES $UNIT_TEST_FILES
+ $MANUAL_CHECK_FILES $JERRY_CORE_FILES $JERRY_EXT_FILES $JERRY_PORT_FILES $JERRY_LIBM_FILES $JERRY_MAIN_FILES $UNIT_TEST_FILES
wrongmathcall:tests/unit-libm/test-libm.inc.h
variableScope:jerry-libm/*.c
invalidPointerCast:jerry-libm/*.c
-arithOperationsOnVoidPointer:jerry-libc/*.c
commaSeparatedReturn:*
guard_stack = []
for line in fileinput.input(fname):
- if_match = re.match('^# *if(.*)', line)
- elif_match = re.match('^# *elif(.*)', line)
- else_match = re.match('^# *else', line)
- endif_match = re.match('^# *endif', line)
+ if_match = re.match('^ *# *if(.*)', line)
+ elif_match = re.match('^ *# *elif(.*)', line)
+ else_match = re.match('^ *# *else', line)
+ endif_match = re.match('^ *# *endif', line)
if if_match is not None:
guard_stack.append([process_guard(if_match.group(1))])
elif elif_match is not None:
+++ /dev/null
-#!/bin/bash
-
-# 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.
-
-echo "#define JERRY_MCU_SCRIPT \\" > $2
-# escape all " characters, wrap each line in double quotes and end the line with '\'
-sed 's/"/\\"/g' $1 | sed 's/^.*$/"\0" \\/g' >> $2
-echo >> $2
+++ /dev/null
-#!/bin/bash
-
-# 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.
-
-commit_first=$1
-shift
-
-commit_second=$1
-shift
-
-exceptions="-e '' $*"
-
-if [[ "$commit_first" == "" ]] || [[ "$commit_second" == "" ]]
-then
- exit 1
-fi
-
-perf_first=`git notes --ref=arm-linux-perf show $commit_first | grep -v $exceptions`
-if [ $? -ne 0 ]
-then
- exit 1
-fi
-
-perf_second=`git notes --ref=arm-linux-perf show $commit_second | grep -v $exceptions`
-if [ $? -ne 0 ]
-then
- exit 1
-fi
-
-n=0
-rel_mult=1.0
-for bench in `echo "$perf_first" | cut -d ':' -f 1`
-do
- value1=`echo "$perf_first" | grep "^$bench: " | cut -d ':' -f 2 | cut -d 's' -f 1`
- value2=`echo "$perf_second" | grep "^$bench: " | cut -d ':' -f 2 | cut -d 's' -f 1`
- rel=`echo $value1 $value2 | awk '{print $2 / $1; }'`
- percent=`echo $rel | awk '{print (1.0 - $1) * 100; }'`
-
- n=`echo $n | awk '{print $1 + 1;}'`;
- rel_mult=`echo $rel_mult $rel | awk '{print $1 * $2;}'`
-
- echo $bench":"$value1"s ->"$value2"s ("$percent" %)"
-done
-
-rel_gmean=`echo $rel_mult $n | awk '{print $1 ^ (1.0 / $2);}'`
-percent_gmean=`echo $rel_gmean | awk '{print (1.0 - $1) * 100;}'`
-
-echo
-echo $n $rel_mult $rel_gmean "("$percent_gmean "%)"
[ELIF]
# Maximum number of nested blocks for function / method body
-max-nested-blocks=5
+max-nested-blocks=7
[LOGGING]
max-branches=15
# Maximum number of statements in function / method body
-max-statements=50
+max-statements=75
# Maximum number of parents for a class (see R0901).
max-parents=7
import argparse
import collections
+import hashlib
import os
+import platform
import subprocess
import sys
import settings
OUTPUT_DIR = os.path.join(settings.PROJECT_DIR, 'build', 'tests')
-Options = collections.namedtuple('Options', ['name', 'build_args', 'test_args'])
-Options.__new__.__defaults__ = ([], [])
+Options = collections.namedtuple('Options', ['name', 'build_args', 'test_args', 'skip'])
+Options.__new__.__defaults__ = ([], [], False)
-def get_binary_path(bin_dir_path):
- return os.path.join(bin_dir_path, 'jerry')
+def skip_if(condition, desc):
+ return desc if condition else False
+
+OPTIONS_PROFILE_MIN = ['--profile=minimal']
+OPTIONS_PROFILE_ES51 = [] # NOTE: same as ['--profile=es5.1']
+OPTIONS_PROFILE_ES2015 = ['--profile=es2015-subset']
+OPTIONS_DEBUG = ['--debug']
+OPTIONS_SNAPSHOT = ['--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on']
+OPTIONS_UNITTESTS = ['--unittests=on', '--jerry-cmdline=off', '--error-messages=on',
+ '--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on',
+ '--line-info=on', '--mem-stats=on']
+OPTIONS_DOCTESTS = ['--doctests=on', '--jerry-cmdline=off', '--error-messages=on',
+ '--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on']
# Test options for unittests
JERRY_UNITTESTS_OPTIONS = [
- Options('unittests',
- ['--unittests', '--profile=es2015-subset', '--jerry-cmdline=off', '--error-messages=on',
- '--snapshot-save=on', '--snapshot-exec=on', '--line-info=on', '--vm-exec-stop=on',
- '--mem-stats=on']),
- Options('unittests-debug',
- ['--unittests', '--debug', '--profile=es2015-subset', '--jerry-cmdline=off',
- '--error-messages=on', '--snapshot-save=on', '--snapshot-exec=on', '--line-info=on',
- '--vm-exec-stop=on', '--mem-stats=on']),
- Options('doctests',
- ['--doctests', '--jerry-cmdline=off', '--error-messages=on', '--snapshot-save=on',
- '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es2015-subset']),
- Options('doctests-debug',
- ['--doctests', '--jerry-cmdline=off', '--debug', '--error-messages=on',
- '--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es2015-subset']),
+ Options('unittests-es2015_subset',
+ OPTIONS_UNITTESTS + OPTIONS_PROFILE_ES2015),
+ Options('unittests-es2015_subset-debug',
+ OPTIONS_UNITTESTS + OPTIONS_PROFILE_ES2015 + OPTIONS_DEBUG),
+ Options('doctests-es2015_subset',
+ OPTIONS_DOCTESTS + OPTIONS_PROFILE_ES2015),
+ Options('doctests-es2015_subset-debug',
+ OPTIONS_DOCTESTS + OPTIONS_PROFILE_ES2015 + OPTIONS_DEBUG),
Options('unittests-es5.1',
- ['--unittests', '--profile=es5.1', '--jerry-cmdline=off', '--error-messages=on',
- '--snapshot-save=on', '--snapshot-exec=on', '--line-info=on', '--vm-exec-stop=on',
- '--mem-stats=on']),
+ OPTIONS_UNITTESTS + OPTIONS_PROFILE_ES51),
Options('unittests-es5.1-debug',
- ['--unittests', '--debug', '--profile=es5.1', '--jerry-cmdline=off',
- '--error-messages=on', '--snapshot-save=on', '--snapshot-exec=on', '--line-info=on',
- '--vm-exec-stop=on', '--mem-stats=on']),
+ OPTIONS_UNITTESTS + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG),
Options('doctests-es5.1',
- ['--doctests', '--jerry-cmdline=off', '--error-messages=on', '--snapshot-save=on',
- '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es5.1']),
+ OPTIONS_DOCTESTS + OPTIONS_PROFILE_ES51),
Options('doctests-es5.1-debug',
- ['--doctests', '--jerry-cmdline=off', '--debug', '--error-messages=on',
- '--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es5.1'])
+ OPTIONS_DOCTESTS + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG)
]
# Test options for jerry-tests
JERRY_TESTS_OPTIONS = [
- Options('jerry_tests'),
- Options('jerry_tests-debug',
- ['--debug']),
- Options('jerry_tests-debug-cpointer_32bit',
- ['--debug', '--cpointer-32bit=on', '--mem-heap=1024']),
- Options('jerry_tests-snapshot',
- ['--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'],
+ Options('jerry_tests-es5.1',
+ OPTIONS_PROFILE_ES51),
+ Options('jerry_tests-es5.1-snapshot',
+ OPTIONS_PROFILE_ES51 + OPTIONS_SNAPSHOT,
['--snapshot']),
- Options('jerry_tests-debug-snapshot',
- ['--debug', '--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'],
+ Options('jerry_tests-es5.1-debug',
+ OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG),
+ Options('jerry_tests-es5.1-debug-snapshot',
+ OPTIONS_PROFILE_ES51 + OPTIONS_SNAPSHOT + OPTIONS_DEBUG,
['--snapshot']),
+ Options('jerry_tests-es5.1-debug-cpointer_32bit',
+ OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + ['--cpointer-32bit=on', '--mem-heap=1024']),
+ Options('jerry_tests-es5.1-debug-external_context',
+ OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + ['--external-context=on']),
Options('jerry_tests-es2015_subset-debug',
- ['--debug', '--profile=es2015-subset']),
- Options('jerry_tests-es5.1-debug',
- ['--debug', '--profile=es5.1']),
- Options('jerry_tests-debug-external_context',
- ['--debug', '--jerry-libc=off', '--external-context=on'])
+ OPTIONS_PROFILE_ES2015 + OPTIONS_DEBUG),
]
# Test options for jerry-test-suite
JERRY_TEST_SUITE_OPTIONS = JERRY_TESTS_OPTIONS[:]
JERRY_TEST_SUITE_OPTIONS.extend([
Options('jerry_test_suite-minimal',
- ['--profile=minimal']),
+ OPTIONS_PROFILE_MIN),
Options('jerry_test_suite-minimal-snapshot',
- ['--profile=minimal', '--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'],
+ OPTIONS_PROFILE_MIN + OPTIONS_SNAPSHOT,
['--snapshot']),
Options('jerry_test_suite-minimal-debug',
- ['--debug', '--profile=minimal']),
+ OPTIONS_PROFILE_MIN + OPTIONS_DEBUG),
Options('jerry_test_suite-minimal-debug-snapshot',
- ['--debug', '--profile=minimal', '--snapshot-save=on', '--snapshot-exec=on',
- '--jerry-cmdline-snapshot=on'],
+ OPTIONS_PROFILE_MIN + OPTIONS_SNAPSHOT + OPTIONS_DEBUG,
['--snapshot']),
Options('jerry_test_suite-es2015_subset',
- ['--profile=es2015-subset']),
+ OPTIONS_PROFILE_ES2015),
Options('jerry_test_suite-es2015_subset-snapshot',
- ['--profile=es2015-subset', '--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'],
+ OPTIONS_PROFILE_ES2015 + OPTIONS_SNAPSHOT,
['--snapshot']),
Options('jerry_test_suite-es2015_subset-debug-snapshot',
- ['--debug', '--profile=es2015-subset', '--snapshot-save=on', '--snapshot-exec=on',
- '--jerry-cmdline-snapshot=on'],
+ OPTIONS_PROFILE_ES2015 + OPTIONS_SNAPSHOT + OPTIONS_DEBUG,
['--snapshot']),
- Options('jerry_test_suite_es5.1',
- ['--profile=es5.1']),
- Options('jerry_test_suite-es5.1-snapshot',
- ['--profile=es5.1', '--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'],
- ['--snapshot']),
- Options('jerry_test_suite-es5.1-debug-snapshot',
- ['--debug', '--profile=es5.1', '--snapshot-save=on', '--snapshot-exec=on',
- '--jerry-cmdline-snapshot=on'],
- ['--snapshot'])
])
# Test options for test262
# Test options for jerry-debugger
DEBUGGER_TEST_OPTIONS = [
Options('jerry_debugger_tests',
- ['--debug', '--jerry-debugger=on', '--jerry-libc=off'])
+ ['--debug', '--jerry-debugger=on'])
]
# Test options for buildoption-test
['--lto=on']),
Options('buildoption_test-error_messages',
['--error-messages=on']),
+ Options('buildoption_test-logging',
+ ['--logging=on']),
Options('buildoption_test-all_in_one',
['--all-in-one=on']),
Options('buildoption_test-valgrind',
['--valgrind=on']),
- Options('buildoption_test-valgrind_freya',
- ['--valgrind-freya=on']),
Options('buildoption_test-mem_stats',
['--mem-stats=on']),
Options('buildoption_test-show_opcodes',
['--show-opcodes=on']),
Options('buildoption_test-show_regexp_opcodes',
['--show-regexp-opcodes=on']),
- Options('buildoption_test-compiler_default_libc',
- ['--jerry-libc=off']),
Options('buildoption_test-cpointer_32bit',
- ['--jerry-libc=off', '--compile-flag=-m32', '--cpointer-32bit=on', '--system-allocator=on']),
+ ['--compile-flag=-m32', '--cpointer-32bit=on', '--system-allocator=on'],
+ skip=skip_if(
+ platform.system() != 'Linux' or (platform.machine() != 'i386' and platform.machine() != 'x86_64'),
+ '-m32 is only supported on x86[-64]-linux')
+ ),
+ Options('buildoption_test-no_lcache_prophashmap',
+ ['--compile-flag=-DCONFIG_ECMA_LCACHE_DISABLE', '--compile-flag=-DCONFIG_ECMA_PROPERTY_HASHMAP_DISABLE']),
Options('buildoption_test-external_context',
- ['--jerry-libc=off', '--external-context=on']),
+ ['--external-context=on']),
+ Options('buildoption_test-shared_libs',
+ ['--shared-libs=on']),
Options('buildoption_test-cmdline_test',
['--jerry-cmdline-test=on']),
Options('buildoption_test-cmdline_snapshot',
BINARY_CACHE = {}
+TERM_NORMAL = '\033[0m'
+TERM_YELLOW = '\033[1;33m'
+TERM_BLUE = '\033[1;34m'
+
+def report_command(cmd_type, cmd, env=None):
+ sys.stderr.write('%s%s%s\n' % (TERM_BLUE, cmd_type, TERM_NORMAL))
+ if env is not None:
+ sys.stderr.write(''.join('%s%s=%r \\%s\n' % (TERM_BLUE, var, val, TERM_NORMAL)
+ for var, val in sorted(env.items())))
+ sys.stderr.write('%s%s%s\n' % (TERM_BLUE, (' \\%s\n\t%s' % (TERM_NORMAL, TERM_BLUE)).join(cmd), TERM_NORMAL))
+
+def report_skip(job):
+ sys.stderr.write('%sSkipping: %s' % (TERM_YELLOW, job.name))
+ if job.skip:
+ sys.stderr.write(' (%s)' % job.skip)
+ sys.stderr.write('%s\n' % TERM_NORMAL)
+
def create_binary(job, options):
- build_cmd = [settings.BUILD_SCRIPT]
- build_cmd.extend(job.build_args)
+ build_args = job.build_args[:]
+ if options.buildoptions:
+ for option in options.buildoptions.split(','):
+ if option not in build_args:
+ build_args.append(option)
+
+ build_cmd = [settings.BUILD_SCRIPT] + build_args
build_dir_path = os.path.join(options.outdir, job.name)
build_cmd.append('--builddir=%s' % build_dir_path)
+ install_dir_path = os.path.join(build_dir_path, 'local')
+ build_cmd.append('--install=%s' % install_dir_path)
+
if options.toolchain:
build_cmd.append('--toolchain=%s' % options.toolchain)
- if options.buildoptions:
- build_cmd.extend(options.buildoptions.split(','))
-
- sys.stderr.write('Build command: %s\n' % ' '.join(build_cmd))
+ report_command('Build command:', build_cmd)
- binary_key = tuple(job.build_args)
+ binary_key = tuple(sorted(build_args))
if binary_key in BINARY_CACHE:
ret, build_dir_path = BINARY_CACHE[binary_key]
sys.stderr.write('(skipping: already built at %s with returncode %d)\n' % (build_dir_path, ret))
- return ret, os.path.join(build_dir_path, 'bin')
+ return ret, build_dir_path
try:
subprocess.check_output(build_cmd)
ret = err.returncode
BINARY_CACHE[binary_key] = (ret, build_dir_path)
- return ret, os.path.join(build_dir_path, 'bin')
+ return ret, build_dir_path
+
+def get_binary_path(build_dir_path):
+ return os.path.join(build_dir_path, 'local', 'bin', 'jerry')
+
+def hash_binary(bin_path):
+ blocksize = 65536
+ hasher = hashlib.sha1()
+ with open(bin_path, 'rb') as bin_file:
+ buf = bin_file.read(blocksize)
+ while len(buf) > 0:
+ hasher.update(buf)
+ buf = bin_file.read(blocksize)
+ return hasher.hexdigest()
+
+def iterate_test_runner_jobs(jobs, options):
+ tested_paths = set()
+ tested_hashes = {}
+
+ for job in jobs:
+ ret_build, build_dir_path = create_binary(job, options)
+ if ret_build:
+ yield job, ret_build, None
-def run_check(runnable):
- sys.stderr.write('Test command: %s\n' % ' '.join(runnable))
+ if build_dir_path in tested_paths:
+ sys.stderr.write('(skipping: already tested with %s)\n' % build_dir_path)
+ continue
+ else:
+ tested_paths.add(build_dir_path)
- try:
- ret = subprocess.check_call(runnable)
- except subprocess.CalledProcessError as err:
- return err.returncode
+ bin_path = get_binary_path(build_dir_path)
+ bin_hash = hash_binary(bin_path)
- return ret
+ if bin_hash in tested_hashes:
+ sys.stderr.write('(skipping: already tested with equivalent %s)\n' % tested_hashes[bin_hash])
+ continue
+ else:
+ tested_hashes[bin_hash] = build_dir_path
+
+ test_cmd = [settings.TEST_RUNNER_SCRIPT, bin_path]
+
+ yield job, ret_build, test_cmd
+
+def run_check(runnable, env=None):
+ report_command('Test command:', runnable, env=env)
+
+ if env is not None:
+ full_env = dict(os.environ)
+ full_env.update(env)
+ env = full_env
+
+ proc = subprocess.Popen(runnable, env=env)
+ proc.wait()
+ return proc.returncode
def run_jerry_debugger_tests(options):
ret_build = ret_test = 0
for job in DEBUGGER_TEST_OPTIONS:
- ret_build, bin_dir_path = create_binary(job, options)
+ ret_build, build_dir_path = create_binary(job, options)
if ret_build:
break
test_case_path = os.path.join(settings.DEBUGGER_TESTS_DIR, test_case)
test_cmd = [
settings.DEBUGGER_TEST_RUNNER_SCRIPT,
- get_binary_path(bin_dir_path),
+ get_binary_path(build_dir_path),
settings.DEBUGGER_CLIENT_SCRIPT,
os.path.relpath(test_case_path, settings.PROJECT_DIR)
]
def run_jerry_tests(options):
ret_build = ret_test = 0
- for job in JERRY_TESTS_OPTIONS:
- ret_build, bin_dir_path = create_binary(job, options)
+ for job, ret_build, test_cmd in iterate_test_runner_jobs(JERRY_TESTS_OPTIONS, options):
if ret_build:
break
- test_cmd = [
- settings.TEST_RUNNER_SCRIPT,
- get_binary_path(bin_dir_path),
- settings.JERRY_TESTS_DIR
- ]
+ test_cmd.append(settings.JERRY_TESTS_DIR)
+
+ if options.quiet:
+ test_cmd.append("-q")
+
skip_list = []
- if '--profile=es2015-subset' not in job.build_args:
- skip_list.append(r"es2015\/")
- else:
+ if '--profile=es2015-subset' in job.build_args:
skip_list.append(r"es5.1\/")
+ else:
+ skip_list.append(r"es2015\/")
if options.skip_list:
skip_list.append(options.skip_list)
- if options.quiet:
- test_cmd.append("-q")
-
if skip_list:
test_cmd.append("--skip-list=" + ",".join(skip_list))
if job.test_args:
test_cmd.extend(job.test_args)
- ret_test |= run_check(test_cmd)
+ ret_test |= run_check(test_cmd, env=dict(TZ='UTC'))
return ret_build | ret_test
def run_jerry_test_suite(options):
ret_build = ret_test = 0
- for job in JERRY_TEST_SUITE_OPTIONS:
- ret_build, bin_dir_path = create_binary(job, options)
+ for job, ret_build, test_cmd in iterate_test_runner_jobs(JERRY_TEST_SUITE_OPTIONS, options):
if ret_build:
break
- test_cmd = [settings.TEST_RUNNER_SCRIPT, get_binary_path(bin_dir_path)]
-
if '--profile=minimal' in job.build_args:
test_cmd.append(settings.JERRY_TEST_SUITE_MINIMAL_LIST)
elif '--profile=es2015-subset' in job.build_args:
def run_test262_test_suite(options):
ret_build = ret_test = 0
for job in TEST262_TEST_SUITE_OPTIONS:
- ret_build, bin_dir_path = create_binary(job, options)
+ ret_build, build_dir_path = create_binary(job, options)
if ret_build:
break
test_cmd = [
settings.TEST262_RUNNER_SCRIPT,
- get_binary_path(bin_dir_path),
+ get_binary_path(build_dir_path),
settings.TEST262_TEST_SUITE_DIR
]
if job.test_args:
test_cmd.extend(job.test_args)
- ret_test |= run_check(test_cmd)
+ ret_test |= run_check(test_cmd, env=dict(TZ='America/Los_Angeles'))
return ret_build | ret_test
def run_unittests(options):
ret_build = ret_test = 0
for job in JERRY_UNITTESTS_OPTIONS:
- ret_build, bin_dir_path = create_binary(job, options)
+ ret_build, build_dir_path = create_binary(job, options)
if ret_build:
break
- ret_test |= run_check([
- settings.UNITTEST_RUNNER_SCRIPT,
- bin_dir_path,
- "-q" if options.quiet else "",
- ])
+ ret_test |= run_check(
+ [settings.UNITTEST_RUNNER_SCRIPT] +
+ [os.path.join(build_dir_path, 'tests')] +
+ (["-q"] if options.quiet else [])
+ )
return ret_build | ret_test
def run_buildoption_test(options):
for job in JERRY_BUILDOPTIONS:
+ if job.skip:
+ report_skip(job)
+ continue
+
ret, _ = create_binary(job, options)
if ret:
break
TEST_CASE=$3
CLIENT_ARGS=""
+TERM_NORMAL='\033[0m'
+TERM_RED='\033[1;31m'
+TERM_GREEN='\033[1;32m'
+
if [[ $TEST_CASE == *"client_source"* ]]; then
START_DEBUG_SERVER="${JERRY} --start-debug-server --debugger-wait-source &"
if [[ $TEST_CASE == *"client_source_multiple"* ]]; then
RESULT_TEMP=`mktemp ${TEST_CASE}.out.XXXXXXXXXX`
-(cat "${TEST_CASE}.cmd" | ${DEBUGGER_CLIENT} --non-interactive ${CLIENT_ARGS}) &> ${RESULT_TEMP}
+(cat "${TEST_CASE}.cmd" | ${DEBUGGER_CLIENT} --non-interactive ${CLIENT_ARGS}) >${RESULT_TEMP} 2>&1
+
+if [[ $TEST_CASE == *"restart"* ]]; then
+ CONTINUE_CASE=$(sed "s/restart/continue/g" <<< "$TEST_CASE")
+ (cat "${CONTINUE_CASE}.cmd" | ${DEBUGGER_CLIENT} --non-interactive ${CLIENT_ARGS}) >>${RESULT_TEMP} 2>&1
+fi
+
diff -U0 ${TEST_CASE}.expected ${RESULT_TEMP}
STATUS_CODE=$?
if [ ${STATUS_CODE} -ne 0 ]
then
- echo "${TEST_CASE} failed"
+ echo -e "${TERM_RED}FAIL: ${TEST_CASE}${TERM_NORMAL}\n"
else
- echo "${TEST_CASE} passed"
+ echo -e "${TERM_GREEN}PASS: ${TEST_CASE}${TERM_NORMAL}\n"
fi
exit ${STATUS_CODE}
+++ /dev/null
-#!/bin/bash
-
-# 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.
-
-NUM_COMMITS=$1
-BENCH=./tests/benchmarks/jerry/loop_arithmetics_1kk.js
-TARGET=release.linux
-
-trap ctrl_c INT
-
-function ctrl_c() {
- git checkout master >&/dev/null
- exit 1
-}
-
-commits_to_push=`git log -$NUM_COMMITS | grep "^commit [0-9a-f]*$" | awk 'BEGIN { s = ""; } { s = $2" "s; } END { print s; }'`
-
-for commit_hash in $commits_to_push
-do
- git checkout $commit_hash >&/dev/null
-
- echo -e -n " > Testing...\n > "
- echo `git log --format=%B -n 1 $commit_hash`
- make -s $TARGET
- ./tools/rss-measure.sh $TARGET $BENCH
- echo
-done
-
-git checkout master >&/dev/null
then
TIMEOUT_CMD=`which gtimeout`
fi
+if [ -z "${RUNTIME}" ]
+then
+ COMMAND="${TIMEOUT_CMD} ${TIMEOUT} ${ENGINE}"
+else
+ COMMAND="${TIMEOUT_CMD} ${TIMEOUT} ${RUNTIME} ${ENGINE}"
+fi
if [ $# -lt 2 ]
then
rm -rf "${PATH_TO_TEST262}/test/suite/bestPractice"
rm -rf "${PATH_TO_TEST262}/test/suite/intl402"
-# TODO: Enable these tests after daylight saving calculation is fixed.
-rm -f "${PATH_TO_TEST262}/test/suite/ch15/15.9/15.9.3/S15.9.3.1_A5_T1.js"
-rm -f "${PATH_TO_TEST262}/test/suite/ch15/15.9/15.9.3/S15.9.3.1_A5_T2.js"
-rm -f "${PATH_TO_TEST262}/test/suite/ch15/15.9/15.9.3/S15.9.3.1_A5_T3.js"
-rm -f "${PATH_TO_TEST262}/test/suite/ch15/15.9/15.9.3/S15.9.3.1_A5_T4.js"
-rm -f "${PATH_TO_TEST262}/test/suite/ch15/15.9/15.9.3/S15.9.3.1_A5_T5.js"
-rm -f "${PATH_TO_TEST262}/test/suite/ch15/15.9/15.9.3/S15.9.3.1_A5_T6.js"
+echo "Starting test262 testing for ${ENGINE}. Running test262 may take several minutes."
-echo "Starting test262 testing for ${ENGINE}. Running test262 may take a several minutes."
-python2 "${PATH_TO_TEST262}"/tools/packaging/test262.py --command "${TIMEOUT_CMD} ${TIMEOUT} ${ENGINE}" \
+function progress_monitor() {
+ NUM_LINES_GOTTEN=0
+ (>&2 echo)
+ while read line
+ do
+ if [[ $((NUM_LINES_GOTTEN % 100)) == 0 ]]
+ then
+ (>&2 echo -ne "\rExecuted approx ${NUM_LINES_GOTTEN} tests...")
+ fi
+ echo "$line"
+ NUM_LINES_GOTTEN=$((NUM_LINES_GOTTEN + 1))
+ done
+ (>&2 echo)
+ (>&2 echo)
+}
+
+python2 "${PATH_TO_TEST262}"/tools/packaging/test262.py --command "${COMMAND}" \
--tests="${PATH_TO_TEST262}" --summary \
- &> "${REPORT_PATH}"
+ | progress_monitor > "${REPORT_PATH}"
+
TEST262_EXIT_CODE=$?
if [ $TEST262_EXIT_CODE -ne 0 ]
then
- echo -e "\nFailed to run test2626\n"
+ echo -e "\nFailed to run test262\n"
echo "$0: see ${REPORT_PATH} for details about failures"
exit $TEST262_EXIT_CODE
fi
TEST_FAILED=$OUTPUT_DIR/$TESTS_BASENAME.failed
TEST_PASSED=$OUTPUT_DIR/$TESTS_BASENAME.passed
+TERM_NORMAL="\033[0m"
+TERM_RED="\033[1;31m"
+TERM_GREEN="\033[1;32m"
+
+trap 'exit' SIGINT
+
VERBOSE=1
if [[ "$1" == "-q" ]]
then
if [[ "$1" =~ ^--skip-list=.* ]]
then
SKIP_LIST=${1#--skip-list=}
- SKIP_LIST=(${SKIP_LIST//,/ })
+ SKIP_LIST=${SKIP_LIST//,/ }
shift
fi
then
TESTS_DIR=$TESTS
- ( cd $TESTS; find . -name "[^N]*.js" ) | sort > $TEST_FILES
+ ( cd $TESTS; find . -name "*.js" ) | sort > $TEST_FILES
elif [ -f $TESTS ]
then
TESTS_DIR=`dirname $TESTS`
fi
# Remove the skipped tests from list
-for TEST in "${SKIP_LIST[@]}"
+for TEST in ${SKIP_LIST}
do
( sed -i -r "/$TEST/d" $TEST_FILES )
done
# Testing snapshot
SNAPSHOT_TEMP=`mktemp $(basename -s .js $test).snapshot.XXXXXXXXXX`
- cmd_line="${SNAPSHOT_TOOL#$ROOT_DIR} generate -o $SNAPSHOT_TEMP ${full_test#$ROOT_DIR}"
- $TIMEOUT_CMD $TIMEOUT $SNAPSHOT_TOOL generate -o $SNAPSHOT_TEMP $full_test &> $ENGINE_TEMP
+ $TIMEOUT_CMD $TIMEOUT $RUNTIME $SNAPSHOT_TOOL generate -o $SNAPSHOT_TEMP $full_test &> $ENGINE_TEMP
status_code=$?
+ comment=" (generate snapshot)"
if [ $status_code -eq 0 ]
then
- test $VERBOSE && echo "[$tested/$TOTAL] $cmd_line: PASS"
+ test $VERBOSE && printf "[%4d/%4d] %bPASS: %s%s%b\n" "$tested" "$TOTAL" "$TERM_GREEN" "${full_test#$ROOT_DIR}" "$comment" "$TERM_NORMAL"
- cmd_line="${ENGINE#$ROOT_DIR} $ENGINE_ARGS --exec-snapshot $SNAPSHOT_TEMP"
- $TIMEOUT_CMD $TIMEOUT $ENGINE $ENGINE_ARGS --exec-snapshot $SNAPSHOT_TEMP &> $ENGINE_TEMP
+ $TIMEOUT_CMD $TIMEOUT $RUNTIME $ENGINE $ENGINE_ARGS --exec-snapshot $SNAPSHOT_TEMP &> $ENGINE_TEMP
status_code=$?
+ comment=" (execute snapshot)"
fi
rm -f $SNAPSHOT_TEMP
else
- cmd_line="${ENGINE#$ROOT_DIR} $ENGINE_ARGS ${full_test#$ROOT_DIR}"
- $TIMEOUT_CMD $TIMEOUT $ENGINE $ENGINE_ARGS $full_test &> $ENGINE_TEMP
+ $TIMEOUT_CMD $TIMEOUT $RUNTIME $ENGINE $ENGINE_ARGS $full_test &> $ENGINE_TEMP
status_code=$?
+ comment=""
fi
if [ $status_code -ne $error_code ]
then
- echo "[$tested/$TOTAL] $cmd_line: FAIL ($status_code)"
+ printf "[%4d/%4d] %bFAIL (%d): %s%s%b\n" "$tested" "$TOTAL" "$TERM_RED" "$status_code" "${full_test#$ROOT_DIR}" "$comment" "$TERM_NORMAL"
cat $ENGINE_TEMP
echo "$status_code: $test" >> $TEST_FAILED
failed=$((failed+1))
else
- test $VERBOSE && echo "[$tested/$TOTAL] $cmd_line: $PASS"
-
+ test $VERBOSE && printf "[%4d/%4d] %b%s: %s%s%b\n" "$tested" "$TOTAL" "$TERM_GREEN" "$PASS" "${full_test#$ROOT_DIR}" "$comment" "$TERM_NORMAL"
echo "$test" >> $TEST_PASSED
passed=$((passed+1))
rm -f $ENGINE_TEMP
ratio=$(echo $passed*100/$TOTAL | bc)
+if [ $passed -eq $TOTAL ]
+then
+ success_color=$TERM_GREEN
+else
+ success_color=$TERM_RED
+fi
if [ "$IS_SNAPSHOT" == true ]
then
ENGINE_ARGS="--snapshot $ENGINE_ARGS"
fi
-echo "[summary] ${ENGINE#$ROOT_DIR} $ENGINE_ARGS ${TESTS#$ROOT_DIR}: $passed PASS, $failed FAIL, $TOTAL total, $ratio% success"
+echo -e "\n[summary] ${ENGINE#$ROOT_DIR} $ENGINE_ARGS ${TESTS#$ROOT_DIR}\n"
+echo -e "TOTAL: $TOTAL"
+echo -e "${TERM_GREEN}PASS: $passed${TERM_NORMAL}"
+echo -e "${TERM_RED}FAIL: $failed${TERM_NORMAL}\n"
+echo -e "${success_color}Success: $ratio%${TERM_NORMAL}\n"
if [ $failed -ne 0 ]
then
+++ /dev/null
-#!/bin/bash
-
-# 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.
-
-TARGET="$1" #debug.linux release.linux
-TARGET_IP="$2" # ip address of target board
-TARGET_USER="$3" # login
-TARGET_PASS="$4" # password
-
-if [ $# -lt 4 ]
-then
- echo "This script runs ./jerry/* and ./jerry-test-suite/* tests on the remote board."
- echo ""
- echo "Usage:"
- echo " 1st parameter: target to be tested: {debug.linux, release.linux}"
- echo " 2nd parameter: ip address of target board: {110.110.110.110}"
- echo " 3rd parameter: ssh login to target board: {login}"
- echo " 4th parameter: ssh password to target board: {password}"
- echo ""
- echo "Example:"
- echo " ./tools/runners/run-tests-remote.sh debug.linux 110.110.110.110 login password"
- exit 1
-fi
-
-BASE_DIR=$(dirname "$(readlink -f "$0")" )
-
-OUT_DIR="${BASE_DIR}"/../.././build/bin
-LOGS_PATH_FULL="${OUT_DIR}"/"${TARGET}"/check
-
-export SSHPASS="${TARGET_PASS}"
-
-rm -rf "${LOGS_PATH_FULL}"
-
-mkdir -p "${LOGS_PATH_FULL}"
-
-REMOTE_TMP_DIR=$(sshpass -e ssh "${TARGET_USER}"@"${TARGET_IP}" 'mktemp -d')
-REMOTE_TMP_TAR=$(sshpass -e ssh "${TARGET_USER}"@"${TARGET_IP}" 'mktemp')
-LOCAL_TMP_TAR=$(mktemp)
-
-tar -zcf "${LOCAL_TMP_TAR}" \
- "${BASE_DIR}"/../.././build/bin/"${TARGET}" \
- "${BASE_DIR}"/../.././tests/benchmarks \
- "${BASE_DIR}"/../.././tests/jerry \
- "${BASE_DIR}"/../.././tests/jerry-test-suite \
- "${BASE_DIR}"/../.././tools/runners \
- "${BASE_DIR}"/../.././tools/precommit-full-testing.sh > /dev/null 2>&1
-
-sshpass -e scp "${LOCAL_TMP_TAR}" "${TARGET_USER}"@"${TARGET_IP}":"${REMOTE_TMP_TAR}"
-
-sshpass -e ssh "${TARGET_USER}"@"${TARGET_IP}" \
- "tar -zxf \"${REMOTE_TMP_TAR}\" -C \"${REMOTE_TMP_DIR}\"; rm \"${REMOTE_TMP_TAR}\";\
- cd \"${REMOTE_TMP_DIR}\"; \
- ./tools/precommit-full-testing.sh ./build/bin \"$TARGET\" > ./build/bin/\"${TARGET}\"/check/run.log 2>&1; \
- echo \$? > ./build/bin/\"${TARGET}\"/check/IS_TEST_OK"
-
-sshpass -e scp -r "${TARGET_USER}"@"${TARGET_IP}":"${REMOTE_TMP_DIR}"/build/bin/"${TARGET}"/check/* "${LOGS_PATH_FULL}"
-sshpass -e ssh "${TARGET_USER}"@"${TARGET_IP}" "rm -rf \"${REMOTE_TMP_DIR}\""
-
-STATUS=$(cat "${LOGS_PATH_FULL}"/IS_TEST_OK)
-
-if [ "${STATUS}" == 0 ] ; then
- echo "${TARGET} testing passed."
- exit 0
-else
- echo "${TARGET} testing failed."
- echo "See logs in ${LOGS_PATH_FULL} directory for details."
- exit 1
-fi
\ No newline at end of file
+++ /dev/null
-#!/bin/bash
-
-# 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.
-
-TARGET_IP="$1"
-TARGET_USER="$2"
-TARGET_PASS="$3"
-
-if [ $# -lt 3 ]
-then
- echo "This script runs unittests on the remote board."
- echo ""
- echo "Usage:"
- echo " 1st parameter: ip address of target board: {110.110.110.110}"
- echo " 2nd parameter: ssh login to target board: {login}"
- echo " 3rd parameter: ssh password to target board: {password}"
- echo ""
- echo "Example:"
- echo " ./tools/runners/run-unittests-remote.sh 110.110.110.110 login password"
- exit 1
-fi
-
-BASE_DIR=$(dirname "$(readlink -f "$0")" )
-
-OUT_DIR="${BASE_DIR}"/../.././build/bin
-
-rm -rf "${OUT_DIR}"/unittests/check
-
-mkdir -p "${OUT_DIR}"/unittests/check
-
-export SSHPASS="${TARGET_PASS}"
-REMOTE_TMP_DIR=$(sshpass -e ssh "${TARGET_USER}"@"${TARGET_IP}" 'mktemp -d')
-
-sshpass -e scp "${BASE_DIR}"/../../tools/runners/run-unittests.sh "${TARGET_USER}"@"${TARGET_IP}":"${REMOTE_TMP_DIR}"
-sshpass -e scp -r "${OUT_DIR}"/unittests/* "${TARGET_USER}"@"${TARGET_IP}":"${REMOTE_TMP_DIR}"
-
-sshpass -e ssh "${TARGET_USER}"@"${TARGET_IP}" "mkdir -p \"${REMOTE_TMP_DIR}\"/check; \
- \"${REMOTE_TMP_DIR}\"/run-unittests.sh \"${REMOTE_TMP_DIR}\"; \
- echo \$? > \"${REMOTE_TMP_DIR}\"/check/IS_REMOTE_TEST_OK"
-
-sshpass -e scp -r "${TARGET_USER}"@$"{TARGET_IP}":"${REMOTE_TMP_DIR}"/check "${OUT_DIR}"/unittests
-
-sshpass -e ssh "${TARGET_USER}"@"${TARGET_IP}" "rm -rf \"${REMOTE_TMP_DIR}\""
-
-STATUS=$(cat "${OUT_DIR}"/unittests/check/IS_REMOTE_TEST_OK)
-
-if [ "${STATUS}" == 0 ] ; then
- echo "Unit tests run passed."
- exit 0
-else
- echo "Unit tests run failed. See ${OUT_DIR}/unittests/unit_tests_run.log for details."
- exit 1
-fi
rm -f $UNITTEST_ERROR $UNITTEST_OK
-UNITTESTS=$(ls $DIR/unit-*)
-total=$(ls $DIR/unit-* | wc -l)
+UNITTESTS=$(find $DIR -maxdepth 1 -type f -name 'unit-*')
+total=$(find $DIR -maxdepth 1 -type f -name 'unit-*' | wc -l)
if [ "$total" -eq 0 ]
then
UNITTEST_TEMP=`mktemp unittest-out.XXXXXXXXXX`
+TERM_NORMAL="\033[0m"
+TERM_RED="\033[1;31m"
+TERM_GREEN="\033[1;32m"
+
for unit_test in $UNITTESTS
do
- cmd_line="${unit_test#$ROOT_DIR}"
- $unit_test &>$UNITTEST_TEMP
+ cmd_line="$RUNTIME ${unit_test#$ROOT_DIR}"
+ $RUNTIME $unit_test &>$UNITTEST_TEMP
status_code=$?
if [ $status_code -ne 0 ]
then
- echo "[$tested/$total] $cmd_line: FAIL ($status_code)"
+ printf "[%4d/%4d] %bFAIL (%d): %s%b\n" "$tested" "$total" "$TERM_RED" "$status_code" "${unit_test#$ROOT_DIR}" "$TERM_NORMAL"
cat $UNITTEST_TEMP
echo "$status_code: $unit_test" >> $UNITTEST_ERROR
failed=$((failed+1))
else
- test $VERBOSE && echo "[$tested/$total] $cmd_line: PASS"
-
+ test $VERBOSE && printf "[%4d/%4d] %bPASS: %s%b\n" "$tested" "$total" "$TERM_GREEN" "${unit_test#$ROOT_DIR}" "$TERM_NORMAL"
echo "$unit_test" >> $UNITTEST_OK
passed=$((passed+1))
rm -f $UNITTEST_TEMP
ratio=$(echo $passed*100/$total | bc)
+if [ $passed -eq $total ]
+then
+ success_color=$TERM_GREEN
+else
+ success_color=$TERM_RED
+fi
-echo "[summary] ${DIR#$ROOT_DIR}/unit-*: $passed PASS, $failed FAIL, $total total, $ratio% success"
+echo -e "\n[summary] ${DIR#$ROOT_DIR}/unit-*\n"
+echo -e "TOTAL: $total"
+echo -e "${TERM_GREEN}PASS: $passed${TERM_NORMAL}"
+echo -e "${TERM_RED}FAIL: $failed${TERM_NORMAL}\n"
+echo -e "${success_color}Success: $ratio%${TERM_NORMAL}\n"
if [ $failed -ne 0 ]
then
BUILD_SCRIPT = path.join(TOOLS_DIR, 'build.py')
CPPCHECK_SCRIPT = path.join(TOOLS_DIR, 'check-cppcheck.sh')
-DEBUGGER_CLIENT_SCRIPT = path.join(PROJECT_DIR, 'jerry-debugger/jerry-client-ws.py')
+DEBUGGER_CLIENT_SCRIPT = path.join(PROJECT_DIR, 'jerry-debugger/jerry_client.py')
DEBUGGER_TEST_RUNNER_SCRIPT = path.join(TOOLS_DIR, 'runners/run-debugger-test.sh')
DOXYGEN_SCRIPT = path.join(TOOLS_DIR, 'check-doxygen.sh')
LICENSE_SCRIPT = path.join(TOOLS_DIR, 'check-license.py')
+++ /dev/null
-#!/bin/bash
-
-# 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.
-
-INPUT_PATH="$1"
-VERSION=$(git log -n 1 --pretty=format:"%H")
-SYSTEM=$(uname -a)
-TMP_DIR="afl-testing"
-USAGE="Usage:\n\t./tools/sort-fails.sh PATH_TO_DIR_WITH_FAILS"
-
-if [ "$#" -ne 1 ]
-then
- echo -e "${USAGE}";
- echo "Argument number mismatch...";
- exit 1;
-fi
-
-rm "$TMP_DIR" -r; mkdir "$TMP_DIR";
-
-make debug.linux VALGRIND=ON -j && echo "Build OK";
-
-for file in "$INPUT_PATH"/*;
-do
- key1=$(./build/bin/debug.linux/jerry --abort-on-fail $file 2>&1);
- key2=$(valgrind --default-suppressions=yes ./build/bin/debug.linux/jerry --abort-on-fail $file 2>&1 \
- | sed -e 's/^==*[0-9][0-9]*==*//g' \
- | sed -e 's/^ Command: .*//g');
-
- hash1=$(echo -n $key1 | md5sum);
- hash2=$(echo -n $key2 | md5sum);
-
- dir="$TMP_DIR/$hash1";
- head="$TMP_DIR/$hash1.err.md";
- body="$dir/$hash2.err.md";
-
- if [ ! -s "$dir" ]; then
- mkdir -p "$dir"; touch "$head";
- echo "###### Version: $VERSION" >> "$head";
- echo "###### System:" >> "$head";
- echo '```' >> "$head";
- echo "$SYSTEM" >> "$head";
- echo '```' >> "$head";
- echo "###### Output:" >> "$head";
- echo '```' >> "$head";
- echo "$key1" >> "$head";
- echo '```' >> "$head";
- fi
-
- if [ ! -s "$body" ]; then
- touch "$body";
- echo '###### Unique backtrace:```' >> "$body";
- echo '```' >> "$body";
- echo "$key2" >> "$body"
- echo '```' >> "$body";
- fi
-
- echo "###### Test case($file):" >> "$body";
- echo '```js' >> "$body";
- cat "$file" >> "$body";
- echo '```' >> "$body";
-
-done
-
-cd "$TMP_DIR";
-for dir in */ ; do
- for file in "$dir"/*;
- do
- cat "$file" >> "${dir%/*}.err.md"
- done
- rm $dir -r;
-done
EXT_REFERENCE_HANDLER_MD="10.EXT-REFERENCE-HANDLER.md"
EXT_REFERENCE_AUTORELEASE_MD="11.EXT-REFERENCE-AUTORELEASE.md"
EXT_REFERENCE_MODULE_MD="12.EXT-REFERENCE-MODULE.md"
+DEBUGGER_TRANSPORT_MD="13.DEBUGGER-TRANSPORT.md"
declare -A titles
titles[$EXT_REFERENCE_HANDLER_MD]="'Extension API: External Function Handlers'"
titles[$EXT_REFERENCE_AUTORELEASE_MD]="'Extension API: Autorelease Values'"
titles[$EXT_REFERENCE_MODULE_MD]="'Extension API: Module Support'"
+titles[$DEBUGGER_TRANSPORT_MD]="'Debugger Transport'"
for docfile in $docs_dir/*.md; do
docfile_base=`basename $docfile`
unset(BUILDAPIEMULTESTER CACHE)
unset(BUILD_TEST_LIB CACHE)
unset(BUILD_HOST_HELPER CACHE)
+unset(CREATE_SHARED_LIB CACHE)
TUV_BUILDTESTER ?= yes
TUV_BUILDAPIEMULTESTER ?= no
TUV_BUILDHOSTHELPER ?= no
+TUV_CREATE_SHARED_LIB ?= no
OUTPUT_ROOT := build
BUILD_FOLDER := ./$(OUTPUT_ROOT)/$(TUV_PLATFORM)/$(TUV_BUILD_TYPE)
-DCMAKE_BUILD_TYPE=$(TUV_BUILD_TYPE) \
-DTARGET_PLATFORM=$(TUV_PLATFORM) \
-DBUILDTESTER=${TUV_BUILDTESTER} \
- -DBUILD_HOST_HELPER=${TUV_BUILDHOSTHELPER}
+ -DBUILD_HOST_HELPER=${TUV_BUILDHOSTHELPER} \
+ -DCREATE_SHARED_LIB=${TUV_CREATE_SHARED_LIB} \
+ -DTUV_FEATURE_PROCESS=ON
ifneq ($(TUV_BOARD),unknown)
CMAKE_DEFINES += -DTARGET_BOARD=${TUV_BOARD}
--- /dev/null
+# 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.
+
+set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSTEM_PROCESSOR i686)
+
+if(NOT DEFINED CMAKE_C_COMPILER)
+ set(CMAKE_C_COMPILER CL.exe)
+endif()
${INCLUDE_ROOT}/uv-errno.h
${INCLUDE_ROOT}/uv-threadpool.h
${INCLUDE_ROOT}/uv-version.h
-# ${SOURCE_ROOT}/fs-poll.c
+ ${SOURCE_ROOT}/fs-poll.c
${SOURCE_ROOT}/heap-inl.h
${SOURCE_ROOT}/inet.c
${SOURCE_ROOT}/queue.h
LIBRARY_OUTPUT_DIRECTORY "${LIB_OUT}"
RUNTIME_OUTPUT_DIRECTORY "${BIN_OUT}")
+# build tuv shared library
+if (DEFINED CREATE_SHARED_LIB AND CREATE_SHARED_LIB STREQUAL "yes")
+ set(TARGETSHAREDLIBNAME tuv_shared)
+ add_library(${TARGETSHAREDLIBNAME} SHARED ${LIB_TUV_SRCFILES})
+ target_include_directories(${TARGETSHAREDLIBNAME} SYSTEM PRIVATE ${TARGET_INC})
+ target_include_directories(${TARGETSHAREDLIBNAME} PUBLIC ${LIB_TUV_INCDIRS})
+ set_target_properties(${TARGETSHAREDLIBNAME} PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${LIB_OUT}"
+ COMPILE_FLAGS -fPIC
+ OUTPUT_NAME tuv)
+endif()
+
if(DEFINED COPY_TARGET_LIB)
add_custom_command(TARGET ${TARGETLIBNAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${TARGETLIBNAME}>
--- /dev/null
+# Copyright 2015 Samsung Electronics Co., Ltd.
+#
+# 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.
+
+# linux common
+include("cmake/option/option_windows_common.cmake")
+
+# i686 specific
+
${UNIX_PATH}/internal.h
${UNIX_PATH}/loop.c
${UNIX_PATH}/loop-watcher.c
-# ${UNIX_PATH}/pipe.c
${UNIX_PATH}/poll.c
${UNIX_PATH}/process.c
# ${UNIX_PATH}/proctitle.c
-# ${UNIX_PATH}/signal.c
${UNIX_PATH}/spinlock.h
${UNIX_PATH}/stream.c
${UNIX_PATH}/tcp.c
"${TEST_ROOT}/test_active.c"
"${TEST_ROOT}/test_walk_handles.c"
"${TEST_ROOT}/test_async.c"
- )
+ )
+
+# { TUV_CHANGES@20180803:
+# Made signal build time configurable }
+if(TUV_FEATURE_PROCESS)
+ set(TUV_FEATURE_PIPE ON)
+ set(TUV_FEATURE_SIGNAL ON)
+ set(FLAGS_COMMON "${FLAGS_COMMON}" "-DTUV_FEATURE_PROCESS=1")
+ set(TEST_UNITFILES "${TEST_UNITFILES}"
+ "${TEST_ROOT}/test_ipc.c"
+ "${TEST_ROOT}/test_spawn.c")
+endif()
+
+
+# { TUV_CHANGES@20180724:
+# Made pipe build time configurable }
+if(TUV_FEATURE_PIPE)
+ set(PLATFORM_SRCFILES "${PLATFORM_SRCFILES}"
+ ${UNIX_PATH}/pipe.c)
+ set(FLAGS_COMMON "${FLAGS_COMMON}" "-DTUV_FEATURE_PIPE=1")
+ set(TEST_UNITFILES "${TEST_UNITFILES}"
+ "${TEST_ROOT}/test_pipe_bind_error.c"
+ "${TEST_ROOT}/test_pipe_close_stdout_read_stdin.c"
+ "${TEST_ROOT}/test_pipe_connect_error.c"
+ "${TEST_ROOT}/test_pipe_connect_multiple.c"
+ "${TEST_ROOT}/test_pipe_connect_prepare.c"
+ "${TEST_ROOT}/test_pipe_getsockname.c"
+ "${TEST_ROOT}/test_pipe_pending_instances.c"
+ "${TEST_ROOT}/test_pipe_sendmsg.c"
+ "${TEST_ROOT}/test_pipe_server_close.c"
+ "${TEST_ROOT}/test_pipe_set_non_blocking.c"
+ )
+endif()
+
+# { TUV_CHANGES@20180723:
+# Made signal build time configurable }
+if(TUV_FEATURE_SIGNAL)
+ set(PLATFORM_SRCFILES "${PLATFORM_SRCFILES}"
+ ${UNIX_PATH}/signal.c)
+ set(FLAGS_COMMON "${FLAGS_COMMON}" "-DTUV_FEATURE_SIGNAL=1")
+ set(TEST_UNITFILES "${TEST_UNITFILES}" "${TEST_ROOT}/test_signal.c")
+endif()
# configuration values
set(CONFIG_FILESYSTEM 1)
--- /dev/null
+# Copyright 2015-2017 Samsung Electronics Co., Ltd.
+#
+# 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_C_FLAGS_DEBUG "-O0 -g -DDEBUG")
+#set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG")
+
+# unix common source files
+set(WIN_PATH "${SOURCE_ROOT}/win")
+
+# test include
+set(TUV_TEST_INCDIRS "${TEST_ROOT}")
+
+#
+# { TUV_CHANGES@20161129:
+# It corresponds to uv.gyp's section "Windows" }
+#
+set(PLATFORM_SRCFILES
+ ${INCLUDE_ROOT}/uv-win.h
+ ${WIN_PATH}/async.c
+ ${WIN_PATH}/atomicops-inl.h
+ ${WIN_PATH}/core.c
+ ${WIN_PATH}/detect-wakeup.c
+ ${WIN_PATH}/dl.c
+ ${WIN_PATH}/error.c
+ ${WIN_PATH}/fs.c
+ ${WIN_PATH}/fs-event.c
+ ${WIN_PATH}/getaddrinfo.c
+ ${WIN_PATH}/getnameinfo.c
+ ${WIN_PATH}/handle.c
+ ${WIN_PATH}/handle-inl.h
+ ${WIN_PATH}/internal.h
+ ${WIN_PATH}/loop-watcher.c
+ ${WIN_PATH}/pipe.c
+ ${WIN_PATH}/thread.c
+ ${WIN_PATH}/poll.c
+ ${WIN_PATH}/process.c
+ ${WIN_PATH}/process-stdio.c
+ ${WIN_PATH}/req.c
+ ${WIN_PATH}/req-inl.h
+ ${WIN_PATH}/signal.c
+ ${WIN_PATH}/snprintf.c
+ ${WIN_PATH}/stream.c
+ ${WIN_PATH}/stream-inl.h
+ ${WIN_PATH}/tcp.c
+ ${WIN_PATH}/tty.c
+ ${WIN_PATH}/timer.c
+ ${WIN_PATH}/udp.c
+ ${WIN_PATH}/util.c
+ ${WIN_PATH}/winapi.c
+ ${WIN_PATH}/winapi.h
+ ${WIN_PATH}/winsock.c
+ ${WIN_PATH}/winsock.h
+ )
+
+set(TEST_MAINFILE "${TEST_ROOT}/runner_main.c")
+
+set(TEST_UNITFILES
+ ${TEST_ROOT}/test_idle.c
+ ${TEST_ROOT}/test_timer.c
+ ${TEST_ROOT}/test_timer_again.c
+ ${TEST_ROOT}/test_fs.c
+ ${TEST_ROOT}/test_cwd.c
+ ${TEST_ROOT}/test_error.c
+ ${TEST_ROOT}/test_tcp_open.c
+ ${TEST_ROOT}/test_shutdown_eof.c
+ ${TEST_ROOT}/echo_server.c
+ ${TEST_ROOT}/test_getaddrinfo.c
+ ${TEST_ROOT}/test_threadpool.c
+ ${TEST_ROOT}/test_condvar.c
+ ${TEST_ROOT}/test_active.c
+ ${TEST_ROOT}/test_walk_handles.c
+ ${TEST_ROOT}/test_async.c
+ )
+
+# configuration values
+set(CONFIG_FILESYSTEM 1)
#define SIGPROF 27
#define TCP_NODELAY 1
-//-----------------------------------------------------------------------------
-// TUV_CHANGES@20171130:
-// Not used. I believe we can remove those.
-#define _SC_CLK_TCK 0x0006
-#define _SC_NPROCESSORS_ONLN 0x0061
-#define CLOCK_MONOTONIC 1
+#ifndef _SC_CLK_TCK
+#define _SC_CLK_TCK 0x0006
+#endif
+
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC 1
+#endif
//-----------------------------------------------------------------------------
// date time extension
/* Expand this list if necessary. */
#define UV_ERRNO_MAP(XX) \
+ XX(E2BIG, "argument list too long") \
+ XX(EACCES, "permission denied") \
XX(EADDRINUSE, "address already in use") \
+ XX(EADDRNOTAVAIL, "address not available") \
XX(EAFNOSUPPORT, "address family not supported") \
XX(EAGAIN, "resource temporarily unavailable") \
XX(EAI_ADDRFAMILY, "address family not supported") \
XX(EAI_SERVICE, "service not available for socket type") \
XX(EAI_SOCKTYPE, "socket type not supported") \
XX(EALREADY, "connection already in progress") \
+ XX(EBADF, "bad file descriptor") \
XX(EBUSY, "resource busy or locked") \
XX(ECANCELED, "operation canceled") \
+ XX(ECHARSET, "invalid Unicode character") \
+ XX(ECONNABORTED, "software caused connection abort") \
XX(ECONNREFUSED, "connection refused") \
+ XX(ECONNRESET, "connection reset by peer") \
+ XX(EEXIST, "file already exists") \
+ XX(EFAULT, "bad address in system call argument") \
+ XX(EHOSTUNREACH, "host is unreachable") \
XX(EINVAL, "invalid argument") \
XX(EIO, "i/o error") \
+ XX(EISCONN, "socket is already connected") \
+ XX(EISDIR, "illegal operation on a directory") \
XX(ELOOP, "too many symbolic links encountered") \
+ XX(EMFILE, "too many open files") \
+ XX(EMSGSIZE, "message too long") \
XX(ENAMETOOLONG, "name too long") \
+ XX(ENETUNREACH, "network is unreachable") \
XX(ENOBUFS, "no buffer space available") \
XX(ENOENT, "no such file or directory") \
XX(ENOMEM, "not enough memory") \
XX(ENOSPC, "no space left on device") \
+ XX(ENOSYS, "function not implemented") \
+ XX(ENOTCONN, "socket is not connected") \
XX(ENOTDIR, "not a directory") \
+ XX(ENOTEMPTY, "directory not empty") \
+ XX(ENOTSOCK, "socket operation on non-socket") \
+ XX(ENOTSUP, "operation not supported on socket") \
XX(EPERM, "operation not permitted") \
+ XX(EPIPE, "broken pipe") \
+ XX(ESRCH, "no such process") \
+ XX(EPROTONOSUPPORT, "protocol not supported") \
+ XX(EROFS, "read-only file system") \
XX(ETIMEDOUT, "connection timed out") \
+ XX(EXDEV, "cross-device link not permitted") \
XX(EOF, "end of file") \
+ XX(UNKNOWN, "unknown error") \
#define UV_HANDLE_TYPE_MAP(XX) \
XX(ASYNC, async) \
handle->close_cb = close_cb;
switch (handle->type) {
+#ifdef TUV_FEATURE_PIPE
+ case UV_NAMED_PIPE:
+ uv__pipe_close((uv_pipe_t*)handle);
+ break;
+#endif
+
case UV_TTY:
uv__stream_close((uv_stream_t*)handle);
break;
uv__timer_close((uv_timer_t*)handle);
break;
+// { TUV_CHANGES@20180803:
+// Made signal build time configurable }
+#if TUV_FEATURE_PROCESS
+ case UV_PROCESS:
+ uv__process_close((uv_process_t*)handle);
+ break;
+#endif
+
case UV_POLL:
uv__poll_close((uv_poll_t*)handle);
break;
+#ifdef TUV_FEATURE_SIGNAL
+ case UV_SIGNAL:
+ uv__signal_close((uv_signal_t*) handle);
+ /* Signal handles may not be closed immediately. The signal code will */
+ /* itself close uv__make_close_pending whenever appropriate. */
+ return;
+#endif
+
default:
assert(0);
}
case UV_IDLE:
case UV_ASYNC:
case UV_TIMER:
- // case UV_PROCESS:
+ case UV_PROCESS:
// case UV_FS_EVENT:
// case UV_FS_POLL:
case UV_POLL:
- // case UV_SIGNAL:
+ case UV_SIGNAL:
break;
case UV_NAMED_PIPE:
cnt++;
}
- /* Allcoate memory for the directory entries. */
+ /* Allocate memory for the directory entries. */
dents = (uv__dirent_t**) malloc(sizeof (uv__dirent_t*) * cnt);
if (cnt > 0 && dents == NULL) {
int err;
req = container_of(w, uv_getaddrinfo_t, work_req);
-#if defined(__NUTTX__) || defined(__TIZENRT__)
+#if defined(__NUTTX__)
err = 0;
#else
/* Only IPv4 is supported now. (Not support IPv6.)*/
void uv_freeaddrinfo(struct addrinfo* ai) {
-#if !defined(__NUTTX__) && !defined(__TIZENRT__)
+#if !defined(__NUTTX__)
if (ai)
freeaddrinfo(ai);
#endif
return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
}
+
+// { TUV_CHANGES@20180803:
+// Made signal build time configurable }
+#if TUV_FEATURE_PROCESS
+int uv_exepath(char* buffer, size_t* size) {
+ ssize_t n;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ n = *size - 1;
+ if (n > 0)
+ n = readlink("/proc/self/exe", buffer, n);
+
+ if (n == -1)
+ return -errno;
+
+ buffer[n] = '\0';
+ *size = n;
+
+ return 0;
+}
+#endif /* TUV_FEATURE_PROCESS */
void* saved_data;
int err;
+#ifdef TUV_FEATURE_SIGNAL
+ uv__signal_global_once_init();
+#endif
+
saved_data = loop->data;
memset(loop, 0, sizeof(*loop));
loop->data = saved_data;
loop->closing_handles = NULL;
uv__update_time(loop);
uv__async_init(&loop->async_watcher);
+#ifdef TUV_FEATURE_SIGNAL
+ loop->signal_pipefd[0] = -1;
+ loop->signal_pipefd[1] = -1;
+#endif
loop->backend_fd = -1;
loop->emfile_fd = -1;
if (err)
return err;
+#ifdef TUV_FEATURE_SIGNAL
+ err = uv_signal_init(loop, &loop->child_watcher);
+ if (err)
+ goto fail_signal_init;
+#endif
+
uv__handle_unref(&loop->child_watcher);
loop->child_watcher.flags |= UV__HANDLE_INTERNAL;
QUEUE_INIT(&loop->process_handles);
uv_rwlock_destroy(&loop->cloexec_lock);
fail_rwlock_init:
+#ifdef TUV_FEATURE_SIGNAL
+ uv__signal_loop_cleanup(loop);
+#endif
+
+fail_signal_init:
uv__platform_loop_delete(loop);
return err;
void uv__loop_close(uv_loop_t* loop) {
+#ifdef TUV_FEATURE_SIGNAL
+ uv__signal_loop_cleanup(loop);
+#endif
uv__platform_loop_delete(loop);
uv__async_stop(loop, &loop->async_watcher);
#include <fcntl.h>
#include <poll.h>
+#if !defined(__NUTTX__) && !defined(__TIZENRT__)
+
#if defined(__APPLE__) && !TARGET_OS_IPHONE
# include <crt_externs.h>
+# define environ (*_NSGetEnviron())
+#else
+extern char **environ;
#endif
#if defined(__linux__) || defined(__GLIBC__)
# include <grp.h>
#endif
+// { TUV_CHANGES@20180803:
+// Made signal build time configurable }
+#if TUV_FEATURE_PROCESS
+static void uv__chld(uv_signal_t* handle, int signum) {
+ uv_process_t* process;
+ uv_loop_t* loop;
+ int exit_status;
+ int term_signal;
+ int status;
+ pid_t pid;
+ QUEUE pending;
+ QUEUE* q;
+ QUEUE* h;
+
+ assert(signum == SIGCHLD);
+
+ QUEUE_INIT(&pending);
+ loop = handle->loop;
+
+ h = &loop->process_handles;
+ q = QUEUE_HEAD(h);
+ while (q != h) {
+ process = QUEUE_DATA(q, uv_process_t, queue);
+ q = QUEUE_NEXT(q);
+
+ do
+ pid = waitpid(process->pid, &status, WNOHANG);
+ while (pid == -1 && errno == EINTR);
+
+ if (pid == 0)
+ continue;
+
+ if (pid == -1) {
+ if (errno != ECHILD)
+ abort();
+ continue;
+ }
+
+ process->status = status;
+ QUEUE_REMOVE(&process->queue);
+ QUEUE_INSERT_TAIL(&pending, &process->queue);
+ }
+
+ h = &pending;
+ q = QUEUE_HEAD(h);
+ while (q != h) {
+ process = QUEUE_DATA(q, uv_process_t, queue);
+ q = QUEUE_NEXT(q);
+
+ QUEUE_REMOVE(&process->queue);
+ QUEUE_INIT(&process->queue);
+ uv__handle_stop(process);
+
+ if (process->exit_cb == NULL)
+ continue;
+
+ exit_status = 0;
+ if (WIFEXITED(process->status))
+ exit_status = WEXITSTATUS(process->status);
+
+ term_signal = 0;
+ if (WIFSIGNALED(process->status))
+ term_signal = WTERMSIG(process->status);
+
+ process->exit_cb(process, exit_status, term_signal);
+ }
+ assert(QUEUE_EMPTY(&pending));
+}
+
+
+int uv__make_socketpair(int fds[2], int flags) {
+#if defined(__linux__)
+ static int no_cloexec;
+
+ if (no_cloexec)
+ goto skip;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0)
+ return 0;
+
+ /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported.
+ * Anything else is a genuine error.
+ */
+ if (errno != EINVAL)
+ return -errno;
+
+ no_cloexec = 1;
+
+skip:
+#endif
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
+ return -errno;
+
+ uv__cloexec(fds[0], 1);
+ uv__cloexec(fds[1], 1);
+
+ if (flags & UV__F_NONBLOCK) {
+ uv__nonblock(fds[0], 1);
+ uv__nonblock(fds[1], 1);
+ }
+
+ return 0;
+}
+#endif /* TUV_FEATURE_PROCESS */
int uv__make_pipe(int fds[2], int flags) {
#if defined(__linux__)
return 0;
}
+
+
+// { TUV_CHANGES@20180803:
+// Made signal build time configurable }
+#if TUV_FEATURE_PROCESS
+/*
+ * Used for initializing stdio streams like options.stdin_stream. Returns
+ * zero on success. See also the cleanup section in uv_spawn().
+ */
+static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
+ int mask;
+ int fd;
+
+ mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
+
+ switch (container->flags & mask) {
+ case UV_IGNORE:
+ return 0;
+
+ case UV_CREATE_PIPE:
+ assert(container->data.stream != NULL);
+ if (container->data.stream->type != UV_NAMED_PIPE)
+ return -EINVAL;
+ else
+ return uv__make_socketpair(fds, 0);
+
+ case UV_INHERIT_FD:
+ case UV_INHERIT_STREAM:
+ if (container->flags & UV_INHERIT_FD)
+ fd = container->data.fd;
+ else
+ fd = uv__stream_fd(container->data.stream);
+
+ if (fd == -1)
+ return -EINVAL;
+
+ fds[1] = fd;
+ return 0;
+
+ default:
+ assert(0 && "Unexpected flags");
+ return -EINVAL;
+ }
+}
+
+
+static int uv__process_open_stream(uv_stdio_container_t* container,
+ int pipefds[2],
+ int writable) {
+ int flags;
+ int err;
+
+ if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0)
+ return 0;
+
+ err = uv__close(pipefds[1]);
+ if (err != 0)
+ abort();
+
+ pipefds[1] = -1;
+ uv__nonblock(pipefds[0], 1);
+
+ if (container->data.stream->type == UV_NAMED_PIPE &&
+ ((uv_pipe_t*)container->data.stream)->ipc)
+ flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE;
+ else if (writable)
+ flags = UV_STREAM_WRITABLE;
+ else
+ flags = UV_STREAM_READABLE;
+
+ return uv__stream_open(container->data.stream, pipefds[0], flags);
+}
+
+
+static void uv__process_close_stream(uv_stdio_container_t* container) {
+ if (!(container->flags & UV_CREATE_PIPE)) return;
+ uv__stream_close((uv_stream_t*)container->data.stream);
+}
+
+
+static void uv__write_int(int fd, int val) {
+ ssize_t n;
+
+ do
+ n = write(fd, &val, sizeof(val));
+ while (n == -1 && errno == EINTR);
+
+ if (n == -1 && errno == EPIPE)
+ return; /* parent process has quit */
+
+ assert(n == sizeof(val));
+}
+
+
+#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
+/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
+ * avoided. Since this isn't called on those targets, the function
+ * doesn't even need to be defined for them.
+ */
+static void uv__process_child_init(const uv_process_options_t* options,
+ int stdio_count,
+ int (*pipes)[2],
+ int error_fd) {
+ int close_fd;
+ int use_fd;
+ int fd;
+
+ if (options->flags & UV_PROCESS_DETACHED)
+ setsid();
+
+ /* First duplicate low numbered fds, since it's not safe to duplicate them,
+ * they could get replaced. Example: swapping stdout and stderr; without
+ * this fd 2 (stderr) would be duplicated into fd 1, thus making both
+ * stdout and stderr go to the same fd, which was not the intention. */
+ for (fd = 0; fd < stdio_count; fd++) {
+ use_fd = pipes[fd][1];
+ if (use_fd < 0 || use_fd >= fd)
+ continue;
+ pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
+ if (pipes[fd][1] == -1) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+ }
+
+ for (fd = 0; fd < stdio_count; fd++) {
+ close_fd = pipes[fd][0];
+ use_fd = pipes[fd][1];
+
+ if (use_fd < 0) {
+ if (fd >= 3)
+ continue;
+ else {
+ /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
+ * set
+ */
+ use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
+ close_fd = use_fd;
+
+ if (use_fd == -1) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+ }
+ }
+
+ if (fd == use_fd)
+ uv__cloexec(use_fd, 0);
+ else
+ fd = dup2(use_fd, fd);
+
+ if (fd == -1) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if (fd <= 2)
+ uv__nonblock(fd, 0);
+
+ if (close_fd >= stdio_count)
+ uv__close(close_fd);
+ }
+
+ for (fd = 0; fd < stdio_count; fd++) {
+ use_fd = pipes[fd][1];
+
+ if (use_fd >= stdio_count)
+ uv__close(use_fd);
+ }
+
+ if (options->cwd != NULL && chdir(options->cwd)) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
+ /* When dropping privileges from root, the `setgroups` call will
+ * remove any extraneous groups. If we don't call this, then
+ * even though our uid has dropped, we may still have groups
+ * that enable us to do super-user things. This will fail if we
+ * aren't root, so don't bother checking the return value, this
+ * is just done as an optimistic privilege dropping function.
+ */
+ SAVE_ERRNO(setgroups(0, NULL));
+ }
+
+ if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if (options->env != NULL) {
+ environ = options->env;
+ }
+
+ execvp(options->file, options->args);
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+}
+#endif
+
+
+int uv_spawn(uv_loop_t* loop,
+ uv_process_t* process,
+ const uv_process_options_t* options) {
+#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
+ /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
+ return -ENOSYS;
+#else
+ int signal_pipe[2] = { -1, -1 };
+ int (*pipes)[2];
+ int stdio_count;
+ ssize_t r;
+ pid_t pid;
+ int err;
+ int exec_errorno;
+ int i;
+ int status;
+
+ assert(options->file != NULL);
+ assert(!(options->flags & ~(UV_PROCESS_DETACHED |
+ UV_PROCESS_SETGID |
+ UV_PROCESS_SETUID |
+ UV_PROCESS_WINDOWS_HIDE |
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
+
+ uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
+ QUEUE_INIT(&process->queue);
+
+ stdio_count = options->stdio_count;
+ if (stdio_count < 3)
+ stdio_count = 3;
+
+ err = -ENOMEM;
+ pipes = uv__malloc(stdio_count * sizeof(*pipes));
+ if (pipes == NULL)
+ goto error;
+
+ for (i = 0; i < stdio_count; i++) {
+ pipes[i][0] = -1;
+ pipes[i][1] = -1;
+ }
+
+ for (i = 0; i < options->stdio_count; i++) {
+ err = uv__process_init_stdio(options->stdio + i, pipes[i]);
+ if (err)
+ goto error;
+ }
+
+ /* This pipe is used by the parent to wait until
+ * the child has called `execve()`. We need this
+ * to avoid the following race condition:
+ *
+ * if ((pid = fork()) > 0) {
+ * kill(pid, SIGTERM);
+ * }
+ * else if (pid == 0) {
+ * execve("/bin/cat", argp, envp);
+ * }
+ *
+ * The parent sends a signal immediately after forking.
+ * Since the child may not have called `execve()` yet,
+ * there is no telling what process receives the signal,
+ * our fork or /bin/cat.
+ *
+ * To avoid ambiguity, we create a pipe with both ends
+ * marked close-on-exec. Then, after the call to `fork()`,
+ * the parent polls the read end until it EOFs or errors with EPIPE.
+ */
+ err = uv__make_pipe(signal_pipe, 0);
+ if (err)
+ goto error;
+
+ uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
+
+ /* Acquire write lock to prevent opening new fds in worker threads */
+ uv_rwlock_wrlock(&loop->cloexec_lock);
+ pid = fork();
+
+ if (pid == -1) {
+ err = -errno;
+ uv_rwlock_wrunlock(&loop->cloexec_lock);
+ uv__close(signal_pipe[0]);
+ uv__close(signal_pipe[1]);
+ goto error;
+ }
+
+ if (pid == 0) {
+ uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
+ abort();
+ }
+
+ /* Release lock in parent process */
+ uv_rwlock_wrunlock(&loop->cloexec_lock);
+ uv__close(signal_pipe[1]);
+
+ process->status = 0;
+ exec_errorno = 0;
+ do
+ r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
+ while (r == -1 && errno == EINTR);
+
+ if (r == 0)
+ ; /* okay, EOF */
+ else if (r == sizeof(exec_errorno)) {
+ do
+ err = waitpid(pid, &status, 0); /* okay, read errorno */
+ while (err == -1 && errno == EINTR);
+ assert(err == pid);
+ } else if (r == -1 && errno == EPIPE) {
+ do
+ err = waitpid(pid, &status, 0); /* okay, got EPIPE */
+ while (err == -1 && errno == EINTR);
+ assert(err == pid);
+ } else
+ abort();
+
+ uv__close_nocheckstdio(signal_pipe[0]);
+
+ for (i = 0; i < options->stdio_count; i++) {
+ err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0);
+ if (err == 0)
+ continue;
+
+ while (i--)
+ uv__process_close_stream(options->stdio + i);
+
+ goto error;
+ }
+
+ /* Only activate this handle if exec() happened successfully */
+ if (exec_errorno == 0) {
+ QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
+ uv__handle_start(process);
+ }
+
+ process->pid = pid;
+ process->exit_cb = options->exit_cb;
+
+ uv__free(pipes);
+ return exec_errorno;
+
+error:
+ if (pipes != NULL) {
+ for (i = 0; i < stdio_count; i++) {
+ if (i < options->stdio_count)
+ if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
+ continue;
+ if (pipes[i][0] != -1)
+ uv__close_nocheckstdio(pipes[i][0]);
+ if (pipes[i][1] != -1)
+ uv__close_nocheckstdio(pipes[i][1]);
+ }
+ uv__free(pipes);
+ }
+
+ return err;
+#endif
+}
+
+
+int uv_process_kill(uv_process_t* process, int signum) {
+ return uv_kill(process->pid, signum);
+}
+
+
+int uv_kill(int pid, int signum) {
+ if (kill(pid, signum))
+ return -errno;
+ else
+ return 0;
+}
+
+
+void uv__process_close(uv_process_t* handle) {
+ QUEUE_REMOVE(&handle->queue);
+ uv__handle_stop(handle);
+ if (QUEUE_EMPTY(&handle->loop->process_handles))
+ uv_signal_stop(&handle->loop->child_watcher);
+}
+
+#endif /* TUV_FEATURE_PROCESS */
+
+#else /* defined(__NUTTX__) || defined(__TIZENRT__) */
+
+int uv__make_pipe(int fds[2], int flags) {
+ if (pipe(fds))
+ return -errno;
+
+ uv__cloexec(fds[0], 1);
+ uv__cloexec(fds[1], 1);
+
+ if (flags & UV__F_NONBLOCK) {
+ uv__nonblock(fds[0], 1);
+ uv__nonblock(fds[1], 1);
+ }
+
+ return 0;
+}
+
+#endif /* !defined(__NUTTX__) && !defined(__TIZENRT__) */
return -EAGAIN;
switch (client->type) {
+#ifdef TUV_FEATURE_PIPE
case UV_NAMED_PIPE:
+#endif
case UV_TCP:
err = uv__stream_open(client,
server->accepted_fd,
err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
break;
+#ifdef TUV_FEATURE_PIPE
+ case UV_NAMED_PIPE:
+ err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
+ break;
+#endif
+
default:
err = -EINVAL;
}
assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT));
}
+
+#ifdef TUV_FEATURE_PIPE
+int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
+ /* Don't need to check the file descriptor, uv__nonblock()
+ * will fail with EBADF if it's not valid.
+ */
+ return uv__nonblock(uv__stream_fd(handle), !blocking);
+}
+#endif
abort();
return -EINVAL; /* Satisfy the compiler. */
}
+
+
+#ifdef TUV_FEATURE_PIPE
+int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
+ return -pthread_barrier_init(barrier, NULL, count);
+}
+
+
+void uv_barrier_destroy(uv_barrier_t* barrier) {
+ if (pthread_barrier_destroy(barrier))
+ abort();
+}
+
+
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int r = pthread_barrier_wait(barrier);
+ if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ abort();
+ return r == PTHREAD_BARRIER_SERIAL_THREAD;
+}
+#endif
addrlen = sizeof *addr;
break;
}
+#if !defined(__TIZENRT__) || defined(CONFIG_NET_IPv6)
case AF_INET6:
{
struct sockaddr_in6* addr = (void*)&taddr;
addrlen = sizeof *addr;
break;
}
+#endif
default:
assert(0 && "unsupported address family");
abort();
#include <stdio.h>
#include <stdlib.h> /* malloc */
#include <string.h> /* memset */
-#include <unistd.h> /* usleep */
#if defined(_WIN32)
# include <malloc.h> /* malloc */
#else
+# include <unistd.h> /* usleep */
# include <net/if.h> /* if_nametoindex */
#endif
free,
};
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(_WIN32) || defined(TUV_FEATURE_PIPE)
char* uv__strdup(const char* s) {
size_t len = strlen(s) + 1;
char* m = uv__malloc(len);
}
+void uv_stop(uv_loop_t* loop) {
+ loop->stop_flag = 1;
+}
+
+
uint64_t uv_now(const uv_loop_t* loop) {
return loop->time;
}
/* Pause the calling thread for a number of milliseconds. */
void uv_sleep(int msec) {
+#ifdef _WIN32
+ Sleep(msec);
+#else
usleep(msec * 1000);
+#endif
}
/* Allocator prototypes */
void *uv__calloc(size_t count, size_t size);
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(_WIN32) || defined(TUV_FEATURE_PIPE)
char *uv__strdup(const char* s);
#endif
void* uv__malloc(size_t size);
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "atomicops-inl.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ !handle->async_sent) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
+ uv_req_t* req;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_ASYNC);
+ handle->async_sent = 0;
+ handle->async_cb = async_cb;
+
+ req = &handle->async_req;
+ uv_req_init(loop, req);
+ req->type = UV_WAKEUP;
+ req->data = handle;
+
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+int tuv_async_deinit(uv_loop_t* loop, uv_async_t* handle) {
+ /* No operation required */
+ return 0;
+}
+
+void uv_async_close(uv_loop_t* loop, uv_async_t* handle) {
+ if (!((uv_async_t*)handle)->async_sent) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+
+ uv__handle_closing(handle);
+}
+
+
+int uv_async_send(uv_async_t* handle) {
+ uv_loop_t* loop = handle->loop;
+
+ if (handle->type != UV_ASYNC) {
+ /* Can't set errno because that's not thread-safe. */
+ return -1;
+ }
+
+ /* The user should make sure never to call uv_async_send to a closing */
+ /* or closed handle. */
+ assert(!(handle->flags & UV__HANDLE_CLOSING));
+
+ if (!uv__atomic_exchange_set(&handle->async_sent)) {
+ POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
+ }
+
+ return 0;
+}
+
+
+void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
+ uv_req_t* req) {
+ assert(handle->type == UV_ASYNC);
+ assert(req->type == UV_WAKEUP);
+
+ handle->async_sent = 0;
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ } else if (handle->async_cb != NULL) {
+ handle->async_cb(handle);
+ }
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef UV_WIN_ATOMICOPS_INL_H_
+#define UV_WIN_ATOMICOPS_INL_H_
+
+#include "uv.h"
+
+
+/* Atomic set operation on char */
+#ifdef _MSC_VER /* MSVC */
+
+/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */
+/* efficient than InterlockedExchange, but InterlockedExchange8 does not */
+/* exist, and interlocked operations on larger targets might require the */
+/* target to be aligned. */
+#pragma intrinsic(_InterlockedOr8)
+
+static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) {
+ return _InterlockedOr8(target, 1);
+}
+
+#else /* GCC */
+
+/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
+static inline char uv__atomic_exchange_set(char volatile* target) {
+ const char one = 1;
+ char old_value;
+ __asm__ __volatile__ ("lock xchgb %0, %1\n\t"
+ : "=r"(old_value), "=m"(*target)
+ : "0"(one), "m"(*target)
+ : "memory");
+ return old_value;
+}
+
+#endif
+
+#endif /* UV_WIN_ATOMICOPS_INL_H_ */
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
+#include <crtdbg.h>
+#endif
+
+#include "uv.h"
+#include "internal.h"
+#include "queue.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+/* uv_once initialization guards */
+static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
+
+
+#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
+/* Our crt debug report handler allows us to temporarily disable asserts
+ * just for the current thread.
+ */
+
+UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE;
+
+static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
+ if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
+ return FALSE;
+
+ if (ret_val) {
+ /* Set ret_val to 0 to continue with normal execution.
+ * Set ret_val to 1 to trigger a breakpoint.
+ */
+
+ if(IsDebuggerPresent())
+ *ret_val = 1;
+ else
+ *ret_val = 0;
+ }
+
+ /* Don't call _CrtDbgReport. */
+ return TRUE;
+}
+#else
+UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE;
+#endif
+
+
+#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
+static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
+ const wchar_t* function, const wchar_t * file, unsigned int line,
+ uintptr_t reserved) {
+ /* No-op. */
+}
+#endif
+
+static uv_loop_t** uv__loops;
+static int uv__loops_size;
+static int uv__loops_capacity;
+#define UV__LOOPS_CHUNK_SIZE 8
+static uv_mutex_t uv__loops_lock;
+
+static void uv__loops_init() {
+ uv_mutex_init(&uv__loops_lock);
+ uv__loops = uv__calloc(UV__LOOPS_CHUNK_SIZE, sizeof(uv_loop_t*));
+ if (!uv__loops)
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ uv__loops_size = 0;
+ uv__loops_capacity = UV__LOOPS_CHUNK_SIZE;
+}
+
+static int uv__loops_add(uv_loop_t* loop) {
+ uv_loop_t** new_loops;
+ int new_capacity, i;
+
+ uv_mutex_lock(&uv__loops_lock);
+
+ if (uv__loops_size == uv__loops_capacity) {
+ new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE;
+ new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity);
+ if (!new_loops)
+ goto failed_loops_realloc;
+ uv__loops = new_loops;
+ for (i = uv__loops_capacity; i < new_capacity; ++i)
+ uv__loops[i] = NULL;
+ uv__loops_capacity = new_capacity;
+ }
+ uv__loops[uv__loops_size] = loop;
+ ++uv__loops_size;
+
+ uv_mutex_unlock(&uv__loops_lock);
+ return 0;
+
+failed_loops_realloc:
+ uv_mutex_unlock(&uv__loops_lock);
+ return ERROR_OUTOFMEMORY;
+}
+
+static void uv__loops_remove(uv_loop_t* loop) {
+ int loop_index;
+ int smaller_capacity;
+ uv_loop_t** new_loops;
+
+ uv_mutex_lock(&uv__loops_lock);
+
+ for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) {
+ if (uv__loops[loop_index] == loop)
+ break;
+ }
+ /* If loop was not found, ignore */
+ if (loop_index == uv__loops_size)
+ goto loop_removed;
+
+ uv__loops[loop_index] = uv__loops[uv__loops_size - 1];
+ uv__loops[uv__loops_size - 1] = NULL;
+ --uv__loops_size;
+
+ /* If we didn't grow to big skip downsizing */
+ if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
+ goto loop_removed;
+
+ /* Downsize only if more than half of buffer is free */
+ smaller_capacity = uv__loops_capacity / 2;
+ if (uv__loops_size >= smaller_capacity)
+ goto loop_removed;
+ new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity);
+ if (!new_loops)
+ goto loop_removed;
+ uv__loops = new_loops;
+ uv__loops_capacity = smaller_capacity;
+
+loop_removed:
+ uv_mutex_unlock(&uv__loops_lock);
+}
+
+void uv__wake_all_loops() {
+ int i;
+ uv_loop_t* loop;
+
+ uv_mutex_lock(&uv__loops_lock);
+ for (i = 0; i < uv__loops_size; ++i) {
+ loop = uv__loops[i];
+ assert(loop);
+ if (loop->iocp != INVALID_HANDLE_VALUE)
+ PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
+ }
+ uv_mutex_unlock(&uv__loops_lock);
+}
+
+static void uv_init(void) {
+ /* Tell Windows that we will handle critical errors. */
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
+ SEM_NOOPENFILEERRORBOX);
+
+ /* Tell the CRT to not exit the application when an invalid parameter is
+ * passed. The main issue is that invalid FDs will trigger this behavior.
+ */
+#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
+ _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
+#endif
+
+ /* We also need to setup our debug report handler because some CRT
+ * functions (eg _get_osfhandle) raise an assert when called with invalid
+ * FDs even though they return the proper error code in the release build.
+ */
+#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
+ _CrtSetReportHook(uv__crt_dbg_report_handler);
+#endif
+
+ /* Initialize tracking of all uv loops */
+ uv__loops_init();
+
+ /* Fetch winapi function pointers. This must be done first because other
+ * initialization code might need these function pointers to be loaded.
+ */
+ uv_winapi_init();
+
+ /* Initialize winsock */
+ uv_winsock_init();
+
+ /* Initialize FS */
+ uv_fs_init();
+
+ /* Initialize signal stuff */
+ uv_signals_init();
+
+ /* Initialize console */
+ uv_console_init();
+
+ /* Initialize utilities */
+ uv__util_init();
+
+ /* Initialize system wakeup detection */
+ uv__init_detect_system_wakeup();
+}
+
+
+int uv_loop_init(uv_loop_t* loop) {
+ int err;
+
+ /* Initialize libuv itself first */
+ uv__once_init();
+
+ /* Create an I/O completion port */
+ loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
+ if (loop->iocp == NULL)
+ return uv_translate_sys_error(GetLastError());
+
+ /* To prevent uninitialized memory access, loop->time must be initialized
+ * to zero before calling uv_update_time for the first time.
+ */
+ loop->time = 0;
+ uv_update_time(loop);
+
+ QUEUE_INIT(&loop->wq);
+ QUEUE_INIT(&loop->handle_queue);
+ QUEUE_INIT(&loop->active_reqs);
+ loop->active_handles = 0;
+
+ loop->pending_reqs_tail = NULL;
+
+ loop->endgame_handles = NULL;
+
+ RB_INIT(&loop->timers);
+
+ loop->check_handles = NULL;
+ loop->prepare_handles = NULL;
+ loop->idle_handles = NULL;
+
+ loop->next_prepare_handle = NULL;
+ loop->next_check_handle = NULL;
+ loop->next_idle_handle = NULL;
+
+ memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
+
+ loop->active_tcp_streams = 0;
+ loop->active_udp_streams = 0;
+
+ loop->timer_counter = 0;
+ loop->stop_flag = 0;
+
+ err = uv_mutex_init(&loop->wq_mutex);
+ if (err)
+ goto fail_mutex_init;
+
+ err = uv_async_init(loop, &loop->wq_async, uv__work_done);
+ if (err)
+ goto fail_async_init;
+
+ uv__handle_unref(&loop->wq_async);
+ loop->wq_async.flags |= UV__HANDLE_INTERNAL;
+
+ err = uv__loops_add(loop);
+ if (err)
+ goto fail_async_init;
+
+ return 0;
+
+fail_async_init:
+ uv_mutex_destroy(&loop->wq_mutex);
+
+fail_mutex_init:
+ CloseHandle(loop->iocp);
+ loop->iocp = INVALID_HANDLE_VALUE;
+
+ return err;
+}
+
+
+void uv__once_init(void) {
+ uv_once(&uv_init_guard_, uv_init);
+}
+
+
+void uv__loop_close(uv_loop_t* loop) {
+ size_t i;
+
+ uv__loops_remove(loop);
+
+ /* close the async handle without needing an extra loop iteration */
+ assert(!loop->wq_async.async_sent);
+ loop->wq_async.close_cb = NULL;
+ uv__handle_closing(&loop->wq_async);
+ uv__handle_close(&loop->wq_async);
+
+ for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
+ SOCKET sock = loop->poll_peer_sockets[i];
+ if (sock != 0 && sock != INVALID_SOCKET)
+ closesocket(sock);
+ }
+
+ uv_mutex_lock(&loop->wq_mutex);
+ assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
+ assert(!uv__has_active_reqs(loop));
+ uv_mutex_unlock(&loop->wq_mutex);
+ uv_mutex_destroy(&loop->wq_mutex);
+
+ CloseHandle(loop->iocp);
+}
+
+
+int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
+ return UV_ENOSYS;
+}
+
+
+int uv_backend_fd(const uv_loop_t* loop) {
+ return -1;
+}
+
+
+int uv_backend_timeout(const uv_loop_t* loop) {
+ if (loop->stop_flag != 0)
+ return 0;
+
+ if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
+ return 0;
+
+ if (loop->pending_reqs_tail)
+ return 0;
+
+ if (loop->endgame_handles)
+ return 0;
+
+ if (loop->idle_handles)
+ return 0;
+
+ return uv__next_timeout(loop);
+}
+
+
+static void uv_poll(uv_loop_t* loop, DWORD timeout) {
+ DWORD bytes;
+ ULONG_PTR key;
+ OVERLAPPED* overlapped;
+ uv_req_t* req;
+ int repeat;
+ uint64_t timeout_time;
+
+ timeout_time = loop->time + timeout;
+
+ for (repeat = 0; ; repeat++) {
+ GetQueuedCompletionStatus(loop->iocp,
+ &bytes,
+ &key,
+ &overlapped,
+ timeout);
+
+ if (overlapped) {
+ /* Package was dequeued */
+ req = uv_overlapped_to_req(overlapped);
+ uv_insert_pending_req(loop, req);
+
+ /* Some time might have passed waiting for I/O,
+ * so update the loop time here.
+ */
+ uv_update_time(loop);
+ } else if (GetLastError() != WAIT_TIMEOUT) {
+ /* Serious error */
+ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
+ } else if (timeout > 0) {
+ /* GetQueuedCompletionStatus can occasionally return a little early.
+ * Make sure that the desired timeout target time is reached.
+ */
+ uv_update_time(loop);
+ if (timeout_time > loop->time) {
+ timeout = (DWORD)(timeout_time - loop->time);
+ /* The first call to GetQueuedCompletionStatus should return very
+ * close to the target time and the second should reach it, but
+ * this is not stated in the documentation. To make sure a busy
+ * loop cannot happen, the timeout is increased exponentially
+ * starting on the third round.
+ */
+ timeout += repeat ? (1 << (repeat - 1)) : 0;
+ continue;
+ }
+ }
+ break;
+ }
+}
+
+
+static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
+ BOOL success;
+ uv_req_t* req;
+ OVERLAPPED_ENTRY overlappeds[128];
+ ULONG count;
+ ULONG i;
+ int repeat;
+ uint64_t timeout_time;
+
+ timeout_time = loop->time + timeout;
+
+ for (repeat = 0; ; repeat++) {
+ success = pGetQueuedCompletionStatusEx(loop->iocp,
+ overlappeds,
+ ARRAY_SIZE(overlappeds),
+ &count,
+ timeout,
+ FALSE);
+
+ if (success) {
+ for (i = 0; i < count; i++) {
+ /* Package was dequeued, but see if it is not a empty package
+ * meant only to wake us up.
+ */
+ if (overlappeds[i].lpOverlapped) {
+ req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
+ uv_insert_pending_req(loop, req);
+ }
+ }
+
+ /* Some time might have passed waiting for I/O,
+ * so update the loop time here.
+ */
+ uv_update_time(loop);
+ } else if (GetLastError() != WAIT_TIMEOUT) {
+ /* Serious error */
+ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
+ } else if (timeout > 0) {
+ /* GetQueuedCompletionStatus can occasionally return a little early.
+ * Make sure that the desired timeout target time is reached.
+ */
+ uv_update_time(loop);
+ if (timeout_time > loop->time) {
+ timeout = (DWORD)(timeout_time - loop->time);
+ /* The first call to GetQueuedCompletionStatus should return very
+ * close to the target time and the second should reach it, but
+ * this is not stated in the documentation. To make sure a busy
+ * loop cannot happen, the timeout is increased exponentially
+ * starting on the third round.
+ */
+ timeout += repeat ? (1 << (repeat - 1)) : 0;
+ continue;
+ }
+ }
+ break;
+ }
+}
+
+
+static int uv__loop_alive(const uv_loop_t* loop) {
+ return loop->active_handles > 0 ||
+ !QUEUE_EMPTY(&loop->active_reqs) ||
+ loop->endgame_handles != NULL;
+}
+
+
+int uv_loop_alive(const uv_loop_t* loop) {
+ return uv__loop_alive(loop);
+}
+
+
+int uv_run(uv_loop_t *loop, uv_run_mode mode) {
+ DWORD timeout;
+ int r;
+ int ran_pending;
+ void (*poll)(uv_loop_t* loop, DWORD timeout);
+
+ if (pGetQueuedCompletionStatusEx)
+ poll = &uv_poll_ex;
+ else
+ poll = &uv_poll;
+
+ r = uv__loop_alive(loop);
+ if (!r)
+ uv_update_time(loop);
+
+ while (r != 0 && loop->stop_flag == 0) {
+ uv_update_time(loop);
+ uv_process_timers(loop);
+
+ ran_pending = uv_process_reqs(loop);
+ uv_idle_invoke(loop);
+ uv_prepare_invoke(loop);
+
+ timeout = 0;
+ if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
+ timeout = uv_backend_timeout(loop);
+
+ (*poll)(loop, timeout);
+
+ uv_check_invoke(loop);
+ uv_process_endgames(loop);
+
+ if (mode == UV_RUN_ONCE) {
+ /* UV_RUN_ONCE implies forward progress: at least one callback must have
+ * been invoked when it returns. uv__io_poll() can return without doing
+ * I/O (meaning: no callbacks) when its timeout expires - which means we
+ * have pending timers that satisfy the forward progress constraint.
+ *
+ * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
+ * the check.
+ */
+ uv_process_timers(loop);
+ }
+
+ r = uv__loop_alive(loop);
+ if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
+ break;
+ }
+
+ /* The if statement lets the compiler compile it to a conditional store.
+ * Avoids dirtying a cache line.
+ */
+ if (loop->stop_flag != 0)
+ loop->stop_flag = 0;
+
+ return r;
+}
+
+
+int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
+ uv_os_fd_t fd_out;
+
+ switch (handle->type) {
+ case UV_TCP:
+ fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket;
+ break;
+
+ case UV_NAMED_PIPE:
+ fd_out = ((uv_pipe_t*) handle)->handle;
+ break;
+
+ case UV_TTY:
+ fd_out = ((uv_tty_t*) handle)->handle;
+ break;
+
+ case UV_UDP:
+ fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket;
+ break;
+
+ case UV_POLL:
+ fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket;
+ break;
+
+ default:
+ return UV_EINVAL;
+ }
+
+ if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ *fd = fd_out;
+ return 0;
+}
+
+
+int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
+ int r;
+ int len;
+ SOCKET socket;
+
+ if (handle == NULL || value == NULL)
+ return UV_EINVAL;
+
+ if (handle->type == UV_TCP)
+ socket = ((uv_tcp_t*) handle)->socket;
+ else if (handle->type == UV_UDP)
+ socket = ((uv_udp_t*) handle)->socket;
+ else
+ return UV_ENOTSUP;
+
+ len = sizeof(*value);
+
+ if (*value == 0)
+ r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len);
+ else
+ r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len);
+
+ if (r == SOCKET_ERROR)
+ return uv_translate_sys_error(WSAGetLastError());
+
+ return 0;
+}
--- /dev/null
+#include "uv.h"
+#include "internal.h"
+#include "winapi.h"
+
+static void uv__register_system_resume_callback();
+
+void uv__init_detect_system_wakeup() {
+ /* Try registering system power event callback. This is the cleanest
+ * method, but it will only work on Win8 and above.
+ */
+ uv__register_system_resume_callback();
+}
+
+static ULONG CALLBACK uv__system_resume_callback(PVOID Context,
+ ULONG Type,
+ PVOID Setting) {
+ if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC)
+ uv__wake_all_loops();
+
+ return 0;
+}
+
+static void uv__register_system_resume_callback() {
+ _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient;
+ _HPOWERNOTIFY registration_handle;
+
+ if (pPowerRegisterSuspendResumeNotification == NULL)
+ return;
+
+ recipient.Callback = uv__system_resume_callback;
+ recipient.Context = NULL;
+ (*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK,
+ &recipient,
+ ®istration_handle);
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+static int uv__dlerror(uv_lib_t* lib, int errorno);
+
+
+int uv_dlopen(const char* filename, uv_lib_t* lib) {
+ WCHAR filename_w[32768];
+
+ lib->handle = NULL;
+ lib->errmsg = NULL;
+
+ if (!MultiByteToWideChar(CP_UTF8,
+ 0,
+ filename,
+ -1,
+ filename_w,
+ ARRAY_SIZE(filename_w))) {
+ return uv__dlerror(lib, GetLastError());
+ }
+
+ lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (lib->handle == NULL) {
+ return uv__dlerror(lib, GetLastError());
+ }
+
+ return 0;
+}
+
+
+void uv_dlclose(uv_lib_t* lib) {
+ if (lib->errmsg) {
+ LocalFree((void*)lib->errmsg);
+ lib->errmsg = NULL;
+ }
+
+ if (lib->handle) {
+ /* Ignore errors. No good way to signal them without leaking memory. */
+ FreeLibrary(lib->handle);
+ lib->handle = NULL;
+ }
+}
+
+
+int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
+ *ptr = (void*) GetProcAddress(lib->handle, name);
+ return uv__dlerror(lib, *ptr ? 0 : GetLastError());
+}
+
+
+const char* uv_dlerror(const uv_lib_t* lib) {
+ return lib->errmsg ? lib->errmsg : "no error";
+}
+
+
+static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
+ DWORD_PTR args[1] = { (DWORD_PTR) errorno };
+ LPSTR fallback_error = "error: %1!d!";
+
+ FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ fallback_error, 0, 0,
+ (LPSTR) &lib->errmsg,
+ 0, (va_list*) args);
+}
+
+
+
+static int uv__dlerror(uv_lib_t* lib, int errorno) {
+ DWORD res;
+
+ if (lib->errmsg) {
+ LocalFree((void*)lib->errmsg);
+ lib->errmsg = NULL;
+ }
+
+ if (errorno) {
+ res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ (LPSTR) &lib->errmsg, 0, NULL);
+ if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
+ res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ 0, (LPSTR) &lib->errmsg, 0, NULL);
+ }
+
+ if (!res) {
+ uv__format_fallback_error(lib, errorno);
+ }
+ }
+
+ return errorno ? -1 : 0;
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/*
+ * Display an error message and abort the event loop.
+ */
+void uv_fatal_error(const int errorno, const char* syscall) {
+ char* buf = NULL;
+ const char* errmsg;
+
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
+
+ if (buf) {
+ errmsg = buf;
+ } else {
+ errmsg = "Unknown error";
+ }
+
+ /* FormatMessage messages include a newline character already, */
+ /* so don't add another. */
+ if (syscall) {
+ fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
+ } else {
+ fprintf(stderr, "(%d) %s", errorno, errmsg);
+ }
+
+ if (buf) {
+ LocalFree(buf);
+ }
+
+ *((char*)NULL) = 0xff; /* Force debug break */
+ abort();
+}
+
+
+int uv_translate_sys_error(int sys_errno) {
+ if (sys_errno <= 0) {
+ return sys_errno; /* If < 0 then it's already a libuv error. */
+ }
+
+ switch (sys_errno) {
+ case ERROR_NOACCESS: return UV_EACCES;
+ case WSAEACCES: return UV_EACCES;
+ case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
+ case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
+ case WSAEADDRINUSE: return UV_EADDRINUSE;
+ case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
+ case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
+ case WSAEWOULDBLOCK: return UV_EAGAIN;
+ case WSAEALREADY: return UV_EALREADY;
+ case ERROR_INVALID_FLAGS: return UV_EBADF;
+ case ERROR_INVALID_HANDLE: return UV_EBADF;
+ case ERROR_LOCK_VIOLATION: return UV_EBUSY;
+ case ERROR_PIPE_BUSY: return UV_EBUSY;
+ case ERROR_SHARING_VIOLATION: return UV_EBUSY;
+ case ERROR_OPERATION_ABORTED: return UV_ECANCELED;
+ case WSAEINTR: return UV_ECANCELED;
+ case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET;
+ case ERROR_CONNECTION_ABORTED: return UV_ECONNABORTED;
+ case WSAECONNABORTED: return UV_ECONNABORTED;
+ case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED;
+ case WSAECONNREFUSED: return UV_ECONNREFUSED;
+ case ERROR_NETNAME_DELETED: return UV_ECONNRESET;
+ case WSAECONNRESET: return UV_ECONNRESET;
+ case ERROR_ALREADY_EXISTS: return UV_EEXIST;
+ case ERROR_FILE_EXISTS: return UV_EEXIST;
+ case ERROR_BUFFER_OVERFLOW: return UV_EFAULT;
+ case WSAEFAULT: return UV_EFAULT;
+ case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
+ case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
+ case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL;
+ case ERROR_INVALID_DATA: return UV_EINVAL;
+ case ERROR_INVALID_PARAMETER: return UV_EINVAL;
+ case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL;
+ case WSAEINVAL: return UV_EINVAL;
+ case WSAEPFNOSUPPORT: return UV_EINVAL;
+ case WSAESOCKTNOSUPPORT: return UV_EINVAL;
+ case ERROR_BEGINNING_OF_MEDIA: return UV_EIO;
+ case ERROR_BUS_RESET: return UV_EIO;
+ case ERROR_CRC: return UV_EIO;
+ case ERROR_DEVICE_DOOR_OPEN: return UV_EIO;
+ case ERROR_DEVICE_REQUIRES_CLEANING: return UV_EIO;
+ case ERROR_DISK_CORRUPT: return UV_EIO;
+ case ERROR_EOM_OVERFLOW: return UV_EIO;
+ case ERROR_FILEMARK_DETECTED: return UV_EIO;
+ case ERROR_GEN_FAILURE: return UV_EIO;
+ case ERROR_INVALID_BLOCK_LENGTH: return UV_EIO;
+ case ERROR_IO_DEVICE: return UV_EIO;
+ case ERROR_NO_DATA_DETECTED: return UV_EIO;
+ case ERROR_NO_SIGNAL_SENT: return UV_EIO;
+ case ERROR_OPEN_FAILED: return UV_EIO;
+ case ERROR_SETMARK_DETECTED: return UV_EIO;
+ case ERROR_SIGNAL_REFUSED: return UV_EIO;
+ case WSAEISCONN: return UV_EISCONN;
+ case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP;
+ case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
+ case WSAEMFILE: return UV_EMFILE;
+ case WSAEMSGSIZE: return UV_EMSGSIZE;
+ case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG;
+ case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
+ case WSAENETUNREACH: return UV_ENETUNREACH;
+ case WSAENOBUFS: return UV_ENOBUFS;
+ case ERROR_BAD_PATHNAME: return UV_ENOENT;
+ case ERROR_DIRECTORY: return UV_ENOENT;
+ case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
+ case ERROR_INVALID_NAME: return UV_ENOENT;
+ case ERROR_INVALID_DRIVE: return UV_ENOENT;
+ case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT;
+ case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
+ case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
+ case WSAHOST_NOT_FOUND: return UV_ENOENT;
+ case WSANO_DATA: return UV_ENOENT;
+ case ERROR_NOT_ENOUGH_MEMORY: return UV_ENOMEM;
+ case ERROR_OUTOFMEMORY: return UV_ENOMEM;
+ case ERROR_CANNOT_MAKE: return UV_ENOSPC;
+ case ERROR_DISK_FULL: return UV_ENOSPC;
+ case ERROR_EA_TABLE_FULL: return UV_ENOSPC;
+ case ERROR_END_OF_MEDIA: return UV_ENOSPC;
+ case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC;
+ case ERROR_NOT_CONNECTED: return UV_ENOTCONN;
+ case WSAENOTCONN: return UV_ENOTCONN;
+ case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY;
+ case WSAENOTSOCK: return UV_ENOTSOCK;
+ case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
+ case ERROR_BROKEN_PIPE: return UV_EOF;
+ case ERROR_ACCESS_DENIED: return UV_EPERM;
+ case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
+ case ERROR_BAD_PIPE: return UV_EPIPE;
+ case ERROR_NO_DATA: return UV_EPIPE;
+ case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE;
+ case WSAESHUTDOWN: return UV_EPIPE;
+ case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT;
+ case ERROR_WRITE_PROTECT: return UV_EROFS;
+ case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT;
+ case WSAETIMEDOUT: return UV_ETIMEDOUT;
+ case ERROR_NOT_SAME_DEVICE: return UV_EXDEV;
+ case ERROR_INVALID_FUNCTION: return UV_EISDIR;
+ case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
+ default: return UV_UNKNOWN;
+ }
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+const unsigned int uv_directory_watcher_buffer_size = 4096;
+
+
+static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
+ uv_fs_event_t* handle) {
+ assert(handle->dir_handle != INVALID_HANDLE_VALUE);
+ assert(!handle->req_pending);
+
+ memset(&(handle->req.u.io.overlapped), 0,
+ sizeof(handle->req.u.io.overlapped));
+ if (!ReadDirectoryChangesW(handle->dir_handle,
+ handle->buffer,
+ uv_directory_watcher_buffer_size,
+ (handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
+ FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_SECURITY,
+ NULL,
+ &handle->req.u.io.overlapped,
+ NULL)) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(&handle->req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
+ }
+
+ handle->req_pending = 1;
+}
+
+static void uv_relative_path(const WCHAR* filename,
+ const WCHAR* dir,
+ WCHAR** relpath) {
+ size_t relpathlen;
+ size_t filenamelen = wcslen(filename);
+ size_t dirlen = wcslen(dir);
+ if (dirlen > 0 && dir[dirlen - 1] == '\\')
+ dirlen--;
+ relpathlen = filenamelen - dirlen - 1;
+ *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR));
+ if (!*relpath)
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ wcsncpy(*relpath, filename + dirlen + 1, relpathlen);
+ (*relpath)[relpathlen] = L'\0';
+}
+
+static int uv_split_path(const WCHAR* filename, WCHAR** dir,
+ WCHAR** file) {
+ int len = wcslen(filename);
+ int i = len;
+ while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
+
+ if (i == 0) {
+ if (dir) {
+ *dir = (WCHAR*)uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
+ if (!*dir) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!GetCurrentDirectoryW(MAX_PATH, *dir)) {
+ uv__free(*dir);
+ *dir = NULL;
+ return -1;
+ }
+ }
+
+ *file = wcsdup(filename);
+ } else {
+ if (dir) {
+ *dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR));
+ if (!*dir) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+ wcsncpy(*dir, filename, i + 1);
+ (*dir)[i + 1] = L'\0';
+ }
+
+ *file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
+ if (!*file) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+ wcsncpy(*file, filename + i + 1, len - i - 1);
+ (*file)[len - i - 1] = L'\0';
+ }
+
+ return 0;
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ handle->buffer = NULL;
+ handle->req_pending = 0;
+ handle->filew = NULL;
+ handle->short_filew = NULL;
+ handle->dirw = NULL;
+
+ uv_req_init(loop, (uv_req_t*)&handle->req);
+ handle->req.type = UV_FS_EVENT_REQ;
+ handle->req.data = handle;
+
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+ int name_size, is_path_dir;
+ DWORD attr, last_error;
+ WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
+ WCHAR short_path[MAX_PATH];
+
+ if (uv__is_active(handle))
+ return UV_EINVAL;
+
+ handle->cb = cb;
+ handle->path = uv__strdup(path);
+ if (!handle->path) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ uv__handle_start(handle);
+
+ /* Convert name to UTF16. */
+
+ name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) *
+ sizeof(WCHAR);
+ pathw = (WCHAR*)uv__malloc(name_size);
+ if (!pathw) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!MultiByteToWideChar(CP_UTF8,
+ 0,
+ path,
+ -1,
+ pathw,
+ name_size / sizeof(WCHAR))) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Determine whether path is a file or a directory. */
+ attr = GetFileAttributesW(pathw);
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
+
+ if (is_path_dir) {
+ /* path is a directory, so that's the directory that we will watch. */
+ handle->dirw = pathw;
+ dir_to_watch = pathw;
+ } else {
+ /*
+ * path is a file. So we split path into dir & file parts, and
+ * watch the dir directory.
+ */
+
+ /* Convert to short path. */
+ if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ dir_to_watch = dir;
+ uv__free(pathw);
+ pathw = NULL;
+ }
+
+ handle->dir_handle = CreateFileW(dir_to_watch,
+ FILE_LIST_DIRECTORY,
+ FILE_SHARE_READ | FILE_SHARE_DELETE |
+ FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS |
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (dir) {
+ uv__free(dir);
+ dir = NULL;
+ }
+
+ if (handle->dir_handle == INVALID_HANDLE_VALUE) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (CreateIoCompletionPort(handle->dir_handle,
+ handle->loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (!handle->buffer) {
+ handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size);
+ }
+ if (!handle->buffer) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ memset(&(handle->req.u.io.overlapped), 0,
+ sizeof(handle->req.u.io.overlapped));
+
+ if (!ReadDirectoryChangesW(handle->dir_handle,
+ handle->buffer,
+ uv_directory_watcher_buffer_size,
+ (flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
+ FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_SECURITY,
+ NULL,
+ &handle->req.u.io.overlapped,
+ NULL)) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ handle->req_pending = 1;
+ return 0;
+
+error:
+ if (handle->path) {
+ uv__free(handle->path);
+ handle->path = NULL;
+ }
+
+ if (handle->filew) {
+ uv__free(handle->filew);
+ handle->filew = NULL;
+ }
+
+ if (handle->short_filew) {
+ uv__free(handle->short_filew);
+ handle->short_filew = NULL;
+ }
+
+ uv__free(pathw);
+
+ if (handle->dir_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->dir_handle);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (handle->buffer) {
+ uv__free(handle->buffer);
+ handle->buffer = NULL;
+ }
+
+ return uv_translate_sys_error(last_error);
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ if (handle->dir_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->dir_handle);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ }
+
+ uv__handle_stop(handle);
+
+ if (handle->filew) {
+ uv__free(handle->filew);
+ handle->filew = NULL;
+ }
+
+ if (handle->short_filew) {
+ uv__free(handle->short_filew);
+ handle->short_filew = NULL;
+ }
+
+ if (handle->path) {
+ uv__free(handle->path);
+ handle->path = NULL;
+ }
+
+ if (handle->dirw) {
+ uv__free(handle->dirw);
+ handle->dirw = NULL;
+ }
+
+ return 0;
+}
+
+
+static int file_info_cmp(WCHAR* str, WCHAR* file_name, int file_name_len) {
+ int str_len;
+
+ str_len = wcslen(str);
+
+ /*
+ Since we only care about equality, return early if the strings
+ aren't the same length
+ */
+ if (str_len != (file_name_len / sizeof(WCHAR)))
+ return -1;
+
+ return _wcsnicmp(str, file_name, str_len);
+}
+
+
+void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
+ uv_fs_event_t* handle) {
+ FILE_NOTIFY_INFORMATION* file_info;
+ int err, sizew, size;
+ char* filename = NULL;
+ WCHAR* filenamew = NULL;
+ WCHAR* long_filenamew = NULL;
+ DWORD offset = 0;
+
+ assert(req->type == UV_FS_EVENT_REQ);
+ assert(handle->req_pending);
+ handle->req_pending = 0;
+
+ /* Don't report any callbacks if:
+ * - We're closing, just push the handle onto the endgame queue
+ * - We are not active, just ignore the callback
+ */
+ if (!uv__is_active(handle)) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+ return;
+ }
+
+ file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
+
+ if (REQ_SUCCESS(req)) {
+ if (req->u.io.overlapped.InternalHigh > 0) {
+ do {
+ file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
+ assert(!filename);
+ assert(!filenamew);
+ assert(!long_filenamew);
+
+ /*
+ * Fire the event only if we were asked to watch a directory,
+ * or if the filename filter matches.
+ */
+ if (handle->dirw ||
+ file_info_cmp(handle->filew,
+ file_info->FileName,
+ file_info->FileNameLength) == 0 ||
+ file_info_cmp(handle->short_filew,
+ file_info->FileName,
+ file_info->FileNameLength) == 0) {
+
+ if (handle->dirw) {
+ /*
+ * We attempt to resolve the long form of the file name explicitly.
+ * We only do this for file names that might still exist on disk.
+ * If this fails, we use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
+ */
+ if (file_info->Action != FILE_ACTION_REMOVED &&
+ file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
+ /* Construct a full path to the file. */
+ size = wcslen(handle->dirw) +
+ file_info->FileNameLength / sizeof(WCHAR) + 2;
+
+ filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
+ if (!filenamew) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
+ file_info->FileNameLength / (DWORD)sizeof(WCHAR),
+ file_info->FileName);
+
+ filenamew[size - 1] = L'\0';
+
+ /* Convert to long name. */
+ size = GetLongPathNameW(filenamew, NULL, 0);
+
+ if (size) {
+ long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
+ if (!long_filenamew) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ size = GetLongPathNameW(filenamew, long_filenamew, size);
+ if (size) {
+ long_filenamew[size] = '\0';
+ } else {
+ uv__free(long_filenamew);
+ long_filenamew = NULL;
+ }
+ }
+
+ uv__free(filenamew);
+
+ if (long_filenamew) {
+ /* Get the file name out of the long path. */
+ uv_relative_path(long_filenamew,
+ handle->dirw,
+ &filenamew);
+ uv__free(long_filenamew);
+ long_filenamew = filenamew;
+ sizew = -1;
+ } else {
+ /* We couldn't get the long filename, use the one reported. */
+ filenamew = file_info->FileName;
+ sizew = file_info->FileNameLength / sizeof(WCHAR);
+ }
+ } else {
+ /*
+ * Removed or renamed events cannot be resolved to the long form.
+ * We therefore use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
+ */
+ filenamew = file_info->FileName;
+ sizew = file_info->FileNameLength / sizeof(WCHAR);
+ }
+ } else {
+ /* We already have the long name of the file, so just use it. */
+ filenamew = handle->filew;
+ sizew = -1;
+ }
+
+ /* Convert the filename to utf8. */
+ uv__convert_utf16_to_utf8(filenamew, sizew, &filename);
+
+ switch (file_info->Action) {
+ case FILE_ACTION_ADDED:
+ case FILE_ACTION_REMOVED:
+ case FILE_ACTION_RENAMED_OLD_NAME:
+ case FILE_ACTION_RENAMED_NEW_NAME:
+ handle->cb(handle, filename, UV_RENAME, 0);
+ break;
+
+ case FILE_ACTION_MODIFIED:
+ handle->cb(handle, filename, UV_CHANGE, 0);
+ break;
+ }
+
+ uv__free(filename);
+ filename = NULL;
+ uv__free(long_filenamew);
+ long_filenamew = NULL;
+ filenamew = NULL;
+ }
+
+ offset = file_info->NextEntryOffset;
+ } while (offset && !(handle->flags & UV__HANDLE_CLOSING));
+ } else {
+ handle->cb(handle, NULL, UV_CHANGE, 0);
+ }
+ } else {
+ err = GET_REQ_ERROR(req);
+ handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
+ }
+
+ if (!(handle->flags & UV__HANDLE_CLOSING)) {
+ uv_fs_event_queue_readdirchanges(loop, handle);
+ } else {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+}
+
+
+void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+
+ uv__handle_closing(handle);
+
+ if (!handle->req_pending) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+}
+
+
+void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
+ if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ if (handle->buffer) {
+ uv__free(handle->buffer);
+ handle->buffer = NULL;
+ }
+
+ uv__handle_close(handle);
+ }
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <direct.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include <stdio.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+#include "handle-inl.h"
+
+#include <wincrypt.h>
+
+
+#define UV_FS_FREE_PATHS 0x0002
+#define UV_FS_FREE_PTR 0x0008
+#define UV_FS_CLEANEDUP 0x0010
+
+
+#define QUEUE_FS_TP_JOB(loop, req) \
+ do { \
+ uv__req_register(loop, req); \
+ uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \
+ } while (0)
+
+#define SET_REQ_RESULT(req, result_value) \
+ do { \
+ req->result = (result_value); \
+ if (req->result == -1) { \
+ req->sys_errno_ = _doserrno; \
+ req->result = uv_translate_sys_error(req->sys_errno_); \
+ } \
+ } while (0)
+
+#define SET_REQ_WIN32_ERROR(req, sys_errno) \
+ do { \
+ req->sys_errno_ = (sys_errno); \
+ req->result = uv_translate_sys_error(req->sys_errno_); \
+ } while (0)
+
+#define SET_REQ_UV_ERROR(req, uv_errno, sys_errno) \
+ do { \
+ req->result = (uv_errno); \
+ req->sys_errno_ = (sys_errno); \
+ } while (0)
+
+#define VERIFY_FD(fd, req) \
+ if (fd == -1) { \
+ req->result = UV_EBADF; \
+ req->sys_errno_ = ERROR_INVALID_HANDLE; \
+ return; \
+ }
+
+#define FILETIME_TO_UINT(filetime) \
+ (*((uint64_t*) &(filetime)) - 116444736000000000ULL)
+
+#define FILETIME_TO_TIME_T(filetime) \
+ (FILETIME_TO_UINT(filetime) / 10000000ULL)
+
+#define FILETIME_TO_TIME_NS(filetime, secs) \
+ ((FILETIME_TO_UINT(filetime) - (secs * 10000000ULL)) * 100)
+
+#define FILETIME_TO_TIMESPEC(ts, filetime) \
+ do { \
+ (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \
+ (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \
+ } while(0)
+
+#define TIME_T_TO_FILETIME(time, filetime_ptr) \
+ do { \
+ uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \
+ 116444736000000000ULL; \
+ (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
+ (filetime_ptr)->dwHighDateTime = bigtime >> 32; \
+ } while(0)
+
+#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
+#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
+ ((c) >= L'A' && (c) <= L'Z'))
+
+const WCHAR JUNCTION_PREFIX[] = L"\\??\\";
+const WCHAR JUNCTION_PREFIX_LEN = 4;
+
+const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\";
+const WCHAR LONG_PATH_PREFIX_LEN = 4;
+
+const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\";
+const WCHAR UNC_PATH_PREFIX_LEN = 8;
+
+
+void uv_fs_init() {
+ _fmode = _O_BINARY;
+}
+
+
+INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
+ const char* new_path, const int copy_path) {
+ char* buf;
+ char* pos;
+ ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0;
+
+ /* new_path can only be set if path is also set. */
+ assert(new_path == NULL || path != NULL);
+
+ if (path != NULL) {
+ pathw_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ path,
+ -1,
+ NULL,
+ 0);
+ if (pathw_len == 0) {
+ return GetLastError();
+ }
+
+ buf_sz += pathw_len * sizeof(WCHAR);
+ }
+
+ if (path != NULL && copy_path) {
+ path_len = 1 + strlen(path);
+ buf_sz += path_len;
+ }
+
+ if (new_path != NULL) {
+ new_pathw_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ new_path,
+ -1,
+ NULL,
+ 0);
+ if (new_pathw_len == 0) {
+ return GetLastError();
+ }
+
+ buf_sz += new_pathw_len * sizeof(WCHAR);
+ }
+
+
+ if (buf_sz == 0) {
+ req->file.pathw = NULL;
+ req->fs.info.new_pathw = NULL;
+ req->path = NULL;
+ return 0;
+ }
+
+ buf = (char*) uv__malloc(buf_sz);
+ if (buf == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ pos = buf;
+
+ if (path != NULL) {
+ DWORD r = MultiByteToWideChar(CP_UTF8,
+ 0,
+ path,
+ -1,
+ (WCHAR*) pos,
+ pathw_len);
+ assert(r == (DWORD) pathw_len);
+ req->file.pathw = (WCHAR*) pos;
+ pos += r * sizeof(WCHAR);
+ } else {
+ req->file.pathw = NULL;
+ }
+
+ if (new_path != NULL) {
+ DWORD r = MultiByteToWideChar(CP_UTF8,
+ 0,
+ new_path,
+ -1,
+ (WCHAR*) pos,
+ new_pathw_len);
+ assert(r == (DWORD) new_pathw_len);
+ req->fs.info.new_pathw = (WCHAR*) pos;
+ pos += r * sizeof(WCHAR);
+ } else {
+ req->fs.info.new_pathw = NULL;
+ }
+
+ req->path = path;
+ if (path != NULL && copy_path) {
+ memcpy(pos, path, path_len);
+ assert(path_len == buf_sz - (pos - buf));
+ req->path = pos;
+ }
+
+ req->flags |= UV_FS_FREE_PATHS;
+
+ return 0;
+}
+
+
+
+INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
+ uv_fs_type fs_type, const uv_fs_cb cb) {
+ uv_req_init(loop, (uv_req_t*) req);
+
+ req->type = UV_FS;
+ req->loop = loop;
+ req->flags = 0;
+ req->fs_type = fs_type;
+ req->result = 0;
+ req->ptr = NULL;
+ req->path = NULL;
+ req->cb = cb;
+ memset(&req->fs, 0, sizeof(req->fs));
+}
+
+
+static int fs__wide_to_utf8(WCHAR* w_source_ptr,
+ DWORD w_source_len,
+ char** target_ptr,
+ uint64_t* target_len_ptr) {
+ int r;
+ int target_len;
+ char* target;
+ target_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ w_source_ptr,
+ w_source_len,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+
+ if (target_len == 0) {
+ return -1;
+ }
+
+ if (target_len_ptr != NULL) {
+ *target_len_ptr = target_len;
+ }
+
+ if (target_ptr == NULL) {
+ return 0;
+ }
+
+ target = uv__malloc(target_len + 1);
+ if (target == NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return -1;
+ }
+
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ w_source_ptr,
+ w_source_len,
+ target,
+ target_len,
+ NULL,
+ NULL);
+ assert(r == target_len);
+ target[target_len] = '\0';
+ *target_ptr = target;
+ return 0;
+}
+
+
+INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
+ uint64_t* target_len_ptr) {
+ char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer;
+ WCHAR* w_target;
+ DWORD w_target_len;
+ DWORD bytes;
+
+ if (!DeviceIoControl(handle,
+ FSCTL_GET_REPARSE_POINT,
+ NULL,
+ 0,
+ buffer,
+ sizeof buffer,
+ &bytes,
+ NULL)) {
+ return -1;
+ }
+
+ if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+ /* Real symlink */
+ w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
+ (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
+ sizeof(WCHAR));
+ w_target_len =
+ reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
+ sizeof(WCHAR);
+
+ /* Real symlinks can contain pretty much everything, but the only thing */
+ /* we really care about is undoing the implicit conversion to an NT */
+ /* namespaced path that CreateSymbolicLink will perform on absolute */
+ /* paths. If the path is win32-namespaced then the user must have */
+ /* explicitly made it so, and we better just return the unmodified */
+ /* reparse data. */
+ if (w_target_len >= 4 &&
+ w_target[0] == L'\\' &&
+ w_target[1] == L'?' &&
+ w_target[2] == L'?' &&
+ w_target[3] == L'\\') {
+ /* Starts with \??\ */
+ if (w_target_len >= 6 &&
+ ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
+ (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
+ w_target[5] == L':' &&
+ (w_target_len == 6 || w_target[6] == L'\\')) {
+ /* \??\<drive>:\ */
+ w_target += 4;
+ w_target_len -= 4;
+
+ } else if (w_target_len >= 8 &&
+ (w_target[4] == L'U' || w_target[4] == L'u') &&
+ (w_target[5] == L'N' || w_target[5] == L'n') &&
+ (w_target[6] == L'C' || w_target[6] == L'c') &&
+ w_target[7] == L'\\') {
+ /* \??\UNC\<server>\<share>\ - make sure the final path looks like */
+ /* \\<server>\<share>\ */
+ w_target += 6;
+ w_target[0] = L'\\';
+ w_target_len -= 6;
+ }
+ }
+
+ } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+ /* Junction. */
+ w_target = reparse_data->MountPointReparseBuffer.PathBuffer +
+ (reparse_data->MountPointReparseBuffer.SubstituteNameOffset /
+ sizeof(WCHAR));
+ w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
+ sizeof(WCHAR);
+
+ /* Only treat junctions that look like \??\<drive>:\ as symlink. */
+ /* Junctions can also be used as mount points, like \??\Volume{<guid>}, */
+ /* but that's confusing for programs since they wouldn't be able to */
+ /* actually understand such a path when returned by uv_readlink(). */
+ /* UNC paths are never valid for junctions so we don't care about them. */
+ if (!(w_target_len >= 6 &&
+ w_target[0] == L'\\' &&
+ w_target[1] == L'?' &&
+ w_target[2] == L'?' &&
+ w_target[3] == L'\\' &&
+ ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
+ (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
+ w_target[5] == L':' &&
+ (w_target_len == 6 || w_target[6] == L'\\'))) {
+ SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
+ return -1;
+ }
+
+ /* Remove leading \??\ */
+ w_target += 4;
+ w_target_len -= 4;
+
+ } else {
+ /* Reparse tag does not indicate a symlink. */
+ SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
+ return -1;
+ }
+
+ return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr);
+}
+
+
+void fs__open(uv_fs_t* req) {
+ DWORD access;
+ DWORD share;
+ DWORD disposition;
+ DWORD attributes = 0;
+ HANDLE file;
+ int fd, current_umask;
+ int flags = req->fs.info.file_flags;
+
+ /* Obtain the active umask. umask() never fails and returns the previous */
+ /* umask. */
+ current_umask = umask(0);
+ umask(current_umask);
+
+ /* convert flags and mode to CreateFile parameters */
+ switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
+ case _O_RDONLY:
+ access = FILE_GENERIC_READ;
+ break;
+ case _O_WRONLY:
+ access = FILE_GENERIC_WRITE;
+ break;
+ case _O_RDWR:
+ access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
+ break;
+ default:
+ goto einval;
+ }
+
+ if (flags & _O_APPEND) {
+ access &= ~FILE_WRITE_DATA;
+ access |= FILE_APPEND_DATA;
+ }
+
+ /*
+ * Here is where we deviate significantly from what CRT's _open()
+ * does. We indiscriminately use all the sharing modes, to match
+ * UNIX semantics. In particular, this ensures that the file can
+ * be deleted even whilst it's open, fixing issue #1449.
+ */
+ share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+
+ switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
+ case 0:
+ case _O_EXCL:
+ disposition = OPEN_EXISTING;
+ break;
+ case _O_CREAT:
+ disposition = OPEN_ALWAYS;
+ break;
+ case _O_CREAT | _O_EXCL:
+ case _O_CREAT | _O_TRUNC | _O_EXCL:
+ disposition = CREATE_NEW;
+ break;
+ case _O_TRUNC:
+ case _O_TRUNC | _O_EXCL:
+ disposition = TRUNCATE_EXISTING;
+ break;
+ case _O_CREAT | _O_TRUNC:
+ disposition = CREATE_ALWAYS;
+ break;
+ default:
+ goto einval;
+ }
+
+ attributes |= FILE_ATTRIBUTE_NORMAL;
+ if (flags & _O_CREAT) {
+ if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) {
+ attributes |= FILE_ATTRIBUTE_READONLY;
+ }
+ }
+
+ if (flags & _O_TEMPORARY ) {
+ attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
+ access |= DELETE;
+ }
+
+ if (flags & _O_SHORT_LIVED) {
+ attributes |= FILE_ATTRIBUTE_TEMPORARY;
+ }
+
+ switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) {
+ case 0:
+ break;
+ case _O_SEQUENTIAL:
+ attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
+ break;
+ case _O_RANDOM:
+ attributes |= FILE_FLAG_RANDOM_ACCESS;
+ break;
+ default:
+ goto einval;
+ }
+
+ /* Setting this flag makes it possible to open a directory. */
+ attributes |= FILE_FLAG_BACKUP_SEMANTICS;
+
+ file = CreateFileW(req->file.pathw,
+ access,
+ share,
+ NULL,
+ disposition,
+ attributes,
+ NULL);
+ if (file == INVALID_HANDLE_VALUE) {
+ DWORD error = GetLastError();
+ if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) &&
+ !(flags & _O_EXCL)) {
+ /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */
+ /* specified, it means the path referred to a directory. */
+ SET_REQ_UV_ERROR(req, UV_EISDIR, error);
+ } else {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ }
+ return;
+ }
+
+ fd = _open_osfhandle((intptr_t) file, flags);
+ if (fd < 0) {
+ /* The only known failure mode for _open_osfhandle() is EMFILE, in which
+ * case GetLastError() will return zero. However we'll try to handle other
+ * errors as well, should they ever occur.
+ */
+ if (errno == EMFILE)
+ SET_REQ_UV_ERROR(req, UV_EMFILE, ERROR_TOO_MANY_OPEN_FILES);
+ else if (GetLastError() != ERROR_SUCCESS)
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ else
+ SET_REQ_WIN32_ERROR(req, UV_UNKNOWN);
+ CloseHandle(file);
+ return;
+ }
+
+ SET_REQ_RESULT(req, fd);
+ return;
+
+ einval:
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
+}
+
+void fs__close(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int result;
+
+ VERIFY_FD(fd, req);
+
+ if (fd > 2)
+ result = _close(fd);
+ else
+ result = 0;
+
+ /* _close doesn't set _doserrno on failure, but it does always set errno
+ * to EBADF on failure.
+ */
+ if (result == -1) {
+ assert(errno == EBADF);
+ SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE);
+ } else {
+ req->result = 0;
+ }
+}
+
+
+void fs__read(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int64_t offset = req->fs.info.offset;
+ HANDLE handle;
+ OVERLAPPED overlapped, *overlapped_ptr;
+ LARGE_INTEGER offset_;
+ DWORD bytes;
+ DWORD error;
+ int result;
+ unsigned int index;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (offset != -1) {
+ memset(&overlapped, 0, sizeof overlapped);
+ overlapped_ptr = &overlapped;
+ } else {
+ overlapped_ptr = NULL;
+ }
+
+ index = 0;
+ bytes = 0;
+ do {
+ DWORD incremental_bytes;
+
+ if (offset != -1) {
+ offset_.QuadPart = offset + bytes;
+ overlapped.Offset = offset_.LowPart;
+ overlapped.OffsetHigh = offset_.HighPart;
+ }
+
+ result = ReadFile(handle,
+ req->fs.info.bufs[index].base,
+ req->fs.info.bufs[index].len,
+ &incremental_bytes,
+ overlapped_ptr);
+ bytes += incremental_bytes;
+ ++index;
+ } while (result && index < req->fs.info.nbufs);
+
+ if (result || bytes > 0) {
+ SET_REQ_RESULT(req, bytes);
+ } else {
+ error = GetLastError();
+ if (error == ERROR_HANDLE_EOF) {
+ SET_REQ_RESULT(req, bytes);
+ } else {
+ SET_REQ_WIN32_ERROR(req, error);
+ }
+ }
+}
+
+
+void fs__write(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int64_t offset = req->fs.info.offset;
+ HANDLE handle;
+ OVERLAPPED overlapped, *overlapped_ptr;
+ LARGE_INTEGER offset_;
+ DWORD bytes;
+ int result;
+ unsigned int index;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (offset != -1) {
+ memset(&overlapped, 0, sizeof overlapped);
+ overlapped_ptr = &overlapped;
+ } else {
+ overlapped_ptr = NULL;
+ }
+
+ index = 0;
+ bytes = 0;
+ do {
+ DWORD incremental_bytes;
+
+ if (offset != -1) {
+ offset_.QuadPart = offset + bytes;
+ overlapped.Offset = offset_.LowPart;
+ overlapped.OffsetHigh = offset_.HighPart;
+ }
+
+ result = WriteFile(handle,
+ req->fs.info.bufs[index].base,
+ req->fs.info.bufs[index].len,
+ &incremental_bytes,
+ overlapped_ptr);
+ bytes += incremental_bytes;
+ ++index;
+ } while (result && index < req->fs.info.nbufs);
+
+ if (result || bytes > 0) {
+ SET_REQ_RESULT(req, bytes);
+ } else {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ }
+}
+
+
+void fs__rmdir(uv_fs_t* req) {
+ int result = _wrmdir(req->file.pathw);
+ SET_REQ_RESULT(req, result);
+}
+
+
+void fs__unlink(uv_fs_t* req) {
+ const WCHAR* pathw = req->file.pathw;
+ HANDLE handle;
+ BY_HANDLE_FILE_INFORMATION info;
+ FILE_DISPOSITION_INFORMATION disposition;
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS status;
+
+ handle = CreateFileW(pathw,
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (!GetFileInformationByHandle(handle, &info)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ /* Do not allow deletion of directories, unless it is a symlink. When */
+ /* the path refers to a non-symlink directory, report EPERM as mandated */
+ /* by POSIX.1. */
+
+ /* Check if it is a reparse point. If it's not, it's a normal directory. */
+ if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
+ CloseHandle(handle);
+ return;
+ }
+
+ /* Read the reparse point and check if it is a valid symlink. */
+ /* If not, don't unlink. */
+ if (fs__readlink_handle(handle, NULL, NULL) < 0) {
+ DWORD error = GetLastError();
+ if (error == ERROR_SYMLINK_NOT_SUPPORTED)
+ error = ERROR_ACCESS_DENIED;
+ SET_REQ_WIN32_ERROR(req, error);
+ CloseHandle(handle);
+ return;
+ }
+ }
+
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+ /* Remove read-only attribute */
+ FILE_BASIC_INFORMATION basic = { 0 };
+
+ basic.FileAttributes = info.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY);
+
+ status = pNtSetInformationFile(handle,
+ &iosb,
+ &basic,
+ sizeof basic,
+ FileBasicInformation);
+ if (!NT_SUCCESS(status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ CloseHandle(handle);
+ return;
+ }
+ }
+
+ /* Try to set the delete flag. */
+ disposition.DeleteFile = TRUE;
+ status = pNtSetInformationFile(handle,
+ &iosb,
+ &disposition,
+ sizeof disposition,
+ FileDispositionInformation);
+ if (NT_SUCCESS(status)) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ }
+
+ CloseHandle(handle);
+}
+
+
+void fs__mkdir(uv_fs_t* req) {
+ /* TODO: use req->mode. */
+ int result = _wmkdir(req->file.pathw);
+ SET_REQ_RESULT(req, result);
+}
+
+
+/* OpenBSD original: lib/libc/stdio/mktemp.c */
+void fs__mkdtemp(uv_fs_t* req) {
+ static const WCHAR *tempchars =
+ L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ static const size_t num_chars = 62;
+ static const size_t num_x = 6;
+ WCHAR *cp, *ep;
+ unsigned int tries, i;
+ size_t len;
+ HCRYPTPROV h_crypt_prov;
+ uint64_t v;
+ BOOL released;
+
+ len = wcslen(req->file.pathw);
+ ep = req->file.pathw + len;
+ if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) {
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
+ return;
+ }
+
+ if (!CryptAcquireContext(&h_crypt_prov, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ tries = TMP_MAX;
+ do {
+ if (!CryptGenRandom(h_crypt_prov, sizeof(v), (BYTE*) &v)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ break;
+ }
+
+ cp = ep - num_x;
+ for (i = 0; i < num_x; i++) {
+ *cp++ = tempchars[v % num_chars];
+ v /= num_chars;
+ }
+
+ if (_wmkdir(req->file.pathw) == 0) {
+ len = strlen(req->path);
+ wcstombs((char*) req->path + len - num_x, ep - num_x, num_x);
+ SET_REQ_RESULT(req, 0);
+ break;
+ } else if (errno != EEXIST) {
+ SET_REQ_RESULT(req, -1);
+ break;
+ }
+ } while (--tries);
+
+ released = CryptReleaseContext(h_crypt_prov, 0);
+ assert(released);
+ if (tries == 0) {
+ SET_REQ_RESULT(req, -1);
+ }
+}
+
+
+void fs__scandir(uv_fs_t* req) {
+ static const size_t dirents_initial_size = 32;
+
+ HANDLE dir_handle = INVALID_HANDLE_VALUE;
+
+ uv__dirent_t** dirents = NULL;
+ size_t dirents_size = 0;
+ size_t dirents_used = 0;
+
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS status;
+
+ /* Buffer to hold directory entries returned by NtQueryDirectoryFile.
+ * It's important that this buffer can hold at least one entry, regardless
+ * of the length of the file names present in the enumerated directory.
+ * A file name is at most 256 WCHARs long.
+ * According to MSDN, the buffer must be aligned at an 8-byte boundary.
+ */
+#if _MSC_VER
+ __declspec(align(8)) char buffer[8192];
+#else
+ __attribute__ ((aligned (8))) char buffer[8192];
+#endif
+
+ STATIC_ASSERT(sizeof buffer >=
+ sizeof(FILE_DIRECTORY_INFORMATION) + 256 * sizeof(WCHAR));
+
+ /* Open the directory. */
+ dir_handle =
+ CreateFileW(req->file.pathw,
+ FILE_LIST_DIRECTORY | SYNCHRONIZE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+ if (dir_handle == INVALID_HANDLE_VALUE)
+ goto win32_error;
+
+ /* Read the first chunk. */
+ status = pNtQueryDirectoryFile(dir_handle,
+ NULL,
+ NULL,
+ NULL,
+ &iosb,
+ &buffer,
+ sizeof buffer,
+ FileDirectoryInformation,
+ FALSE,
+ NULL,
+ TRUE);
+
+ /* If the handle is not a directory, we'll get STATUS_INVALID_PARAMETER.
+ * This should be reported back as UV_ENOTDIR.
+ */
+ if (status == STATUS_INVALID_PARAMETER)
+ goto not_a_directory_error;
+
+ while (NT_SUCCESS(status)) {
+ char* position = buffer;
+ size_t next_entry_offset = 0;
+
+ do {
+ FILE_DIRECTORY_INFORMATION* info;
+ uv__dirent_t* dirent;
+
+ size_t wchar_len;
+ size_t utf8_len;
+
+ /* Obtain a pointer to the current directory entry. */
+ position += next_entry_offset;
+ info = (FILE_DIRECTORY_INFORMATION*) position;
+
+ /* Fetch the offset to the next directory entry. */
+ next_entry_offset = info->NextEntryOffset;
+
+ /* Compute the length of the filename in WCHARs. */
+ wchar_len = info->FileNameLength / sizeof info->FileName[0];
+
+ /* Skip over '.' and '..' entries. It has been reported that
+ * the SharePoint driver includes the terminating zero byte in
+ * the filename length. Strip those first.
+ */
+ while (wchar_len > 0 && info->FileName[wchar_len - 1] == L'\0')
+ wchar_len -= 1;
+
+ if (wchar_len == 0)
+ continue;
+ if (wchar_len == 1 && info->FileName[0] == L'.')
+ continue;
+ if (wchar_len == 2 && info->FileName[0] == L'.' &&
+ info->FileName[1] == L'.')
+ continue;
+
+ /* Compute the space required to store the filename as UTF-8. */
+ utf8_len = WideCharToMultiByte(
+ CP_UTF8, 0, &info->FileName[0], wchar_len, NULL, 0, NULL, NULL);
+ if (utf8_len == 0)
+ goto win32_error;
+
+ /* Resize the dirent array if needed. */
+ if (dirents_used >= dirents_size) {
+ size_t new_dirents_size =
+ dirents_size == 0 ? dirents_initial_size : dirents_size << 1;
+ uv__dirent_t** new_dirents =
+ uv__realloc(dirents, new_dirents_size * sizeof *dirents);
+
+ if (new_dirents == NULL)
+ goto out_of_memory_error;
+
+ dirents_size = new_dirents_size;
+ dirents = new_dirents;
+ }
+
+ /* Allocate space for the uv dirent structure. The dirent structure
+ * includes room for the first character of the filename, but `utf8_len`
+ * doesn't count the NULL terminator at this point.
+ */
+ dirent = uv__malloc(sizeof *dirent + utf8_len);
+ if (dirent == NULL)
+ goto out_of_memory_error;
+
+ dirents[dirents_used++] = dirent;
+
+ /* Convert file name to UTF-8. */
+ if (WideCharToMultiByte(CP_UTF8,
+ 0,
+ &info->FileName[0],
+ wchar_len,
+ &dirent->d_name[0],
+ utf8_len,
+ NULL,
+ NULL) == 0)
+ goto win32_error;
+
+ /* Add a null terminator to the filename. */
+ dirent->d_name[utf8_len] = '\0';
+
+ /* Fill out the type field. */
+ if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE)
+ dirent->d_type = UV__DT_CHAR;
+ else if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
+ dirent->d_type = UV__DT_LINK;
+ else if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ dirent->d_type = UV__DT_DIR;
+ else
+ dirent->d_type = UV__DT_FILE;
+ } while (next_entry_offset != 0);
+
+ /* Read the next chunk. */
+ status = pNtQueryDirectoryFile(dir_handle,
+ NULL,
+ NULL,
+ NULL,
+ &iosb,
+ &buffer,
+ sizeof buffer,
+ FileDirectoryInformation,
+ FALSE,
+ NULL,
+ FALSE);
+
+ /* After the first pNtQueryDirectoryFile call, the function may return
+ * STATUS_SUCCESS even if the buffer was too small to hold at least one
+ * directory entry.
+ */
+ if (status == STATUS_SUCCESS && iosb.Information == 0)
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ if (status != STATUS_NO_MORE_FILES)
+ goto nt_error;
+
+ CloseHandle(dir_handle);
+
+ /* Store the result in the request object. */
+ req->ptr = dirents;
+ if (dirents != NULL)
+ req->flags |= UV_FS_FREE_PTR;
+
+ SET_REQ_RESULT(req, dirents_used);
+
+ /* `nbufs` will be used as index by uv_fs_scandir_next. */
+ req->fs.info.nbufs = 0;
+
+ return;
+
+nt_error:
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ goto cleanup;
+
+win32_error:
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto cleanup;
+
+not_a_directory_error:
+ SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY);
+ goto cleanup;
+
+out_of_memory_error:
+ SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
+ goto cleanup;
+
+cleanup:
+ if (dir_handle != INVALID_HANDLE_VALUE)
+ CloseHandle(dir_handle);
+ while (dirents_used > 0)
+ uv__free(dirents[--dirents_used]);
+ if (dirents != NULL)
+ uv__free(dirents);
+}
+
+
+INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
+ FILE_ALL_INFORMATION file_info;
+ FILE_FS_VOLUME_INFORMATION volume_info;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+
+ nt_status = pNtQueryInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileAllInformation);
+
+ /* Buffer overflow (a warning status code) is expected here. */
+ if (NT_ERROR(nt_status)) {
+ SetLastError(pRtlNtStatusToDosError(nt_status));
+ return -1;
+ }
+
+ nt_status = pNtQueryVolumeInformationFile(handle,
+ &io_status,
+ &volume_info,
+ sizeof volume_info,
+ FileFsVolumeInformation);
+
+ /* Buffer overflow (a warning status code) is expected here. */
+ if (io_status.Status == STATUS_NOT_IMPLEMENTED) {
+ statbuf->st_dev = 0;
+ } else if (NT_ERROR(nt_status)) {
+ SetLastError(pRtlNtStatusToDosError(nt_status));
+ return -1;
+ } else {
+ statbuf->st_dev = volume_info.VolumeSerialNumber;
+ }
+
+ /* Todo: st_mode should probably always be 0666 for everyone. We might also
+ * want to report 0777 if the file is a .exe or a directory.
+ *
+ * Currently it's based on whether the 'readonly' attribute is set, which
+ * makes little sense because the semantics are so different: the 'read-only'
+ * flag is just a way for a user to protect against accidental deletion, and
+ * serves no security purpose. Windows uses ACLs for that.
+ *
+ * Also people now use uv_fs_chmod() to take away the writable bit for good
+ * reasons. Windows however just makes the file read-only, which makes it
+ * impossible to delete the file afterwards, since read-only files can't be
+ * deleted.
+ *
+ * IOW it's all just a clusterfuck and we should think of something that
+ * makes slightly more sense.
+ *
+ * And uv_fs_chmod should probably just fail on windows or be a total no-op.
+ * There's nothing sensible it can do anyway.
+ */
+ statbuf->st_mode = 0;
+
+ if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ /*
+ * It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have
+ * any link data. In that case DeviceIoControl() in fs__readlink_handle() sets
+ * the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode
+ * calculated below will indicate a normal directory or file, as if
+ * FILE_ATTRIBUTE_REPARSE_POINT was not present.
+ */
+ if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) {
+ statbuf->st_mode |= S_IFLNK;
+ } else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) {
+ return -1;
+ }
+ }
+
+ if (statbuf->st_mode == 0) {
+ if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ statbuf->st_mode |= _S_IFDIR;
+ statbuf->st_size = 0;
+ } else {
+ statbuf->st_mode |= _S_IFREG;
+ statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
+ }
+ }
+
+ if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
+ statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6);
+ else
+ statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
+ ((_S_IREAD | _S_IWRITE) >> 6);
+
+ FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime);
+
+ statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart;
+
+ /* st_blocks contains the on-disk allocation size in 512-byte units. */
+ statbuf->st_blocks =
+ file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL;
+
+ statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
+
+ /* The st_blksize is supposed to be the 'optimal' number of bytes for reading
+ * and writing to the disk. That is, for any definition of 'optimal' - it's
+ * supposed to at least avoid read-update-write behavior when writing to the
+ * disk.
+ *
+ * However nobody knows this and even fewer people actually use this value,
+ * and in order to fill it out we'd have to make another syscall to query the
+ * volume for FILE_FS_SECTOR_SIZE_INFORMATION.
+ *
+ * Therefore we'll just report a sensible value that's quite commonly okay
+ * on modern hardware.
+ */
+ statbuf->st_blksize = 2048;
+
+ /* Todo: set st_flags to something meaningful. Also provide a wrapper for
+ * chattr(2).
+ */
+ statbuf->st_flags = 0;
+
+ /* Windows has nothing sensible to say about these values, so they'll just
+ * remain empty.
+ */
+ statbuf->st_gid = 0;
+ statbuf->st_uid = 0;
+ statbuf->st_rdev = 0;
+ statbuf->st_gen = 0;
+
+ return 0;
+}
+
+
+INLINE static void fs__stat_prepare_path(WCHAR* pathw) {
+ size_t len = wcslen(pathw);
+
+ /* TODO: ignore namespaced paths. */
+ if (len > 1 && pathw[len - 2] != L':' &&
+ (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) {
+ pathw[len - 1] = '\0';
+ }
+}
+
+
+INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
+ HANDLE handle;
+ DWORD flags;
+
+ flags = FILE_FLAG_BACKUP_SEMANTICS;
+ if (do_lstat) {
+ flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+ }
+
+ handle = CreateFileW(req->file.pathw,
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ flags,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__stat_handle(handle, &req->statbuf) != 0) {
+ DWORD error = GetLastError();
+ if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) {
+ /* We opened a reparse point but it was not a symlink. Try again. */
+ fs__stat_impl(req, 0);
+
+ } else {
+ /* Stat failed. */
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ }
+
+ CloseHandle(handle);
+ return;
+ }
+
+ req->ptr = &req->statbuf;
+ req->result = 0;
+ CloseHandle(handle);
+}
+
+
+static void fs__stat(uv_fs_t* req) {
+ fs__stat_prepare_path(req->file.pathw);
+ fs__stat_impl(req, 0);
+}
+
+
+static void fs__lstat(uv_fs_t* req) {
+ fs__stat_prepare_path(req->file.pathw);
+ fs__stat_impl(req, 1);
+}
+
+
+static void fs__fstat(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (fs__stat_handle(handle, &req->statbuf) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ req->ptr = &req->statbuf;
+ req->result = 0;
+}
+
+
+static void fs__rename(uv_fs_t* req) {
+ if (!MoveFileExW(req->file.pathw, req->fs.info.new_pathw, MOVEFILE_REPLACE_EXISTING)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ SET_REQ_RESULT(req, 0);
+}
+
+
+INLINE static void fs__sync_impl(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int result;
+
+ VERIFY_FD(fd, req);
+
+ result = FlushFileBuffers(uv__get_osfhandle(fd)) ? 0 : -1;
+ if (result == -1) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ } else {
+ SET_REQ_RESULT(req, result);
+ }
+}
+
+
+static void fs__fsync(uv_fs_t* req) {
+ fs__sync_impl(req);
+}
+
+
+static void fs__fdatasync(uv_fs_t* req) {
+ fs__sync_impl(req);
+}
+
+
+static void fs__ftruncate(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+ NTSTATUS status;
+ IO_STATUS_BLOCK io_status;
+ FILE_END_OF_FILE_INFORMATION eof_info;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ eof_info.EndOfFile.QuadPart = req->fs.info.offset;
+
+ status = pNtSetInformationFile(handle,
+ &io_status,
+ &eof_info,
+ sizeof eof_info,
+ FileEndOfFileInformation);
+
+ if (NT_SUCCESS(status)) {
+ SET_REQ_RESULT(req, 0);
+ } else {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ }
+}
+
+
+static void fs__sendfile(uv_fs_t* req) {
+ int fd_in = req->file.fd, fd_out = req->fs.info.fd_out;
+ size_t length = req->fs.info.bufsml[0].len;
+ int64_t offset = req->fs.info.offset;
+ const size_t max_buf_size = 65536;
+ size_t buf_size = length < max_buf_size ? length : max_buf_size;
+ int n, result = 0;
+ int64_t result_offset = 0;
+ char* buf = (char*) uv__malloc(buf_size);
+ if (!buf) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (offset != -1) {
+ result_offset = _lseeki64(fd_in, offset, SEEK_SET);
+ }
+
+ if (result_offset == -1) {
+ result = -1;
+ } else {
+ while (length > 0) {
+ n = _read(fd_in, buf, length < buf_size ? length : buf_size);
+ if (n == 0) {
+ break;
+ } else if (n == -1) {
+ result = -1;
+ break;
+ }
+
+ length -= n;
+
+ n = _write(fd_out, buf, n);
+ if (n == -1) {
+ result = -1;
+ break;
+ }
+
+ result += n;
+ }
+ }
+
+ uv__free(buf);
+
+ SET_REQ_RESULT(req, result);
+}
+
+
+static void fs__access(uv_fs_t* req) {
+ DWORD attr = GetFileAttributesW(req->file.pathw);
+
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ /*
+ * Access is possible if
+ * - write access wasn't requested,
+ * - or the file isn't read-only,
+ * - or it's a directory.
+ * (Directories cannot be read-only on Windows.)
+ */
+ if (!(req->flags & W_OK) ||
+ !(attr & FILE_ATTRIBUTE_READONLY) ||
+ (attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ SET_REQ_RESULT(req, 0);
+ } else {
+ SET_REQ_WIN32_ERROR(req, UV_EPERM);
+ }
+
+}
+
+
+static void fs__chmod(uv_fs_t* req) {
+ int result = _wchmod(req->file.pathw, req->fs.info.mode);
+ SET_REQ_RESULT(req, result);
+}
+
+
+static void fs__fchmod(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_BASIC_INFORMATION file_info;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ nt_status = pNtQueryInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileBasicInformation);
+
+ if (!NT_SUCCESS(nt_status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
+ return;
+ }
+
+ if (req->fs.info.mode & _S_IWRITE) {
+ file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
+ } else {
+ file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
+ }
+
+ nt_status = pNtSetInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileBasicInformation);
+
+ if (!NT_SUCCESS(nt_status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
+ return;
+ }
+
+ SET_REQ_SUCCESS(req);
+}
+
+
+INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
+ FILETIME filetime_a, filetime_m;
+
+ TIME_T_TO_FILETIME(atime, &filetime_a);
+ TIME_T_TO_FILETIME(mtime, &filetime_m);
+
+ if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void fs__utime(uv_fs_t* req) {
+ HANDLE handle;
+
+ handle = CreateFileW(req->file.pathw,
+ FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ CloseHandle(handle);
+
+ req->result = 0;
+}
+
+
+static void fs__futime(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ req->result = 0;
+}
+
+
+static void fs__link(uv_fs_t* req) {
+ DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL);
+ if (r == 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ } else {
+ req->result = 0;
+ }
+}
+
+
+static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
+ const WCHAR* new_path) {
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ REPARSE_DATA_BUFFER *buffer = NULL;
+ int created = 0;
+ int target_len;
+ int is_absolute, is_long_path;
+ int needed_buf_size, used_buf_size, used_data_size, path_buf_len;
+ int start, len, i;
+ int add_slash;
+ DWORD bytes;
+ WCHAR* path_buf;
+
+ target_len = wcslen(path);
+ is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0;
+
+ if (is_long_path) {
+ is_absolute = 1;
+ } else {
+ is_absolute = target_len >= 3 && IS_LETTER(path[0]) &&
+ path[1] == L':' && IS_SLASH(path[2]);
+ }
+
+ if (!is_absolute) {
+ /* Not supporting relative paths */
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED);
+ return;
+ }
+
+ /* Do a pessimistic calculation of the required buffer size */
+ needed_buf_size =
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
+ JUNCTION_PREFIX_LEN * sizeof(WCHAR) +
+ 2 * (target_len + 2) * sizeof(WCHAR);
+
+ /* Allocate the buffer */
+ buffer = (REPARSE_DATA_BUFFER*)uv__malloc(needed_buf_size);
+ if (!buffer) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ /* Grab a pointer to the part of the buffer where filenames go */
+ path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer);
+ path_buf_len = 0;
+
+ /* Copy the substitute (internal) target path */
+ start = path_buf_len;
+
+ wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX,
+ JUNCTION_PREFIX_LEN);
+ path_buf_len += JUNCTION_PREFIX_LEN;
+
+ add_slash = 0;
+ for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
+ if (IS_SLASH(path[i])) {
+ add_slash = 1;
+ continue;
+ }
+
+ if (add_slash) {
+ path_buf[path_buf_len++] = L'\\';
+ add_slash = 0;
+ }
+
+ path_buf[path_buf_len++] = path[i];
+ }
+ path_buf[path_buf_len++] = L'\\';
+ len = path_buf_len - start;
+
+ /* Set the info about the substitute name */
+ buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR);
+
+ /* Insert null terminator */
+ path_buf[path_buf_len++] = L'\0';
+
+ /* Copy the print name of the target path */
+ start = path_buf_len;
+ add_slash = 0;
+ for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
+ if (IS_SLASH(path[i])) {
+ add_slash = 1;
+ continue;
+ }
+
+ if (add_slash) {
+ path_buf[path_buf_len++] = L'\\';
+ add_slash = 0;
+ }
+
+ path_buf[path_buf_len++] = path[i];
+ }
+ len = path_buf_len - start;
+ if (len == 2) {
+ path_buf[path_buf_len++] = L'\\';
+ len++;
+ }
+
+ /* Set the info about the print name */
+ buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR);
+
+ /* Insert another null terminator */
+ path_buf[path_buf_len++] = L'\0';
+
+ /* Calculate how much buffer space was actually used */
+ used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
+ path_buf_len * sizeof(WCHAR);
+ used_data_size = used_buf_size -
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
+
+ /* Put general info in the data buffer */
+ buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ buffer->ReparseDataLength = used_data_size;
+ buffer->Reserved = 0;
+
+ /* Create a new directory */
+ if (!CreateDirectoryW(new_path, NULL)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto error;
+ }
+ created = 1;
+
+ /* Open the directory */
+ handle = CreateFileW(new_path,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS |
+ FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto error;
+ }
+
+ /* Create the actual reparse point */
+ if (!DeviceIoControl(handle,
+ FSCTL_SET_REPARSE_POINT,
+ buffer,
+ used_buf_size,
+ NULL,
+ 0,
+ &bytes,
+ NULL)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto error;
+ }
+
+ /* Clean up */
+ CloseHandle(handle);
+ uv__free(buffer);
+
+ SET_REQ_RESULT(req, 0);
+ return;
+
+error:
+ uv__free(buffer);
+
+ if (handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle);
+ }
+
+ if (created) {
+ RemoveDirectoryW(new_path);
+ }
+}
+
+
+static void fs__symlink(uv_fs_t* req) {
+ WCHAR* pathw = req->file.pathw;
+ WCHAR* new_pathw = req->fs.info.new_pathw;
+ int flags = req->fs.info.file_flags;
+ int result;
+
+
+ if (flags & UV_FS_SYMLINK_JUNCTION) {
+ fs__create_junction(req, pathw, new_pathw);
+ } else if (pCreateSymbolicLinkW) {
+ result = pCreateSymbolicLinkW(new_pathw,
+ pathw,
+ flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1;
+ if (result == -1) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ } else {
+ SET_REQ_RESULT(req, result);
+ }
+ } else {
+ SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
+ }
+}
+
+
+static void fs__readlink(uv_fs_t* req) {
+ HANDLE handle;
+
+ handle = CreateFileW(req->file.pathw,
+ 0,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ req->flags |= UV_FS_FREE_PTR;
+ SET_REQ_RESULT(req, 0);
+
+ CloseHandle(handle);
+}
+
+
+static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
+ int r;
+ DWORD w_realpath_len;
+ WCHAR* w_realpath_ptr = NULL;
+ WCHAR* w_realpath_buf;
+
+ w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
+ if (w_realpath_len == 0) {
+ return -1;
+ }
+
+ w_realpath_buf = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR));
+ if (w_realpath_buf == NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return -1;
+ }
+ w_realpath_ptr = w_realpath_buf;
+
+ if (pGetFinalPathNameByHandleW(handle,
+ w_realpath_ptr,
+ w_realpath_len,
+ VOLUME_NAME_DOS) == 0) {
+ uv__free(w_realpath_buf);
+ SetLastError(ERROR_INVALID_HANDLE);
+ return -1;
+ }
+
+ /* convert UNC path to long path */
+ if (wcsncmp(w_realpath_ptr,
+ UNC_PATH_PREFIX,
+ UNC_PATH_PREFIX_LEN) == 0) {
+ w_realpath_ptr += 6;
+ *w_realpath_ptr = L'\\';
+ w_realpath_len -= 6;
+ } else if (wcsncmp(w_realpath_ptr,
+ LONG_PATH_PREFIX,
+ LONG_PATH_PREFIX_LEN) == 0) {
+ w_realpath_ptr += 4;
+ w_realpath_len -= 4;
+ } else {
+ uv__free(w_realpath_buf);
+ SetLastError(ERROR_INVALID_HANDLE);
+ return -1;
+ }
+
+ r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL);
+ uv__free(w_realpath_buf);
+ return r;
+}
+
+static void fs__realpath(uv_fs_t* req) {
+ HANDLE handle;
+
+ if (!pGetFinalPathNameByHandleW) {
+ SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
+ return;
+ }
+
+ handle = CreateFileW(req->file.pathw,
+ 0,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) {
+ CloseHandle(handle);
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ CloseHandle(handle);
+ req->flags |= UV_FS_FREE_PTR;
+ SET_REQ_RESULT(req, 0);
+}
+
+
+static void fs__chown(uv_fs_t* req) {
+ req->result = 0;
+}
+
+
+static void fs__fchown(uv_fs_t* req) {
+ req->result = 0;
+}
+
+
+static void uv__fs_work(struct uv__work* w) {
+ uv_fs_t* req;
+
+ req = container_of(w, uv_fs_t, work_req);
+ assert(req->type == UV_FS);
+
+#define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
+ switch (req->fs_type) {
+ XX(OPEN, open)
+ XX(CLOSE, close)
+ XX(READ, read)
+ XX(WRITE, write)
+ XX(SENDFILE, sendfile)
+ XX(STAT, stat)
+ XX(LSTAT, lstat)
+ XX(FSTAT, fstat)
+ XX(FTRUNCATE, ftruncate)
+ XX(UTIME, utime)
+ XX(FUTIME, futime)
+ XX(ACCESS, access)
+ XX(CHMOD, chmod)
+ XX(FCHMOD, fchmod)
+ XX(FSYNC, fsync)
+ XX(FDATASYNC, fdatasync)
+ XX(UNLINK, unlink)
+ XX(RMDIR, rmdir)
+ XX(MKDIR, mkdir)
+ XX(MKDTEMP, mkdtemp)
+ XX(RENAME, rename)
+ XX(SCANDIR, scandir)
+ XX(LINK, link)
+ XX(SYMLINK, symlink)
+ XX(READLINK, readlink)
+ XX(REALPATH, realpath)
+ XX(CHOWN, chown)
+ XX(FCHOWN, fchown);
+ default:
+ assert(!"bad uv_fs_type");
+ }
+}
+
+
+static void uv__fs_done(struct uv__work* w, int status) {
+ uv_fs_t* req;
+
+ req = container_of(w, uv_fs_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ if (status == UV_ECANCELED) {
+ assert(req->result == 0);
+ req->result = UV_ECANCELED;
+ }
+
+ req->cb(req);
+}
+
+
+void uv_fs_req_cleanup(uv_fs_t* req) {
+ if (req->flags & UV_FS_CLEANEDUP)
+ return;
+
+ if (req->flags & UV_FS_FREE_PATHS)
+ uv__free(req->file.pathw);
+
+ if (req->flags & UV_FS_FREE_PTR) {
+ if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL)
+ uv__fs_scandir_cleanup(req);
+ else
+ uv__free(req->ptr);
+ }
+
+ if (req->fs.info.bufs != req->fs.info.bufsml)
+ uv__free(req->fs.info.bufs);
+
+ req->path = NULL;
+ req->file.pathw = NULL;
+ req->fs.info.new_pathw = NULL;
+ req->fs.info.bufs = NULL;
+ req->ptr = NULL;
+
+ req->flags |= UV_FS_CLEANEDUP;
+}
+
+
+int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
+ int mode, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_OPEN, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.file_flags = flags;
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__open(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_CLOSE, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__close(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_read(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file fd,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return UV_EINVAL;
+
+ uv_fs_req_init(loop, req, UV_FS_READ, cb);
+
+ req->file.fd = fd;
+
+ req->fs.info.nbufs = nbufs;
+ req->fs.info.bufs = req->fs.info.bufsml;
+ if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
+ req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->fs.info.bufs == NULL)
+ return UV_ENOMEM;
+
+ memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->fs.info.offset = offset;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__read(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_write(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file fd,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return UV_EINVAL;
+
+ uv_fs_req_init(loop, req, UV_FS_WRITE, cb);
+
+ req->file.fd = fd;
+
+ req->fs.info.nbufs = nbufs;
+ req->fs.info.bufs = req->fs.info.bufsml;
+ if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
+ req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->fs.info.bufs == NULL)
+ return UV_ENOMEM;
+
+ memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->fs.info.offset = offset;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__write(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_UNLINK, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__unlink(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_MKDIR, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__mkdir(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb);
+
+ err = fs__capture_path(req, tpl, NULL, TRUE);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__mkdtemp(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_RMDIR, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__rmdir(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_SCANDIR, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.file_flags = flags;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__scandir(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ const char* new_path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_LINK, cb);
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__link(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ const char* new_path, int flags, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb);
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.file_flags = flags;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__symlink(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_READLINK, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__readlink(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ if (!req || !path) {
+ return UV_EINVAL;
+ }
+
+ uv_fs_req_init(loop, req, UV_FS_REALPATH, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__realpath(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
+ uv_gid_t gid, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_CHOWN, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__chown(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid,
+ uv_gid_t gid, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb);
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fchown(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_STAT, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__stat(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_LSTAT, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__lstat(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FSTAT, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fstat(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ const char* new_path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_RENAME, cb);
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__rename(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FSYNC, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fsync(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fdatasync(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
+ int64_t offset, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb);
+
+ req->file.fd = fd;
+ req->fs.info.offset = offset;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__ftruncate(req);
+ return req->result;
+ }
+}
+
+
+
+int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
+ uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb);
+
+ req->file.fd = fd_in;
+ req->fs.info.fd_out = fd_out;
+ req->fs.info.offset = in_offset;
+ req->fs.info.bufsml[0].len = length;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__sendfile(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_access(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_ACCESS, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ req->flags = flags;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ }
+
+ fs__access(req);
+ return req->result;
+}
+
+
+int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_CHMOD, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__chmod(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
+ uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb);
+
+ req->file.fd = fd;
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fchmod(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
+ double mtime, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_UTIME, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.time.atime = atime;
+ req->fs.time.mtime = mtime;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__utime(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
+ double mtime, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FUTIME, cb);
+
+ req->file.fd = fd;
+ req->fs.time.atime = atime;
+ req->fs.time.mtime = mtime;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__futime(req);
+ return req->result;
+ }
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+
+/* EAI_* constants. */
+#include <winsock2.h>
+
+
+int uv__getaddrinfo_translate_error(int sys_err) {
+ switch (sys_err) {
+ case 0: return 0;
+ case WSATRY_AGAIN: return UV_EAI_AGAIN;
+ case WSAEINVAL: return UV_EAI_BADFLAGS;
+ case WSANO_RECOVERY: return UV_EAI_FAIL;
+ case WSAEAFNOSUPPORT: return UV_EAI_FAMILY;
+ case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY;
+ case WSAHOST_NOT_FOUND: return UV_EAI_NONAME;
+ case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE;
+ case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE;
+ default: return uv_translate_sys_error(sys_err);
+ }
+}
+
+
+/*
+ * MinGW is missing this
+ */
+#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
+ typedef struct addrinfoW {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ WCHAR* ai_canonname;
+ struct sockaddr* ai_addr;
+ struct addrinfoW* ai_next;
+ } ADDRINFOW, *PADDRINFOW;
+
+ DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
+ const WCHAR* service,
+ const ADDRINFOW* hints,
+ PADDRINFOW* result);
+
+ DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
+#endif
+
+
+/* adjust size value to be multiple of 4. Use to keep pointer aligned */
+/* Do we need different versions of this for different architectures? */
+#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
+
+
+static void uv__getaddrinfo_work(struct uv__work* w) {
+ uv_getaddrinfo_t* req;
+ struct addrinfoW* hints;
+ int err;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+ hints = req->addrinfow;
+ req->addrinfow = NULL;
+ err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
+ req->retcode = uv__getaddrinfo_translate_error(err);
+}
+
+
+/*
+ * Called from uv_run when complete. Call user specified callback
+ * then free returned addrinfo
+ * Returned addrinfo strings are converted from UTF-16 to UTF-8.
+ *
+ * To minimize allocation we calculate total size required,
+ * and copy all structs and referenced strings into the one block.
+ * Each size calculation is adjusted to avoid unaligned pointers.
+ */
+static void uv__getaddrinfo_done(struct uv__work* w, int status) {
+ uv_getaddrinfo_t* req;
+ int addrinfo_len = 0;
+ int name_len = 0;
+ size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
+ struct addrinfoW* addrinfow_ptr;
+ struct addrinfo* addrinfo_ptr;
+ char* alloc_ptr = NULL;
+ char* cur_ptr = NULL;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+
+ /* release input parameter memory */
+ uv__free(req->alloc);
+ req->alloc = NULL;
+
+ if (status == UV_ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ goto complete;
+ }
+
+ if (req->retcode == 0) {
+ /* convert addrinfoW to addrinfo */
+ /* first calculate required length */
+ addrinfow_ptr = req->addrinfow;
+ while (addrinfow_ptr != NULL) {
+ addrinfo_len += addrinfo_struct_len +
+ ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
+ if (addrinfow_ptr->ai_canonname != NULL) {
+ name_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ addrinfow_ptr->ai_canonname,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (name_len == 0) {
+ req->retcode = uv_translate_sys_error(GetLastError());
+ goto complete;
+ }
+ addrinfo_len += ALIGNED_SIZE(name_len);
+ }
+ addrinfow_ptr = addrinfow_ptr->ai_next;
+ }
+
+ /* allocate memory for addrinfo results */
+ alloc_ptr = (char*)uv__malloc(addrinfo_len);
+
+ /* do conversions */
+ if (alloc_ptr != NULL) {
+ cur_ptr = alloc_ptr;
+ addrinfow_ptr = req->addrinfow;
+
+ while (addrinfow_ptr != NULL) {
+ /* copy addrinfo struct data */
+ assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
+ addrinfo_ptr = (struct addrinfo*)cur_ptr;
+ addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
+ addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
+ addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
+ addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
+ addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
+ addrinfo_ptr->ai_canonname = NULL;
+ addrinfo_ptr->ai_addr = NULL;
+ addrinfo_ptr->ai_next = NULL;
+
+ cur_ptr += addrinfo_struct_len;
+
+ /* copy sockaddr */
+ if (addrinfo_ptr->ai_addrlen > 0) {
+ assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
+ alloc_ptr + addrinfo_len);
+ memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
+ addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
+ cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
+ }
+
+ /* convert canonical name to UTF-8 */
+ if (addrinfow_ptr->ai_canonname != NULL) {
+ name_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ addrinfow_ptr->ai_canonname,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ assert(name_len > 0);
+ assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
+ name_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ addrinfow_ptr->ai_canonname,
+ -1,
+ cur_ptr,
+ name_len,
+ NULL,
+ NULL);
+ assert(name_len > 0);
+ addrinfo_ptr->ai_canonname = cur_ptr;
+ cur_ptr += ALIGNED_SIZE(name_len);
+ }
+ assert(cur_ptr <= alloc_ptr + addrinfo_len);
+
+ /* set next ptr */
+ addrinfow_ptr = addrinfow_ptr->ai_next;
+ if (addrinfow_ptr != NULL) {
+ addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
+ }
+ }
+ req->addrinfo = (struct addrinfo*)alloc_ptr;
+ } else {
+ req->retcode = UV_EAI_MEMORY;
+ }
+ }
+
+ /* return memory to system */
+ if (req->addrinfow != NULL) {
+ FreeAddrInfoW(req->addrinfow);
+ req->addrinfow = NULL;
+ }
+
+complete:
+ uv__req_unregister(req->loop, req);
+
+ /* finally do callback with converted result */
+ if (req->getaddrinfo_cb)
+ req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
+}
+
+
+void uv_freeaddrinfo(struct addrinfo* ai) {
+ char* alloc_ptr = (char*)ai;
+
+ /* release copied result memory */
+ uv__free(alloc_ptr);
+}
+
+
+/*
+ * Entry point for getaddrinfo
+ * we convert the UTF-8 strings to UNICODE
+ * and save the UNICODE string pointers in the req
+ * We also copy hints so that caller does not need to keep memory until the
+ * callback.
+ * return 0 if a callback will be made
+ * return error code if validation fails
+ *
+ * To minimize allocation we calculate total size required,
+ * and copy all structs and referenced strings into the one block.
+ * Each size calculation is adjusted to avoid unaligned pointers.
+ */
+int uv_getaddrinfo(uv_loop_t* loop,
+ uv_getaddrinfo_t* req,
+ uv_getaddrinfo_cb getaddrinfo_cb,
+ const char* node,
+ const char* service,
+ const struct addrinfo* hints) {
+ int nodesize = 0;
+ int servicesize = 0;
+ int hintssize = 0;
+ char* alloc_ptr = NULL;
+ int err;
+
+ if (req == NULL || (node == NULL && service == NULL)) {
+ return UV_EINVAL;
+ }
+
+ uv_req_init(loop, (uv_req_t*)req);
+
+ req->getaddrinfo_cb = getaddrinfo_cb;
+ req->addrinfo = NULL;
+ req->type = UV_GETADDRINFO;
+ req->loop = loop;
+ req->retcode = 0;
+
+ /* calculate required memory size for all input values */
+ if (node != NULL) {
+ nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) *
+ sizeof(WCHAR));
+ if (nodesize == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+
+ if (service != NULL) {
+ servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8,
+ 0,
+ service,
+ -1,
+ NULL,
+ 0) *
+ sizeof(WCHAR));
+ if (servicesize == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+ if (hints != NULL) {
+ hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
+ }
+
+ /* allocate memory for inputs, and partition it as needed */
+ alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
+ if (!alloc_ptr) {
+ err = WSAENOBUFS;
+ goto error;
+ }
+
+ /* save alloc_ptr now so we can free if error */
+ req->alloc = (void*)alloc_ptr;
+
+ /* convert node string to UTF16 into allocated memory and save pointer in */
+ /* the request. */
+ if (node != NULL) {
+ req->node = (WCHAR*)alloc_ptr;
+ if (MultiByteToWideChar(CP_UTF8,
+ 0,
+ node,
+ -1,
+ (WCHAR*) alloc_ptr,
+ nodesize / sizeof(WCHAR)) == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ alloc_ptr += nodesize;
+ } else {
+ req->node = NULL;
+ }
+
+ /* convert service string to UTF16 into allocated memory and save pointer */
+ /* in the req. */
+ if (service != NULL) {
+ req->service = (WCHAR*)alloc_ptr;
+ if (MultiByteToWideChar(CP_UTF8,
+ 0,
+ service,
+ -1,
+ (WCHAR*) alloc_ptr,
+ servicesize / sizeof(WCHAR)) == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ alloc_ptr += servicesize;
+ } else {
+ req->service = NULL;
+ }
+
+ /* copy hints to allocated memory and save pointer in req */
+ if (hints != NULL) {
+ req->addrinfow = (struct addrinfoW*)alloc_ptr;
+ req->addrinfow->ai_family = hints->ai_family;
+ req->addrinfow->ai_socktype = hints->ai_socktype;
+ req->addrinfow->ai_protocol = hints->ai_protocol;
+ req->addrinfow->ai_flags = hints->ai_flags;
+ req->addrinfow->ai_addrlen = 0;
+ req->addrinfow->ai_canonname = NULL;
+ req->addrinfow->ai_addr = NULL;
+ req->addrinfow->ai_next = NULL;
+ } else {
+ req->addrinfow = NULL;
+ }
+
+ uv__req_register(loop, req);
+
+ if (getaddrinfo_cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getaddrinfo_work,
+ uv__getaddrinfo_done);
+ return 0;
+ } else {
+ uv__getaddrinfo_work(&req->work_req);
+ uv__getaddrinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+
+error:
+ if (req != NULL) {
+ uv__free(req->alloc);
+ req->alloc = NULL;
+ }
+ return uv_translate_sys_error(err);
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+*
+* 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.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+
+#ifndef GetNameInfo
+int WSAAPI GetNameInfoW(
+ const SOCKADDR *pSockaddr,
+ socklen_t SockaddrLength,
+ PWCHAR pNodeBuffer,
+ DWORD NodeBufferSize,
+ PWCHAR pServiceBuffer,
+ DWORD ServiceBufferSize,
+ INT Flags
+);
+#endif
+
+static void uv__getnameinfo_work(struct uv__work* w) {
+ uv_getnameinfo_t* req;
+ WCHAR host[NI_MAXHOST];
+ WCHAR service[NI_MAXSERV];
+ int ret = 0;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ if (GetNameInfoW((struct sockaddr*)&req->storage,
+ sizeof(req->storage),
+ host,
+ ARRAY_SIZE(host),
+ service,
+ ARRAY_SIZE(service),
+ req->flags)) {
+ ret = WSAGetLastError();
+ }
+ req->retcode = uv__getaddrinfo_translate_error(ret);
+
+ /* convert results to UTF-8 */
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ host,
+ -1,
+ req->host,
+ sizeof(req->host),
+ NULL,
+ NULL);
+
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ service,
+ -1,
+ req->service,
+ sizeof(req->service),
+ NULL,
+ NULL);
+}
+
+
+/*
+* Called from uv_run when complete.
+*/
+static void uv__getnameinfo_done(struct uv__work* w, int status) {
+ uv_getnameinfo_t* req;
+ char* host;
+ char* service;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+ host = service = NULL;
+
+ if (status == UV_ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ } else if (req->retcode == 0) {
+ host = req->host;
+ service = req->service;
+ }
+
+ if (req->getnameinfo_cb)
+ req->getnameinfo_cb(req, req->retcode, host, service);
+}
+
+
+/*
+* Entry point for getnameinfo
+* return 0 if a callback will be made
+* return error code if validation fails
+*/
+int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags) {
+ if (req == NULL || addr == NULL)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in));
+ } else if (addr->sa_family == AF_INET6) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in6));
+ } else {
+ return UV_EINVAL;
+ }
+
+ uv_req_init(loop, (uv_req_t*)req);
+ uv__req_register(loop, req);
+
+ req->getnameinfo_cb = getnameinfo_cb;
+ req->flags = flags;
+ req->type = UV_GETNAMEINFO;
+ req->loop = loop;
+ req->retcode = 0;
+
+ if (getnameinfo_cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getnameinfo_work,
+ uv__getnameinfo_done);
+ return 0;
+ } else {
+ uv__getnameinfo_work(&req->work_req);
+ uv__getnameinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef UV_WIN_HANDLE_INL_H_
+#define UV_WIN_HANDLE_INL_H_
+
+#include <assert.h>
+#include <io.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define DECREASE_ACTIVE_COUNT(loop, handle) \
+ do { \
+ if (--(handle)->activecnt == 0 && \
+ !((handle)->flags & UV__HANDLE_CLOSING)) { \
+ uv__handle_stop((handle)); \
+ } \
+ assert((handle)->activecnt >= 0); \
+ } while (0)
+
+
+#define INCREASE_ACTIVE_COUNT(loop, handle) \
+ do { \
+ if ((handle)->activecnt++ == 0) { \
+ uv__handle_start((handle)); \
+ } \
+ assert((handle)->activecnt > 0); \
+ } while (0)
+
+
+#define DECREASE_PENDING_REQ_COUNT(handle) \
+ do { \
+ assert(handle->reqs_pending > 0); \
+ handle->reqs_pending--; \
+ \
+ if (handle->flags & UV__HANDLE_CLOSING && \
+ handle->reqs_pending == 0) { \
+ uv_want_endgame(loop, (uv_handle_t*)handle); \
+ } \
+ } while (0)
+
+
+#define uv__handle_closing(handle) \
+ do { \
+ assert(!((handle)->flags & UV__HANDLE_CLOSING)); \
+ \
+ if (!(((handle)->flags & UV__HANDLE_ACTIVE) && \
+ ((handle)->flags & UV__HANDLE_REF))) \
+ uv__active_handle_add((uv_handle_t*) (handle)); \
+ \
+ (handle)->flags |= UV__HANDLE_CLOSING; \
+ (handle)->flags &= ~UV__HANDLE_ACTIVE; \
+ } while (0)
+
+
+#define uv__handle_close(handle) \
+ do { \
+ QUEUE_REMOVE(&(handle)->handle_queue); \
+ uv__active_handle_rm((uv_handle_t*) (handle)); \
+ \
+ (handle)->flags |= UV_HANDLE_CLOSED; \
+ \
+ if ((handle)->close_cb) \
+ (handle)->close_cb((uv_handle_t*) (handle)); \
+ } while (0)
+
+
+INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
+ if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
+ handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
+
+ handle->endgame_next = loop->endgame_handles;
+ loop->endgame_handles = handle;
+ }
+}
+
+
+INLINE static void uv_process_endgames(uv_loop_t* loop) {
+ uv_handle_t* handle;
+
+ while (loop->endgame_handles) {
+ handle = loop->endgame_handles;
+ loop->endgame_handles = handle->endgame_next;
+
+ handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED;
+
+ switch (handle->type) {
+ case UV_TCP:
+ uv_tcp_endgame(loop, (uv_tcp_t*) handle);
+ break;
+
+ case UV_NAMED_PIPE:
+ uv_pipe_endgame(loop, (uv_pipe_t*) handle);
+ break;
+
+ case UV_TTY:
+ uv_tty_endgame(loop, (uv_tty_t*) handle);
+ break;
+
+ case UV_UDP:
+ uv_udp_endgame(loop, (uv_udp_t*) handle);
+ break;
+
+ case UV_POLL:
+ uv_poll_endgame(loop, (uv_poll_t*) handle);
+ break;
+
+ case UV_TIMER:
+ uv_timer_endgame(loop, (uv_timer_t*) handle);
+ break;
+
+ case UV_PREPARE:
+ case UV_CHECK:
+ case UV_IDLE:
+ uv_loop_watcher_endgame(loop, handle);
+ break;
+
+ case UV_ASYNC:
+ uv_async_endgame(loop, (uv_async_t*) handle);
+ break;
+
+ case UV_SIGNAL:
+ uv_signal_endgame(loop, (uv_signal_t*) handle);
+ break;
+
+ case UV_PROCESS:
+ uv_process_endgame(loop, (uv_process_t*) handle);
+ break;
+
+ case UV_FS_EVENT:
+ uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
+ break;
+
+ case UV_FS_POLL:
+ uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ }
+}
+
+INLINE static HANDLE uv__get_osfhandle(int fd)
+{
+ /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */
+ /* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */
+ /* for invalid FDs in release builds (or if you let the assert continue). */
+ /* So this wrapper function disables asserts when calling _get_osfhandle. */
+
+ HANDLE handle;
+ UV_BEGIN_DISABLE_CRT_ASSERT();
+ handle = (HANDLE) _get_osfhandle(fd);
+ UV_END_DISABLE_CRT_ASSERT();
+ return handle;
+}
+
+#endif /* UV_WIN_HANDLE_INL_H_ */
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+
+
+uv_handle_type uv_guess_handle(uv_file file) {
+ HANDLE handle;
+ DWORD mode;
+
+ if (file < 0) {
+ return UV_UNKNOWN_HANDLE;
+ }
+
+ handle = uv__get_osfhandle(file);
+
+ switch (GetFileType(handle)) {
+ case FILE_TYPE_CHAR:
+ if (GetConsoleMode(handle, &mode)) {
+ return UV_TTY;
+ } else {
+ return UV_FILE;
+ }
+
+ case FILE_TYPE_PIPE:
+ return UV_NAMED_PIPE;
+
+ case FILE_TYPE_DISK:
+ return UV_FILE;
+
+ default:
+ return UV_UNKNOWN_HANDLE;
+ }
+}
+
+
+int uv_is_active(const uv_handle_t* handle) {
+ return (handle->flags & UV__HANDLE_ACTIVE) &&
+ !(handle->flags & UV__HANDLE_CLOSING);
+}
+
+
+void uv_close(uv_handle_t* handle, uv_close_cb cb) {
+ uv_loop_t* loop = handle->loop;
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ assert(0);
+ return;
+ }
+
+ handle->close_cb = cb;
+
+ /* Handle-specific close actions */
+ switch (handle->type) {
+ case UV_TCP:
+ uv_tcp_close(loop, (uv_tcp_t*)handle);
+ return;
+
+ case UV_NAMED_PIPE:
+ uv_pipe_close(loop, (uv_pipe_t*) handle);
+ return;
+
+ case UV_TTY:
+ uv_tty_close((uv_tty_t*) handle);
+ return;
+
+ case UV_UDP:
+ uv_udp_close(loop, (uv_udp_t*) handle);
+ return;
+
+ case UV_POLL:
+ uv_poll_close(loop, (uv_poll_t*) handle);
+ return;
+
+ case UV_TIMER:
+ uv_timer_stop((uv_timer_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_PREPARE:
+ uv_prepare_stop((uv_prepare_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_CHECK:
+ uv_check_stop((uv_check_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_IDLE:
+ uv_idle_stop((uv_idle_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_ASYNC:
+ uv_async_close(loop, (uv_async_t*) handle);
+ return;
+
+ case UV_SIGNAL:
+ uv_signal_close(loop, (uv_signal_t*) handle);
+ return;
+
+ case UV_PROCESS:
+ uv_process_close(loop, (uv_process_t*) handle);
+ return;
+
+ case UV_FS_EVENT:
+ uv_fs_event_close(loop, (uv_fs_event_t*) handle);
+ return;
+
+ case UV_FS_POLL:
+ uv__fs_poll_close((uv_fs_poll_t*) handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ default:
+ /* Not supported */
+ abort();
+ }
+}
+
+
+int uv_is_closing(const uv_handle_t* handle) {
+ return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED));
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef UV_WIN_INTERNAL_H_
+#define UV_WIN_INTERNAL_H_
+
+#include "uv.h"
+#include "../uv-common.h"
+
+#include "tree.h"
+#include "winapi.h"
+#include "winsock.h"
+
+#ifdef _MSC_VER
+# define INLINE __inline
+# define UV_THREAD_LOCAL __declspec( thread )
+#else
+# define INLINE inline
+# define UV_THREAD_LOCAL __thread
+#endif
+
+
+#ifdef _DEBUG
+
+extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
+
+#define UV_BEGIN_DISABLE_CRT_ASSERT() \
+ { \
+ int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \
+ uv__crt_assert_enabled = FALSE;
+
+
+#define UV_END_DISABLE_CRT_ASSERT() \
+ uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \
+ }
+
+#else
+#define UV_BEGIN_DISABLE_CRT_ASSERT()
+#define UV_END_DISABLE_CRT_ASSERT()
+#endif
+
+/*
+ * Handles
+ * (also see handle-inl.h)
+ */
+
+/* Used by all handles. */
+#define UV_HANDLE_CLOSED 0x00000002
+#define UV_HANDLE_ENDGAME_QUEUED 0x00000008
+
+/* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */
+/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */
+/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */
+/* uv-common.h: #define UV_HANDLE_INTERNAL 0x00000080 */
+
+/* Used by streams and UDP handles. */
+#define UV_HANDLE_READING 0x00000100
+#define UV_HANDLE_BOUND 0x00000200
+#define UV_HANDLE_LISTENING 0x00000800
+#define UV_HANDLE_CONNECTION 0x00001000
+#define UV_HANDLE_READABLE 0x00008000
+#define UV_HANDLE_WRITABLE 0x00010000
+#define UV_HANDLE_READ_PENDING 0x00020000
+#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000
+#define UV_HANDLE_ZERO_READ 0x00080000
+#define UV_HANDLE_EMULATE_IOCP 0x00100000
+#define UV_HANDLE_BLOCKING_WRITES 0x00200000
+#define UV_HANDLE_CANCELLATION_PENDING 0x00400000
+
+/* Used by uv_tcp_t and uv_udp_t handles */
+#define UV_HANDLE_IPV6 0x01000000
+
+/* Only used by uv_tcp_t handles. */
+#define UV_HANDLE_TCP_NODELAY 0x02000000
+#define UV_HANDLE_TCP_KEEPALIVE 0x04000000
+#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000
+#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000
+#define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000
+#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000
+
+/* Only used by uv_pipe_t handles. */
+#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000
+#define UV_HANDLE_PIPESERVER 0x02000000
+#define UV_HANDLE_PIPE_READ_CANCELABLE 0x04000000
+
+/* Only used by uv_tty_t handles. */
+#define UV_HANDLE_TTY_READABLE 0x01000000
+#define UV_HANDLE_TTY_RAW 0x02000000
+#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000
+#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000
+
+/* Only used by uv_poll_t handles. */
+#define UV_HANDLE_POLL_SLOW 0x02000000
+
+
+/*
+ * Requests: see req-inl.h
+ */
+
+
+/*
+ * Streams: see stream-inl.h
+ */
+
+
+/*
+ * TCP
+ */
+
+typedef struct {
+ WSAPROTOCOL_INFOW socket_info;
+ int delayed_error;
+} uv__ipc_socket_info_ex;
+
+int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
+int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
+int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
+int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[],
+ unsigned int nbufs);
+
+void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req);
+void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_write_t* req);
+void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_req_t* req);
+void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_connect_t* req);
+
+void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
+void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
+
+int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
+ int tcp_connection);
+
+int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
+ LPWSAPROTOCOL_INFOW protocol_info);
+
+
+/*
+ * UDP
+ */
+void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
+void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
+ uv_udp_send_t* req);
+
+void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle);
+void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
+
+
+/*
+ * Pipes
+ */
+int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
+ char* name, size_t nameSize);
+
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
+int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
+int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
+int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle,
+ uv_write_cb cb);
+void uv__pipe_pause_read(uv_pipe_t* handle);
+void uv__pipe_unpause_read(uv_pipe_t* handle);
+void uv__pipe_stop_read(uv_pipe_t* handle);
+
+void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* req);
+void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_write_t* req);
+void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* raw_req);
+void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_connect_t* req);
+void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_shutdown_t* req);
+
+void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
+void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle);
+void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
+
+
+/*
+ * TTY
+ */
+void uv_console_init();
+
+int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+int uv_tty_read_stop(uv_tty_t* handle);
+int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
+int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[],
+ unsigned int nbufs);
+void uv_tty_close(uv_tty_t* handle);
+
+void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req);
+void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_write_t* req);
+/* TODO: remove me */
+void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* raw_req);
+/* TODO: remove me */
+void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_connect_t* req);
+
+void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
+
+
+/*
+ * Poll watchers
+ */
+void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+ uv_req_t* req);
+
+int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle);
+void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
+
+
+/*
+ * Timers
+ */
+void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle);
+
+DWORD uv__next_timeout(const uv_loop_t* loop);
+void uv_process_timers(uv_loop_t* loop);
+
+
+/*
+ * Loop watchers
+ */
+void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle);
+
+void uv_prepare_invoke(uv_loop_t* loop);
+void uv_check_invoke(uv_loop_t* loop);
+void uv_idle_invoke(uv_loop_t* loop);
+
+void uv__once_init();
+
+
+/*
+ * Async watcher
+ */
+void uv_async_close(uv_loop_t* loop, uv_async_t* handle);
+void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle);
+
+void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
+ uv_req_t* req);
+
+
+/*
+ * Signal watcher
+ */
+void uv_signals_init();
+int uv__signal_dispatch(int signum);
+
+void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle);
+void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
+
+void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
+ uv_req_t* req);
+
+
+/*
+ * Spawn
+ */
+void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
+void uv_process_close(uv_loop_t* loop, uv_process_t* handle);
+void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
+
+
+/*
+ * Error
+ */
+int uv_translate_sys_error(int sys_errno);
+
+
+/*
+ * FS
+ */
+void uv_fs_init();
+
+
+/*
+ * FS Event
+ */
+void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
+ uv_fs_event_t* handle);
+void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
+void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
+
+
+/*
+ * Stat poller.
+ */
+void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
+
+
+/*
+ * Utilities.
+ */
+void uv__util_init();
+
+uint64_t uv__hrtime(double scale);
+int uv_parent_pid();
+int uv_current_pid();
+__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
+int uv__getpwuid_r(uv_passwd_t* pwd);
+int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
+
+
+/*
+ * Process stdio handles.
+ */
+int uv__stdio_create(uv_loop_t* loop,
+ const uv_process_options_t* options,
+ BYTE** buffer_ptr);
+void uv__stdio_destroy(BYTE* buffer);
+void uv__stdio_noinherit(BYTE* buffer);
+int uv__stdio_verify(BYTE* buffer, WORD size);
+WORD uv__stdio_size(BYTE* buffer);
+HANDLE uv__stdio_handle(BYTE* buffer, int fd);
+
+
+/*
+ * Winapi and ntapi utility functions
+ */
+void uv_winapi_init();
+
+
+/*
+ * Winsock utility functions
+ */
+void uv_winsock_init();
+
+int uv_ntstatus_to_winsock_error(NTSTATUS status);
+
+BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
+BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
+
+int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
+ int* addr_len, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+
+int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
+ AFD_POLL_INFO* info_out, OVERLAPPED* overlapped);
+
+/* Whether there are any non-IFS LSPs stacked on TCP */
+extern int uv_tcp_non_ifs_lsp_ipv4;
+extern int uv_tcp_non_ifs_lsp_ipv6;
+
+/* Ip address used to bind to any port at any interface */
+extern struct sockaddr_in uv_addr_ip4_any_;
+extern struct sockaddr_in6 uv_addr_ip6_any_;
+
+/*
+ * Wake all loops with fake message
+ */
+void uv__wake_all_loops();
+
+/*
+ * Init system wake-up detection
+ */
+void uv__init_detect_system_wakeup();
+
+#endif /* UV_WIN_INTERNAL_H_ */
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+
+
+void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ handle->flags |= UV_HANDLE_CLOSED;
+ uv__handle_close(handle);
+ }
+}
+
+
+#define UV_LOOP_WATCHER_DEFINE(name, NAME) \
+ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \
+ \
+ return 0; \
+ } \
+ \
+ \
+ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
+ uv_loop_t* loop = handle->loop; \
+ uv_##name##_t* old_head; \
+ \
+ assert(handle->type == UV_##NAME); \
+ \
+ if (uv__is_active(handle)) \
+ return 0; \
+ \
+ if (cb == NULL) \
+ return UV_EINVAL; \
+ \
+ old_head = loop->name##_handles; \
+ \
+ handle->name##_next = old_head; \
+ handle->name##_prev = NULL; \
+ \
+ if (old_head) { \
+ old_head->name##_prev = handle; \
+ } \
+ \
+ loop->name##_handles = handle; \
+ \
+ handle->name##_cb = cb; \
+ uv__handle_start(handle); \
+ \
+ return 0; \
+ } \
+ \
+ \
+ int uv_##name##_stop(uv_##name##_t* handle) { \
+ uv_loop_t* loop = handle->loop; \
+ \
+ assert(handle->type == UV_##NAME); \
+ \
+ if (!uv__is_active(handle)) \
+ return 0; \
+ \
+ /* Update loop head if needed */ \
+ if (loop->name##_handles == handle) { \
+ loop->name##_handles = handle->name##_next; \
+ } \
+ \
+ /* Update the iterator-next pointer of needed */ \
+ if (loop->next_##name##_handle == handle) { \
+ loop->next_##name##_handle = handle->name##_next; \
+ } \
+ \
+ if (handle->name##_prev) { \
+ handle->name##_prev->name##_next = handle->name##_next; \
+ } \
+ if (handle->name##_next) { \
+ handle->name##_next->name##_prev = handle->name##_prev; \
+ } \
+ \
+ uv__handle_stop(handle); \
+ \
+ return 0; \
+ } \
+ \
+ \
+ void uv_##name##_invoke(uv_loop_t* loop) { \
+ uv_##name##_t* handle; \
+ \
+ (loop)->next_##name##_handle = (loop)->name##_handles; \
+ \
+ while ((loop)->next_##name##_handle != NULL) { \
+ handle = (loop)->next_##name##_handle; \
+ (loop)->next_##name##_handle = handle->name##_next; \
+ \
+ handle->name##_cb(handle); \
+ } \
+ }
+
+UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
+UV_LOOP_WATCHER_DEFINE(check, CHECK)
+UV_LOOP_WATCHER_DEFINE(idle, IDLE)
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;
+
+struct uv__ipc_queue_item_s {
+ /*
+ * NOTE: It is important for socket_info_ex to be the first field,
+ * because we will we assigning it to the pending_ipc_info.socket_info
+ */
+ uv__ipc_socket_info_ex socket_info_ex;
+ QUEUE member;
+ int tcp_connection;
+};
+
+/* A zero-size buffer for use by uv_pipe_read */
+static char uv_zero_[] = "";
+
+/* Null uv_buf_t */
+static const uv_buf_t uv_null_buf_ = { 0, NULL };
+
+/* The timeout that the pipe will wait for the remote end to write data */
+/* when the local ends wants to shut it down. */
+static const int64_t eof_timeout = 50; /* ms */
+
+static const int default_pending_pipe_instances = 4;
+
+/* Pipe prefix */
+static char pipe_prefix[] = "\\\\?\\pipe";
+static const int pipe_prefix_len = sizeof(pipe_prefix) - 1;
+
+/* IPC protocol flags. */
+#define UV_IPC_RAW_DATA 0x0001
+#define UV_IPC_TCP_SERVER 0x0002
+#define UV_IPC_TCP_CONNECTION 0x0004
+
+/* IPC frame header. */
+typedef struct {
+ int flags;
+ uint64_t raw_data_length;
+} uv_ipc_frame_header_t;
+
+/* IPC frame, which contains an imported TCP socket stream. */
+typedef struct {
+ uv_ipc_frame_header_t header;
+ uv__ipc_socket_info_ex socket_info_ex;
+} uv_ipc_frame_uv_stream;
+
+static void eof_timer_init(uv_pipe_t* pipe);
+static void eof_timer_start(uv_pipe_t* pipe);
+static void eof_timer_stop(uv_pipe_t* pipe);
+static void eof_timer_cb(uv_timer_t* timer);
+static void eof_timer_destroy(uv_pipe_t* pipe);
+static void eof_timer_close_cb(uv_handle_t* handle);
+
+
+static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
+ snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId());
+}
+
+
+int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
+ uv_stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
+
+ handle->reqs_pending = 0;
+ handle->handle = INVALID_HANDLE_VALUE;
+ handle->name = NULL;
+ handle->pipe.conn.ipc_pid = 0;
+ handle->pipe.conn.remaining_ipc_rawdata_bytes = 0;
+ QUEUE_INIT(&handle->pipe.conn.pending_ipc_info.queue);
+ handle->pipe.conn.pending_ipc_info.queue_len = 0;
+ handle->ipc = ipc;
+ handle->pipe.conn.non_overlapped_writes_tail = NULL;
+ handle->pipe.conn.readfile_thread = NULL;
+
+ uv_req_init(loop, (uv_req_t*) &handle->pipe.conn.ipc_header_write_req);
+
+ return 0;
+}
+
+
+static void uv_pipe_connection_init(uv_pipe_t* handle) {
+ uv_connection_init((uv_stream_t*) handle);
+ handle->read_req.data = handle;
+ handle->pipe.conn.eof_timer = NULL;
+ assert(!(handle->flags & UV_HANDLE_PIPESERVER));
+ if (pCancelSynchronousIo &&
+ handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
+ uv_mutex_init(&handle->pipe.conn.readfile_mutex);
+ handle->flags |= UV_HANDLE_PIPE_READ_CANCELABLE;
+ }
+}
+
+
+static HANDLE open_named_pipe(const WCHAR* name, DWORD* duplex_flags) {
+ HANDLE pipeHandle;
+
+ /*
+ * Assume that we have a duplex pipe first, so attempt to
+ * connect with GENERIC_READ | GENERIC_WRITE.
+ */
+ pipeHandle = CreateFileW(name,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ return pipeHandle;
+ }
+
+ /*
+ * If the pipe is not duplex CreateFileW fails with
+ * ERROR_ACCESS_DENIED. In that case try to connect
+ * as a read-only or write-only.
+ */
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
+ pipeHandle = CreateFileW(name,
+ GENERIC_READ | FILE_WRITE_ATTRIBUTES,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_READABLE;
+ return pipeHandle;
+ }
+ }
+
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
+ pipeHandle = CreateFileW(name,
+ GENERIC_WRITE | FILE_READ_ATTRIBUTES,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_WRITABLE;
+ return pipeHandle;
+ }
+ }
+
+ return INVALID_HANDLE_VALUE;
+}
+
+
+static void close_pipe(uv_pipe_t* pipe) {
+ assert(pipe->u.fd == -1 || pipe->u.fd > 2);
+ if (pipe->u.fd == -1)
+ CloseHandle(pipe->handle);
+ else
+ close(pipe->u.fd);
+
+ pipe->u.fd = -1;
+ pipe->handle = INVALID_HANDLE_VALUE;
+}
+
+
+int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
+ char* name, size_t nameSize) {
+ HANDLE pipeHandle;
+ int err;
+ char* ptr = (char*)handle;
+
+ for (;;) {
+ uv_unique_pipe_name(ptr, name, nameSize);
+
+ pipeHandle = CreateNamedPipeA(name,
+ access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ /* No name collisions. We're done. */
+ break;
+ }
+
+ err = GetLastError();
+ if (err != ERROR_PIPE_BUSY && err != ERROR_ACCESS_DENIED) {
+ goto error;
+ }
+
+ /* Pipe name collision. Increment the pointer and try again. */
+ ptr++;
+ }
+
+ if (CreateIoCompletionPort(pipeHandle,
+ loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ err = GetLastError();
+ goto error;
+ }
+
+ uv_pipe_connection_init(handle);
+ handle->handle = pipeHandle;
+
+ return 0;
+
+ error:
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
+ }
+
+ return err;
+}
+
+
+static int uv_set_pipe_handle(uv_loop_t* loop,
+ uv_pipe_t* handle,
+ HANDLE pipeHandle,
+ int fd,
+ DWORD duplex_flags) {
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_MODE_INFORMATION mode_info;
+ DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ DWORD current_mode = 0;
+ DWORD err = 0;
+
+ if (!(handle->flags & UV_HANDLE_PIPESERVER) &&
+ handle->handle != INVALID_HANDLE_VALUE)
+ return UV_EBUSY;
+
+ if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
+ err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED) {
+ /*
+ * SetNamedPipeHandleState can fail if the handle doesn't have either
+ * GENERIC_WRITE or FILE_WRITE_ATTRIBUTES.
+ * But if the handle already has the desired wait and blocking modes
+ * we can continue.
+ */
+ if (!GetNamedPipeHandleState(pipeHandle, ¤t_mode, NULL, NULL,
+ NULL, NULL, 0)) {
+ return -1;
+ } else if (current_mode & PIPE_NOWAIT) {
+ SetLastError(ERROR_ACCESS_DENIED);
+ return -1;
+ }
+ } else {
+ /* If this returns ERROR_INVALID_PARAMETER we probably opened
+ * something that is not a pipe. */
+ if (err == ERROR_INVALID_PARAMETER) {
+ SetLastError(WSAENOTSOCK);
+ }
+ return -1;
+ }
+ }
+
+ /* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */
+ nt_status = pNtQueryInformationFile(pipeHandle,
+ &io_status,
+ &mode_info,
+ sizeof(mode_info),
+ FileModeInformation);
+ if (nt_status != STATUS_SUCCESS) {
+ return -1;
+ }
+
+ if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT ||
+ mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) {
+ /* Non-overlapped pipe. */
+ handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE;
+ } else {
+ /* Overlapped pipe. Try to associate with IOCP. */
+ if (CreateIoCompletionPort(pipeHandle,
+ loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ handle->flags |= UV_HANDLE_EMULATE_IOCP;
+ }
+ }
+
+ handle->handle = pipeHandle;
+ handle->u.fd = fd;
+ handle->flags |= duplex_flags;
+
+ return 0;
+}
+
+
+static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
+ uv_loop_t* loop;
+ uv_pipe_t* handle;
+ uv_shutdown_t* req;
+
+ req = (uv_shutdown_t*) parameter;
+ assert(req);
+ handle = (uv_pipe_t*) req->handle;
+ assert(handle);
+ loop = handle->loop;
+ assert(loop);
+
+ FlushFileBuffers(handle->handle);
+
+ /* Post completed */
+ POST_COMPLETION_FOR_REQ(loop, req);
+
+ return 0;
+}
+
+
+void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
+ int err;
+ DWORD result;
+ uv_shutdown_t* req;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_PIPE_LOCAL_INFORMATION pipe_info;
+ uv__ipc_queue_item_t* item;
+
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ handle->flags &= ~UV_HANDLE_PIPE_READ_CANCELABLE;
+ uv_mutex_destroy(&handle->pipe.conn.readfile_mutex);
+ }
+
+ if ((handle->flags & UV_HANDLE_CONNECTION) &&
+ handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ req = handle->stream.conn.shutdown_req;
+
+ /* Clear the shutdown_req field so we don't go here again. */
+ handle->stream.conn.shutdown_req = NULL;
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ /* Already closing. Cancel the shutdown. */
+ if (req->cb) {
+ req->cb(req, UV_ECANCELED);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ /* Try to avoid flushing the pipe buffer in the thread pool. */
+ nt_status = pNtQueryInformationFile(handle->handle,
+ &io_status,
+ &pipe_info,
+ sizeof pipe_info,
+ FilePipeLocalInformation);
+
+ if (nt_status != STATUS_SUCCESS) {
+ /* Failure */
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
+ if (req->cb) {
+ err = pRtlNtStatusToDosError(nt_status);
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) {
+ /* Short-circuit, no need to call FlushFileBuffers. */
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ return;
+ }
+
+ /* Run FlushFileBuffers in the thread pool. */
+ result = QueueUserWorkItem(pipe_shutdown_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION);
+ if (result) {
+ return;
+
+ } else {
+ /* Failure. */
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
+ if (req->cb) {
+ err = GetLastError();
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+ }
+
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ if (handle->flags & UV_HANDLE_CONNECTION) {
+ /* Free pending sockets */
+ while (!QUEUE_EMPTY(&handle->pipe.conn.pending_ipc_info.queue)) {
+ QUEUE* q;
+ SOCKET socket;
+
+ q = QUEUE_HEAD(&handle->pipe.conn.pending_ipc_info.queue);
+ QUEUE_REMOVE(q);
+ item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
+
+ /* Materialize socket and close it */
+ socket = WSASocketW(FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ &item->socket_info_ex.socket_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+ uv__free(item);
+
+ if (socket != INVALID_SOCKET)
+ closesocket(socket);
+ }
+ handle->pipe.conn.pending_ipc_info.queue_len = 0;
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(handle->read_req.wait_handle);
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (handle->read_req.event_handle) {
+ CloseHandle(handle->read_req.event_handle);
+ handle->read_req.event_handle = NULL;
+ }
+ }
+ }
+
+ if (handle->flags & UV_HANDLE_PIPESERVER) {
+ assert(handle->pipe.serv.accept_reqs);
+ uv__free(handle->pipe.serv.accept_reqs);
+ handle->pipe.serv.accept_reqs = NULL;
+ }
+
+ uv__handle_close(handle);
+ }
+}
+
+
+void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
+ if (handle->flags & UV_HANDLE_BOUND)
+ return;
+ handle->pipe.serv.pending_instances = count;
+ handle->flags |= UV_HANDLE_PIPESERVER;
+}
+
+
+/* Creates a pipe server. */
+int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
+ uv_loop_t* loop = handle->loop;
+ int i, err, nameSize;
+ uv_pipe_accept_t* req;
+
+ if (handle->flags & UV_HANDLE_BOUND) {
+ return UV_EINVAL;
+ }
+
+ if (!name) {
+ return UV_EINVAL;
+ }
+
+ if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
+ handle->pipe.serv.pending_instances = default_pending_pipe_instances;
+ }
+
+ handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*)
+ uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances);
+ if (!handle->pipe.serv.accept_reqs) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+ req = &handle->pipe.serv.accept_reqs[i];
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_ACCEPT;
+ req->data = handle;
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ req->next_pending = NULL;
+ }
+
+ /* Convert name to UTF16. */
+ nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
+ handle->name = (WCHAR*)uv__malloc(nameSize);
+ if (!handle->name) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!MultiByteToWideChar(CP_UTF8,
+ 0,
+ name,
+ -1,
+ handle->name,
+ nameSize / sizeof(WCHAR))) {
+ err = GetLastError();
+ goto error;
+ }
+
+ /*
+ * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE.
+ * If this fails then there's already a pipe server for the given pipe name.
+ */
+ handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
+ FILE_FLAG_FIRST_PIPE_INSTANCE,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
+
+ if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED) {
+ err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */
+ } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) {
+ err = WSAEACCES; /* Translates to UV_EACCES. */
+ }
+ goto error;
+ }
+
+ if (uv_set_pipe_handle(loop,
+ handle,
+ handle->pipe.serv.accept_reqs[0].pipeHandle,
+ -1,
+ 0)) {
+ err = GetLastError();
+ goto error;
+ }
+
+ handle->pipe.serv.pending_accepts = NULL;
+ handle->flags |= UV_HANDLE_PIPESERVER;
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+
+error:
+ if (handle->name) {
+ uv__free(handle->name);
+ handle->name = NULL;
+ }
+
+ if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle);
+ handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
+ uv_loop_t* loop;
+ uv_pipe_t* handle;
+ uv_connect_t* req;
+ HANDLE pipeHandle = INVALID_HANDLE_VALUE;
+ DWORD duplex_flags;
+
+ req = (uv_connect_t*) parameter;
+ assert(req);
+ handle = (uv_pipe_t*) req->handle;
+ assert(handle);
+ loop = handle->loop;
+ assert(loop);
+
+ /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */
+ /* We wait for the pipe to become available with WaitNamedPipe. */
+ while (WaitNamedPipeW(handle->name, 30000)) {
+ /* The pipe is now available, try to connect. */
+ pipeHandle = open_named_pipe(handle->name, &duplex_flags);
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ break;
+ }
+
+ SwitchToThread();
+ }
+
+ if (pipeHandle != INVALID_HANDLE_VALUE &&
+ !uv_set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ SET_REQ_ERROR(req, GetLastError());
+ }
+
+ /* Post completed */
+ POST_COMPLETION_FOR_REQ(loop, req);
+
+ return 0;
+}
+
+
+void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
+ const char* name, uv_connect_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int err, nameSize;
+ HANDLE pipeHandle = INVALID_HANDLE_VALUE;
+ DWORD duplex_flags;
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_CONNECT;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+
+ /* Convert name to UTF16. */
+ nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
+ handle->name = (WCHAR*)uv__malloc(nameSize);
+ if (!handle->name) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!MultiByteToWideChar(CP_UTF8,
+ 0,
+ name,
+ -1,
+ handle->name,
+ nameSize / sizeof(WCHAR))) {
+ err = GetLastError();
+ goto error;
+ }
+
+ pipeHandle = open_named_pipe(handle->name, &duplex_flags);
+ if (pipeHandle == INVALID_HANDLE_VALUE) {
+ if (GetLastError() == ERROR_PIPE_BUSY) {
+ /* Wait for the server to make a pipe instance available. */
+ if (!QueueUserWorkItem(&pipe_connect_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION)) {
+ err = GetLastError();
+ goto error;
+ }
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+
+ return;
+ }
+
+ err = GetLastError();
+ goto error;
+ }
+
+ assert(pipeHandle != INVALID_HANDLE_VALUE);
+
+ if (uv_set_pipe_handle(loop,
+ (uv_pipe_t*) req->handle,
+ pipeHandle,
+ -1,
+ duplex_flags)) {
+ err = GetLastError();
+ goto error;
+ }
+
+ SET_REQ_SUCCESS(req);
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ return;
+
+error:
+ if (handle->name) {
+ uv__free(handle->name);
+ handle->name = NULL;
+ }
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
+ }
+
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, err);
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ return;
+}
+
+
+void uv__pipe_pause_read(uv_pipe_t* handle) {
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ /* Pause the ReadFile task briefly, to work
+ around the Windows kernel bug that causes
+ any access to a NamedPipe to deadlock if
+ any process has called ReadFile */
+ HANDLE h;
+ uv_mutex_lock(&handle->pipe.conn.readfile_mutex);
+ h = handle->pipe.conn.readfile_thread;
+ while (h) {
+ /* spinlock: we expect this to finish quickly,
+ or we are probably about to deadlock anyways
+ (in the kernel), so it doesn't matter */
+ pCancelSynchronousIo(h);
+ SwitchToThread(); /* yield thread control briefly */
+ h = handle->pipe.conn.readfile_thread;
+ }
+ }
+}
+
+
+void uv__pipe_unpause_read(uv_pipe_t* handle) {
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ uv_mutex_unlock(&handle->pipe.conn.readfile_mutex);
+ }
+}
+
+
+void uv__pipe_stop_read(uv_pipe_t* handle) {
+ handle->flags &= ~UV_HANDLE_READING;
+ uv__pipe_pause_read((uv_pipe_t*)handle);
+ uv__pipe_unpause_read((uv_pipe_t*)handle);
+}
+
+
+/* Cleans up uv_pipe_t (server or connection) and all resources associated */
+/* with it. */
+void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
+ int i;
+ HANDLE pipeHandle;
+
+ uv__pipe_stop_read(handle);
+
+ if (handle->name) {
+ uv__free(handle->name);
+ handle->name = NULL;
+ }
+
+ if (handle->flags & UV_HANDLE_PIPESERVER) {
+ for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+ pipeHandle = handle->pipe.serv.accept_reqs[i].pipeHandle;
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
+ handle->pipe.serv.accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE;
+ }
+ }
+ handle->handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (handle->flags & UV_HANDLE_CONNECTION) {
+ handle->flags &= ~UV_HANDLE_WRITABLE;
+ eof_timer_destroy(handle);
+ }
+
+ if ((handle->flags & UV_HANDLE_CONNECTION)
+ && handle->handle != INVALID_HANDLE_VALUE)
+ close_pipe(handle);
+}
+
+
+void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->flags &= ~UV_HANDLE_LISTENING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+
+ uv_pipe_cleanup(loop, handle);
+
+ if (handle->reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+
+ handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+ uv__handle_closing(handle);
+}
+
+
+static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_pipe_accept_t* req, BOOL firstInstance) {
+ assert(handle->flags & UV_HANDLE_LISTENING);
+
+ if (!firstInstance) {
+ assert(req->pipeHandle == INVALID_HANDLE_VALUE);
+
+ req->pipeHandle = CreateNamedPipeW(handle->name,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
+
+ if (req->pipeHandle == INVALID_HANDLE_VALUE) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ return;
+ }
+
+ if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) {
+ CloseHandle(req->pipeHandle);
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ return;
+ }
+ }
+
+ assert(req->pipeHandle != INVALID_HANDLE_VALUE);
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+
+ if (!ConnectNamedPipe(req->pipeHandle, &req->u.io.overlapped) &&
+ GetLastError() != ERROR_IO_PENDING) {
+ if (GetLastError() == ERROR_PIPE_CONNECTED) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ CloseHandle(req->pipeHandle);
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ }
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ return;
+ }
+
+ handle->reqs_pending++;
+}
+
+
+int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
+ uv_loop_t* loop = server->loop;
+ uv_pipe_t* pipe_client;
+ uv_pipe_accept_t* req;
+ QUEUE* q;
+ uv__ipc_queue_item_t* item;
+ int err;
+
+ if (server->ipc) {
+ if (QUEUE_EMPTY(&server->pipe.conn.pending_ipc_info.queue)) {
+ /* No valid pending sockets. */
+ return WSAEWOULDBLOCK;
+ }
+
+ q = QUEUE_HEAD(&server->pipe.conn.pending_ipc_info.queue);
+ QUEUE_REMOVE(q);
+ server->pipe.conn.pending_ipc_info.queue_len--;
+ item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
+
+ err = uv_tcp_import((uv_tcp_t*)client,
+ &item->socket_info_ex,
+ item->tcp_connection);
+ if (err != 0)
+ return err;
+
+ uv__free(item);
+
+ } else {
+ pipe_client = (uv_pipe_t*)client;
+
+ /* Find a connection instance that has been connected, but not yet */
+ /* accepted. */
+ req = server->pipe.serv.pending_accepts;
+
+ if (!req) {
+ /* No valid connections found, so we error out. */
+ return WSAEWOULDBLOCK;
+ }
+
+ /* Initialize the client handle and copy the pipeHandle to the client */
+ uv_pipe_connection_init(pipe_client);
+ pipe_client->handle = req->pipeHandle;
+ pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+
+ /* Prepare the req to pick up a new connection */
+ server->pipe.serv.pending_accepts = req->next_pending;
+ req->next_pending = NULL;
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+
+ if (!(server->flags & UV__HANDLE_CLOSING)) {
+ uv_pipe_queue_accept(loop, server, req, FALSE);
+ }
+ }
+
+ return 0;
+}
+
+
+/* Starts listening for connections for the given pipe. */
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int i;
+
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->stream.serv.connection_cb = cb;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ return WSAEINVAL;
+ }
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return WSAEISCONN;
+ }
+
+ if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ handle->flags |= UV_HANDLE_LISTENING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ handle->stream.serv.connection_cb = cb;
+
+ /* First pipe handle should have already been created in uv_pipe_bind */
+ assert(handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE);
+
+ for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+ uv_pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0);
+ }
+
+ return 0;
+}
+
+
+static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
+ int result;
+ DWORD bytes;
+ uv_read_t* req = (uv_read_t*) parameter;
+ uv_pipe_t* handle = (uv_pipe_t*) req->data;
+ uv_loop_t* loop = handle->loop;
+ HANDLE hThread = NULL;
+ DWORD err;
+ uv_mutex_t *m = &handle->pipe.conn.readfile_mutex;
+
+ assert(req != NULL);
+ assert(req->type == UV_READ);
+ assert(handle->type == UV_NAMED_PIPE);
+
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ uv_mutex_lock(m); /* mutex controls *setting* of readfile_thread */
+ if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), &hThread,
+ 0, TRUE, DUPLICATE_SAME_ACCESS)) {
+ handle->pipe.conn.readfile_thread = hThread;
+ } else {
+ hThread = NULL;
+ }
+ uv_mutex_unlock(m);
+ }
+restart_readfile:
+ result = ReadFile(handle->handle,
+ &uv_zero_,
+ 0,
+ &bytes,
+ NULL);
+ if (!result) {
+ err = GetLastError();
+ if (err == ERROR_OPERATION_ABORTED &&
+ handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ if (handle->flags & UV_HANDLE_READING) {
+ /* just a brief break to do something else */
+ handle->pipe.conn.readfile_thread = NULL;
+ /* resume after it is finished */
+ uv_mutex_lock(m);
+ handle->pipe.conn.readfile_thread = hThread;
+ uv_mutex_unlock(m);
+ goto restart_readfile;
+ } else {
+ result = 1; /* successfully stopped reading */
+ }
+ }
+ }
+ if (hThread) {
+ assert(hThread == handle->pipe.conn.readfile_thread);
+ /* mutex does not control clearing readfile_thread */
+ handle->pipe.conn.readfile_thread = NULL;
+ uv_mutex_lock(m);
+ /* only when we hold the mutex lock is it safe to
+ open or close the handle */
+ CloseHandle(hThread);
+ uv_mutex_unlock(m);
+ }
+
+ if (!result) {
+ SET_REQ_ERROR(req, err);
+ }
+
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+}
+
+
+static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) {
+ int result;
+ DWORD bytes;
+ uv_write_t* req = (uv_write_t*) parameter;
+ uv_pipe_t* handle = (uv_pipe_t*) req->handle;
+ uv_loop_t* loop = handle->loop;
+
+ assert(req != NULL);
+ assert(req->type == UV_WRITE);
+ assert(handle->type == UV_NAMED_PIPE);
+ assert(req->write_buffer.base);
+
+ result = WriteFile(handle->handle,
+ req->write_buffer.base,
+ req->write_buffer.len,
+ &bytes,
+ NULL);
+
+ if (!result) {
+ SET_REQ_ERROR(req, GetLastError());
+ }
+
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+}
+
+
+static void CALLBACK post_completion_read_wait(void* context, BOOLEAN timed_out) {
+ uv_read_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_read_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->data;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out) {
+ uv_write_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_write_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->handle;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
+ uv_read_t* req;
+ int result;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ assert(handle->handle != INVALID_HANDLE_VALUE);
+
+ req = &handle->read_req;
+
+ if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
+ if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION)) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ goto error;
+ }
+ } else {
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
+ }
+
+ /* Do 0-read */
+ result = ReadFile(handle->handle,
+ &uv_zero_,
+ 0,
+ NULL,
+ &req->u.io.overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ goto error;
+ }
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (!req->event_handle) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ }
+ if (req->wait_handle == INVALID_HANDLE_VALUE) {
+ if (!RegisterWaitForSingleObject(&req->wait_handle,
+ req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ SET_REQ_ERROR(req, GetLastError());
+ goto error;
+ }
+ }
+ }
+ }
+
+ /* Start the eof timer if there is one */
+ eof_timer_start(handle);
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ return;
+
+error:
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+}
+
+
+int uv_pipe_read_start(uv_pipe_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ uv_loop_t* loop = handle->loop;
+
+ handle->flags |= UV_HANDLE_READING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb = read_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* read request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
+ uv_pipe_queue_read(loop, handle);
+
+ return 0;
+}
+
+
+static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle,
+ uv_write_t* req) {
+ req->next_req = NULL;
+ if (handle->pipe.conn.non_overlapped_writes_tail) {
+ req->next_req =
+ handle->pipe.conn.non_overlapped_writes_tail->next_req;
+ handle->pipe.conn.non_overlapped_writes_tail->next_req = (uv_req_t*)req;
+ handle->pipe.conn.non_overlapped_writes_tail = req;
+ } else {
+ req->next_req = (uv_req_t*)req;
+ handle->pipe.conn.non_overlapped_writes_tail = req;
+ }
+}
+
+
+static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) {
+ uv_write_t* req;
+
+ if (handle->pipe.conn.non_overlapped_writes_tail) {
+ req = (uv_write_t*)handle->pipe.conn.non_overlapped_writes_tail->next_req;
+
+ if (req == handle->pipe.conn.non_overlapped_writes_tail) {
+ handle->pipe.conn.non_overlapped_writes_tail = NULL;
+ } else {
+ handle->pipe.conn.non_overlapped_writes_tail->next_req =
+ req->next_req;
+ }
+
+ return req;
+ } else {
+ /* queue empty */
+ return NULL;
+ }
+}
+
+
+static void uv_queue_non_overlapped_write(uv_pipe_t* handle) {
+ uv_write_t* req = uv_remove_non_overlapped_write_req(handle);
+ if (req) {
+ if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION)) {
+ uv_fatal_error(GetLastError(), "QueueUserWorkItem");
+ }
+ }
+}
+
+
+static int uv_pipe_write_impl(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_pipe_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ int err;
+ int result;
+ uv_tcp_t* tcp_send_handle;
+ uv_write_t* ipc_header_req = NULL;
+ uv_ipc_frame_uv_stream ipc_frame;
+
+ if (nbufs != 1 && (nbufs != 0 || !send_handle)) {
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ /* Only TCP handles are supported for sharing. */
+ if (send_handle && ((send_handle->type != UV_TCP) ||
+ (!(send_handle->flags & UV_HANDLE_BOUND) &&
+ !(send_handle->flags & UV_HANDLE_CONNECTION)))) {
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ assert(handle->handle != INVALID_HANDLE_VALUE);
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_WRITE;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+ req->ipc_header = 0;
+ req->event_handle = NULL;
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ if (handle->ipc) {
+ assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
+ ipc_frame.header.flags = 0;
+
+ /* Use the IPC framing protocol. */
+ if (send_handle) {
+ tcp_send_handle = (uv_tcp_t*)send_handle;
+
+ if (handle->pipe.conn.ipc_pid == 0) {
+ handle->pipe.conn.ipc_pid = uv_current_pid();
+ }
+
+ err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid,
+ &ipc_frame.socket_info_ex.socket_info);
+ if (err) {
+ return err;
+ }
+
+ ipc_frame.socket_info_ex.delayed_error = tcp_send_handle->delayed_error;
+
+ ipc_frame.header.flags |= UV_IPC_TCP_SERVER;
+
+ if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) {
+ ipc_frame.header.flags |= UV_IPC_TCP_CONNECTION;
+ }
+ }
+
+ if (nbufs == 1) {
+ ipc_frame.header.flags |= UV_IPC_RAW_DATA;
+ ipc_frame.header.raw_data_length = bufs[0].len;
+ }
+
+ /*
+ * Use the provided req if we're only doing a single write.
+ * If we're doing multiple writes, use ipc_header_write_req to do
+ * the first write, and then use the provided req for the second write.
+ */
+ if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
+ ipc_header_req = req;
+ } else {
+ /*
+ * Try to use the preallocated write req if it's available.
+ * Otherwise allocate a new one.
+ */
+ if (handle->pipe.conn.ipc_header_write_req.type != UV_WRITE) {
+ ipc_header_req = (uv_write_t*)&handle->pipe.conn.ipc_header_write_req;
+ } else {
+ ipc_header_req = (uv_write_t*)uv__malloc(sizeof(uv_write_t));
+ if (!ipc_header_req) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+ }
+
+ uv_req_init(loop, (uv_req_t*) ipc_header_req);
+ ipc_header_req->type = UV_WRITE;
+ ipc_header_req->handle = (uv_stream_t*) handle;
+ ipc_header_req->cb = NULL;
+ ipc_header_req->ipc_header = 1;
+ }
+
+ /* Write the header or the whole frame. */
+ memset(&ipc_header_req->u.io.overlapped, 0,
+ sizeof(ipc_header_req->u.io.overlapped));
+
+ /* Using overlapped IO, but wait for completion before returning.
+ This write is blocking because ipc_frame is on stack. */
+ ipc_header_req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
+ if (!ipc_header_req->u.io.overlapped.hEvent) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+
+ result = WriteFile(handle->handle,
+ &ipc_frame,
+ ipc_frame.header.flags & UV_IPC_TCP_SERVER ?
+ sizeof(ipc_frame) : sizeof(ipc_frame.header),
+ NULL,
+ &ipc_header_req->u.io.overlapped);
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ err = GetLastError();
+ CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+ return err;
+ }
+
+ if (!result) {
+ /* Request not completed immediately. Wait for it.*/
+ if (WaitForSingleObject(ipc_header_req->u.io.overlapped.hEvent, INFINITE) !=
+ WAIT_OBJECT_0) {
+ err = GetLastError();
+ CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+ return err;
+ }
+ }
+ ipc_header_req->u.io.queued_bytes = 0;
+ CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+ ipc_header_req->u.io.overlapped.hEvent = NULL;
+
+ REGISTER_HANDLE_REQ(loop, handle, ipc_header_req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+
+ /* If we don't have any raw data to write - we're done. */
+ if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
+ return 0;
+ }
+ }
+
+ if ((handle->flags &
+ (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) ==
+ (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) {
+ DWORD bytes;
+ result = WriteFile(handle->handle,
+ bufs[0].base,
+ bufs[0].len,
+ &bytes,
+ NULL);
+
+ if (!result) {
+ err = GetLastError();
+ return err;
+ } else {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ }
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+ } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
+ req->write_buffer = bufs[0];
+ uv_insert_non_overlapped_write_req(handle, req);
+ if (handle->stream.conn.write_reqs_pending == 0) {
+ uv_queue_non_overlapped_write(handle);
+ }
+
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = bufs[0].len;
+ handle->write_queue_size += req->u.io.queued_bytes;
+ } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) {
+ /* Using overlapped IO, but wait for completion before returning */
+ req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
+ if (!req->u.io.overlapped.hEvent) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+
+ result = WriteFile(handle->handle,
+ bufs[0].base,
+ bufs[0].len,
+ NULL,
+ &req->u.io.overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ err = GetLastError();
+ CloseHandle(req->u.io.overlapped.hEvent);
+ return err;
+ }
+
+ if (result) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ } else {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = bufs[0].len;
+ handle->write_queue_size += req->u.io.queued_bytes;
+ if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) !=
+ WAIT_OBJECT_0) {
+ err = GetLastError();
+ CloseHandle(req->u.io.overlapped.hEvent);
+ return uv_translate_sys_error(err);
+ }
+ }
+ CloseHandle(req->u.io.overlapped.hEvent);
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ return 0;
+ } else {
+ result = WriteFile(handle->handle,
+ bufs[0].base,
+ bufs[0].len,
+ NULL,
+ &req->u.io.overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ return GetLastError();
+ }
+
+ if (result) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ } else {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = bufs[0].len;
+ handle->write_queue_size += req->u.io.queued_bytes;
+ }
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ if (!RegisterWaitForSingleObject(&req->wait_handle,
+ req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ return GetLastError();
+ }
+ }
+ }
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+
+ return 0;
+}
+
+
+int uv_pipe_write(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_pipe_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, NULL, cb);
+}
+
+
+int uv_pipe_write2(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_pipe_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ if (!handle->ipc) {
+ return WSAEINVAL;
+ }
+
+ return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, send_handle, cb);
+}
+
+
+static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_buf_t buf) {
+ /* If there is an eof timer running, we don't need it any more, */
+ /* so discard it. */
+ eof_timer_destroy(handle);
+
+ handle->flags &= ~UV_HANDLE_READABLE;
+ uv_read_stop((uv_stream_t*) handle);
+
+ handle->read_cb((uv_stream_t*) handle, UV_EOF, &buf);
+}
+
+
+static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
+ uv_buf_t buf) {
+ /* If there is an eof timer running, we don't need it any more, */
+ /* so discard it. */
+ eof_timer_destroy(handle);
+
+ uv_read_stop((uv_stream_t*) handle);
+
+ handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(error), &buf);
+}
+
+
+static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
+ int error, uv_buf_t buf) {
+ if (error == ERROR_BROKEN_PIPE) {
+ uv_pipe_read_eof(loop, handle, buf);
+ } else {
+ uv_pipe_read_error(loop, handle, error, buf);
+ }
+}
+
+
+void uv__pipe_insert_pending_socket(uv_pipe_t* handle,
+ uv__ipc_socket_info_ex* info,
+ int tcp_connection) {
+ uv__ipc_queue_item_t* item;
+
+ item = (uv__ipc_queue_item_t*) uv__malloc(sizeof(*item));
+ if (item == NULL)
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+
+ memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex));
+ item->tcp_connection = tcp_connection;
+ QUEUE_INSERT_TAIL(&handle->pipe.conn.pending_ipc_info.queue, &item->member);
+ handle->pipe.conn.pending_ipc_info.queue_len++;
+}
+
+
+void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* req) {
+ DWORD bytes, avail;
+ uv_buf_t buf;
+ uv_ipc_frame_uv_stream ipc_frame;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+ eof_timer_stop(handle);
+
+ if (!REQ_SUCCESS(req)) {
+ /* An error occurred doing the 0-read. */
+ if (handle->flags & UV_HANDLE_READING) {
+ uv_pipe_read_error_or_eof(loop,
+ handle,
+ GET_REQ_ERROR(req),
+ uv_null_buf_);
+ }
+ } else {
+ /* Do non-blocking reads until the buffer is empty */
+ while (handle->flags & UV_HANDLE_READING) {
+ if (!PeekNamedPipe(handle->handle,
+ NULL,
+ 0,
+ NULL,
+ &avail,
+ NULL)) {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_);
+ break;
+ }
+
+ if (avail == 0) {
+ /* There is nothing to read after all. */
+ break;
+ }
+
+ if (handle->ipc) {
+ /* Use the IPC framing protocol to read the incoming data. */
+ if (handle->pipe.conn.remaining_ipc_rawdata_bytes == 0) {
+ /* We're reading a new frame. First, read the header. */
+ assert(avail >= sizeof(ipc_frame.header));
+
+ if (!ReadFile(handle->handle,
+ &ipc_frame.header,
+ sizeof(ipc_frame.header),
+ &bytes,
+ NULL)) {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(),
+ uv_null_buf_);
+ break;
+ }
+
+ assert(bytes == sizeof(ipc_frame.header));
+ assert(ipc_frame.header.flags <= (UV_IPC_TCP_SERVER | UV_IPC_RAW_DATA |
+ UV_IPC_TCP_CONNECTION));
+
+ if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) {
+ assert(avail - sizeof(ipc_frame.header) >=
+ sizeof(ipc_frame.socket_info_ex));
+
+ /* Read the TCP socket info. */
+ if (!ReadFile(handle->handle,
+ &ipc_frame.socket_info_ex,
+ sizeof(ipc_frame) - sizeof(ipc_frame.header),
+ &bytes,
+ NULL)) {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(),
+ uv_null_buf_);
+ break;
+ }
+
+ assert(bytes == sizeof(ipc_frame) - sizeof(ipc_frame.header));
+
+ /* Store the pending socket info. */
+ uv__pipe_insert_pending_socket(
+ handle,
+ &ipc_frame.socket_info_ex,
+ ipc_frame.header.flags & UV_IPC_TCP_CONNECTION);
+ }
+
+ if (ipc_frame.header.flags & UV_IPC_RAW_DATA) {
+ handle->pipe.conn.remaining_ipc_rawdata_bytes =
+ ipc_frame.header.raw_data_length;
+ continue;
+ }
+ } else {
+ avail = min(avail, (DWORD)handle->pipe.conn.remaining_ipc_rawdata_bytes);
+ }
+ }
+
+ buf = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, avail, &buf);
+ if (buf.base == NULL || buf.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
+ break;
+ }
+ assert(buf.base != NULL);
+
+ if (ReadFile(handle->handle,
+ buf.base,
+ min(buf.len, avail),
+ &bytes,
+ NULL)) {
+ /* Successful read */
+ if (handle->ipc) {
+ assert(handle->pipe.conn.remaining_ipc_rawdata_bytes >= bytes);
+ handle->pipe.conn.remaining_ipc_rawdata_bytes =
+ handle->pipe.conn.remaining_ipc_rawdata_bytes - bytes;
+ }
+ handle->read_cb((uv_stream_t*)handle, bytes, &buf);
+
+ /* Read again only if bytes == buf.len */
+ if (bytes <= buf.len) {
+ break;
+ }
+ } else {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf);
+ break;
+ }
+ }
+
+ /* Post another 0-read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_pipe_queue_read(loop, handle);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_write_t* req) {
+ int err;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ assert(handle->write_queue_size >= req->u.io.queued_bytes);
+ handle->write_queue_size -= req->u.io.queued_bytes;
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(req->wait_handle);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (req->event_handle) {
+ CloseHandle(req->event_handle);
+ req->event_handle = NULL;
+ }
+ }
+
+ if (req->ipc_header) {
+ if (req == &handle->pipe.conn.ipc_header_write_req) {
+ req->type = UV_UNKNOWN_REQ;
+ } else {
+ uv__free(req);
+ }
+ } else {
+ if (req->cb) {
+ err = GET_REQ_ERROR(req);
+ req->cb(req, uv_translate_sys_error(err));
+ }
+ }
+
+ handle->stream.conn.write_reqs_pending--;
+
+ if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE &&
+ handle->pipe.conn.non_overlapped_writes_tail) {
+ assert(handle->stream.conn.write_reqs_pending > 0);
+ uv_queue_non_overlapped_write(handle);
+ }
+
+ if (handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* raw_req) {
+ uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ /* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */
+ assert(req->pipeHandle == INVALID_HANDLE_VALUE);
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (REQ_SUCCESS(req)) {
+ assert(req->pipeHandle != INVALID_HANDLE_VALUE);
+ req->next_pending = handle->pipe.serv.pending_accepts;
+ handle->pipe.serv.pending_accepts = req;
+
+ if (handle->stream.serv.connection_cb) {
+ handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
+ }
+ } else {
+ if (req->pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(req->pipeHandle);
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ }
+ if (!(handle->flags & UV__HANDLE_CLOSING)) {
+ uv_pipe_queue_accept(loop, handle, req, FALSE);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_connect_t* req) {
+ int err;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (req->cb) {
+ err = 0;
+ if (REQ_SUCCESS(req)) {
+ uv_pipe_connection_init(handle);
+ } else {
+ err = GET_REQ_ERROR(req);
+ }
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_shutdown_t* req) {
+ assert(handle->type == UV_NAMED_PIPE);
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (handle->flags & UV_HANDLE_READABLE) {
+ /* Initialize and optionally start the eof timer. Only do this if the */
+ /* pipe is readable and we haven't seen EOF come in ourselves. */
+ eof_timer_init(handle);
+
+ /* If reading start the timer right now. */
+ /* Otherwise uv_pipe_queue_read will start it. */
+ if (handle->flags & UV_HANDLE_READ_PENDING) {
+ eof_timer_start(handle);
+ }
+
+ } else {
+ /* This pipe is not readable. We can just close it to let the other end */
+ /* know that we're done writing. */
+ close_pipe(handle);
+ }
+
+ if (req->cb) {
+ req->cb(req, 0);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+static void eof_timer_init(uv_pipe_t* pipe) {
+ int r;
+
+ assert(pipe->pipe.conn.eof_timer == NULL);
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ pipe->pipe.conn.eof_timer = (uv_timer_t*) uv__malloc(sizeof *pipe->pipe.conn.eof_timer);
+
+ r = uv_timer_init(pipe->loop, pipe->pipe.conn.eof_timer);
+ assert(r == 0); /* timers can't fail */
+ pipe->pipe.conn.eof_timer->data = pipe;
+ uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer);
+}
+
+
+static void eof_timer_start(uv_pipe_t* pipe) {
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ if (pipe->pipe.conn.eof_timer != NULL) {
+ uv_timer_start(pipe->pipe.conn.eof_timer, eof_timer_cb, eof_timeout, 0);
+ }
+}
+
+
+static void eof_timer_stop(uv_pipe_t* pipe) {
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ if (pipe->pipe.conn.eof_timer != NULL) {
+ uv_timer_stop(pipe->pipe.conn.eof_timer);
+ }
+}
+
+
+static void eof_timer_cb(uv_timer_t* timer) {
+ uv_pipe_t* pipe = (uv_pipe_t*) timer->data;
+ uv_loop_t* loop = timer->loop;
+
+ assert(pipe->type == UV_NAMED_PIPE);
+
+ /* This should always be true, since we start the timer only */
+ /* in uv_pipe_queue_read after successfully calling ReadFile, */
+ /* or in uv_process_pipe_shutdown_req if a read is pending, */
+ /* and we always immediately stop the timer in */
+ /* uv_process_pipe_read_req. */
+ assert(pipe->flags & UV_HANDLE_READ_PENDING);
+
+ /* If there are many packets coming off the iocp then the timer callback */
+ /* may be called before the read request is coming off the queue. */
+ /* Therefore we check here if the read request has completed but will */
+ /* be processed later. */
+ if ((pipe->flags & UV_HANDLE_READ_PENDING) &&
+ HasOverlappedIoCompleted(&pipe->read_req.u.io.overlapped)) {
+ return;
+ }
+
+ /* Force both ends off the pipe. */
+ close_pipe(pipe);
+
+ /* Stop reading, so the pending read that is going to fail will */
+ /* not be reported to the user. */
+ uv_read_stop((uv_stream_t*) pipe);
+
+ /* Report the eof and update flags. This will get reported even if the */
+ /* user stopped reading in the meantime. TODO: is that okay? */
+ uv_pipe_read_eof(loop, pipe, uv_null_buf_);
+}
+
+
+static void eof_timer_destroy(uv_pipe_t* pipe) {
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ if (pipe->pipe.conn.eof_timer) {
+ uv_close((uv_handle_t*) pipe->pipe.conn.eof_timer, eof_timer_close_cb);
+ pipe->pipe.conn.eof_timer = NULL;
+ }
+}
+
+
+static void eof_timer_close_cb(uv_handle_t* handle) {
+ assert(handle->type == UV_TIMER);
+ uv__free(handle);
+}
+
+
+int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
+ HANDLE os_handle = uv__get_osfhandle(file);
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_ACCESS_INFORMATION access;
+ DWORD duplex_flags = 0;
+
+ if (os_handle == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
+ * underlying OS handle and forget about the original fd.
+ * We could also opt to use the original OS handle and just never close it,
+ * but then there would be no reliable way to cancel pending read operations
+ * upon close.
+ */
+ if (file <= 2) {
+ if (!DuplicateHandle(INVALID_HANDLE_VALUE,
+ os_handle,
+ INVALID_HANDLE_VALUE,
+ &os_handle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS))
+ return uv_translate_sys_error(GetLastError());
+ file = -1;
+ }
+
+ /* Determine what kind of permissions we have on this handle.
+ * Cygwin opens the pipe in message mode, but we can support it,
+ * just query the access flags and set the stream flags accordingly.
+ */
+ nt_status = pNtQueryInformationFile(os_handle,
+ &io_status,
+ &access,
+ sizeof(access),
+ FileAccessInformation);
+ if (nt_status != STATUS_SUCCESS)
+ return UV_EINVAL;
+
+ if (pipe->ipc) {
+ if (!(access.AccessFlags & FILE_WRITE_DATA) ||
+ !(access.AccessFlags & FILE_READ_DATA)) {
+ return UV_EINVAL;
+ }
+ }
+
+ if (access.AccessFlags & FILE_WRITE_DATA)
+ duplex_flags |= UV_HANDLE_WRITABLE;
+ if (access.AccessFlags & FILE_READ_DATA)
+ duplex_flags |= UV_HANDLE_READABLE;
+
+ if (os_handle == INVALID_HANDLE_VALUE ||
+ uv_set_pipe_handle(pipe->loop,
+ pipe,
+ os_handle,
+ file,
+ duplex_flags) == -1) {
+ return UV_EINVAL;
+ }
+
+ uv_pipe_connection_init(pipe);
+
+ if (pipe->ipc) {
+ assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
+ pipe->pipe.conn.ipc_pid = uv_parent_pid();
+ assert(pipe->pipe.conn.ipc_pid != -1);
+ }
+ return 0;
+}
+
+
+static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_NAME_INFORMATION tmp_name_info;
+ FILE_NAME_INFORMATION* name_info;
+ WCHAR* name_buf;
+ unsigned int addrlen;
+ unsigned int name_size;
+ unsigned int name_len;
+ int err;
+
+ name_info = NULL;
+
+ if (handle->handle == INVALID_HANDLE_VALUE) {
+ *size = 0;
+ return UV_EINVAL;
+ }
+
+ uv__pipe_pause_read((uv_pipe_t*)handle); /* cast away const warning */
+
+ nt_status = pNtQueryInformationFile(handle->handle,
+ &io_status,
+ &tmp_name_info,
+ sizeof tmp_name_info,
+ FileNameInformation);
+ if (nt_status == STATUS_BUFFER_OVERFLOW) {
+ name_size = sizeof(*name_info) + tmp_name_info.FileNameLength;
+ name_info = uv__malloc(name_size);
+ if (!name_info) {
+ *size = 0;
+ err = UV_ENOMEM;
+ goto cleanup;
+ }
+
+ nt_status = pNtQueryInformationFile(handle->handle,
+ &io_status,
+ name_info,
+ name_size,
+ FileNameInformation);
+ }
+
+ if (nt_status != STATUS_SUCCESS) {
+ *size = 0;
+ err = uv_translate_sys_error(pRtlNtStatusToDosError(nt_status));
+ goto error;
+ }
+
+ if (!name_info) {
+ /* the struct on stack was used */
+ name_buf = tmp_name_info.FileName;
+ name_len = tmp_name_info.FileNameLength;
+ } else {
+ name_buf = name_info->FileName;
+ name_len = name_info->FileNameLength;
+ }
+
+ if (name_len == 0) {
+ *size = 0;
+ err = 0;
+ goto error;
+ }
+
+ name_len /= sizeof(WCHAR);
+
+ /* check how much space we need */
+ addrlen = WideCharToMultiByte(CP_UTF8,
+ 0,
+ name_buf,
+ name_len,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (!addrlen) {
+ *size = 0;
+ err = uv_translate_sys_error(GetLastError());
+ goto error;
+ } else if (pipe_prefix_len + addrlen >= *size) {
+ /* "\\\\.\\pipe" + name */
+ *size = pipe_prefix_len + addrlen + 1;
+ err = UV_ENOBUFS;
+ goto error;
+ }
+
+ memcpy(buffer, pipe_prefix, pipe_prefix_len);
+ addrlen = WideCharToMultiByte(CP_UTF8,
+ 0,
+ name_buf,
+ name_len,
+ buffer+pipe_prefix_len,
+ *size-pipe_prefix_len,
+ NULL,
+ NULL);
+ if (!addrlen) {
+ *size = 0;
+ err = uv_translate_sys_error(GetLastError());
+ goto error;
+ }
+
+ addrlen += pipe_prefix_len;
+ *size = addrlen;
+ buffer[addrlen] = '\0';
+
+ err = 0;
+ goto cleanup;
+
+error:
+ uv__free(name_info);
+
+cleanup:
+ uv__pipe_unpause_read((uv_pipe_t*)handle); /* cast away const warning */
+ return err;
+}
+
+
+int uv_pipe_pending_count(uv_pipe_t* handle) {
+ if (!handle->ipc)
+ return 0;
+ return handle->pipe.conn.pending_ipc_info.queue_len;
+}
+
+
+int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ if (handle->flags & UV_HANDLE_BOUND)
+ return uv__pipe_getname(handle, buffer, size);
+
+ if (handle->flags & UV_HANDLE_CONNECTION ||
+ handle->handle != INVALID_HANDLE_VALUE) {
+ *size = 0;
+ return 0;
+ }
+
+ return UV_EBADF;
+}
+
+
+int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ /* emulate unix behaviour */
+ if (handle->flags & UV_HANDLE_BOUND)
+ return UV_ENOTCONN;
+
+ if (handle->handle != INVALID_HANDLE_VALUE)
+ return uv__pipe_getname(handle, buffer, size);
+
+ return UV_EBADF;
+}
+
+
+uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
+ if (!handle->ipc)
+ return UV_UNKNOWN_HANDLE;
+ if (handle->pipe.conn.pending_ipc_info.queue_len == 0)
+ return UV_UNKNOWN_HANDLE;
+ else
+ return UV_TCP;
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <io.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
+ {0xe70f1aa0, 0xab8b, 0x11cf,
+ {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
+ {0xf9eab0c0, 0x26d4, 0x11d0,
+ {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
+ {0x9fc48064, 0x7298, 0x43e4,
+ {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
+};
+
+typedef struct uv_single_fd_set_s {
+ unsigned int fd_count;
+ SOCKET fd_array[1];
+} uv_single_fd_set_t;
+
+
+static OVERLAPPED overlapped_dummy_;
+static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;
+
+static AFD_POLL_INFO afd_poll_info_dummy_;
+
+
+static void uv__init_overlapped_dummy(void) {
+ HANDLE event;
+
+ event = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (event == NULL)
+ uv_fatal_error(GetLastError(), "CreateEvent");
+
+ memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_);
+ overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1);
+}
+
+
+static OVERLAPPED* uv__get_overlapped_dummy() {
+ uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
+ return &overlapped_dummy_;
+}
+
+
+static AFD_POLL_INFO* uv__get_afd_poll_info_dummy() {
+ return &afd_poll_info_dummy_;
+}
+
+
+static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+ uv_req_t* req;
+ AFD_POLL_INFO* afd_poll_info;
+ DWORD result;
+
+ /* Find a yet unsubmitted req to submit. */
+ if (handle->submitted_events_1 == 0) {
+ req = &handle->poll_req_1;
+ afd_poll_info = &handle->afd_poll_info_1;
+ handle->submitted_events_1 = handle->events;
+ handle->mask_events_1 = 0;
+ handle->mask_events_2 = handle->events;
+ } else if (handle->submitted_events_2 == 0) {
+ req = &handle->poll_req_2;
+ afd_poll_info = &handle->afd_poll_info_2;
+ handle->submitted_events_2 = handle->events;
+ handle->mask_events_1 = handle->events;
+ handle->mask_events_2 = 0;
+ } else {
+ /* Just wait until there's an unsubmitted req. */
+ /* This will happen almost immediately as one of the 2 outstanding */
+ /* requests is about to return. When this happens, */
+ /* uv__fast_poll_process_poll_req will be called, and the pending */
+ /* events, if needed, will be processed in a subsequent request. */
+ return;
+ }
+
+ /* Setting Exclusive to TRUE makes the other poll request return if there */
+ /* is any. */
+ afd_poll_info->Exclusive = TRUE;
+ afd_poll_info->NumberOfHandles = 1;
+ afd_poll_info->Timeout.QuadPart = INT64_MAX;
+ afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
+ afd_poll_info->Handles[0].Status = 0;
+ afd_poll_info->Handles[0].Events = 0;
+
+ if (handle->events & UV_READABLE) {
+ afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE |
+ AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT;
+ } else {
+ if (handle->events & UV_DISCONNECT) {
+ afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT;
+ }
+ }
+ if (handle->events & UV_WRITABLE) {
+ afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
+ }
+
+ memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
+
+ result = uv_msafd_poll((SOCKET) handle->peer_socket,
+ afd_poll_info,
+ afd_poll_info,
+ &req->u.io.overlapped);
+ if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
+ /* Queue this req, reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, req);
+ }
+}
+
+
+static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+ AFD_POLL_INFO afd_poll_info;
+ DWORD result;
+
+ afd_poll_info.Exclusive = TRUE;
+ afd_poll_info.NumberOfHandles = 1;
+ afd_poll_info.Timeout.QuadPart = INT64_MAX;
+ afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
+ afd_poll_info.Handles[0].Status = 0;
+ afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
+
+ result = uv_msafd_poll(handle->socket,
+ &afd_poll_info,
+ uv__get_afd_poll_info_dummy(),
+ uv__get_overlapped_dummy());
+
+ if (result == SOCKET_ERROR) {
+ DWORD error = WSAGetLastError();
+ if (error != WSA_IO_PENDING)
+ return error;
+ }
+
+ return 0;
+}
+
+
+static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+ uv_req_t* req) {
+ unsigned char mask_events;
+ AFD_POLL_INFO* afd_poll_info;
+
+ if (req == &handle->poll_req_1) {
+ afd_poll_info = &handle->afd_poll_info_1;
+ handle->submitted_events_1 = 0;
+ mask_events = handle->mask_events_1;
+ } else if (req == &handle->poll_req_2) {
+ afd_poll_info = &handle->afd_poll_info_2;
+ handle->submitted_events_2 = 0;
+ mask_events = handle->mask_events_2;
+ } else {
+ assert(0);
+ return;
+ }
+
+ /* Report an error unless the select was just interrupted. */
+ if (!REQ_SUCCESS(req)) {
+ DWORD error = GET_REQ_SOCK_ERROR(req);
+ if (error != WSAEINTR && handle->events != 0) {
+ handle->events = 0; /* Stop the watcher */
+ handle->poll_cb(handle, uv_translate_sys_error(error), 0);
+ }
+
+ } else if (afd_poll_info->NumberOfHandles >= 1) {
+ unsigned char events = 0;
+
+ if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE |
+ AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) {
+ events |= UV_READABLE;
+ if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) {
+ events |= UV_DISCONNECT;
+ }
+ }
+ if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND |
+ AFD_POLL_CONNECT_FAIL)) != 0) {
+ events |= UV_WRITABLE;
+ }
+
+ events &= handle->events & ~mask_events;
+
+ if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
+ /* Stop polling. */
+ handle->events = 0;
+ if (uv__is_active(handle))
+ uv__handle_stop(handle);
+ }
+
+ if (events != 0) {
+ handle->poll_cb(handle, 0, events);
+ }
+ }
+
+ if ((handle->events & ~(handle->submitted_events_1 |
+ handle->submitted_events_2)) != 0) {
+ uv__fast_poll_submit_poll_req(loop, handle);
+ } else if ((handle->flags & UV__HANDLE_CLOSING) &&
+ handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
+ assert(handle->type == UV_POLL);
+ assert(!(handle->flags & UV__HANDLE_CLOSING));
+ assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
+
+ handle->events = events;
+
+ if (handle->events != 0) {
+ uv__handle_start(handle);
+ } else {
+ uv__handle_stop(handle);
+ }
+
+ if ((handle->events & ~(handle->submitted_events_1 |
+ handle->submitted_events_2)) != 0) {
+ uv__fast_poll_submit_poll_req(handle->loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+ handle->events = 0;
+ uv__handle_closing(handle);
+
+ if (handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ return 0;
+ } else {
+ /* Cancel outstanding poll requests by executing another, unique poll */
+ /* request that forces the outstanding ones to return. */
+ return uv__fast_poll_cancel_poll_req(loop, handle);
+ }
+}
+
+
+static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
+ WSAPROTOCOL_INFOW* protocol_info) {
+ SOCKET sock = 0;
+
+ sock = WSASocketW(protocol_info->iAddressFamily,
+ protocol_info->iSocketType,
+ protocol_info->iProtocol,
+ protocol_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+ if (sock == INVALID_SOCKET) {
+ return INVALID_SOCKET;
+ }
+
+ if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
+ goto error;
+ };
+
+ if (CreateIoCompletionPort((HANDLE) sock,
+ iocp,
+ (ULONG_PTR) sock,
+ 0) == NULL) {
+ goto error;
+ }
+
+ return sock;
+
+ error:
+ closesocket(sock);
+ return INVALID_SOCKET;
+}
+
+
+static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
+ WSAPROTOCOL_INFOW* protocol_info) {
+ int index, i;
+ SOCKET peer_socket;
+
+ index = -1;
+ for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
+ if (memcmp((void*) &protocol_info->ProviderId,
+ (void*) &uv_msafd_provider_ids[i],
+ sizeof protocol_info->ProviderId) == 0) {
+ index = i;
+ }
+ }
+
+ /* Check if the protocol uses an msafd socket. */
+ if (index < 0) {
+ return INVALID_SOCKET;
+ }
+
+ /* If we didn't (try) to create a peer socket yet, try to make one. Don't */
+ /* try again if the peer socket creation failed earlier for the same */
+ /* protocol. */
+ peer_socket = loop->poll_peer_sockets[index];
+ if (peer_socket == 0) {
+ peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
+ loop->poll_peer_sockets[index] = peer_socket;
+ }
+
+ return peer_socket;
+}
+
+
+static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
+ uv_req_t* req = (uv_req_t*) arg;
+ uv_poll_t* handle = (uv_poll_t*) req->data;
+ unsigned char reported_events;
+ int r;
+ uv_single_fd_set_t rfds, wfds, efds;
+ struct timeval timeout;
+
+ assert(handle->type == UV_POLL);
+ assert(req->type == UV_POLL_REQ);
+
+ if (handle->events & UV_READABLE) {
+ rfds.fd_count = 1;
+ rfds.fd_array[0] = handle->socket;
+ } else {
+ rfds.fd_count = 0;
+ }
+
+ if (handle->events & UV_WRITABLE) {
+ wfds.fd_count = 1;
+ wfds.fd_array[0] = handle->socket;
+ efds.fd_count = 1;
+ efds.fd_array[0] = handle->socket;
+ } else {
+ wfds.fd_count = 0;
+ efds.fd_count = 0;
+ }
+
+ /* Make the select() time out after 3 minutes. If select() hangs because */
+ /* the user closed the socket, we will at least not hang indefinitely. */
+ timeout.tv_sec = 3 * 60;
+ timeout.tv_usec = 0;
+
+ r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout);
+ if (r == SOCKET_ERROR) {
+ /* Queue this req, reporting an error. */
+ SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError());
+ POST_COMPLETION_FOR_REQ(handle->loop, req);
+ return 0;
+ }
+
+ reported_events = 0;
+
+ if (r > 0) {
+ if (rfds.fd_count > 0) {
+ assert(rfds.fd_count == 1);
+ assert(rfds.fd_array[0] == handle->socket);
+ reported_events |= UV_READABLE;
+ }
+
+ if (wfds.fd_count > 0) {
+ assert(wfds.fd_count == 1);
+ assert(wfds.fd_array[0] == handle->socket);
+ reported_events |= UV_WRITABLE;
+ } else if (efds.fd_count > 0) {
+ assert(efds.fd_count == 1);
+ assert(efds.fd_array[0] == handle->socket);
+ reported_events |= UV_WRITABLE;
+ }
+ }
+
+ SET_REQ_SUCCESS(req);
+ req->u.io.overlapped.InternalHigh = (DWORD) reported_events;
+ POST_COMPLETION_FOR_REQ(handle->loop, req);
+
+ return 0;
+}
+
+
+static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+ uv_req_t* req;
+
+ /* Find a yet unsubmitted req to submit. */
+ if (handle->submitted_events_1 == 0) {
+ req = &handle->poll_req_1;
+ handle->submitted_events_1 = handle->events;
+ handle->mask_events_1 = 0;
+ handle->mask_events_2 = handle->events;
+ } else if (handle->submitted_events_2 == 0) {
+ req = &handle->poll_req_2;
+ handle->submitted_events_2 = handle->events;
+ handle->mask_events_1 = handle->events;
+ handle->mask_events_2 = 0;
+ } else {
+ assert(0);
+ return;
+ }
+
+ if (!QueueUserWorkItem(uv__slow_poll_thread_proc,
+ (void*) req,
+ WT_EXECUTELONGFUNCTION)) {
+ /* Make this req pending, reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, req);
+ }
+}
+
+
+
+static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+ uv_req_t* req) {
+ unsigned char mask_events;
+ int err;
+
+ if (req == &handle->poll_req_1) {
+ handle->submitted_events_1 = 0;
+ mask_events = handle->mask_events_1;
+ } else if (req == &handle->poll_req_2) {
+ handle->submitted_events_2 = 0;
+ mask_events = handle->mask_events_2;
+ } else {
+ assert(0);
+ return;
+ }
+
+ if (!REQ_SUCCESS(req)) {
+ /* Error. */
+ if (handle->events != 0) {
+ err = GET_REQ_ERROR(req);
+ handle->events = 0; /* Stop the watcher */
+ handle->poll_cb(handle, uv_translate_sys_error(err), 0);
+ }
+ } else {
+ /* Got some events. */
+ int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events;
+ if (events != 0) {
+ handle->poll_cb(handle, 0, events);
+ }
+ }
+
+ if ((handle->events & ~(handle->submitted_events_1 |
+ handle->submitted_events_2)) != 0) {
+ uv__slow_poll_submit_poll_req(loop, handle);
+ } else if ((handle->flags & UV__HANDLE_CLOSING) &&
+ handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
+ assert(handle->type == UV_POLL);
+ assert(!(handle->flags & UV__HANDLE_CLOSING));
+ assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
+
+ handle->events = events;
+
+ if (handle->events != 0) {
+ uv__handle_start(handle);
+ } else {
+ uv__handle_stop(handle);
+ }
+
+ if ((handle->events &
+ ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) {
+ uv__slow_poll_submit_poll_req(handle->loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+ handle->events = 0;
+ uv__handle_closing(handle);
+
+ if (handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+
+ return 0;
+}
+
+
+int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
+ return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
+}
+
+
+int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
+ uv_os_sock_t socket) {
+ WSAPROTOCOL_INFOW protocol_info;
+ int len;
+ SOCKET peer_socket, base_socket;
+ DWORD bytes;
+ DWORD yes = 1;
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
+ return uv_translate_sys_error(WSAGetLastError());
+
+ /* Try to obtain a base handle for the socket. This increases this chances */
+ /* that we find an AFD handle and are able to use the fast poll mechanism. */
+ /* This will always fail on windows XP/2k3, since they don't support the */
+ /* SIO_BASE_HANDLE ioctl. */
+#ifndef NDEBUG
+ base_socket = INVALID_SOCKET;
+#endif
+
+ if (WSAIoctl(socket,
+ SIO_BASE_HANDLE,
+ NULL,
+ 0,
+ &base_socket,
+ sizeof base_socket,
+ &bytes,
+ NULL,
+ NULL) == 0) {
+ assert(base_socket != 0 && base_socket != INVALID_SOCKET);
+ socket = base_socket;
+ }
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
+ handle->socket = socket;
+ handle->events = 0;
+
+ /* Obtain protocol information about the socket. */
+ len = sizeof protocol_info;
+ if (getsockopt(socket,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &len) != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ /* Get the peer socket that is needed to enable fast poll. If the returned */
+ /* value is NULL, the protocol is not implemented by MSAFD and we'll have */
+ /* to use slow mode. */
+ peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
+
+ if (peer_socket != INVALID_SOCKET) {
+ /* Initialize fast poll specific fields. */
+ handle->peer_socket = peer_socket;
+ } else {
+ /* Initialize slow poll specific fields. */
+ handle->flags |= UV_HANDLE_POLL_SLOW;
+ }
+
+ /* Initialize 2 poll reqs. */
+ handle->submitted_events_1 = 0;
+ uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1));
+ handle->poll_req_1.type = UV_POLL_REQ;
+ handle->poll_req_1.data = handle;
+
+ handle->submitted_events_2 = 0;
+ uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2));
+ handle->poll_req_2.type = UV_POLL_REQ;
+ handle->poll_req_2.data = handle;
+
+ return 0;
+}
+
+
+int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ err = uv__fast_poll_set(handle->loop, handle, events);
+ } else {
+ err = uv__slow_poll_set(handle->loop, handle, events);
+ }
+
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ handle->poll_cb = cb;
+
+ return 0;
+}
+
+
+int uv_poll_stop(uv_poll_t* handle) {
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ err = uv__fast_poll_set(handle->loop, handle, 0);
+ } else {
+ err = uv__slow_poll_set(handle->loop, handle, 0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ uv__fast_poll_process_poll_req(loop, handle, req);
+ } else {
+ uv__slow_poll_process_poll_req(loop, handle, req);
+ }
+}
+
+
+int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ return uv__fast_poll_close(loop, handle);
+ } else {
+ return uv__slow_poll_close(loop, handle);
+ }
+}
+
+
+void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ assert(handle->submitted_events_1 == 0);
+ assert(handle->submitted_events_2 == 0);
+
+ uv__handle_close(handle);
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+
+
+/*
+ * The `child_stdio_buffer` buffer has the following layout:
+ * int number_of_fds
+ * unsigned char crt_flags[number_of_fds]
+ * HANDLE os_handle[number_of_fds]
+ */
+#define CHILD_STDIO_SIZE(count) \
+ (sizeof(int) + \
+ sizeof(unsigned char) * (count) + \
+ sizeof(uintptr_t) * (count))
+
+#define CHILD_STDIO_COUNT(buffer) \
+ *((unsigned int*) (buffer))
+
+#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
+ *((unsigned char*) (buffer) + sizeof(int) + fd)
+
+#define CHILD_STDIO_HANDLE(buffer, fd) \
+ *((HANDLE*) ((unsigned char*) (buffer) + \
+ sizeof(int) + \
+ sizeof(unsigned char) * \
+ CHILD_STDIO_COUNT((buffer)) + \
+ sizeof(HANDLE) * (fd)))
+
+
+/* CRT file descriptor mode flags */
+#define FOPEN 0x01
+#define FEOFLAG 0x02
+#define FCRLF 0x04
+#define FPIPE 0x08
+#define FNOINHERIT 0x10
+#define FAPPEND 0x20
+#define FDEV 0x40
+#define FTEXT 0x80
+
+
+/*
+ * Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited
+ * the parent process. Don't check for errors - the stdio handles may not be
+ * valid, or may be closed already. There is no guarantee that this function
+ * does a perfect job.
+ */
+void uv_disable_stdio_inheritance(void) {
+ HANDLE handle;
+ STARTUPINFOW si;
+
+ /* Make the windows stdio handles non-inheritable. */
+ handle = GetStdHandle(STD_INPUT_HANDLE);
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE)
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+
+ handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE)
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+
+ handle = GetStdHandle(STD_ERROR_HANDLE);
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE)
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+
+ /* Make inherited CRT FDs non-inheritable. */
+ GetStartupInfoW(&si);
+ if (uv__stdio_verify(si.lpReserved2, si.cbReserved2))
+ uv__stdio_noinherit(si.lpReserved2);
+}
+
+
+static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
+ uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
+ char pipe_name[64];
+ SECURITY_ATTRIBUTES sa;
+ DWORD server_access = 0;
+ DWORD client_access = 0;
+ HANDLE child_pipe = INVALID_HANDLE_VALUE;
+ int err;
+
+ if (flags & UV_READABLE_PIPE) {
+ /* The server needs inbound access too, otherwise CreateNamedPipe() */
+ /* won't give us the FILE_READ_ATTRIBUTES permission. We need that to */
+ /* probe the state of the write buffer when we're trying to shutdown */
+ /* the pipe. */
+ server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
+ client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
+ }
+ if (flags & UV_WRITABLE_PIPE) {
+ server_access |= PIPE_ACCESS_INBOUND;
+ client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+ }
+
+ /* Create server pipe handle. */
+ err = uv_stdio_pipe_server(loop,
+ server_pipe,
+ server_access,
+ pipe_name,
+ sizeof(pipe_name));
+ if (err)
+ goto error;
+
+ /* Create child pipe handle. */
+ sa.nLength = sizeof sa;
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ child_pipe = CreateFileA(pipe_name,
+ client_access,
+ 0,
+ &sa,
+ OPEN_EXISTING,
+ server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0,
+ NULL);
+ if (child_pipe == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
+ goto error;
+ }
+
+#ifndef NDEBUG
+ /* Validate that the pipe was opened in the right mode. */
+ {
+ DWORD mode;
+ BOOL r = GetNamedPipeHandleState(child_pipe,
+ &mode,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0);
+ assert(r == TRUE);
+ assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
+ }
+#endif
+
+ /* Do a blocking ConnectNamedPipe. This should not block because we have */
+ /* both ends of the pipe created. */
+ if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
+ if (GetLastError() != ERROR_PIPE_CONNECTED) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+
+ /* The server end is now readable and/or writable. */
+ if (flags & UV_READABLE_PIPE)
+ server_pipe->flags |= UV_HANDLE_WRITABLE;
+ if (flags & UV_WRITABLE_PIPE)
+ server_pipe->flags |= UV_HANDLE_READABLE;
+
+ *child_pipe_ptr = child_pipe;
+ return 0;
+
+ error:
+ if (server_pipe->handle != INVALID_HANDLE_VALUE) {
+ uv_pipe_cleanup(loop, server_pipe);
+ }
+
+ if (child_pipe != INVALID_HANDLE_VALUE) {
+ CloseHandle(child_pipe);
+ }
+
+ return err;
+}
+
+
+static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
+ HANDLE current_process;
+
+
+ /* _get_osfhandle will sometimes return -2 in case of an error. This seems */
+ /* to happen when fd <= 2 and the process' corresponding stdio handle is */
+ /* set to NULL. Unfortunately DuplicateHandle will happily duplicate */
+ /* (HANDLE) -2, so this situation goes unnoticed until someone tries to */
+ /* use the duplicate. Therefore we filter out known-invalid handles here. */
+ if (handle == INVALID_HANDLE_VALUE ||
+ handle == NULL ||
+ handle == (HANDLE) -2) {
+ *dup = INVALID_HANDLE_VALUE;
+ return ERROR_INVALID_HANDLE;
+ }
+
+ current_process = GetCurrentProcess();
+
+ if (!DuplicateHandle(current_process,
+ handle,
+ current_process,
+ dup,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS)) {
+ *dup = INVALID_HANDLE_VALUE;
+ return GetLastError();
+ }
+
+ return 0;
+}
+
+
+static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
+ HANDLE handle;
+
+ if (fd == -1) {
+ *dup = INVALID_HANDLE_VALUE;
+ return ERROR_INVALID_HANDLE;
+ }
+
+ handle = uv__get_osfhandle(fd);
+ return uv__duplicate_handle(loop, handle, dup);
+}
+
+
+int uv__create_nul_handle(HANDLE* handle_ptr,
+ DWORD access) {
+ HANDLE handle;
+ SECURITY_ATTRIBUTES sa;
+
+ sa.nLength = sizeof sa;
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ handle = CreateFileW(L"NUL",
+ access,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sa,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ return GetLastError();
+ }
+
+ *handle_ptr = handle;
+ return 0;
+}
+
+
+int uv__stdio_create(uv_loop_t* loop,
+ const uv_process_options_t* options,
+ BYTE** buffer_ptr) {
+ BYTE* buffer;
+ int count, i;
+ int err;
+
+ count = options->stdio_count;
+
+ if (count < 0 || count > 255) {
+ /* Only support FDs 0-255 */
+ return ERROR_NOT_SUPPORTED;
+ } else if (count < 3) {
+ /* There should always be at least 3 stdio handles. */
+ count = 3;
+ }
+
+ /* Allocate the child stdio buffer */
+ buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count));
+ if (buffer == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */
+ /* clean up on failure. */
+ CHILD_STDIO_COUNT(buffer) = count;
+ for (i = 0; i < count; i++) {
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
+ CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
+ }
+
+ for (i = 0; i < count; i++) {
+ uv_stdio_container_t fdopt;
+ if (i < options->stdio_count) {
+ fdopt = options->stdio[i];
+ } else {
+ fdopt.flags = UV_IGNORE;
+ }
+
+ switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
+ UV_INHERIT_STREAM)) {
+ case UV_IGNORE:
+ /* Starting a process with no stdin/stout/stderr can confuse it. */
+ /* So no matter what the user specified, we make sure the first */
+ /* three FDs are always open in their typical modes, e.g. stdin */
+ /* be readable and stdout/err should be writable. For FDs > 2, don't */
+ /* do anything - all handles in the stdio buffer are initialized with */
+ /* INVALID_HANDLE_VALUE, which should be okay. */
+ if (i <= 2) {
+ DWORD access = (i == 0) ? FILE_GENERIC_READ :
+ FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+
+ err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
+ access);
+ if (err)
+ goto error;
+
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ }
+ break;
+
+ case UV_CREATE_PIPE: {
+ /* Create a pair of two connected pipe ends; one end is turned into */
+ /* an uv_pipe_t for use by the parent. The other one is given to */
+ /* the child. */
+ uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
+ HANDLE child_pipe = INVALID_HANDLE_VALUE;
+
+ /* Create a new, connected pipe pair. stdio[i].stream should point */
+ /* to an uninitialized, but not connected pipe handle. */
+ assert(fdopt.data.stream->type == UV_NAMED_PIPE);
+ assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
+ assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
+
+ err = uv__create_stdio_pipe_pair(loop,
+ parent_pipe,
+ &child_pipe,
+ fdopt.flags);
+ if (err)
+ goto error;
+
+ CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
+ break;
+ }
+
+ case UV_INHERIT_FD: {
+ /* Inherit a raw FD. */
+ HANDLE child_handle;
+
+ /* Make an inheritable duplicate of the handle. */
+ err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
+ if (err) {
+ /* If fdopt.data.fd is not valid and fd fd <= 2, then ignore the */
+ /* error. */
+ if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
+ CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
+ break;
+ }
+ goto error;
+ }
+
+ /* Figure out what the type is. */
+ switch (GetFileType(child_handle)) {
+ case FILE_TYPE_DISK:
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;
+ break;
+
+ case FILE_TYPE_PIPE:
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
+ break;
+
+ case FILE_TYPE_CHAR:
+ case FILE_TYPE_REMOTE:
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ break;
+
+ case FILE_TYPE_UNKNOWN:
+ if (GetLastError() != 0) {
+ err = GetLastError();
+ CloseHandle(child_handle);
+ goto error;
+ }
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ break;
+
+ default:
+ assert(0);
+ return -1;
+ }
+
+ CHILD_STDIO_HANDLE(buffer, i) = child_handle;
+ break;
+ }
+
+ case UV_INHERIT_STREAM: {
+ /* Use an existing stream as the stdio handle for the child. */
+ HANDLE stream_handle, child_handle;
+ unsigned char crt_flags;
+ uv_stream_t* stream = fdopt.data.stream;
+
+ /* Leech the handle out of the stream. */
+ if (stream->type == UV_TTY) {
+ stream_handle = ((uv_tty_t*) stream)->handle;
+ crt_flags = FOPEN | FDEV;
+ } else if (stream->type == UV_NAMED_PIPE &&
+ stream->flags & UV_HANDLE_CONNECTION) {
+ stream_handle = ((uv_pipe_t*) stream)->handle;
+ crt_flags = FOPEN | FPIPE;
+ } else {
+ stream_handle = INVALID_HANDLE_VALUE;
+ crt_flags = 0;
+ }
+
+ if (stream_handle == NULL ||
+ stream_handle == INVALID_HANDLE_VALUE) {
+ /* The handle is already closed, or not yet created, or the */
+ /* stream type is not supported. */
+ err = ERROR_NOT_SUPPORTED;
+ goto error;
+ }
+
+ /* Make an inheritable copy of the handle. */
+ err = uv__duplicate_handle(loop, stream_handle, &child_handle);
+ if (err)
+ goto error;
+
+ CHILD_STDIO_HANDLE(buffer, i) = child_handle;
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
+ break;
+ }
+
+ default:
+ assert(0);
+ return -1;
+ }
+ }
+
+ *buffer_ptr = buffer;
+ return 0;
+
+ error:
+ uv__stdio_destroy(buffer);
+ return err;
+}
+
+
+void uv__stdio_destroy(BYTE* buffer) {
+ int i, count;
+
+ count = CHILD_STDIO_COUNT(buffer);
+ for (i = 0; i < count; i++) {
+ HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
+ if (handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle);
+ }
+ }
+
+ uv__free(buffer);
+}
+
+
+void uv__stdio_noinherit(BYTE* buffer) {
+ int i, count;
+
+ count = CHILD_STDIO_COUNT(buffer);
+ for (i = 0; i < count; i++) {
+ HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
+ if (handle != INVALID_HANDLE_VALUE) {
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+ }
+ }
+}
+
+
+int uv__stdio_verify(BYTE* buffer, WORD size) {
+ unsigned int count;
+
+ /* Check the buffer pointer. */
+ if (buffer == NULL)
+ return 0;
+
+ /* Verify that the buffer is at least big enough to hold the count. */
+ if (size < CHILD_STDIO_SIZE(0))
+ return 0;
+
+ /* Verify if the count is within range. */
+ count = CHILD_STDIO_COUNT(buffer);
+ if (count > 256)
+ return 0;
+
+ /* Verify that the buffer size is big enough to hold info for N FDs. */
+ if (size < CHILD_STDIO_SIZE(count))
+ return 0;
+
+ return 1;
+}
+
+
+WORD uv__stdio_size(BYTE* buffer) {
+ return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
+}
+
+
+HANDLE uv__stdio_handle(BYTE* buffer, int fd) {
+ return CHILD_STDIO_HANDLE(buffer, fd);
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <limits.h>
+#include <wchar.h>
+#include <malloc.h> /* alloca */
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+#define SIGKILL 9
+
+
+typedef struct env_var {
+ const WCHAR* const wide;
+ const WCHAR* const wide_eq;
+ const size_t len; /* including null or '=' */
+} env_var_t;
+
+#define E_V(str) { L##str, L##str L"=", sizeof(str) }
+
+static const env_var_t required_vars[] = { /* keep me sorted */
+ E_V("HOMEDRIVE"),
+ E_V("HOMEPATH"),
+ E_V("LOGONSERVER"),
+ E_V("PATH"),
+ E_V("SYSTEMDRIVE"),
+ E_V("SYSTEMROOT"),
+ E_V("TEMP"),
+ E_V("USERDOMAIN"),
+ E_V("USERNAME"),
+ E_V("USERPROFILE"),
+ E_V("WINDIR"),
+};
+static size_t n_required_vars = ARRAY_SIZE(required_vars);
+
+
+static HANDLE uv_global_job_handle_;
+static uv_once_t uv_global_job_handle_init_guard_ = UV_ONCE_INIT;
+
+
+static void uv__init_global_job_handle(void) {
+ /* Create a job object and set it up to kill all contained processes when
+ * it's closed. Since this handle is made non-inheritable and we're not
+ * giving it to anyone, we're the only process holding a reference to it.
+ * That means that if this process exits it is closed and all the processes
+ * it contains are killed. All processes created with uv_spawn that are not
+ * spawned with the UV_PROCESS_DETACHED flag are assigned to this job.
+ *
+ * We're setting the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag so only the
+ * processes that we explicitly add are affected, and *their* subprocesses
+ * are not. This ensures that our child processes are not limited in their
+ * ability to use job control on Windows versions that don't deal with
+ * nested jobs (prior to Windows 8 / Server 2012). It also lets our child
+ * processes created detached processes without explicitly breaking away
+ * from job control (which uv_spawn doesn't, either).
+ */
+ SECURITY_ATTRIBUTES attr;
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
+
+ memset(&attr, 0, sizeof attr);
+ attr.bInheritHandle = FALSE;
+
+ memset(&info, 0, sizeof info);
+ info.BasicLimitInformation.LimitFlags =
+ JOB_OBJECT_LIMIT_BREAKAWAY_OK |
+ JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK |
+ JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION |
+ JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+
+ uv_global_job_handle_ = CreateJobObjectW(&attr, NULL);
+ if (uv_global_job_handle_ == NULL)
+ uv_fatal_error(GetLastError(), "CreateJobObjectW");
+
+ if (!SetInformationJobObject(uv_global_job_handle_,
+ JobObjectExtendedLimitInformation,
+ &info,
+ sizeof info))
+ uv_fatal_error(GetLastError(), "SetInformationJobObject");
+}
+
+
+static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
+ int ws_len, r;
+ WCHAR* ws;
+
+ ws_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ s,
+ -1,
+ NULL,
+ 0);
+ if (ws_len <= 0) {
+ return GetLastError();
+ }
+
+ ws = (WCHAR*) uv__malloc(ws_len * sizeof(WCHAR));
+ if (ws == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ r = MultiByteToWideChar(CP_UTF8,
+ 0,
+ s,
+ -1,
+ ws,
+ ws_len);
+ assert(r == ws_len);
+
+ *ws_ptr = ws;
+ return 0;
+}
+
+
+static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
+ handle->exit_cb = NULL;
+ handle->pid = 0;
+ handle->exit_signal = 0;
+ handle->wait_handle = INVALID_HANDLE_VALUE;
+ handle->process_handle = INVALID_HANDLE_VALUE;
+ handle->child_stdio_buffer = NULL;
+ handle->exit_cb_pending = 0;
+
+ uv_req_init(loop, (uv_req_t*)&handle->exit_req);
+ handle->exit_req.type = UV_PROCESS_EXIT;
+ handle->exit_req.data = handle;
+}
+
+
+/*
+ * Path search functions
+ */
+
+/*
+ * Helper function for search_path
+ */
+static WCHAR* search_path_join_test(const WCHAR* dir,
+ size_t dir_len,
+ const WCHAR* name,
+ size_t name_len,
+ const WCHAR* ext,
+ size_t ext_len,
+ const WCHAR* cwd,
+ size_t cwd_len) {
+ WCHAR *result, *result_pos;
+ DWORD attrs;
+ if (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') {
+ /* It's a UNC path so ignore cwd */
+ cwd_len = 0;
+ } else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) {
+ /* It's a full path without drive letter, use cwd's drive letter only */
+ cwd_len = 2;
+ } else if (dir_len >= 2 && dir[1] == L':' &&
+ (dir_len < 3 || (dir[2] != L'/' && dir[2] != L'\\'))) {
+ /* It's a relative path with drive letter (ext.g. D:../some/file)
+ * Replace drive letter in dir by full cwd if it points to the same drive,
+ * otherwise use the dir only.
+ */
+ if (cwd_len < 2 || _wcsnicmp(cwd, dir, 2) != 0) {
+ cwd_len = 0;
+ } else {
+ dir += 2;
+ dir_len -= 2;
+ }
+ } else if (dir_len > 2 && dir[1] == L':') {
+ /* It's an absolute path with drive letter
+ * Don't use the cwd at all
+ */
+ cwd_len = 0;
+ }
+
+ /* Allocate buffer for output */
+ result = result_pos = (WCHAR*)uv__malloc(sizeof(WCHAR) *
+ (cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1));
+
+ /* Copy cwd */
+ wcsncpy(result_pos, cwd, cwd_len);
+ result_pos += cwd_len;
+
+ /* Add a path separator if cwd didn't end with one */
+ if (cwd_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) {
+ result_pos[0] = L'\\';
+ result_pos++;
+ }
+
+ /* Copy dir */
+ wcsncpy(result_pos, dir, dir_len);
+ result_pos += dir_len;
+
+ /* Add a separator if the dir didn't end with one */
+ if (dir_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) {
+ result_pos[0] = L'\\';
+ result_pos++;
+ }
+
+ /* Copy filename */
+ wcsncpy(result_pos, name, name_len);
+ result_pos += name_len;
+
+ if (ext_len) {
+ /* Add a dot if the filename didn't end with one */
+ if (name_len && result_pos[-1] != '.') {
+ result_pos[0] = L'.';
+ result_pos++;
+ }
+
+ /* Copy extension */
+ wcsncpy(result_pos, ext, ext_len);
+ result_pos += ext_len;
+ }
+
+ /* Null terminator */
+ result_pos[0] = L'\0';
+
+ attrs = GetFileAttributesW(result);
+
+ if (attrs != INVALID_FILE_ATTRIBUTES &&
+ !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
+ return result;
+ }
+
+ uv__free(result);
+ return NULL;
+}
+
+
+/*
+ * Helper function for search_path
+ */
+static WCHAR* path_search_walk_ext(const WCHAR *dir,
+ size_t dir_len,
+ const WCHAR *name,
+ size_t name_len,
+ WCHAR *cwd,
+ size_t cwd_len,
+ int name_has_ext) {
+ WCHAR* result;
+
+ /* If the name itself has a nonempty extension, try this extension first */
+ if (name_has_ext) {
+ result = search_path_join_test(dir, dir_len,
+ name, name_len,
+ L"", 0,
+ cwd, cwd_len);
+ if (result != NULL) {
+ return result;
+ }
+ }
+
+ /* Try .com extension */
+ result = search_path_join_test(dir, dir_len,
+ name, name_len,
+ L"com", 3,
+ cwd, cwd_len);
+ if (result != NULL) {
+ return result;
+ }
+
+ /* Try .exe extension */
+ result = search_path_join_test(dir, dir_len,
+ name, name_len,
+ L"exe", 3,
+ cwd, cwd_len);
+ if (result != NULL) {
+ return result;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * search_path searches the system path for an executable filename -
+ * the windows API doesn't provide this as a standalone function nor as an
+ * option to CreateProcess.
+ *
+ * It tries to return an absolute filename.
+ *
+ * Furthermore, it tries to follow the semantics that cmd.exe, with this
+ * exception that PATHEXT environment variable isn't used. Since CreateProcess
+ * can start only .com and .exe files, only those extensions are tried. This
+ * behavior equals that of msvcrt's spawn functions.
+ *
+ * - Do not search the path if the filename already contains a path (either
+ * relative or absolute).
+ *
+ * - If there's really only a filename, check the current directory for file,
+ * then search all path directories.
+ *
+ * - If filename specified has *any* extension, search for the file with the
+ * specified extension first.
+ *
+ * - If the literal filename is not found in a directory, try *appending*
+ * (not replacing) .com first and then .exe.
+ *
+ * - The path variable may contain relative paths; relative paths are relative
+ * to the cwd.
+ *
+ * - Directories in path may or may not end with a trailing backslash.
+ *
+ * - CMD does not trim leading/trailing whitespace from path/pathex entries
+ * nor from the environment variables as a whole.
+ *
+ * - When cmd.exe cannot read a directory, it will just skip it and go on
+ * searching. However, unlike posix-y systems, it will happily try to run a
+ * file that is not readable/executable; if the spawn fails it will not
+ * continue searching.
+ *
+ * UNC path support: we are dealing with UNC paths in both the path and the
+ * filename. This is a deviation from what cmd.exe does (it does not let you
+ * start a program by specifying an UNC path on the command line) but this is
+ * really a pointless restriction.
+ *
+ */
+static WCHAR* search_path(const WCHAR *file,
+ WCHAR *cwd,
+ const WCHAR *path) {
+ int file_has_dir;
+ WCHAR* result = NULL;
+ WCHAR *file_name_start;
+ WCHAR *dot;
+ const WCHAR *dir_start, *dir_end, *dir_path;
+ size_t dir_len;
+ int name_has_ext;
+
+ size_t file_len = wcslen(file);
+ size_t cwd_len = wcslen(cwd);
+
+ /* If the caller supplies an empty filename,
+ * we're not gonna return c:\windows\.exe -- GFY!
+ */
+ if (file_len == 0
+ || (file_len == 1 && file[0] == L'.')) {
+ return NULL;
+ }
+
+ /* Find the start of the filename so we can split the directory from the */
+ /* name. */
+ for (file_name_start = (WCHAR*)file + file_len;
+ file_name_start > file
+ && file_name_start[-1] != L'\\'
+ && file_name_start[-1] != L'/'
+ && file_name_start[-1] != L':';
+ file_name_start--);
+
+ file_has_dir = file_name_start != file;
+
+ /* Check if the filename includes an extension */
+ dot = wcschr(file_name_start, L'.');
+ name_has_ext = (dot != NULL && dot[1] != L'\0');
+
+ if (file_has_dir) {
+ /* The file has a path inside, don't use path */
+ result = path_search_walk_ext(
+ file, file_name_start - file,
+ file_name_start, file_len - (file_name_start - file),
+ cwd, cwd_len,
+ name_has_ext);
+
+ } else {
+ dir_end = path;
+
+ /* The file is really only a name; look in cwd first, then scan path */
+ result = path_search_walk_ext(L"", 0,
+ file, file_len,
+ cwd, cwd_len,
+ name_has_ext);
+
+ while (result == NULL) {
+ if (*dir_end == L'\0') {
+ break;
+ }
+
+ /* Skip the separator that dir_end now points to */
+ if (dir_end != path || *path == L';') {
+ dir_end++;
+ }
+
+ /* Next slice starts just after where the previous one ended */
+ dir_start = dir_end;
+
+ /* Slice until the next ; or \0 is found */
+ dir_end = wcschr(dir_start, L';');
+ if (dir_end == NULL) {
+ dir_end = wcschr(dir_start, L'\0');
+ }
+
+ /* If the slice is zero-length, don't bother */
+ if (dir_end - dir_start == 0) {
+ continue;
+ }
+
+ dir_path = dir_start;
+ dir_len = dir_end - dir_start;
+
+ /* Adjust if the path is quoted. */
+ if (dir_path[0] == '"' || dir_path[0] == '\'') {
+ ++dir_path;
+ --dir_len;
+ }
+
+ if (dir_path[dir_len - 1] == '"' || dir_path[dir_len - 1] == '\'') {
+ --dir_len;
+ }
+
+ result = path_search_walk_ext(dir_path, dir_len,
+ file, file_len,
+ cwd, cwd_len,
+ name_has_ext);
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ * Quotes command line arguments
+ * Returns a pointer to the end (next char to be written) of the buffer
+ */
+WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
+ size_t len = wcslen(source);
+ size_t i;
+ int quote_hit;
+ WCHAR* start;
+
+ if (len == 0) {
+ /* Need double quotation for empty argument */
+ *(target++) = L'"';
+ *(target++) = L'"';
+ return target;
+ }
+
+ if (NULL == wcspbrk(source, L" \t\"")) {
+ /* No quotation needed */
+ wcsncpy(target, source, len);
+ target += len;
+ return target;
+ }
+
+ if (NULL == wcspbrk(source, L"\"\\")) {
+ /*
+ * No embedded double quotes or backlashes, so I can just wrap
+ * quote marks around the whole thing.
+ */
+ *(target++) = L'"';
+ wcsncpy(target, source, len);
+ target += len;
+ *(target++) = L'"';
+ return target;
+ }
+
+ /*
+ * Expected input/output:
+ * input : hello"world
+ * output: "hello\"world"
+ * input : hello""world
+ * output: "hello\"\"world"
+ * input : hello\world
+ * output: hello\world
+ * input : hello\\world
+ * output: hello\\world
+ * input : hello\"world
+ * output: "hello\\\"world"
+ * input : hello\\"world
+ * output: "hello\\\\\"world"
+ * input : hello world\
+ * output: "hello world\\"
+ */
+
+ *(target++) = L'"';
+ start = target;
+ quote_hit = 1;
+
+ for (i = len; i > 0; --i) {
+ *(target++) = source[i - 1];
+
+ if (quote_hit && source[i - 1] == L'\\') {
+ *(target++) = L'\\';
+ } else if(source[i - 1] == L'"') {
+ quote_hit = 1;
+ *(target++) = L'\\';
+ } else {
+ quote_hit = 0;
+ }
+ }
+ target[0] = L'\0';
+ wcsrev(start);
+ *(target++) = L'"';
+ return target;
+}
+
+
+int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
+ char** arg;
+ WCHAR* dst = NULL;
+ WCHAR* temp_buffer = NULL;
+ size_t dst_len = 0;
+ size_t temp_buffer_len = 0;
+ WCHAR* pos;
+ int arg_count = 0;
+ int err = 0;
+
+ /* Count the required size. */
+ for (arg = args; *arg; arg++) {
+ DWORD arg_len;
+
+ arg_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *arg,
+ -1,
+ NULL,
+ 0);
+ if (arg_len == 0) {
+ return GetLastError();
+ }
+
+ dst_len += arg_len;
+
+ if (arg_len > temp_buffer_len)
+ temp_buffer_len = arg_len;
+
+ arg_count++;
+ }
+
+ /* Adjust for potential quotes. Also assume the worst-case scenario */
+ /* that every character needs escaping, so we need twice as much space. */
+ dst_len = dst_len * 2 + arg_count * 2;
+
+ /* Allocate buffer for the final command line. */
+ dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR));
+ if (dst == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ /* Allocate temporary working buffer. */
+ temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR));
+ if (temp_buffer == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ pos = dst;
+ for (arg = args; *arg; arg++) {
+ DWORD arg_len;
+
+ /* Convert argument to wide char. */
+ arg_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *arg,
+ -1,
+ temp_buffer,
+ (int) (dst + dst_len - pos));
+ if (arg_len == 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ if (verbatim_arguments) {
+ /* Copy verbatim. */
+ wcscpy(pos, temp_buffer);
+ pos += arg_len - 1;
+ } else {
+ /* Quote/escape, if needed. */
+ pos = quote_cmd_arg(temp_buffer, pos);
+ }
+
+ *pos++ = *(arg + 1) ? L' ' : L'\0';
+ }
+
+ uv__free(temp_buffer);
+
+ *dst_ptr = dst;
+ return 0;
+
+error:
+ uv__free(dst);
+ uv__free(temp_buffer);
+ return err;
+}
+
+
+int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
+ wchar_t* a_eq;
+ wchar_t* b_eq;
+ wchar_t* A;
+ wchar_t* B;
+ int nb;
+ int r;
+
+ if (na < 0) {
+ a_eq = wcschr(a, L'=');
+ assert(a_eq);
+ na = (int)(long)(a_eq - a);
+ } else {
+ na--;
+ }
+ b_eq = wcschr(b, L'=');
+ assert(b_eq);
+ nb = b_eq - b;
+
+ A = alloca((na+1) * sizeof(wchar_t));
+ B = alloca((nb+1) * sizeof(wchar_t));
+
+ r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na);
+ assert(r==na);
+ A[na] = L'\0';
+ r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb);
+ assert(r==nb);
+ B[nb] = L'\0';
+
+ while (1) {
+ wchar_t AA = *A++;
+ wchar_t BB = *B++;
+ if (AA < BB) {
+ return -1;
+ } else if (AA > BB) {
+ return 1;
+ } else if (!AA && !BB) {
+ return 0;
+ }
+ }
+}
+
+
+static int qsort_wcscmp(const void *a, const void *b) {
+ wchar_t* astr = *(wchar_t* const*)a;
+ wchar_t* bstr = *(wchar_t* const*)b;
+ return env_strncmp(astr, -1, bstr);
+}
+
+
+/*
+ * The way windows takes environment variables is different than what C does;
+ * Windows wants a contiguous block of null-terminated strings, terminated
+ * with an additional null.
+ *
+ * Windows has a few "essential" environment variables. winsock will fail
+ * to initialize if SYSTEMROOT is not defined; some APIs make reference to
+ * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that
+ * these get defined if the input environment block does not contain any
+ * values for them.
+ *
+ * Also add variables known to Cygwin to be required for correct
+ * subprocess operation in many cases:
+ * https://github.com/Alexpux/Cygwin/blob/b266b04fbbd3a595f02ea149e4306d3ab9b1fe3d/winsup/cygwin/environ.cc#L955
+ *
+ */
+int make_program_env(char* env_block[], WCHAR** dst_ptr) {
+ WCHAR* dst;
+ WCHAR* ptr;
+ char** env;
+ size_t env_len = 0;
+ int len;
+ size_t i;
+ DWORD var_size;
+ size_t env_block_count = 1; /* 1 for null-terminator */
+ WCHAR* dst_copy;
+ WCHAR** ptr_copy;
+ WCHAR** env_copy;
+ DWORD* required_vars_value_len = alloca(n_required_vars * sizeof(DWORD*));
+
+ /* first pass: determine size in UTF-16 */
+ for (env = env_block; *env; env++) {
+ int len;
+ if (strchr(*env, '=')) {
+ len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *env,
+ -1,
+ NULL,
+ 0);
+ if (len <= 0) {
+ return GetLastError();
+ }
+ env_len += len;
+ env_block_count++;
+ }
+ }
+
+ /* second pass: copy to UTF-16 environment block */
+ dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR));
+ if (!dst_copy) {
+ return ERROR_OUTOFMEMORY;
+ }
+ env_copy = alloca(env_block_count * sizeof(WCHAR*));
+
+ ptr = dst_copy;
+ ptr_copy = env_copy;
+ for (env = env_block; *env; env++) {
+ if (strchr(*env, '=')) {
+ len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *env,
+ -1,
+ ptr,
+ (int) (env_len - (ptr - dst_copy)));
+ if (len <= 0) {
+ DWORD err = GetLastError();
+ uv__free(dst_copy);
+ return err;
+ }
+ *ptr_copy++ = ptr;
+ ptr += len;
+ }
+ }
+ *ptr_copy = NULL;
+ assert(env_len == ptr - dst_copy);
+
+ /* sort our (UTF-16) copy */
+ qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
+
+ /* third pass: check for required variables */
+ for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) {
+ int cmp;
+ if (!*ptr_copy) {
+ cmp = -1;
+ } else {
+ cmp = env_strncmp(required_vars[i].wide_eq,
+ required_vars[i].len,
+ *ptr_copy);
+ }
+ if (cmp < 0) {
+ /* missing required var */
+ var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
+ required_vars_value_len[i] = var_size;
+ if (var_size != 0) {
+ env_len += required_vars[i].len;
+ env_len += var_size;
+ }
+ i++;
+ } else {
+ ptr_copy++;
+ if (cmp == 0)
+ i++;
+ }
+ }
+
+ /* final pass: copy, in sort order, and inserting required variables */
+ dst = uv__malloc((1+env_len) * sizeof(WCHAR));
+ if (!dst) {
+ uv__free(dst_copy);
+ return ERROR_OUTOFMEMORY;
+ }
+
+ for (ptr = dst, ptr_copy = env_copy, i = 0;
+ *ptr_copy || i < n_required_vars;
+ ptr += len) {
+ int cmp;
+ if (i >= n_required_vars) {
+ cmp = 1;
+ } else if (!*ptr_copy) {
+ cmp = -1;
+ } else {
+ cmp = env_strncmp(required_vars[i].wide_eq,
+ required_vars[i].len,
+ *ptr_copy);
+ }
+ if (cmp < 0) {
+ /* missing required var */
+ len = required_vars_value_len[i];
+ if (len) {
+ wcscpy(ptr, required_vars[i].wide_eq);
+ ptr += required_vars[i].len;
+ var_size = GetEnvironmentVariableW(required_vars[i].wide,
+ ptr,
+ (int) (env_len - (ptr - dst)));
+ if (var_size != len-1) { /* race condition? */
+ uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
+ }
+ }
+ i++;
+ } else {
+ /* copy var from env_block */
+ len = wcslen(*ptr_copy) + 1;
+ wmemcpy(ptr, *ptr_copy, len);
+ ptr_copy++;
+ if (cmp == 0)
+ i++;
+ }
+ }
+
+ /* Terminate with an extra NULL. */
+ assert(env_len == (ptr - dst));
+ *ptr = L'\0';
+
+ uv__free(dst_copy);
+ *dst_ptr = dst;
+ return 0;
+}
+
+/*
+ * Attempt to find the value of the PATH environment variable in the child's
+ * preprocessed environment.
+ *
+ * If found, a pointer into `env` is returned. If not found, NULL is returned.
+ */
+static WCHAR* find_path(WCHAR *env) {
+ for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
+ if (wcsncmp(env, L"PATH=", 5) == 0)
+ return &env[5];
+ }
+
+ return NULL;
+}
+
+/*
+ * Called on Windows thread-pool thread to indicate that
+ * a child process has exited.
+ */
+static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
+ uv_process_t* process = (uv_process_t*) data;
+ uv_loop_t* loop = process->loop;
+
+ assert(didTimeout == FALSE);
+ assert(process);
+ assert(!process->exit_cb_pending);
+
+ process->exit_cb_pending = 1;
+
+ /* Post completed */
+ POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
+}
+
+
+/* Called on main thread after a child process has exited. */
+void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
+ int64_t exit_code;
+ DWORD status;
+
+ assert(handle->exit_cb_pending);
+ handle->exit_cb_pending = 0;
+
+ /* If we're closing, don't call the exit callback. Just schedule a close */
+ /* callback now. */
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ return;
+ }
+
+ /* Unregister from process notification. */
+ if (handle->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(handle->wait_handle);
+ handle->wait_handle = INVALID_HANDLE_VALUE;
+ }
+
+ /* Set the handle to inactive: no callbacks will be made after the exit */
+ /* callback.*/
+ uv__handle_stop(handle);
+
+ if (GetExitCodeProcess(handle->process_handle, &status)) {
+ exit_code = status;
+ } else {
+ /* Unable to to obtain the exit code. This should never happen. */
+ exit_code = uv_translate_sys_error(GetLastError());
+ }
+
+ /* Fire the exit callback. */
+ if (handle->exit_cb) {
+ handle->exit_cb(handle, exit_code, handle->exit_signal);
+ }
+}
+
+
+void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
+ uv__handle_closing(handle);
+
+ if (handle->wait_handle != INVALID_HANDLE_VALUE) {
+ /* This blocks until either the wait was cancelled, or the callback has */
+ /* completed. */
+ BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
+ if (!r) {
+ /* This should never happen, and if it happens, we can't recover... */
+ uv_fatal_error(GetLastError(), "UnregisterWaitEx");
+ }
+
+ handle->wait_handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (!handle->exit_cb_pending) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+}
+
+
+void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
+ assert(!handle->exit_cb_pending);
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ /* Clean-up the process handle. */
+ CloseHandle(handle->process_handle);
+
+ uv__handle_close(handle);
+}
+
+
+int uv_spawn(uv_loop_t* loop,
+ uv_process_t* process,
+ const uv_process_options_t* options) {
+ int i;
+ int err = 0;
+ WCHAR* path = NULL, *alloc_path = NULL;
+ BOOL result;
+ WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
+ *env = NULL, *cwd = NULL;
+ STARTUPINFOW startup;
+ PROCESS_INFORMATION info;
+ DWORD process_flags;
+
+ uv_process_init(loop, process);
+ process->exit_cb = options->exit_cb;
+
+ if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
+ return UV_ENOTSUP;
+ }
+
+ if (options->file == NULL ||
+ options->args == NULL) {
+ return UV_EINVAL;
+ }
+
+ assert(options->file != NULL);
+ assert(!(options->flags & ~(UV_PROCESS_DETACHED |
+ UV_PROCESS_SETGID |
+ UV_PROCESS_SETUID |
+ UV_PROCESS_WINDOWS_HIDE |
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
+
+ err = uv_utf8_to_utf16_alloc(options->file, &application);
+ if (err)
+ goto done;
+
+ err = make_program_args(
+ options->args,
+ options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
+ &arguments);
+ if (err)
+ goto done;
+
+ if (options->env) {
+ err = make_program_env(options->env, &env);
+ if (err)
+ goto done;
+ }
+
+ if (options->cwd) {
+ /* Explicit cwd */
+ err = uv_utf8_to_utf16_alloc(options->cwd, &cwd);
+ if (err)
+ goto done;
+
+ } else {
+ /* Inherit cwd */
+ DWORD cwd_len, r;
+
+ cwd_len = GetCurrentDirectoryW(0, NULL);
+ if (!cwd_len) {
+ err = GetLastError();
+ goto done;
+ }
+
+ cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR));
+ if (cwd == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto done;
+ }
+
+ r = GetCurrentDirectoryW(cwd_len, cwd);
+ if (r == 0 || r >= cwd_len) {
+ err = GetLastError();
+ goto done;
+ }
+ }
+
+ /* Get PATH environment variable. */
+ path = find_path(env);
+ if (path == NULL) {
+ DWORD path_len, r;
+
+ path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
+ if (path_len == 0) {
+ err = GetLastError();
+ goto done;
+ }
+
+ alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR));
+ if (alloc_path == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto done;
+ }
+ path = alloc_path;
+
+ r = GetEnvironmentVariableW(L"PATH", path, path_len);
+ if (r == 0 || r >= path_len) {
+ err = GetLastError();
+ goto done;
+ }
+ }
+
+ err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
+ if (err)
+ goto done;
+
+ application_path = search_path(application,
+ cwd,
+ path);
+ if (application_path == NULL) {
+ /* Not found. */
+ err = ERROR_FILE_NOT_FOUND;
+ goto done;
+ }
+
+ startup.cb = sizeof(startup);
+ startup.lpReserved = NULL;
+ startup.lpDesktop = NULL;
+ startup.lpTitle = NULL;
+ startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+
+ startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
+ startup.lpReserved2 = (BYTE*) process->child_stdio_buffer;
+
+ startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
+ startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
+ startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
+
+ if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
+ /* Use SW_HIDE to avoid any potential process window. */
+ startup.wShowWindow = SW_HIDE;
+ } else {
+ startup.wShowWindow = SW_SHOWDEFAULT;
+ }
+
+ process_flags = CREATE_UNICODE_ENVIRONMENT;
+
+ if (options->flags & UV_PROCESS_DETACHED) {
+ /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
+ * means that libuv might not let you create a fully daemonized process
+ * when run under job control. However the type of job control that libuv
+ * itself creates doesn't trickle down to subprocesses so they can still
+ * daemonize.
+ *
+ * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the
+ * CreateProcess call fail if we're under job control that doesn't allow
+ * breakaway.
+ */
+ process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
+ }
+
+ if (!CreateProcessW(application_path,
+ arguments,
+ NULL,
+ NULL,
+ 1,
+ process_flags,
+ env,
+ cwd,
+ &startup,
+ &info)) {
+ /* CreateProcessW failed. */
+ err = GetLastError();
+ goto done;
+ }
+
+ /* Spawn succeeded */
+ /* Beyond this point, failure is reported asynchronously. */
+
+ process->process_handle = info.hProcess;
+ process->pid = info.dwProcessId;
+
+ /* If the process isn't spawned as detached, assign to the global job */
+ /* object so windows will kill it when the parent process dies. */
+ if (!(options->flags & UV_PROCESS_DETACHED)) {
+ uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
+
+ if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
+ /* AssignProcessToJobObject might fail if this process is under job
+ * control and the job doesn't have the
+ * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version
+ * that doesn't support nested jobs.
+ *
+ * When that happens we just swallow the error and continue without
+ * establishing a kill-child-on-parent-exit relationship, otherwise
+ * there would be no way for libuv applications run under job control
+ * to spawn processes at all.
+ */
+ DWORD err = GetLastError();
+ if (err != ERROR_ACCESS_DENIED)
+ uv_fatal_error(err, "AssignProcessToJobObject");
+ }
+ }
+
+ /* Set IPC pid to all IPC pipes. */
+ for (i = 0; i < options->stdio_count; i++) {
+ const uv_stdio_container_t* fdopt = &options->stdio[i];
+ if (fdopt->flags & UV_CREATE_PIPE &&
+ fdopt->data.stream->type == UV_NAMED_PIPE &&
+ ((uv_pipe_t*) fdopt->data.stream)->ipc) {
+ ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId;
+ }
+ }
+
+ /* Setup notifications for when the child process exits. */
+ result = RegisterWaitForSingleObject(&process->wait_handle,
+ process->process_handle, exit_wait_callback, (void*)process, INFINITE,
+ WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
+ if (!result) {
+ uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
+ }
+
+ CloseHandle(info.hThread);
+
+ assert(!err);
+
+ /* Make the handle active. It will remain active until the exit callback */
+ /* is made or the handle is closed, whichever happens first. */
+ uv__handle_start(process);
+
+ /* Cleanup, whether we succeeded or failed. */
+ done:
+ uv__free(application);
+ uv__free(application_path);
+ uv__free(arguments);
+ uv__free(cwd);
+ uv__free(env);
+ uv__free(alloc_path);
+
+ if (process->child_stdio_buffer != NULL) {
+ /* Clean up child stdio handles. */
+ uv__stdio_destroy(process->child_stdio_buffer);
+ process->child_stdio_buffer = NULL;
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+static int uv__kill(HANDLE process_handle, int signum) {
+ switch (signum) {
+ case SIGTERM:
+ case SIGKILL:
+ case SIGINT: {
+ /* Unconditionally terminate the process. On Windows, killed processes */
+ /* normally return 1. */
+ DWORD status;
+ int err;
+
+ if (TerminateProcess(process_handle, 1))
+ return 0;
+
+ /* If the process already exited before TerminateProcess was called, */
+ /* TerminateProcess will fail with ERROR_ACCESS_DENIED. */
+ err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED &&
+ GetExitCodeProcess(process_handle, &status) &&
+ status != STILL_ACTIVE) {
+ return UV_ESRCH;
+ }
+
+ return uv_translate_sys_error(err);
+ }
+
+ case 0: {
+ /* Health check: is the process still alive? */
+ DWORD status;
+
+ if (!GetExitCodeProcess(process_handle, &status))
+ return uv_translate_sys_error(GetLastError());
+
+ if (status != STILL_ACTIVE)
+ return UV_ESRCH;
+
+ return 0;
+ }
+
+ default:
+ /* Unsupported signal. */
+ return UV_ENOSYS;
+ }
+}
+
+
+int uv_process_kill(uv_process_t* process, int signum) {
+ int err;
+
+ if (process->process_handle == INVALID_HANDLE_VALUE) {
+ return UV_EINVAL;
+ }
+
+ err = uv__kill(process->process_handle, signum);
+ if (err) {
+ return err; /* err is already translated. */
+ }
+
+ process->exit_signal = signum;
+
+ return 0;
+}
+
+
+int uv_kill(int pid, int signum) {
+ int err;
+ HANDLE process_handle = OpenProcess(PROCESS_TERMINATE |
+ PROCESS_QUERY_INFORMATION, FALSE, pid);
+
+ if (process_handle == NULL) {
+ err = GetLastError();
+ if (err == ERROR_INVALID_PARAMETER) {
+ return UV_ESRCH;
+ } else {
+ return uv_translate_sys_error(err);
+ }
+ }
+
+ err = uv__kill(process_handle, signum);
+ CloseHandle(process_handle);
+
+ return err; /* err is already translated. */
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef UV_WIN_REQ_INL_H_
+#define UV_WIN_REQ_INL_H_
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define SET_REQ_STATUS(req, status) \
+ (req)->u.io.overlapped.Internal = (ULONG_PTR) (status)
+
+#define SET_REQ_ERROR(req, error) \
+ SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
+
+#define SET_REQ_SUCCESS(req) \
+ SET_REQ_STATUS((req), STATUS_SUCCESS)
+
+#define GET_REQ_STATUS(req) \
+ ((NTSTATUS) (req)->u.io.overlapped.Internal)
+
+#define REQ_SUCCESS(req) \
+ (NT_SUCCESS(GET_REQ_STATUS((req))))
+
+#define GET_REQ_ERROR(req) \
+ (pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
+
+#define GET_REQ_SOCK_ERROR(req) \
+ (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
+
+
+#define REGISTER_HANDLE_REQ(loop, handle, req) \
+ do { \
+ INCREASE_ACTIVE_COUNT((loop), (handle)); \
+ uv__req_register((loop), (req)); \
+ } while (0)
+
+#define UNREGISTER_HANDLE_REQ(loop, handle, req) \
+ do { \
+ DECREASE_ACTIVE_COUNT((loop), (handle)); \
+ uv__req_unregister((loop), (req)); \
+ } while (0)
+
+
+#define UV_SUCCEEDED_WITHOUT_IOCP(result) \
+ ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP))
+
+#define UV_SUCCEEDED_WITH_IOCP(result) \
+ ((result) || (GetLastError() == ERROR_IO_PENDING))
+
+
+#define POST_COMPLETION_FOR_REQ(loop, req) \
+ if (!PostQueuedCompletionStatus((loop)->iocp, \
+ 0, \
+ 0, \
+ &((req)->u.io.overlapped))) { \
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \
+ }
+
+
+INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) {
+ req->type = UV_UNKNOWN_REQ;
+ SET_REQ_SUCCESS(req);
+}
+
+
+INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
+ return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
+}
+
+
+INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
+ req->next_req = NULL;
+ if (loop->pending_reqs_tail) {
+#ifdef _DEBUG
+ /* Ensure the request is not already in the queue, or the queue
+ * will get corrupted.
+ */
+ uv_req_t* current = loop->pending_reqs_tail;
+ do {
+ assert(req != current);
+ current = current->next_req;
+ } while(current != loop->pending_reqs_tail);
+#endif
+
+ req->next_req = loop->pending_reqs_tail->next_req;
+ loop->pending_reqs_tail->next_req = req;
+ loop->pending_reqs_tail = req;
+ } else {
+ req->next_req = req;
+ loop->pending_reqs_tail = req;
+ }
+}
+
+
+#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \
+ do { \
+ switch (((uv_handle_t*) (req)->handle_at)->type) { \
+ case UV_TCP: \
+ uv_process_tcp_##method##_req(loop, \
+ (uv_tcp_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ case UV_NAMED_PIPE: \
+ uv_process_pipe_##method##_req(loop, \
+ (uv_pipe_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ case UV_TTY: \
+ uv_process_tty_##method##_req(loop, \
+ (uv_tty_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ default: \
+ assert(0); \
+ } \
+ } while (0)
+
+
+INLINE static int uv_process_reqs(uv_loop_t* loop) {
+ uv_req_t* req;
+ uv_req_t* first;
+ uv_req_t* next;
+
+ if (loop->pending_reqs_tail == NULL)
+ return 0;
+
+ first = loop->pending_reqs_tail->next_req;
+ next = first;
+ loop->pending_reqs_tail = NULL;
+
+ while (next != NULL) {
+ req = next;
+ next = req->next_req != first ? req->next_req : NULL;
+
+ switch (req->type) {
+ case UV_READ:
+ DELEGATE_STREAM_REQ(loop, req, read, data);
+ break;
+
+ case UV_WRITE:
+ DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle);
+ break;
+
+ case UV_ACCEPT:
+ DELEGATE_STREAM_REQ(loop, req, accept, data);
+ break;
+
+ case UV_CONNECT:
+ DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle);
+ break;
+
+ case UV_SHUTDOWN:
+ /* Tcp shutdown requests don't come here. */
+ assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
+ uv_process_pipe_shutdown_req(
+ loop,
+ (uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
+ (uv_shutdown_t*) req);
+ break;
+
+ case UV_UDP_RECV:
+ uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
+ break;
+
+ case UV_UDP_SEND:
+ uv_process_udp_send_req(loop,
+ ((uv_udp_send_t*) req)->handle,
+ (uv_udp_send_t*) req);
+ break;
+
+ case UV_WAKEUP:
+ uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
+ break;
+
+ case UV_SIGNAL_REQ:
+ uv_process_signal_req(loop, (uv_signal_t*) req->data, req);
+ break;
+
+ case UV_POLL_REQ:
+ uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
+ break;
+
+ case UV_PROCESS_EXIT:
+ uv_process_proc_exit(loop, (uv_process_t*) req->data);
+ break;
+
+ case UV_FS_EVENT_REQ:
+ uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+
+ return 1;
+}
+
+#endif /* UV_WIN_REQ_INL_H_ */
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * 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.
+ */
+
+#include <assert.h>
+#include <signal.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+RB_HEAD(uv_signal_tree_s, uv_signal_s);
+
+static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
+static ssize_t volatile uv__signal_control_handler_refs = 0;
+static CRITICAL_SECTION uv__signal_lock;
+
+
+void uv_signals_init() {
+ InitializeCriticalSection(&uv__signal_lock);
+}
+
+
+static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
+ /* Compare signums first so all watchers with the same signnum end up */
+ /* adjacent. */
+ if (w1->signum < w2->signum) return -1;
+ if (w1->signum > w2->signum) return 1;
+
+ /* Sort by loop pointer, so we can easily look up the first item after */
+ /* { .signum = x, .loop = NULL } */
+ if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
+ if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
+
+ if ((uintptr_t) w1 < (uintptr_t) w2) return -1;
+ if ((uintptr_t) w1 > (uintptr_t) w2) return 1;
+
+ return 0;
+}
+
+
+RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare);
+
+
+/*
+ * Dispatches signal {signum} to all active uv_signal_t watchers in all loops.
+ * Returns 1 if the signal was dispatched to any watcher, or 0 if there were
+ * no active signal watchers observing this signal.
+ */
+int uv__signal_dispatch(int signum) {
+ uv_signal_t lookup;
+ uv_signal_t* handle;
+ int dispatched = 0;
+
+ EnterCriticalSection(&uv__signal_lock);
+
+ lookup.signum = signum;
+ lookup.loop = NULL;
+
+ for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
+ handle != NULL && handle->signum == signum;
+ handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
+ unsigned long previous = InterlockedExchange(
+ (volatile LONG*) &handle->pending_signum, signum);
+
+ if (!previous) {
+ POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
+ }
+
+ dispatched = 1;
+ }
+
+ LeaveCriticalSection(&uv__signal_lock);
+
+ return dispatched;
+}
+
+
+static BOOL WINAPI uv__signal_control_handler(DWORD type) {
+ switch (type) {
+ case CTRL_C_EVENT:
+ return uv__signal_dispatch(SIGINT);
+
+ case CTRL_BREAK_EVENT:
+ return uv__signal_dispatch(SIGBREAK);
+
+ case CTRL_CLOSE_EVENT:
+ if (uv__signal_dispatch(SIGHUP)) {
+ /* Windows will terminate the process after the control handler */
+ /* returns. After that it will just terminate our process. Therefore */
+ /* block the signal handler so the main loop has some time to pick */
+ /* up the signal and do something for a few seconds. */
+ Sleep(INFINITE);
+ return TRUE;
+ }
+ return FALSE;
+
+ case CTRL_LOGOFF_EVENT:
+ case CTRL_SHUTDOWN_EVENT:
+ /* These signals are only sent to services. Services have their own */
+ /* notification mechanism, so there's no point in handling these. */
+
+ default:
+ /* We don't handle these. */
+ return FALSE;
+ }
+}
+
+
+static int uv__signal_register_control_handler() {
+ /* When this function is called, the uv__signal_lock must be held. */
+
+ /* If the console control handler has already been hooked, just add a */
+ /* reference. */
+ if (uv__signal_control_handler_refs > 0) {
+ uv__signal_control_handler_refs++;
+ return 0;
+ }
+
+ if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
+ return GetLastError();
+
+ uv__signal_control_handler_refs++;
+
+ return 0;
+}
+
+
+static void uv__signal_unregister_control_handler() {
+ /* When this function is called, the uv__signal_lock must be held. */
+ BOOL r;
+
+ /* Don't unregister if the number of console control handlers exceeds one. */
+ /* Just remove a reference in that case. */
+ if (uv__signal_control_handler_refs > 1) {
+ uv__signal_control_handler_refs--;
+ return;
+ }
+
+ assert(uv__signal_control_handler_refs == 1);
+
+ r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE);
+ /* This should never fail; if it does it is probably a bug in libuv. */
+ assert(r);
+
+ uv__signal_control_handler_refs--;
+}
+
+
+static int uv__signal_register(int signum) {
+ switch (signum) {
+ case SIGINT:
+ case SIGBREAK:
+ case SIGHUP:
+ return uv__signal_register_control_handler();
+
+ case SIGWINCH:
+ /* SIGWINCH is generated in tty.c. No need to register anything. */
+ return 0;
+
+ case SIGILL:
+ case SIGABRT_COMPAT:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGTERM:
+ case SIGABRT:
+ /* Signal is never raised. */
+ return 0;
+
+ default:
+ /* Invalid signal. */
+ return ERROR_INVALID_PARAMETER;
+ }
+}
+
+
+static void uv__signal_unregister(int signum) {
+ switch (signum) {
+ case SIGINT:
+ case SIGBREAK:
+ case SIGHUP:
+ uv__signal_unregister_control_handler();
+ return;
+
+ case SIGWINCH:
+ /* SIGWINCH is generated in tty.c. No need to unregister anything. */
+ return;
+
+ case SIGILL:
+ case SIGABRT_COMPAT:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGTERM:
+ case SIGABRT:
+ /* Nothing is registered for this signal. */
+ return;
+
+ default:
+ /* Libuv bug. */
+ assert(0 && "Invalid signum");
+ return;
+ }
+}
+
+
+int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
+ uv_req_t* req;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
+ handle->pending_signum = 0;
+ handle->signum = 0;
+ handle->signal_cb = NULL;
+
+ req = &handle->signal_req;
+ uv_req_init(loop, req);
+ req->type = UV_SIGNAL_REQ;
+ req->data = handle;
+
+ return 0;
+}
+
+
+int uv_signal_stop(uv_signal_t* handle) {
+ uv_signal_t* removed_handle;
+
+ /* If the watcher wasn't started, this is a no-op. */
+ if (handle->signum == 0)
+ return 0;
+
+ EnterCriticalSection(&uv__signal_lock);
+
+ uv__signal_unregister(handle->signum);
+
+ removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
+ assert(removed_handle == handle);
+
+ LeaveCriticalSection(&uv__signal_lock);
+
+ handle->signum = 0;
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
+ int err;
+
+ /* If the user supplies signum == 0, then return an error already. If the */
+ /* signum is otherwise invalid then uv__signal_register will find out */
+ /* eventually. */
+ if (signum == 0) {
+ return UV_EINVAL;
+ }
+
+ /* Short circuit: if the signal watcher is already watching {signum} don't */
+ /* go through the process of deregistering and registering the handler. */
+ /* Additionally, this avoids pending signals getting lost in the (small) */
+ /* time frame that handle->signum == 0. */
+ if (signum == handle->signum) {
+ handle->signal_cb = signal_cb;
+ return 0;
+ }
+
+ /* If the signal handler was already active, stop it first. */
+ if (handle->signum != 0) {
+ int r = uv_signal_stop(handle);
+ /* uv_signal_stop is infallible. */
+ assert(r == 0);
+ }
+
+ EnterCriticalSection(&uv__signal_lock);
+
+ err = uv__signal_register(signum);
+ if (err) {
+ /* Uh-oh, didn't work. */
+ LeaveCriticalSection(&uv__signal_lock);
+ return uv_translate_sys_error(err);
+ }
+
+ handle->signum = signum;
+ RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
+
+ LeaveCriticalSection(&uv__signal_lock);
+
+ handle->signal_cb = signal_cb;
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
+ uv_req_t* req) {
+ long dispatched_signum;
+
+ assert(handle->type == UV_SIGNAL);
+ assert(req->type == UV_SIGNAL_REQ);
+
+ dispatched_signum = InterlockedExchange(
+ (volatile LONG*) &handle->pending_signum, 0);
+ assert(dispatched_signum != 0);
+
+ /* Check if the pending signal equals the signum that we are watching for. */
+ /* These can get out of sync when the handler is stopped and restarted */
+ /* while the signal_req is pending. */
+ if (dispatched_signum == handle->signum)
+ handle->signal_cb(handle, dispatched_signum);
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ /* When it is closing, it must be stopped at this point. */
+ assert(handle->signum == 0);
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
+ uv_signal_stop(handle);
+ uv__handle_closing(handle);
+
+ if (handle->pending_signum == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ assert(handle->signum == 0);
+ assert(handle->pending_signum == 0);
+
+ handle->flags |= UV_HANDLE_CLOSED;
+
+ uv__handle_close(handle);
+}
--- /dev/null
+/* Copyright the libuv project contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer
+ * on overflow...
+ */
+int snprintf(char* buf, size_t len, const char* fmt, ...) {
+ int n;
+ va_list ap;
+ va_start(ap, fmt);
+
+ n = _vscprintf(fmt, ap);
+ vsnprintf_s(buf, len, _TRUNCATE, fmt, ap);
+
+ va_end(ap);
+ return n;
+}
+
+#endif
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef UV_WIN_STREAM_INL_H_
+#define UV_WIN_STREAM_INL_H_
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+INLINE static void uv_stream_init(uv_loop_t* loop,
+ uv_stream_t* handle,
+ uv_handle_type type) {
+ uv__handle_init(loop, (uv_handle_t*) handle, type);
+ handle->write_queue_size = 0;
+ handle->activecnt = 0;
+}
+
+
+INLINE static void uv_connection_init(uv_stream_t* handle) {
+ handle->flags |= UV_HANDLE_CONNECTION;
+ handle->stream.conn.write_reqs_pending = 0;
+
+ uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req));
+ handle->read_req.event_handle = NULL;
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ handle->read_req.type = UV_READ;
+ handle->read_req.data = handle;
+
+ handle->stream.conn.shutdown_req = NULL;
+}
+
+
+#endif /* UV_WIN_STREAM_INL_H_ */
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
+ int err;
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (stream->type) {
+ case UV_TCP:
+ err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_accept(uv_stream_t* server, uv_stream_t* client) {
+ int err;
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (server->type) {
+ case UV_TCP:
+ err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_accept((uv_pipe_t*)server, client);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ int err;
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return UV_EALREADY;
+ }
+
+ if (!(handle->flags & UV_HANDLE_READABLE)) {
+ return UV_ENOTCONN;
+ }
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (handle->type) {
+ case UV_TCP:
+ err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
+ break;
+ case UV_TTY:
+ err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_read_stop(uv_stream_t* handle) {
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_READING))
+ return 0;
+
+ err = 0;
+ if (handle->type == UV_TTY) {
+ err = uv_tty_read_stop((uv_tty_t*) handle);
+ } else {
+ if (handle->type == UV_NAMED_PIPE) {
+ uv__pipe_stop_read((uv_pipe_t*) handle);
+ } else {
+ handle->flags &= ~UV_HANDLE_READING;
+ }
+ DECREASE_ACTIVE_COUNT(handle->loop, handle);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_write(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ return UV_EPIPE;
+ }
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (handle->type) {
+ case UV_TCP:
+ err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_write(loop, req, (uv_pipe_t*) handle, bufs, nbufs, cb);
+ break;
+ case UV_TTY:
+ err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_write2(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ return UV_EPIPE;
+ }
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (handle->type) {
+ case UV_NAMED_PIPE:
+ err = uv_pipe_write2(loop,
+ req,
+ (uv_pipe_t*) handle,
+ bufs,
+ nbufs,
+ send_handle,
+ cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_try_write(uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ if (stream->flags & UV__HANDLE_CLOSING)
+ return UV_EBADF;
+ if (!(stream->flags & UV_HANDLE_WRITABLE))
+ return UV_EPIPE;
+
+ switch (stream->type) {
+ case UV_TCP:
+ return uv__tcp_try_write((uv_tcp_t*) stream, bufs, nbufs);
+ case UV_TTY:
+ return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs);
+ case UV_NAMED_PIPE:
+ return UV_EAGAIN;
+ default:
+ assert(0);
+ return UV_ENOSYS;
+ }
+}
+
+
+int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
+ uv_loop_t* loop = handle->loop;
+
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ return UV_EPIPE;
+ }
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_SHUTDOWN;
+ req->handle = handle;
+ req->cb = cb;
+
+ handle->flags &= ~UV_HANDLE_WRITABLE;
+ handle->stream.conn.shutdown_req = req;
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+
+ return 0;
+}
+
+
+int uv_is_readable(const uv_stream_t* handle) {
+ return !!(handle->flags & UV_HANDLE_READABLE);
+}
+
+
+int uv_is_writable(const uv_stream_t* handle) {
+ return !!(handle->flags & UV_HANDLE_WRITABLE);
+}
+
+
+int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
+ if (handle->type != UV_NAMED_PIPE)
+ return UV_EINVAL;
+
+ if (blocking != 0)
+ handle->flags |= UV_HANDLE_BLOCKING_WRITES;
+ else
+ handle->flags &= ~UV_HANDLE_BLOCKING_WRITES;
+
+ return 0;
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+
+/*
+ * Threshold of active tcp streams for which to preallocate tcp read buffers.
+ * (Due to node slab allocator performing poorly under this pattern,
+ * the optimization is temporarily disabled (threshold=0). This will be
+ * revisited once node allocator is improved.)
+ */
+const unsigned int uv_active_tcp_streams_threshold = 0;
+
+/*
+ * Number of simultaneous pending AcceptEx calls.
+ */
+const unsigned int uv_simultaneous_server_accepts = 32;
+
+/* A zero-size buffer for use by uv_tcp_read */
+static char uv_zero_[] = "";
+
+static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) {
+ if (setsockopt(socket,
+ IPPROTO_TCP,
+ TCP_NODELAY,
+ (const char*)&enable,
+ sizeof enable) == -1) {
+ return WSAGetLastError();
+ }
+ return 0;
+}
+
+
+static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) {
+ if (setsockopt(socket,
+ SOL_SOCKET,
+ SO_KEEPALIVE,
+ (const char*)&enable,
+ sizeof enable) == -1) {
+ return WSAGetLastError();
+ }
+
+ if (enable && setsockopt(socket,
+ IPPROTO_TCP,
+ TCP_KEEPALIVE,
+ (const char*)&delay,
+ sizeof delay) == -1) {
+ return WSAGetLastError();
+ }
+
+ return 0;
+}
+
+
+static int uv_tcp_set_socket(uv_loop_t* loop,
+ uv_tcp_t* handle,
+ SOCKET socket,
+ int family,
+ int imported) {
+ DWORD yes = 1;
+ int non_ifs_lsp;
+ int err;
+
+ if (handle->socket != INVALID_SOCKET)
+ return UV_EBUSY;
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0))
+ return GetLastError();
+
+ /* Associate it with the I/O completion port. */
+ /* Use uv_handle_t pointer as completion key. */
+ if (CreateIoCompletionPort((HANDLE)socket,
+ loop->iocp,
+ (ULONG_PTR)socket,
+ 0) == NULL) {
+ if (imported) {
+ handle->flags |= UV_HANDLE_EMULATE_IOCP;
+ } else {
+ return GetLastError();
+ }
+ }
+
+ if (family == AF_INET6) {
+ non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv6;
+ } else {
+ non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4;
+ }
+
+ if (pSetFileCompletionNotificationModes &&
+ !(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) {
+ if (pSetFileCompletionNotificationModes((HANDLE) socket,
+ FILE_SKIP_SET_EVENT_ON_HANDLE |
+ FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
+ handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
+ } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
+ return GetLastError();
+ }
+ }
+
+ if (handle->flags & UV_HANDLE_TCP_NODELAY) {
+ err = uv__tcp_nodelay(handle, socket, 1);
+ if (err)
+ return err;
+ }
+
+ /* TODO: Use stored delay. */
+ if (handle->flags & UV_HANDLE_TCP_KEEPALIVE) {
+ err = uv__tcp_keepalive(handle, socket, 1, 60);
+ if (err)
+ return err;
+ }
+
+ handle->socket = socket;
+
+ if (family == AF_INET6) {
+ handle->flags |= UV_HANDLE_IPV6;
+ } else {
+ assert(!(handle->flags & UV_HANDLE_IPV6));
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
+ int domain;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return UV_EINVAL;
+
+ if (flags & ~0xFF)
+ return UV_EINVAL;
+
+ uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP);
+ handle->tcp.serv.accept_reqs = NULL;
+ handle->tcp.serv.pending_accepts = NULL;
+ handle->socket = INVALID_SOCKET;
+ handle->reqs_pending = 0;
+ handle->tcp.serv.func_acceptex = NULL;
+ handle->tcp.conn.func_connectex = NULL;
+ handle->tcp.serv.processed_accepts = 0;
+ handle->delayed_error = 0;
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+ */
+
+ if (domain != AF_UNSPEC) {
+ SOCKET sock;
+ DWORD err;
+
+ sock = socket(domain, SOCK_STREAM, 0);
+ if (sock == INVALID_SOCKET) {
+ err = WSAGetLastError();
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+
+ err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0);
+ if (err) {
+ closesocket(sock);
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
+ return uv_tcp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
+void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
+ int err;
+ unsigned int i;
+ uv_tcp_accept_t* req;
+
+ if (handle->flags & UV_HANDLE_CONNECTION &&
+ handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+
+ UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
+
+ err = 0;
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ err = ERROR_OPERATION_ABORTED;
+ } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ }
+
+ if (handle->stream.conn.shutdown_req->cb) {
+ handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req,
+ uv_translate_sys_error(err));
+ }
+
+ handle->stream.conn.shutdown_req = NULL;
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) {
+ closesocket(handle->socket);
+ handle->socket = INVALID_SOCKET;
+ handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
+ }
+
+ if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ for (i = 0; i < uv_simultaneous_server_accepts; i++) {
+ req = &handle->tcp.serv.accept_reqs[i];
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(req->wait_handle);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (req->event_handle) {
+ CloseHandle(req->event_handle);
+ req->event_handle = NULL;
+ }
+ }
+ }
+
+ uv__free(handle->tcp.serv.accept_reqs);
+ handle->tcp.serv.accept_reqs = NULL;
+ }
+
+ if (handle->flags & UV_HANDLE_CONNECTION &&
+ handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(handle->read_req.wait_handle);
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (handle->read_req.event_handle) {
+ CloseHandle(handle->read_req.event_handle);
+ handle->read_req.event_handle = NULL;
+ }
+ }
+
+ uv__handle_close(handle);
+ loop->active_tcp_streams--;
+ }
+}
+
+
+/* Unlike on Unix, here we don't set SO_REUSEADDR, because it doesn't just
+ * allow binding to addresses that are in use by sockets in TIME_WAIT, it
+ * effectively allows 'stealing' a port which is in use by another application.
+ *
+ * SO_EXCLUSIVEADDRUSE is also not good here because it does check all sockets,
+ * regardless of state, so we'd get an error even if the port is in use by a
+ * socket in TIME_WAIT state.
+ *
+ * See issue #1360.
+ *
+ */
+static int uv_tcp_try_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ DWORD err;
+ int r;
+
+ if (handle->socket == INVALID_SOCKET) {
+ SOCKET sock;
+
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
+ return ERROR_INVALID_PARAMETER;
+
+ sock = socket(addr->sa_family, SOCK_STREAM, 0);
+ if (sock == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0);
+ if (err) {
+ closesocket(sock);
+ return err;
+ }
+ }
+
+#ifdef IPV6_V6ONLY
+ if (addr->sa_family == AF_INET6) {
+ int on;
+
+ on = (flags & UV_TCP_IPV6ONLY) != 0;
+
+ /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
+ /* available, or when run on XP/2003 which have no support for dualstack */
+ /* sockets. For now we're silently ignoring the error. */
+ setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ (const char*)&on,
+ sizeof on);
+ }
+#endif
+
+ r = bind(handle->socket, addr, addrlen);
+
+ if (r == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ if (err == WSAEADDRINUSE) {
+ /* Some errors are not to be reported until connect() or listen() */
+ handle->delayed_error = err;
+ } else {
+ return err;
+ }
+ }
+
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+}
+
+
+static void CALLBACK post_completion(void* context, BOOLEAN timed_out) {
+ uv_req_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_req_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->data;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) {
+ uv_write_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_write_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->handle;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
+ uv_loop_t* loop = handle->loop;
+ BOOL success;
+ DWORD bytes;
+ SOCKET accept_socket;
+ short family;
+
+ assert(handle->flags & UV_HANDLE_LISTENING);
+ assert(req->accept_socket == INVALID_SOCKET);
+
+ /* choose family and extension function */
+ if (handle->flags & UV_HANDLE_IPV6) {
+ family = AF_INET6;
+ } else {
+ family = AF_INET;
+ }
+
+ /* Open a socket for the accepted connection. */
+ accept_socket = socket(family, SOCK_STREAM, 0);
+ if (accept_socket == INVALID_SOCKET) {
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ return;
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ closesocket(accept_socket);
+ return;
+ }
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+ }
+
+ success = handle->tcp.serv.func_acceptex(handle->socket,
+ accept_socket,
+ (void*)req->accept_buffer,
+ 0,
+ sizeof(struct sockaddr_storage),
+ sizeof(struct sockaddr_storage),
+ &bytes,
+ &req->u.io.overlapped);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
+ /* Process the req without IOCP. */
+ req->accept_socket = accept_socket;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
+ /* The req will be processed with IOCP. */
+ req->accept_socket = accept_socket;
+ handle->reqs_pending++;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ req->wait_handle == INVALID_HANDLE_VALUE &&
+ !RegisterWaitForSingleObject(&req->wait_handle,
+ req->event_handle, post_completion, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ return;
+ }
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ /* Destroy the preallocated client socket. */
+ closesocket(accept_socket);
+ /* Destroy the event handle */
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ CloseHandle(req->u.io.overlapped.hEvent);
+ req->event_handle = NULL;
+ }
+ }
+}
+
+
+static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
+ uv_read_t* req;
+ uv_buf_t buf;
+ int result;
+ DWORD bytes, flags;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ req = &handle->read_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ /*
+ * Preallocate a read buffer if the number of active streams is below
+ * the threshold.
+ */
+ if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) {
+ handle->flags &= ~UV_HANDLE_ZERO_READ;
+ handle->tcp.conn.read_buffer = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer);
+ if (handle->tcp.conn.read_buffer.base == NULL ||
+ handle->tcp.conn.read_buffer.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer);
+ return;
+ }
+ assert(handle->tcp.conn.read_buffer.base != NULL);
+ buf = handle->tcp.conn.read_buffer;
+ } else {
+ handle->flags |= UV_HANDLE_ZERO_READ;
+ buf.base = (char*) &uv_zero_;
+ buf.len = 0;
+ }
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ assert(req->event_handle);
+ req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+ }
+
+ flags = 0;
+ result = WSARecv(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->u.io.overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ req->wait_handle == INVALID_HANDLE_VALUE &&
+ !RegisterWaitForSingleObject(&req->wait_handle,
+ req->event_handle, post_completion, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ }
+}
+
+
+int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ unsigned int i, simultaneous_accepts;
+ uv_tcp_accept_t* req;
+ int err;
+
+ assert(backlog > 0);
+
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->stream.serv.connection_cb = cb;
+ }
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return WSAEISCONN;
+ }
+
+ if (handle->delayed_error) {
+ return handle->delayed_error;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ err = uv_tcp_try_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip4_any_,
+ sizeof(uv_addr_ip4_any_),
+ 0);
+ if (err)
+ return err;
+ if (handle->delayed_error)
+ return handle->delayed_error;
+ }
+
+ if (!handle->tcp.serv.func_acceptex) {
+ if (!uv_get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) {
+ return WSAEAFNOSUPPORT;
+ }
+ }
+
+ if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
+ listen(handle->socket, backlog) == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ handle->flags |= UV_HANDLE_LISTENING;
+ handle->stream.serv.connection_cb = cb;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+
+ simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1
+ : uv_simultaneous_server_accepts;
+
+ if(!handle->tcp.serv.accept_reqs) {
+ handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*)
+ uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
+ if (!handle->tcp.serv.accept_reqs) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ for (i = 0; i < simultaneous_accepts; i++) {
+ req = &handle->tcp.serv.accept_reqs[i];
+ uv_req_init(loop, (uv_req_t*)req);
+ req->type = UV_ACCEPT;
+ req->accept_socket = INVALID_SOCKET;
+ req->data = handle;
+
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ } else {
+ req->event_handle = NULL;
+ }
+
+ uv_tcp_queue_accept(handle, req);
+ }
+
+ /* Initialize other unused requests too, because uv_tcp_endgame */
+ /* doesn't know how how many requests were initialized, so it will */
+ /* try to clean up {uv_simultaneous_server_accepts} requests. */
+ for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) {
+ req = &handle->tcp.serv.accept_reqs[i];
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_ACCEPT;
+ req->accept_socket = INVALID_SOCKET;
+ req->data = handle;
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ req->event_handle = NULL;
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
+ uv_loop_t* loop = server->loop;
+ int err = 0;
+ int family;
+
+ uv_tcp_accept_t* req = server->tcp.serv.pending_accepts;
+
+ if (!req) {
+ /* No valid connections found, so we error out. */
+ return WSAEWOULDBLOCK;
+ }
+
+ if (req->accept_socket == INVALID_SOCKET) {
+ return WSAENOTCONN;
+ }
+
+ if (server->flags & UV_HANDLE_IPV6) {
+ family = AF_INET6;
+ } else {
+ family = AF_INET;
+ }
+
+ err = uv_tcp_set_socket(client->loop,
+ client,
+ req->accept_socket,
+ family,
+ 0);
+ if (err) {
+ closesocket(req->accept_socket);
+ } else {
+ uv_connection_init((uv_stream_t*) client);
+ /* AcceptEx() implicitly binds the accepted socket. */
+ client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ }
+
+ /* Prepare the req to pick up a new connection */
+ server->tcp.serv.pending_accepts = req->next_pending;
+ req->next_pending = NULL;
+ req->accept_socket = INVALID_SOCKET;
+
+ if (!(server->flags & UV__HANDLE_CLOSING)) {
+ /* Check if we're in a middle of changing the number of pending accepts. */
+ if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
+ uv_tcp_queue_accept(server, req);
+ } else {
+ /* We better be switching to a single pending accept. */
+ assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT);
+
+ server->tcp.serv.processed_accepts++;
+
+ if (server->tcp.serv.processed_accepts >= uv_simultaneous_server_accepts) {
+ server->tcp.serv.processed_accepts = 0;
+ /*
+ * All previously queued accept requests are now processed.
+ * We now switch to queueing just a single accept.
+ */
+ uv_tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]);
+ server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
+ server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
+ }
+ }
+ }
+
+ loop->active_tcp_streams++;
+
+ return err;
+}
+
+
+int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ uv_loop_t* loop = handle->loop;
+
+ handle->flags |= UV_HANDLE_READING;
+ handle->read_cb = read_cb;
+ handle->alloc_cb = alloc_cb;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* read request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ !handle->read_req.event_handle) {
+ handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!handle->read_req.event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ }
+ uv_tcp_queue_read(loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv_tcp_try_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ const struct sockaddr* bind_addr;
+ BOOL success;
+ DWORD bytes;
+ int err;
+
+ if (handle->delayed_error) {
+ return handle->delayed_error;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ if (addrlen == sizeof(uv_addr_ip4_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
+ } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
+ } else {
+ abort();
+ }
+ err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
+ if (err)
+ return err;
+ if (handle->delayed_error)
+ return handle->delayed_error;
+ }
+
+ if (!handle->tcp.conn.func_connectex) {
+ if (!uv_get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) {
+ return WSAEAFNOSUPPORT;
+ }
+ }
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_CONNECT;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ success = handle->tcp.conn.func_connectex(handle->socket,
+ addr,
+ addrlen,
+ NULL,
+ 0,
+ &bytes,
+ &req->u.io.overlapped);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
+ /* Process the req without IOCP. */
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
+ /* The req will be processed with IOCP. */
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ } else {
+ return WSAGetLastError();
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_getsockname(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ int result;
+
+ if (handle->socket == INVALID_SOCKET) {
+ return UV_EINVAL;
+ }
+
+ if (handle->delayed_error) {
+ return uv_translate_sys_error(handle->delayed_error);
+ }
+
+ result = getsockname(handle->socket, name, namelen);
+ if (result != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_getpeername(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ int result;
+
+ if (handle->socket == INVALID_SOCKET) {
+ return UV_EINVAL;
+ }
+
+ if (handle->delayed_error) {
+ return uv_translate_sys_error(handle->delayed_error);
+ }
+
+ result = getpeername(handle->socket, name, namelen);
+ if (result != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_write(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_tcp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ int result;
+ DWORD bytes;
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_WRITE;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+
+ result = WSASend(handle->socket,
+ (WSABUF*) bufs,
+ nbufs,
+ &bytes,
+ 0,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->write_queue_size += req->u.io.queued_bytes;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ !RegisterWaitForSingleObject(&req->wait_handle,
+ req->event_handle, post_write_completion, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+ } else {
+ /* Send failed due to an error, report it later */
+ req->u.io.queued_bytes = 0;
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ }
+
+ return 0;
+}
+
+
+int uv__tcp_try_write(uv_tcp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ int result;
+ DWORD bytes;
+
+ if (handle->stream.conn.write_reqs_pending > 0)
+ return UV_EAGAIN;
+
+ result = WSASend(handle->socket,
+ (WSABUF*) bufs,
+ nbufs,
+ &bytes,
+ 0,
+ NULL,
+ NULL);
+
+ if (result == SOCKET_ERROR)
+ return uv_translate_sys_error(WSAGetLastError());
+ else
+ return bytes;
+}
+
+
+void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_req_t* req) {
+ DWORD bytes, flags, err;
+ uv_buf_t buf;
+
+ assert(handle->type == UV_TCP);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!REQ_SUCCESS(req)) {
+ /* An error occurred doing the read. */
+ if ((handle->flags & UV_HANDLE_READING) ||
+ !(handle->flags & UV_HANDLE_ZERO_READ)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
+ uv_buf_init(NULL, 0) : handle->tcp.conn.read_buffer;
+
+ err = GET_REQ_SOCK_ERROR(req);
+
+ if (err == WSAECONNABORTED) {
+ /*
+ * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
+ */
+ err = WSAECONNRESET;
+ }
+
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(err),
+ &buf);
+ }
+ } else {
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+ /* The read was done with a non-zero buffer length. */
+ if (req->u.io.overlapped.InternalHigh > 0) {
+ /* Successful read */
+ handle->read_cb((uv_stream_t*)handle,
+ req->u.io.overlapped.InternalHigh,
+ &handle->tcp.conn.read_buffer);
+ /* Read again only if bytes == buf.len */
+ if (req->u.io.overlapped.InternalHigh < handle->tcp.conn.read_buffer.len) {
+ goto done;
+ }
+ } else {
+ /* Connection closed */
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+ handle->flags &= ~UV_HANDLE_READABLE;
+
+ buf.base = 0;
+ buf.len = 0;
+ handle->read_cb((uv_stream_t*)handle, UV_EOF, &handle->tcp.conn.read_buffer);
+ goto done;
+ }
+ }
+
+ /* Do nonblocking reads until the buffer is empty */
+ while (handle->flags & UV_HANDLE_READING) {
+ buf = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
+ if (buf.base == NULL || buf.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
+ break;
+ }
+ assert(buf.base != NULL);
+
+ flags = 0;
+ if (WSARecv(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ NULL,
+ NULL) != SOCKET_ERROR) {
+ if (bytes > 0) {
+ /* Successful read */
+ handle->read_cb((uv_stream_t*)handle, bytes, &buf);
+ /* Read again only if bytes == buf.len */
+ if (bytes < buf.len) {
+ break;
+ }
+ } else {
+ /* Connection closed */
+ handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE);
+ DECREASE_ACTIVE_COUNT(loop, handle);
+
+ handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf);
+ break;
+ }
+ } else {
+ err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK) {
+ /* Read buffer was completely empty, report a 0-byte read. */
+ handle->read_cb((uv_stream_t*)handle, 0, &buf);
+ } else {
+ /* Ouch! serious error. */
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+
+ if (err == WSAECONNABORTED) {
+ /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */
+ /* Unix. */
+ err = WSAECONNRESET;
+ }
+
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(err),
+ &buf);
+ }
+ break;
+ }
+ }
+
+done:
+ /* Post another read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_tcp_queue_read(loop, handle);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_write_t* req) {
+ int err;
+
+ assert(handle->type == UV_TCP);
+
+ assert(handle->write_queue_size >= req->u.io.queued_bytes);
+ handle->write_queue_size -= req->u.io.queued_bytes;
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(req->wait_handle);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (req->event_handle) {
+ CloseHandle(req->event_handle);
+ req->event_handle = NULL;
+ }
+ }
+
+ if (req->cb) {
+ err = uv_translate_sys_error(GET_REQ_SOCK_ERROR(req));
+ if (err == UV_ECONNABORTED) {
+ /* use UV_ECANCELED for consistency with Unix */
+ err = UV_ECANCELED;
+ }
+ req->cb(req, err);
+ }
+
+ handle->stream.conn.write_reqs_pending--;
+ if (handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_req_t* raw_req) {
+ uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req;
+ int err;
+
+ assert(handle->type == UV_TCP);
+
+ /* If handle->accepted_socket is not a valid socket, then */
+ /* uv_queue_accept must have failed. This is a serious error. We stop */
+ /* accepting connections and report this error to the connection */
+ /* callback. */
+ if (req->accept_socket == INVALID_SOCKET) {
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->flags &= ~UV_HANDLE_LISTENING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ if (handle->stream.serv.connection_cb) {
+ err = GET_REQ_SOCK_ERROR(req);
+ handle->stream.serv.connection_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(err));
+ }
+ }
+ } else if (REQ_SUCCESS(req) &&
+ setsockopt(req->accept_socket,
+ SOL_SOCKET,
+ SO_UPDATE_ACCEPT_CONTEXT,
+ (char*)&handle->socket,
+ sizeof(handle->socket)) == 0) {
+ req->next_pending = handle->tcp.serv.pending_accepts;
+ handle->tcp.serv.pending_accepts = req;
+
+ /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */
+ if (handle->stream.serv.connection_cb) {
+ handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
+ }
+ } else {
+ /* Error related to accepted socket is ignored because the server */
+ /* socket may still be healthy. If the server socket is broken */
+ /* uv_queue_accept will detect it. */
+ closesocket(req->accept_socket);
+ req->accept_socket = INVALID_SOCKET;
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ uv_tcp_queue_accept(handle, req);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_connect_t* req) {
+ int err;
+
+ assert(handle->type == UV_TCP);
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ err = 0;
+ if (REQ_SUCCESS(req)) {
+ if (setsockopt(handle->socket,
+ SOL_SOCKET,
+ SO_UPDATE_CONNECT_CONTEXT,
+ NULL,
+ 0) == 0) {
+ uv_connection_init((uv_stream_t*)handle);
+ handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ loop->active_tcp_streams++;
+ } else {
+ err = WSAGetLastError();
+ }
+ } else {
+ err = GET_REQ_SOCK_ERROR(req);
+ }
+ req->cb(req, uv_translate_sys_error(err));
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
+ int tcp_connection) {
+ int err;
+ SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ &socket_info_ex->socket_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+
+ if (socket == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ err = uv_tcp_set_socket(tcp->loop,
+ tcp,
+ socket,
+ socket_info_ex->socket_info.iAddressFamily,
+ 1);
+ if (err) {
+ closesocket(socket);
+ return err;
+ }
+
+ if (tcp_connection) {
+ uv_connection_init((uv_stream_t*)tcp);
+ tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ }
+
+ tcp->flags |= UV_HANDLE_BOUND;
+ tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
+
+ tcp->delayed_error = socket_info_ex->delayed_error;
+
+ tcp->loop->active_tcp_streams++;
+ return 0;
+}
+
+
+int uv_tcp_nodelay(uv_tcp_t* handle, int enable) {
+ int err;
+
+ if (handle->socket != INVALID_SOCKET) {
+ err = uv__tcp_nodelay(handle, handle->socket, enable);
+ if (err)
+ return err;
+ }
+
+ if (enable) {
+ handle->flags |= UV_HANDLE_TCP_NODELAY;
+ } else {
+ handle->flags &= ~UV_HANDLE_TCP_NODELAY;
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
+ int err;
+
+ if (handle->socket != INVALID_SOCKET) {
+ err = uv__tcp_keepalive(handle, handle->socket, enable, delay);
+ if (err)
+ return err;
+ }
+
+ if (enable) {
+ handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
+ } else {
+ handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
+ }
+
+ /* TODO: Store delay if handle->socket isn't created yet. */
+
+ return 0;
+}
+
+
+int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
+ LPWSAPROTOCOL_INFOW protocol_info) {
+ if (!(handle->flags & UV_HANDLE_CONNECTION)) {
+ /*
+ * We're about to share the socket with another process. Because
+ * this is a listening socket, we assume that the other process will
+ * be accepting connections on it. So, before sharing the socket
+ * with another process, we call listen here in the parent process.
+ */
+
+ if (!(handle->flags & UV_HANDLE_LISTENING)) {
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (!(handle->delayed_error)) {
+ if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
+ handle->delayed_error = WSAGetLastError();
+ }
+ }
+ }
+ }
+
+ if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) {
+ return WSAGetLastError();
+ }
+
+ handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
+
+ return 0;
+}
+
+
+int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
+ if (handle->flags & UV_HANDLE_CONNECTION) {
+ return UV_EINVAL;
+ }
+
+ /* Check if we're already in the desired mode. */
+ if ((enable && !(handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) ||
+ (!enable && handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) {
+ return 0;
+ }
+
+ /* Don't allow switching from single pending accept to many. */
+ if (enable) {
+ return UV_ENOTSUP;
+ }
+
+ /* Check if we're in a middle of changing the number of pending accepts. */
+ if (handle->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING) {
+ return 0;
+ }
+
+ handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
+
+ /* Flip the changing flag if we have already queued multiple accepts. */
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
+ }
+
+ return 0;
+}
+
+
+static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
+ SOCKET socket = tcp->socket;
+ int non_ifs_lsp;
+
+ /* Check if we have any non-IFS LSPs stacked on top of TCP */
+ non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 :
+ uv_tcp_non_ifs_lsp_ipv4;
+
+ /* If there are non-ifs LSPs then try to obtain a base handle for the */
+ /* socket. This will always fail on Windows XP/3k. */
+ if (non_ifs_lsp) {
+ DWORD bytes;
+ if (WSAIoctl(socket,
+ SIO_BASE_HANDLE,
+ NULL,
+ 0,
+ &socket,
+ sizeof socket,
+ &bytes,
+ NULL,
+ NULL) != 0) {
+ /* Failed. We can't do CancelIo. */
+ return -1;
+ }
+ }
+
+ assert(socket != 0 && socket != INVALID_SOCKET);
+
+ if (!CancelIo((HANDLE) socket)) {
+ return GetLastError();
+ }
+
+ /* It worked. */
+ return 0;
+}
+
+
+void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
+ int close_socket = 1;
+
+ if (tcp->flags & UV_HANDLE_READ_PENDING) {
+ /* In order for winsock to do a graceful close there must not be any */
+ /* any pending reads, or the socket must be shut down for writing */
+ if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
+ /* Just do shutdown on non-shared sockets, which ensures graceful close. */
+ shutdown(tcp->socket, SD_SEND);
+
+ } else if (uv_tcp_try_cancel_io(tcp) == 0) {
+ /* In case of a shared socket, we try to cancel all outstanding I/O, */
+ /* If that works, don't close the socket yet - wait for the read req to */
+ /* return and close the socket in uv_tcp_endgame. */
+ close_socket = 0;
+
+ } else {
+ /* When cancelling isn't possible - which could happen when an LSP is */
+ /* present on an old Windows version, we will have to close the socket */
+ /* with a read pending. That is not nice because trailing sent bytes */
+ /* may not make it to the other side. */
+ }
+
+ } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
+ tcp->tcp.serv.accept_reqs != NULL) {
+ /* Under normal circumstances closesocket() will ensure that all pending */
+ /* accept reqs are canceled. However, when the socket is shared the */
+ /* presence of another reference to the socket in another process will */
+ /* keep the accept reqs going, so we have to ensure that these are */
+ /* canceled. */
+ if (uv_tcp_try_cancel_io(tcp) != 0) {
+ /* When cancellation is not possible, there is another option: we can */
+ /* close the incoming sockets, which will also cancel the accept */
+ /* operations. However this is not cool because we might inadvertently */
+ /* close a socket that just accepted a new connection, which will */
+ /* cause the connection to be aborted. */
+ unsigned int i;
+ for (i = 0; i < uv_simultaneous_server_accepts; i++) {
+ uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];
+ if (req->accept_socket != INVALID_SOCKET &&
+ !HasOverlappedIoCompleted(&req->u.io.overlapped)) {
+ closesocket(req->accept_socket);
+ req->accept_socket = INVALID_SOCKET;
+ }
+ }
+ }
+ }
+
+ if (tcp->flags & UV_HANDLE_READING) {
+ tcp->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, tcp);
+ }
+
+ if (tcp->flags & UV_HANDLE_LISTENING) {
+ tcp->flags &= ~UV_HANDLE_LISTENING;
+ DECREASE_ACTIVE_COUNT(loop, tcp);
+ }
+
+ if (close_socket) {
+ closesocket(tcp->socket);
+ tcp->socket = INVALID_SOCKET;
+ tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
+ }
+
+ tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+ uv__handle_closing(tcp);
+
+ if (tcp->reqs_pending == 0) {
+ uv_want_endgame(tcp->loop, (uv_handle_t*)tcp);
+ }
+}
+
+
+int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
+ WSAPROTOCOL_INFOW protocol_info;
+ int opt_len;
+ int err;
+
+ /* Detect the address family of the socket. */
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(sock,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ err = uv_tcp_set_socket(handle->loop,
+ handle,
+ sock,
+ protocol_info.iAddressFamily,
+ 1);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ return 0;
+}
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__tcp_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+
+ err = uv_tcp_try_bind(handle, addr, addrlen, flags);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb) {
+ int err;
+
+ err = uv_tcp_try_connect(req, handle, addr, addrlen, cb);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL)
+
+static int uv_cond_fallback_init(uv_cond_t* cond);
+static void uv_cond_fallback_destroy(uv_cond_t* cond);
+static void uv_cond_fallback_signal(uv_cond_t* cond);
+static void uv_cond_fallback_broadcast(uv_cond_t* cond);
+static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex);
+static int uv_cond_fallback_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout);
+
+static int uv_cond_condvar_init(uv_cond_t* cond);
+static void uv_cond_condvar_destroy(uv_cond_t* cond);
+static void uv_cond_condvar_signal(uv_cond_t* cond);
+static void uv_cond_condvar_broadcast(uv_cond_t* cond);
+static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex);
+static int uv_cond_condvar_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout);
+
+
+static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
+ DWORD result;
+ HANDLE existing_event, created_event;
+
+ created_event = CreateEvent(NULL, 1, 0, NULL);
+ if (created_event == 0) {
+ /* Could fail in a low-memory situation? */
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+
+ existing_event = InterlockedCompareExchangePointer(&guard->event,
+ created_event,
+ NULL);
+
+ if (existing_event == NULL) {
+ /* We won the race */
+ callback();
+
+ result = SetEvent(created_event);
+ assert(result);
+ guard->ran = 1;
+
+ } else {
+ /* We lost the race. Destroy the event we created and wait for the */
+ /* existing one to become signaled. */
+ CloseHandle(created_event);
+ result = WaitForSingleObject(existing_event, INFINITE);
+ assert(result == WAIT_OBJECT_0);
+ }
+}
+
+
+void uv_once(uv_once_t* guard, void (*callback)(void)) {
+ /* Fast case - avoid WaitForSingleObject. */
+ if (guard->ran) {
+ return;
+ }
+
+ uv__once_inner(guard, callback);
+}
+
+
+/* Verify that uv_thread_t can be stored in a TLS slot. */
+STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*));
+
+static uv_key_t uv__current_thread_key;
+static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT;
+
+
+static void uv__init_current_thread_key(void) {
+ if (uv_key_create(&uv__current_thread_key))
+ abort();
+}
+
+
+struct thread_ctx {
+ void (*entry)(void* arg);
+ void* arg;
+ uv_thread_t self;
+};
+
+
+static UINT __stdcall uv__thread_start(void* arg) {
+ struct thread_ctx *ctx_p;
+ struct thread_ctx ctx;
+
+ ctx_p = arg;
+ ctx = *ctx_p;
+ uv__free(ctx_p);
+
+ uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
+ uv_key_set(&uv__current_thread_key, (void*) ctx.self);
+
+ ctx.entry(ctx.arg);
+
+ return 0;
+}
+
+
+int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
+ struct thread_ctx* ctx;
+ int err;
+ HANDLE thread;
+
+ ctx = uv__malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return UV_ENOMEM;
+
+ ctx->entry = entry;
+ ctx->arg = arg;
+
+ /* Create the thread in suspended state so we have a chance to pass
+ * its own creation handle to it */
+ thread = (HANDLE) _beginthreadex(NULL,
+ 0,
+ uv__thread_start,
+ ctx,
+ CREATE_SUSPENDED,
+ NULL);
+ if (thread == NULL) {
+ err = errno;
+ uv__free(ctx);
+ } else {
+ err = 0;
+ *tid = thread;
+ ctx->self = thread;
+ ResumeThread(thread);
+ }
+
+ switch (err) {
+ case 0:
+ return 0;
+ case EACCES:
+ return UV_EACCES;
+ case EAGAIN:
+ return UV_EAGAIN;
+ case EINVAL:
+ return UV_EINVAL;
+ }
+
+ return UV_EIO;
+}
+
+
+uv_thread_t uv_thread_self(void) {
+ uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
+ return (uv_thread_t) uv_key_get(&uv__current_thread_key);
+}
+
+
+int uv_thread_join(uv_thread_t *tid) {
+ if (WaitForSingleObject(*tid, INFINITE))
+ return uv_translate_sys_error(GetLastError());
+ else {
+ CloseHandle(*tid);
+ *tid = 0;
+ return 0;
+ }
+}
+
+
+int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
+ return *t1 == *t2;
+}
+
+
+int uv_mutex_init(uv_mutex_t* mutex) {
+ InitializeCriticalSection(mutex);
+ return 0;
+}
+
+
+void uv_mutex_destroy(uv_mutex_t* mutex) {
+ DeleteCriticalSection(mutex);
+}
+
+
+void uv_mutex_lock(uv_mutex_t* mutex) {
+ EnterCriticalSection(mutex);
+}
+
+
+int uv_mutex_trylock(uv_mutex_t* mutex) {
+ if (TryEnterCriticalSection(mutex))
+ return 0;
+ else
+ return UV_EBUSY;
+}
+
+
+void uv_mutex_unlock(uv_mutex_t* mutex) {
+ LeaveCriticalSection(mutex);
+}
+
+
+int uv_rwlock_init(uv_rwlock_t* rwlock) {
+ /* Initialize the semaphore that acts as the write lock. */
+ HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
+ if (handle == NULL)
+ return uv_translate_sys_error(GetLastError());
+ rwlock->state_.write_semaphore_ = handle;
+
+ /* Initialize the critical section protecting the reader count. */
+ InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
+
+ /* Initialize the reader count. */
+ rwlock->state_.num_readers_ = 0;
+
+ return 0;
+}
+
+
+void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
+ DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
+ CloseHandle(rwlock->state_.write_semaphore_);
+}
+
+
+void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
+ /* Acquire the lock that protects the reader count. */
+ EnterCriticalSection(&rwlock->state_.num_readers_lock_);
+
+ /* Increase the reader count, and lock for write if this is the first
+ * reader.
+ */
+ if (++rwlock->state_.num_readers_ == 1) {
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
+ if (r != WAIT_OBJECT_0)
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+ }
+
+ /* Release the lock that protects the reader count. */
+ LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+}
+
+
+int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
+ int err;
+
+ if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
+ return UV_EBUSY;
+
+ err = 0;
+
+ if (rwlock->state_.num_readers_ == 0) {
+ /* Currently there are no other readers, which means that the write lock
+ * needs to be acquired.
+ */
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
+ if (r == WAIT_OBJECT_0)
+ rwlock->state_.num_readers_++;
+ else if (r == WAIT_TIMEOUT)
+ err = UV_EBUSY;
+ else if (r == WAIT_FAILED)
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+
+ } else {
+ /* The write lock has already been acquired because there are other
+ * active readers.
+ */
+ rwlock->state_.num_readers_++;
+ }
+
+ LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+ return err;
+}
+
+
+void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
+ EnterCriticalSection(&rwlock->state_.num_readers_lock_);
+
+ if (--rwlock->state_.num_readers_ == 0) {
+ if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
+ uv_fatal_error(GetLastError(), "ReleaseSemaphore");
+ }
+
+ LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+}
+
+
+void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
+ if (r != WAIT_OBJECT_0)
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+}
+
+
+int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
+ if (r == WAIT_OBJECT_0)
+ return 0;
+ else if (r == WAIT_TIMEOUT)
+ return UV_EBUSY;
+ else
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+}
+
+
+void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
+ if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
+ uv_fatal_error(GetLastError(), "ReleaseSemaphore");
+}
+
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ *sem = CreateSemaphore(NULL, value, INT_MAX, NULL);
+ if (*sem == NULL)
+ return uv_translate_sys_error(GetLastError());
+ else
+ return 0;
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (!CloseHandle(*sem))
+ abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+ if (!ReleaseSemaphore(*sem, 1, NULL))
+ abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+ if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0)
+ abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ DWORD r = WaitForSingleObject(*sem, 0);
+
+ if (r == WAIT_OBJECT_0)
+ return 0;
+
+ if (r == WAIT_TIMEOUT)
+ return UV_EAGAIN;
+
+ abort();
+ return -1; /* Satisfy the compiler. */
+}
+
+
+/* This condition variable implementation is based on the SetEvent solution
+ * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+ * We could not use the SignalObjectAndWait solution (section 3.4) because
+ * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and
+ * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs.
+ */
+
+static int uv_cond_fallback_init(uv_cond_t* cond) {
+ int err;
+
+ /* Initialize the count to 0. */
+ cond->fallback.waiters_count = 0;
+
+ InitializeCriticalSection(&cond->fallback.waiters_count_lock);
+
+ /* Create an auto-reset event. */
+ cond->fallback.signal_event = CreateEvent(NULL, /* no security */
+ FALSE, /* auto-reset event */
+ FALSE, /* non-signaled initially */
+ NULL); /* unnamed */
+ if (!cond->fallback.signal_event) {
+ err = GetLastError();
+ goto error2;
+ }
+
+ /* Create a manual-reset event. */
+ cond->fallback.broadcast_event = CreateEvent(NULL, /* no security */
+ TRUE, /* manual-reset */
+ FALSE, /* non-signaled */
+ NULL); /* unnamed */
+ if (!cond->fallback.broadcast_event) {
+ err = GetLastError();
+ goto error;
+ }
+
+ return 0;
+
+error:
+ CloseHandle(cond->fallback.signal_event);
+error2:
+ DeleteCriticalSection(&cond->fallback.waiters_count_lock);
+ return uv_translate_sys_error(err);
+}
+
+
+static int uv_cond_condvar_init(uv_cond_t* cond) {
+ pInitializeConditionVariable(&cond->cond_var);
+ return 0;
+}
+
+
+int uv_cond_init(uv_cond_t* cond) {
+ uv__once_init();
+
+ if (HAVE_CONDVAR_API())
+ return uv_cond_condvar_init(cond);
+ else
+ return uv_cond_fallback_init(cond);
+}
+
+
+static void uv_cond_fallback_destroy(uv_cond_t* cond) {
+ if (!CloseHandle(cond->fallback.broadcast_event))
+ abort();
+ if (!CloseHandle(cond->fallback.signal_event))
+ abort();
+ DeleteCriticalSection(&cond->fallback.waiters_count_lock);
+}
+
+
+static void uv_cond_condvar_destroy(uv_cond_t* cond) {
+ /* nothing to do */
+}
+
+
+void uv_cond_destroy(uv_cond_t* cond) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_destroy(cond);
+ else
+ uv_cond_fallback_destroy(cond);
+}
+
+
+static void uv_cond_fallback_signal(uv_cond_t* cond) {
+ int have_waiters;
+
+ /* Avoid race conditions. */
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ have_waiters = cond->fallback.waiters_count > 0;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ if (have_waiters)
+ SetEvent(cond->fallback.signal_event);
+}
+
+
+static void uv_cond_condvar_signal(uv_cond_t* cond) {
+ pWakeConditionVariable(&cond->cond_var);
+}
+
+
+void uv_cond_signal(uv_cond_t* cond) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_signal(cond);
+ else
+ uv_cond_fallback_signal(cond);
+}
+
+
+static void uv_cond_fallback_broadcast(uv_cond_t* cond) {
+ int have_waiters;
+
+ /* Avoid race conditions. */
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ have_waiters = cond->fallback.waiters_count > 0;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ if (have_waiters)
+ SetEvent(cond->fallback.broadcast_event);
+}
+
+
+static void uv_cond_condvar_broadcast(uv_cond_t* cond) {
+ pWakeAllConditionVariable(&cond->cond_var);
+}
+
+
+void uv_cond_broadcast(uv_cond_t* cond) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_broadcast(cond);
+ else
+ uv_cond_fallback_broadcast(cond);
+}
+
+
+static int uv_cond_wait_helper(uv_cond_t* cond, uv_mutex_t* mutex,
+ DWORD dwMilliseconds) {
+ DWORD result;
+ int last_waiter;
+ HANDLE handles[2] = {
+ cond->fallback.signal_event,
+ cond->fallback.broadcast_event
+ };
+
+ /* Avoid race conditions. */
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ cond->fallback.waiters_count++;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ /* It's ok to release the <mutex> here since Win32 manual-reset events */
+ /* maintain state when used with <SetEvent>. This avoids the "lost wakeup" */
+ /* bug. */
+ uv_mutex_unlock(mutex);
+
+ /* Wait for either event to become signaled due to <uv_cond_signal> being */
+ /* called or <uv_cond_broadcast> being called. */
+ result = WaitForMultipleObjects(2, handles, FALSE, dwMilliseconds);
+
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ cond->fallback.waiters_count--;
+ last_waiter = result == WAIT_OBJECT_0 + 1
+ && cond->fallback.waiters_count == 0;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ /* Some thread called <pthread_cond_broadcast>. */
+ if (last_waiter) {
+ /* We're the last waiter to be notified or to stop waiting, so reset the */
+ /* the manual-reset event. */
+ ResetEvent(cond->fallback.broadcast_event);
+ }
+
+ /* Reacquire the <mutex>. */
+ uv_mutex_lock(mutex);
+
+ if (result == WAIT_OBJECT_0 || result == WAIT_OBJECT_0 + 1)
+ return 0;
+
+ if (result == WAIT_TIMEOUT)
+ return UV_ETIMEDOUT;
+
+ abort();
+ return -1; /* Satisfy the compiler. */
+}
+
+
+static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (uv_cond_wait_helper(cond, mutex, INFINITE))
+ abort();
+}
+
+
+static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (!pSleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
+ abort();
+}
+
+
+void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_wait(cond, mutex);
+ else
+ uv_cond_fallback_wait(cond, mutex);
+}
+
+
+static int uv_cond_fallback_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout) {
+ return uv_cond_wait_helper(cond, mutex, (DWORD)(timeout / 1e6));
+}
+
+
+static int uv_cond_condvar_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout) {
+ if (pSleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
+ return 0;
+ if (GetLastError() != ERROR_TIMEOUT)
+ abort();
+ return UV_ETIMEDOUT;
+}
+
+
+int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex,
+ uint64_t timeout) {
+ if (HAVE_CONDVAR_API())
+ return uv_cond_condvar_timedwait(cond, mutex, timeout);
+ else
+ return uv_cond_fallback_timedwait(cond, mutex, timeout);
+}
+
+
+int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
+ int err;
+
+ barrier->n = count;
+ barrier->count = 0;
+
+ err = uv_mutex_init(&barrier->mutex);
+ if (err)
+ return err;
+
+ err = uv_sem_init(&barrier->turnstile1, 0);
+ if (err)
+ goto error2;
+
+ err = uv_sem_init(&barrier->turnstile2, 1);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ uv_sem_destroy(&barrier->turnstile1);
+error2:
+ uv_mutex_destroy(&barrier->mutex);
+ return err;
+
+}
+
+
+void uv_barrier_destroy(uv_barrier_t* barrier) {
+ uv_sem_destroy(&barrier->turnstile2);
+ uv_sem_destroy(&barrier->turnstile1);
+ uv_mutex_destroy(&barrier->mutex);
+}
+
+
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int serial_thread;
+
+ uv_mutex_lock(&barrier->mutex);
+ if (++barrier->count == barrier->n) {
+ uv_sem_wait(&barrier->turnstile2);
+ uv_sem_post(&barrier->turnstile1);
+ }
+ uv_mutex_unlock(&barrier->mutex);
+
+ uv_sem_wait(&barrier->turnstile1);
+ uv_sem_post(&barrier->turnstile1);
+
+ uv_mutex_lock(&barrier->mutex);
+ serial_thread = (--barrier->count == 0);
+ if (serial_thread) {
+ uv_sem_wait(&barrier->turnstile1);
+ uv_sem_post(&barrier->turnstile2);
+ }
+ uv_mutex_unlock(&barrier->mutex);
+
+ uv_sem_wait(&barrier->turnstile2);
+ uv_sem_post(&barrier->turnstile2);
+ return serial_thread;
+}
+
+
+int uv_key_create(uv_key_t* key) {
+ key->tls_index = TlsAlloc();
+ if (key->tls_index == TLS_OUT_OF_INDEXES)
+ return UV_ENOMEM;
+ return 0;
+}
+
+
+void uv_key_delete(uv_key_t* key) {
+ if (TlsFree(key->tls_index) == FALSE)
+ abort();
+ key->tls_index = TLS_OUT_OF_INDEXES;
+}
+
+
+void* uv_key_get(uv_key_t* key) {
+ void* value;
+
+ value = TlsGetValue(key->tls_index);
+ if (value == NULL)
+ if (GetLastError() != ERROR_SUCCESS)
+ abort();
+
+ return value;
+}
+
+
+void uv_key_set(uv_key_t* key, void* value) {
+ if (TlsSetValue(key->tls_index, value) == FALSE)
+ abort();
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <limits.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "tree.h"
+#include "handle-inl.h"
+
+
+/* The number of milliseconds in one second. */
+#define UV__MILLISEC 1000
+
+
+void uv_update_time(uv_loop_t* loop) {
+ uint64_t new_time = uv__hrtime(UV__MILLISEC);
+ assert(new_time >= loop->time);
+ loop->time = new_time;
+}
+
+
+static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
+ if (a->due < b->due)
+ return -1;
+ if (a->due > b->due)
+ return 1;
+ /*
+ * compare start_id when both has the same due. start_id is
+ * allocated with loop->timer_counter in uv_timer_start().
+ */
+ if (a->start_id < b->start_id)
+ return -1;
+ if (a->start_id > b->start_id)
+ return 1;
+ return 0;
+}
+
+
+RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare);
+
+
+int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_TIMER);
+ handle->timer_cb = NULL;
+ handle->repeat = 0;
+
+ return 0;
+}
+
+
+void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) {
+ uint64_t clamped_timeout;
+
+ clamped_timeout = loop_time + timeout;
+ if (clamped_timeout < timeout)
+ clamped_timeout = (uint64_t) -1;
+
+ return clamped_timeout;
+}
+
+
+int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout,
+ uint64_t repeat) {
+ uv_loop_t* loop = handle->loop;
+ uv_timer_t* old;
+
+ if (timer_cb == NULL)
+ return UV_EINVAL;
+
+ if (uv__is_active(handle))
+ uv_timer_stop(handle);
+
+ handle->timer_cb = timer_cb;
+ handle->due = get_clamped_due_time(loop->time, timeout);
+ handle->repeat = repeat;
+ uv__handle_start(handle);
+
+ /* start_id is the second index to be compared in uv__timer_cmp() */
+ handle->start_id = handle->loop->timer_counter++;
+
+ old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle);
+ assert(old == NULL);
+
+ return 0;
+}
+
+
+int uv_timer_stop(uv_timer_t* handle) {
+ uv_loop_t* loop = handle->loop;
+
+ if (!uv__is_active(handle))
+ return 0;
+
+ RB_REMOVE(uv_timer_tree_s, &loop->timers, handle);
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_timer_again(uv_timer_t* handle) {
+ /* If timer_cb is NULL that means that the timer was never started. */
+ if (!handle->timer_cb) {
+ return UV_EINVAL;
+ }
+
+ if (handle->repeat) {
+ uv_timer_stop(handle);
+ uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
+ }
+
+ return 0;
+}
+
+
+void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
+ assert(handle->type == UV_TIMER);
+ handle->repeat = repeat;
+}
+
+
+uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
+ assert(handle->type == UV_TIMER);
+ return handle->repeat;
+}
+
+
+DWORD uv__next_timeout(const uv_loop_t* loop) {
+ uv_timer_t* timer;
+ int64_t delta;
+
+ /* Check if there are any running timers
+ * Need to cast away const first, since RB_MIN doesn't know what we are
+ * going to do with this return value, it can't be marked const
+ */
+ timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers);
+ if (timer) {
+ delta = timer->due - loop->time;
+ if (delta >= UINT_MAX - 1) {
+ /* A timeout value of UINT_MAX means infinite, so that's no good. */
+ return UINT_MAX - 1;
+ } else if (delta < 0) {
+ /* Negative timeout values are not allowed */
+ return 0;
+ } else {
+ return (DWORD)delta;
+ }
+ } else {
+ /* No timers */
+ return INFINITE;
+ }
+}
+
+
+void uv_process_timers(uv_loop_t* loop) {
+ uv_timer_t* timer;
+
+ /* Call timer callbacks */
+ for (timer = RB_MIN(uv_timer_tree_s, &loop->timers);
+ timer != NULL && timer->due <= loop->time;
+ timer = RB_MIN(uv_timer_tree_s, &loop->timers)) {
+
+ uv_timer_stop(timer);
+ uv_timer_again(timer);
+ timer->timer_cb((uv_timer_t*) timer);
+ }
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#ifndef COMMON_LVB_REVERSE_VIDEO
+# define COMMON_LVB_REVERSE_VIDEO 0x4000
+#endif
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+#ifndef InterlockedOr
+# define InterlockedOr _InterlockedOr
+#endif
+
+#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
+
+#define ANSI_NORMAL 0x00
+#define ANSI_ESCAPE_SEEN 0x02
+#define ANSI_CSI 0x04
+#define ANSI_ST_CONTROL 0x08
+#define ANSI_IGNORE 0x10
+#define ANSI_IN_ARG 0x20
+#define ANSI_IN_STRING 0x40
+#define ANSI_BACKSLASH_SEEN 0x80
+
+#define MAX_INPUT_BUFFER_LENGTH 8192
+#define MAX_CONSOLE_CHAR 8192
+
+#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
+#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
+#endif
+
+static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info);
+static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
+static int uv__cancel_read_console(uv_tty_t* handle);
+
+
+/* Null uv_buf_t */
+static const uv_buf_t uv_null_buf_ = { 0, NULL };
+
+enum uv__read_console_status_e {
+ NOT_STARTED,
+ IN_PROGRESS,
+ TRAP_REQUESTED,
+ COMPLETED
+};
+
+static volatile LONG uv__read_console_status = NOT_STARTED;
+static volatile LONG uv__restore_screen_state;
+static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state;
+
+
+/*
+ * The console virtual window.
+ *
+ * Normally cursor movement in windows is relative to the console screen buffer,
+ * e.g. the application is allowed to overwrite the 'history'. This is very
+ * inconvenient, it makes absolute cursor movement pretty useless. There is
+ * also the concept of 'client rect' which is defined by the actual size of
+ * the console window and the scroll position of the screen buffer, but it's
+ * very volatile because it changes when the user scrolls.
+ *
+ * To make cursor movement behave sensibly we define a virtual window to which
+ * cursor movement is confined. The virtual window is always as wide as the
+ * console screen buffer, but it's height is defined by the size of the
+ * console window. The top of the virtual window aligns with the position
+ * of the caret when the first stdout/err handle is created, unless that would
+ * mean that it would extend beyond the bottom of the screen buffer - in that
+ * that case it's located as far down as possible.
+ *
+ * When the user writes a long text or many newlines, such that the output
+ * reaches beyond the bottom of the virtual window, the virtual window is
+ * shifted downwards, but not resized.
+ *
+ * Since all tty i/o happens on the same console, this window is shared
+ * between all stdout/stderr handles.
+ */
+
+static int uv_tty_virtual_offset = -1;
+static int uv_tty_virtual_height = -1;
+static int uv_tty_virtual_width = -1;
+
+/* We use a semaphore rather than a mutex or critical section because in some
+ cases (uv__cancel_read_console) we need take the lock in the main thread and
+ release it in another thread. Using a semaphore ensures that in such
+ scenario the main thread will still block when trying to acquire the lock. */
+static uv_sem_t uv_tty_output_lock;
+
+static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE;
+
+static WORD uv_tty_default_text_attributes =
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+
+static char uv_tty_default_fg_color = 7;
+static char uv_tty_default_bg_color = 0;
+static char uv_tty_default_fg_bright = 0;
+static char uv_tty_default_bg_bright = 0;
+static char uv_tty_default_inverse = 0;
+
+typedef enum {
+ UV_SUPPORTED,
+ UV_UNCHECKED,
+ UV_UNSUPPORTED
+} uv_vtermstate_t;
+/* Determine whether or not ANSI support is enabled. */
+static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED;
+static void uv__determine_vterm_state(HANDLE handle);
+
+void uv_console_init() {
+ if (uv_sem_init(&uv_tty_output_lock, 1))
+ abort();
+}
+
+
+int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
+ HANDLE handle;
+ CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
+
+ handle = (HANDLE) uv__get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ if (fd <= 2) {
+ /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
+ * underlying OS handle and forget about the original fd.
+ * We could also opt to use the original OS handle and just never close it,
+ * but then there would be no reliable way to cancel pending read operations
+ * upon close.
+ */
+ if (!DuplicateHandle(INVALID_HANDLE_VALUE,
+ handle,
+ INVALID_HANDLE_VALUE,
+ &handle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS))
+ return uv_translate_sys_error(GetLastError());
+ fd = -1;
+ }
+
+ if (!readable) {
+ /* Obtain the screen buffer info with the output handle. */
+ if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Obtain the the tty_output_lock because the virtual window state is */
+ /* shared between all uv_tty_t handles. */
+ uv_sem_wait(&uv_tty_output_lock);
+
+ if (uv__vterm_state == UV_UNCHECKED)
+ uv__determine_vterm_state(handle);
+
+ /* Store the global tty output handle. This handle is used by TTY read */
+ /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */
+ /* is received. */
+ uv_tty_output_handle = handle;
+
+ /* Remember the original console text attributes. */
+ uv_tty_capture_initial_style(&screen_buffer_info);
+
+ uv_tty_update_virtual_window(&screen_buffer_info);
+
+ uv_sem_post(&uv_tty_output_lock);
+ }
+
+
+ uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
+ uv_connection_init((uv_stream_t*) tty);
+
+ tty->handle = handle;
+ tty->u.fd = fd;
+ tty->reqs_pending = 0;
+ tty->flags |= UV_HANDLE_BOUND;
+
+ if (readable) {
+ /* Initialize TTY input specific fields. */
+ tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
+ /* TODO: remove me in v2.x. */
+ tty->tty.rd.unused_ = NULL;
+ tty->tty.rd.read_line_buffer = uv_null_buf_;
+ tty->tty.rd.read_raw_wait = NULL;
+
+ /* Init keycode-to-vt100 mapper state. */
+ tty->tty.rd.last_key_len = 0;
+ tty->tty.rd.last_key_offset = 0;
+ tty->tty.rd.last_utf16_high_surrogate = 0;
+ memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record);
+ } else {
+ /* TTY output specific fields. */
+ tty->flags |= UV_HANDLE_WRITABLE;
+
+ /* Init utf8-to-utf16 conversion state. */
+ tty->tty.wr.utf8_bytes_left = 0;
+ tty->tty.wr.utf8_codepoint = 0;
+
+ /* Initialize eol conversion state */
+ tty->tty.wr.previous_eol = 0;
+
+ /* Init ANSI parser state. */
+ tty->tty.wr.ansi_parser_state = ANSI_NORMAL;
+ }
+
+ return 0;
+}
+
+
+/* Set the default console text attributes based on how the console was
+ * configured when libuv started.
+ */
+static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
+ static int style_captured = 0;
+
+ /* Only do this once.
+ Assumption: Caller has acquired uv_tty_output_lock. */
+ if (style_captured)
+ return;
+
+ /* Save raw win32 attributes. */
+ uv_tty_default_text_attributes = info->wAttributes;
+
+ /* Convert black text on black background to use white text. */
+ if (uv_tty_default_text_attributes == 0)
+ uv_tty_default_text_attributes = 7;
+
+ /* Convert Win32 attributes to ANSI colors. */
+ uv_tty_default_fg_color = 0;
+ uv_tty_default_bg_color = 0;
+ uv_tty_default_fg_bright = 0;
+ uv_tty_default_bg_bright = 0;
+ uv_tty_default_inverse = 0;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_RED)
+ uv_tty_default_fg_color |= 1;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_GREEN)
+ uv_tty_default_fg_color |= 2;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_BLUE)
+ uv_tty_default_fg_color |= 4;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_RED)
+ uv_tty_default_bg_color |= 1;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_GREEN)
+ uv_tty_default_bg_color |= 2;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_BLUE)
+ uv_tty_default_bg_color |= 4;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY)
+ uv_tty_default_fg_bright = 1;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY)
+ uv_tty_default_bg_bright = 1;
+
+ if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
+ uv_tty_default_inverse = 1;
+
+ style_captured = 1;
+}
+
+
+int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
+ DWORD flags;
+ unsigned char was_reading;
+ uv_alloc_cb alloc_cb;
+ uv_read_cb read_cb;
+ int err;
+
+ if (!(tty->flags & UV_HANDLE_TTY_READABLE)) {
+ return UV_EINVAL;
+ }
+
+ if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
+ return 0;
+ }
+
+ switch (mode) {
+ case UV_TTY_MODE_NORMAL:
+ flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
+ break;
+ case UV_TTY_MODE_RAW:
+ flags = ENABLE_WINDOW_INPUT;
+ break;
+ case UV_TTY_MODE_IO:
+ return UV_ENOTSUP;
+ default:
+ return UV_EINVAL;
+ }
+
+ /* If currently reading, stop, and restart reading. */
+ if (tty->flags & UV_HANDLE_READING) {
+ was_reading = 1;
+ alloc_cb = tty->alloc_cb;
+ read_cb = tty->read_cb;
+ err = uv_tty_read_stop(tty);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+ } else {
+ was_reading = 0;
+ }
+
+ uv_sem_wait(&uv_tty_output_lock);
+ if (!SetConsoleMode(tty->handle, flags)) {
+ err = uv_translate_sys_error(GetLastError());
+ uv_sem_post(&uv_tty_output_lock);
+ return err;
+ }
+ uv_sem_post(&uv_tty_output_lock);
+
+ /* Update flag. */
+ tty->flags &= ~UV_HANDLE_TTY_RAW;
+ tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
+
+ /* If we just stopped reading, restart. */
+ if (was_reading) {
+ err = uv_tty_read_start(tty, alloc_cb, read_cb);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_is_tty(uv_file file) {
+ DWORD result;
+ return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0;
+}
+
+
+int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ if (!GetConsoleScreenBufferInfo(tty->handle, &info)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ uv_sem_wait(&uv_tty_output_lock);
+ uv_tty_update_virtual_window(&info);
+ uv_sem_post(&uv_tty_output_lock);
+
+ *width = uv_tty_virtual_width;
+ *height = uv_tty_virtual_height;
+
+ return 0;
+}
+
+
+static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
+ uv_loop_t* loop;
+ uv_tty_t* handle;
+ uv_req_t* req;
+
+ assert(data);
+ assert(!didTimeout);
+
+ req = (uv_req_t*) data;
+ handle = (uv_tty_t*) req->data;
+ loop = handle->loop;
+
+ UnregisterWait(handle->tty.rd.read_raw_wait);
+ handle->tty.rd.read_raw_wait = NULL;
+
+ SET_REQ_SUCCESS(req);
+ POST_COMPLETION_FOR_REQ(loop, req);
+}
+
+
+static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
+ uv_read_t* req;
+ BOOL r;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
+
+ handle->tty.rd.read_line_buffer = uv_null_buf_;
+
+ req = &handle->read_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait,
+ handle->handle,
+ uv_tty_post_raw_read,
+ (void*) req,
+ INFINITE,
+ WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
+ if (!r) {
+ handle->tty.rd.read_raw_wait = NULL;
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+}
+
+
+static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
+ uv_loop_t* loop;
+ uv_tty_t* handle;
+ uv_req_t* req;
+ DWORD bytes, read_bytes;
+ WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3];
+ DWORD chars, read_chars;
+ LONG status;
+ COORD pos;
+ BOOL read_console_success;
+
+ assert(data);
+
+ req = (uv_req_t*) data;
+ handle = (uv_tty_t*) req->data;
+ loop = handle->loop;
+
+ assert(handle->tty.rd.read_line_buffer.base != NULL);
+ assert(handle->tty.rd.read_line_buffer.len > 0);
+
+ /* ReadConsole can't handle big buffers. */
+ if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
+ bytes = handle->tty.rd.read_line_buffer.len;
+ } else {
+ bytes = MAX_INPUT_BUFFER_LENGTH;
+ }
+
+ /* At last, unicode! */
+ /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */
+ chars = bytes / 3;
+
+ status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS);
+ if (status == TRAP_REQUESTED) {
+ SET_REQ_SUCCESS(req);
+ req->u.io.overlapped.InternalHigh = 0;
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+ }
+
+ read_console_success = ReadConsoleW(handle->handle,
+ (void*) utf16,
+ chars,
+ &read_chars,
+ NULL);
+
+ if (read_console_success) {
+ read_bytes = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16,
+ read_chars,
+ handle->tty.rd.read_line_buffer.base,
+ bytes,
+ NULL,
+ NULL);
+ SET_REQ_SUCCESS(req);
+ req->u.io.overlapped.InternalHigh = read_bytes;
+ } else {
+ SET_REQ_ERROR(req, GetLastError());
+ }
+
+ status = InterlockedExchange(&uv__read_console_status, COMPLETED);
+
+ if (status == TRAP_REQUESTED) {
+ /* If we canceled the read by sending a VK_RETURN event, restore the
+ screen state to undo the visual effect of the VK_RETURN */
+ if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) {
+ HANDLE active_screen_buffer;
+ active_screen_buffer = CreateFileA("conout$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (active_screen_buffer != INVALID_HANDLE_VALUE) {
+ pos = uv__saved_screen_state.dwCursorPosition;
+
+ /* If the cursor was at the bottom line of the screen buffer, the
+ VK_RETURN would have caused the buffer contents to scroll up by one
+ line. The right position to reset the cursor to is therefore one line
+ higher */
+ if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
+ pos.Y--;
+
+ SetConsoleCursorPosition(active_screen_buffer, pos);
+ CloseHandle(active_screen_buffer);
+ }
+ }
+ uv_sem_post(&uv_tty_output_lock);
+ }
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+}
+
+
+static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
+ uv_read_t* req;
+ BOOL r;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+ assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
+
+ req = &handle->read_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
+ if (handle->tty.rd.read_line_buffer.base == NULL ||
+ handle->tty.rd.read_line_buffer.len == 0) {
+ handle->read_cb((uv_stream_t*) handle,
+ UV_ENOBUFS,
+ &handle->tty.rd.read_line_buffer);
+ return;
+ }
+ assert(handle->tty.rd.read_line_buffer.base != NULL);
+
+ /* Reset flags No locking is required since there cannot be a line read
+ in progress. We are also relying on the memory barrier provided by
+ QueueUserWorkItem*/
+ uv__restore_screen_state = FALSE;
+ uv__read_console_status = NOT_STARTED;
+ r = QueueUserWorkItem(uv_tty_line_read_thread,
+ (void*) req,
+ WT_EXECUTELONGFUNCTION);
+ if (!r) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+}
+
+
+static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
+ if (handle->flags & UV_HANDLE_TTY_RAW) {
+ uv_tty_queue_read_raw(loop, handle);
+ } else {
+ uv_tty_queue_read_line(loop, handle);
+ }
+}
+
+
+static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
+ size_t* len) {
+#define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str) \
+ case (vk): \
+ if (shift && ctrl) { \
+ *len = sizeof shift_ctrl_str; \
+ return "\033" shift_ctrl_str; \
+ } else if (shift) { \
+ *len = sizeof shift_str ; \
+ return "\033" shift_str; \
+ } else if (ctrl) { \
+ *len = sizeof ctrl_str; \
+ return "\033" ctrl_str; \
+ } else { \
+ *len = sizeof normal_str; \
+ return "\033" normal_str; \
+ }
+
+ switch (code) {
+ /* These mappings are the same as Cygwin's. Unmodified and alt-modified */
+ /* keypad keys comply with linux console, modifiers comply with xterm */
+ /* modifier usage. F1..f12 and shift-f1..f10 comply with linux console, */
+ /* f6..f12 with and without modifiers comply with rxvt. */
+ VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~")
+ VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~")
+ VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B")
+ VK_CASE(VK_NEXT, "[6~", "[6;2~", "[6;5~", "[6;6~")
+ VK_CASE(VK_LEFT, "[D", "[1;2D", "[1;5D", "[1;6D")
+ VK_CASE(VK_CLEAR, "[G", "[1;2G", "[1;5G", "[1;6G")
+ VK_CASE(VK_RIGHT, "[C", "[1;2C", "[1;5C", "[1;6C")
+ VK_CASE(VK_UP, "[A", "[1;2A", "[1;5A", "[1;6A")
+ VK_CASE(VK_HOME, "[1~", "[1;2~", "[1;5~", "[1;6~")
+ VK_CASE(VK_PRIOR, "[5~", "[5;2~", "[5;5~", "[5;6~")
+ VK_CASE(VK_DELETE, "[3~", "[3;2~", "[3;5~", "[3;6~")
+ VK_CASE(VK_NUMPAD0, "[2~", "[2;2~", "[2;5~", "[2;6~")
+ VK_CASE(VK_NUMPAD1, "[4~", "[4;2~", "[4;5~", "[4;6~")
+ VK_CASE(VK_NUMPAD2, "[B", "[1;2B", "[1;5B", "[1;6B")
+ VK_CASE(VK_NUMPAD3, "[6~", "[6;2~", "[6;5~", "[6;6~")
+ VK_CASE(VK_NUMPAD4, "[D", "[1;2D", "[1;5D", "[1;6D")
+ VK_CASE(VK_NUMPAD5, "[G", "[1;2G", "[1;5G", "[1;6G")
+ VK_CASE(VK_NUMPAD6, "[C", "[1;2C", "[1;5C", "[1;6C")
+ VK_CASE(VK_NUMPAD7, "[A", "[1;2A", "[1;5A", "[1;6A")
+ VK_CASE(VK_NUMPAD8, "[1~", "[1;2~", "[1;5~", "[1;6~")
+ VK_CASE(VK_NUMPAD9, "[5~", "[5;2~", "[5;5~", "[5;6~")
+ VK_CASE(VK_DECIMAL, "[3~", "[3;2~", "[3;5~", "[3;6~")
+ VK_CASE(VK_F1, "[[A", "[23~", "[11^", "[23^" )
+ VK_CASE(VK_F2, "[[B", "[24~", "[12^", "[24^" )
+ VK_CASE(VK_F3, "[[C", "[25~", "[13^", "[25^" )
+ VK_CASE(VK_F4, "[[D", "[26~", "[14^", "[26^" )
+ VK_CASE(VK_F5, "[[E", "[28~", "[15^", "[28^" )
+ VK_CASE(VK_F6, "[17~", "[29~", "[17^", "[29^" )
+ VK_CASE(VK_F7, "[18~", "[31~", "[18^", "[31^" )
+ VK_CASE(VK_F8, "[19~", "[32~", "[19^", "[32^" )
+ VK_CASE(VK_F9, "[20~", "[33~", "[20^", "[33^" )
+ VK_CASE(VK_F10, "[21~", "[34~", "[21^", "[34^" )
+ VK_CASE(VK_F11, "[23~", "[23$", "[23^", "[23@" )
+ VK_CASE(VK_F12, "[24~", "[24$", "[24^", "[24@" )
+
+ default:
+ *len = 0;
+ return NULL;
+ }
+#undef VK_CASE
+}
+
+
+void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req) {
+ /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */
+#define KEV handle->tty.rd.last_input_record.Event.KeyEvent
+
+ DWORD records_left, records_read;
+ uv_buf_t buf;
+ off_t buf_used;
+
+ assert(handle->type == UV_TTY);
+ assert(handle->flags & UV_HANDLE_TTY_READABLE);
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!(handle->flags & UV_HANDLE_READING) ||
+ !(handle->flags & UV_HANDLE_TTY_RAW)) {
+ goto out;
+ }
+
+ if (!REQ_SUCCESS(req)) {
+ /* An error occurred while waiting for the event. */
+ if ((handle->flags & UV_HANDLE_READING)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(GET_REQ_ERROR(req)),
+ &uv_null_buf_);
+ }
+ goto out;
+ }
+
+ /* Fetch the number of events */
+ if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(GetLastError()),
+ &uv_null_buf_);
+ goto out;
+ }
+
+ /* Windows sends a lot of events that we're not interested in, so buf */
+ /* will be allocated on demand, when there's actually something to emit. */
+ buf = uv_null_buf_;
+ buf_used = 0;
+
+ while ((records_left > 0 || handle->tty.rd.last_key_len > 0) &&
+ (handle->flags & UV_HANDLE_READING)) {
+ if (handle->tty.rd.last_key_len == 0) {
+ /* Read the next input record */
+ if (!ReadConsoleInputW(handle->handle,
+ &handle->tty.rd.last_input_record,
+ 1,
+ &records_read)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*) handle,
+ uv_translate_sys_error(GetLastError()),
+ &buf);
+ goto out;
+ }
+ records_left--;
+
+ /* If the window was resized, recompute the virtual window size. This */
+ /* will trigger a SIGWINCH signal if the window size changed in an */
+ /* way that matters to libuv. */
+ if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ uv_sem_wait(&uv_tty_output_lock);
+
+ if (uv_tty_output_handle != INVALID_HANDLE_VALUE &&
+ GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) {
+ uv_tty_update_virtual_window(&info);
+ }
+
+ uv_sem_post(&uv_tty_output_lock);
+
+ continue;
+ }
+
+ /* Ignore other events that are not key or resize events. */
+ if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
+ continue;
+ }
+
+ /* Ignore keyup events, unless the left alt key was held and a valid */
+ /* unicode character was emitted. */
+ if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) ||
+ KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) {
+ continue;
+ }
+
+ /* Ignore keypresses to numpad number keys if the left alt is held */
+ /* because the user is composing a character, or windows simulating */
+ /* this. */
+ if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
+ !(KEV.dwControlKeyState & ENHANCED_KEY) &&
+ (KEV.wVirtualKeyCode == VK_INSERT ||
+ KEV.wVirtualKeyCode == VK_END ||
+ KEV.wVirtualKeyCode == VK_DOWN ||
+ KEV.wVirtualKeyCode == VK_NEXT ||
+ KEV.wVirtualKeyCode == VK_LEFT ||
+ KEV.wVirtualKeyCode == VK_CLEAR ||
+ KEV.wVirtualKeyCode == VK_RIGHT ||
+ KEV.wVirtualKeyCode == VK_HOME ||
+ KEV.wVirtualKeyCode == VK_UP ||
+ KEV.wVirtualKeyCode == VK_PRIOR ||
+ KEV.wVirtualKeyCode == VK_NUMPAD0 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD1 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD2 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD3 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD4 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD5 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD6 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD7 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD8 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD9)) {
+ continue;
+ }
+
+ if (KEV.uChar.UnicodeChar != 0) {
+ int prefix_len, char_len;
+
+ /* Character key pressed */
+ if (KEV.uChar.UnicodeChar >= 0xD800 &&
+ KEV.uChar.UnicodeChar < 0xDC00) {
+ /* UTF-16 high surrogate */
+ handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
+ continue;
+ }
+
+ /* Prefix with \u033 if alt was held, but alt was not used as part */
+ /* a compose sequence. */
+ if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
+ && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
+ RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
+ handle->tty.rd.last_key[0] = '\033';
+ prefix_len = 1;
+ } else {
+ prefix_len = 0;
+ }
+
+ if (KEV.uChar.UnicodeChar >= 0xDC00 &&
+ KEV.uChar.UnicodeChar < 0xE000) {
+ /* UTF-16 surrogate pair */
+ WCHAR utf16_buffer[2] = { handle->tty.rd.last_utf16_high_surrogate,
+ KEV.uChar.UnicodeChar};
+ char_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ 2,
+ &handle->tty.rd.last_key[prefix_len],
+ sizeof handle->tty.rd.last_key,
+ NULL,
+ NULL);
+ } else {
+ /* Single UTF-16 character */
+ char_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ &KEV.uChar.UnicodeChar,
+ 1,
+ &handle->tty.rd.last_key[prefix_len],
+ sizeof handle->tty.rd.last_key,
+ NULL,
+ NULL);
+ }
+
+ /* Whatever happened, the last character wasn't a high surrogate. */
+ handle->tty.rd.last_utf16_high_surrogate = 0;
+
+ /* If the utf16 character(s) couldn't be converted something must */
+ /* be wrong. */
+ if (!char_len) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*) handle,
+ uv_translate_sys_error(GetLastError()),
+ &buf);
+ goto out;
+ }
+
+ handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len);
+ handle->tty.rd.last_key_offset = 0;
+ continue;
+
+ } else {
+ /* Function key pressed */
+ const char* vt100;
+ size_t prefix_len, vt100_len;
+
+ vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode,
+ !!(KEV.dwControlKeyState & SHIFT_PRESSED),
+ !!(KEV.dwControlKeyState & (
+ LEFT_CTRL_PRESSED |
+ RIGHT_CTRL_PRESSED)),
+ &vt100_len);
+
+ /* If we were unable to map to a vt100 sequence, just ignore. */
+ if (!vt100) {
+ continue;
+ }
+
+ /* Prefix with \x033 when the alt key was held. */
+ if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
+ handle->tty.rd.last_key[0] = '\033';
+ prefix_len = 1;
+ } else {
+ prefix_len = 0;
+ }
+
+ /* Copy the vt100 sequence to the handle buffer. */
+ assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key);
+ memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len);
+
+ handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len);
+ handle->tty.rd.last_key_offset = 0;
+ continue;
+ }
+ } else {
+ /* Copy any bytes left from the last keypress to the user buffer. */
+ if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
+ /* Allocate a buffer if needed */
+ if (buf_used == 0) {
+ buf = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 1024, &buf);
+ if (buf.base == NULL || buf.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
+ goto out;
+ }
+ assert(buf.base != NULL);
+ }
+
+ buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++];
+
+ /* If the buffer is full, emit it */
+ if ((size_t) buf_used == buf.len) {
+ handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
+ buf = uv_null_buf_;
+ buf_used = 0;
+ }
+
+ continue;
+ }
+
+ /* Apply dwRepeat from the last input record. */
+ if (--KEV.wRepeatCount > 0) {
+ handle->tty.rd.last_key_offset = 0;
+ continue;
+ }
+
+ handle->tty.rd.last_key_len = 0;
+ continue;
+ }
+ }
+
+ /* Send the buffer back to the user */
+ if (buf_used > 0) {
+ handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
+ }
+
+ out:
+ /* Wait for more input events. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_tty_queue_read(loop, handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+
+#undef KEV
+}
+
+
+
+void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req) {
+ uv_buf_t buf;
+
+ assert(handle->type == UV_TTY);
+ assert(handle->flags & UV_HANDLE_TTY_READABLE);
+
+ buf = handle->tty.rd.read_line_buffer;
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+ handle->tty.rd.read_line_buffer = uv_null_buf_;
+
+ if (!REQ_SUCCESS(req)) {
+ /* Read was not successful */
+ if (handle->flags & UV_HANDLE_READING) {
+ /* Real error */
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*) handle,
+ uv_translate_sys_error(GET_REQ_ERROR(req)),
+ &buf);
+ } else {
+ /* The read was cancelled, or whatever we don't care */
+ handle->read_cb((uv_stream_t*) handle, 0, &buf);
+ }
+
+ } else {
+ if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
+ /* Read successful */
+ /* TODO: read unicode, convert to utf-8 */
+ DWORD bytes = req->u.io.overlapped.InternalHigh;
+ handle->read_cb((uv_stream_t*) handle, bytes, &buf);
+ } else {
+ handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
+ handle->read_cb((uv_stream_t*) handle, 0, &buf);
+ }
+ }
+
+ /* Wait for more input events. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_tty_queue_read(loop, handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req) {
+ assert(handle->type == UV_TTY);
+ assert(handle->flags & UV_HANDLE_TTY_READABLE);
+
+ /* If the read_line_buffer member is zero, it must have been an raw read. */
+ /* Otherwise it was a line-buffered read. */
+ /* FIXME: This is quite obscure. Use a flag or something. */
+ if (handle->tty.rd.read_line_buffer.len == 0) {
+ uv_process_tty_read_raw_req(loop, handle, req);
+ } else {
+ uv_process_tty_read_line_req(loop, handle, req);
+ }
+}
+
+
+int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ uv_loop_t* loop = handle->loop;
+
+ if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ handle->flags |= UV_HANDLE_READING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb = read_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* read request pending. */
+ if (handle->flags & UV_HANDLE_READ_PENDING) {
+ return 0;
+ }
+
+ /* Maybe the user stopped reading half-way while processing key events. */
+ /* Short-circuit if this could be the case. */
+ if (handle->tty.rd.last_key_len > 0) {
+ SET_REQ_SUCCESS(&handle->read_req);
+ uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
+ /* Make sure no attempt is made to insert it again until it's handled. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ return 0;
+ }
+
+ uv_tty_queue_read(loop, handle);
+
+ return 0;
+}
+
+
+int uv_tty_read_stop(uv_tty_t* handle) {
+ INPUT_RECORD record;
+ DWORD written, err;
+
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(handle->loop, handle);
+
+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
+ return 0;
+
+ if (handle->flags & UV_HANDLE_TTY_RAW) {
+ /* Cancel raw read */
+ /* Write some bullshit event to force the console wait to return. */
+ memset(&record, 0, sizeof record);
+ if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
+ return GetLastError();
+ }
+ } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
+ /* Cancel line-buffered read if not already pending */
+ err = uv__cancel_read_console(handle);
+ if (err)
+ return err;
+
+ handle->flags |= UV_HANDLE_CANCELLATION_PENDING;
+ }
+
+ return 0;
+}
+
+static int uv__cancel_read_console(uv_tty_t* handle) {
+ HANDLE active_screen_buffer = INVALID_HANDLE_VALUE;
+ INPUT_RECORD record;
+ DWORD written;
+ DWORD err = 0;
+ LONG status;
+
+ assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING));
+
+ /* Hold the output lock during the cancellation, to ensure that further
+ writes don't interfere with the screen state. It will be the ReadConsole
+ thread's responsibility to release the lock. */
+ uv_sem_wait(&uv_tty_output_lock);
+ status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED);
+ if (status != IN_PROGRESS) {
+ /* Either we have managed to set a trap for the other thread before
+ ReadConsole is called, or ReadConsole has returned because the user
+ has pressed ENTER. In either case, there is nothing else to do. */
+ uv_sem_post(&uv_tty_output_lock);
+ return 0;
+ }
+
+ /* Save screen state before sending the VK_RETURN event */
+ active_screen_buffer = CreateFileA("conout$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (active_screen_buffer != INVALID_HANDLE_VALUE &&
+ GetConsoleScreenBufferInfo(active_screen_buffer,
+ &uv__saved_screen_state)) {
+ InterlockedOr(&uv__restore_screen_state, 1);
+ }
+
+ /* Write enter key event to force the console wait to return. */
+ record.EventType = KEY_EVENT;
+ record.Event.KeyEvent.bKeyDown = TRUE;
+ record.Event.KeyEvent.wRepeatCount = 1;
+ record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
+ record.Event.KeyEvent.wVirtualScanCode =
+ MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC);
+ record.Event.KeyEvent.uChar.UnicodeChar = L'\r';
+ record.Event.KeyEvent.dwControlKeyState = 0;
+ if (!WriteConsoleInputW(handle->handle, &record, 1, &written))
+ err = GetLastError();
+
+ if (active_screen_buffer != INVALID_HANDLE_VALUE)
+ CloseHandle(active_screen_buffer);
+
+ return err;
+}
+
+
+static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
+ int old_virtual_width = uv_tty_virtual_width;
+ int old_virtual_height = uv_tty_virtual_height;
+
+ uv_tty_virtual_width = info->dwSize.X;
+ uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
+
+ /* Recompute virtual window offset row. */
+ if (uv_tty_virtual_offset == -1) {
+ uv_tty_virtual_offset = info->dwCursorPosition.Y;
+ } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
+ uv_tty_virtual_height + 1) {
+ /* If suddenly find the cursor outside of the virtual window, it must */
+ /* have somehow scrolled. Update the virtual window offset. */
+ uv_tty_virtual_offset = info->dwCursorPosition.Y -
+ uv_tty_virtual_height + 1;
+ }
+ if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) {
+ uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height;
+ }
+ if (uv_tty_virtual_offset < 0) {
+ uv_tty_virtual_offset = 0;
+ }
+
+ /* If the virtual window size changed, emit a SIGWINCH signal. Don't emit */
+ /* if this was the first time the virtual window size was computed. */
+ if (old_virtual_width != -1 && old_virtual_height != -1 &&
+ (uv_tty_virtual_width != old_virtual_width ||
+ uv_tty_virtual_height != old_virtual_height)) {
+ uv__signal_dispatch(SIGWINCH);
+ }
+}
+
+
+static COORD uv_tty_make_real_coord(uv_tty_t* handle,
+ CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y,
+ unsigned char y_relative) {
+ COORD result;
+
+ uv_tty_update_virtual_window(info);
+
+ /* Adjust y position */
+ if (y_relative) {
+ y = info->dwCursorPosition.Y + y;
+ } else {
+ y = uv_tty_virtual_offset + y;
+ }
+ /* Clip y to virtual client rectangle */
+ if (y < uv_tty_virtual_offset) {
+ y = uv_tty_virtual_offset;
+ } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) {
+ y = uv_tty_virtual_offset + uv_tty_virtual_height - 1;
+ }
+
+ /* Adjust x */
+ if (x_relative) {
+ x = info->dwCursorPosition.X + x;
+ }
+ /* Clip x */
+ if (x < 0) {
+ x = 0;
+ } else if (x >= uv_tty_virtual_width) {
+ x = uv_tty_virtual_width - 1;
+ }
+
+ result.X = (unsigned short) x;
+ result.Y = (unsigned short) y;
+ return result;
+}
+
+
+static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
+ DWORD* error) {
+ DWORD written;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (!WriteConsoleW(handle->handle,
+ (void*) buffer,
+ length,
+ &written,
+ NULL)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
+ int y, unsigned char y_relative, DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ COORD pos;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ retry:
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ }
+
+ pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
+
+ if (!SetConsoleCursorPosition(handle->handle, pos)) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ /* The console may be resized - retry */
+ goto retry;
+ } else {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
+ const COORD origin = {0, 0};
+ const WORD char_attrs = uv_tty_default_text_attributes;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ DWORD count, written;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ /* Reset original text attributes. */
+ if (!SetConsoleTextAttribute(handle->handle, char_attrs)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ /* Move the cursor position to (0, 0). */
+ if (!SetConsoleCursorPosition(handle->handle, origin)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ /* Clear the screen buffer. */
+ retry:
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ count = info.dwSize.X * info.dwSize.Y;
+
+ if (!(FillConsoleOutputCharacterW(handle->handle,
+ L'\x20',
+ count,
+ origin,
+ &written) &&
+ FillConsoleOutputAttribute(handle->handle,
+ char_attrs,
+ written,
+ origin,
+ &written))) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ /* The console may be resized - retry */
+ goto retry;
+ } else {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ /* Move the virtual window up to the top. */
+ uv_tty_virtual_offset = 0;
+ uv_tty_update_virtual_window(&info);
+
+ return 0;
+}
+
+
+static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
+ DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ COORD start, end;
+ DWORD count, written;
+
+ int x1, x2, y1, y2;
+ int x1r, x2r, y1r, y2r;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (dir == 0) {
+ /* Clear from current position */
+ x1 = 0;
+ x1r = 1;
+ } else {
+ /* Clear from column 0 */
+ x1 = 0;
+ x1r = 0;
+ }
+
+ if (dir == 1) {
+ /* Clear to current position */
+ x2 = 0;
+ x2r = 1;
+ } else {
+ /* Clear to end of row. We pretend the console is 65536 characters wide, */
+ /* uv_tty_make_real_coord will clip it to the actual console width. */
+ x2 = 0xffff;
+ x2r = 0;
+ }
+
+ if (!entire_screen) {
+ /* Stay on our own row */
+ y1 = y2 = 0;
+ y1r = y2r = 1;
+ } else {
+ /* Apply columns direction to row */
+ y1 = x1;
+ y1r = x1r;
+ y2 = x2;
+ y2r = x2r;
+ }
+
+ retry:
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
+ end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
+ count = (end.Y * info.dwSize.X + end.X) -
+ (start.Y * info.dwSize.X + start.X) + 1;
+
+ if (!(FillConsoleOutputCharacterW(handle->handle,
+ L'\x20',
+ count,
+ start,
+ &written) &&
+ FillConsoleOutputAttribute(handle->handle,
+ info.wAttributes,
+ written,
+ start,
+ &written))) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ /* The console may be resized - retry */
+ goto retry;
+ } else {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+#define FLIP_FGBG \
+ do { \
+ WORD fg = info.wAttributes & 0xF; \
+ WORD bg = info.wAttributes & 0xF0; \
+ info.wAttributes &= 0xFF00; \
+ info.wAttributes |= fg << 4; \
+ info.wAttributes |= bg >> 4; \
+ } while (0)
+
+static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
+ unsigned short argc = handle->tty.wr.ansi_csi_argc;
+ unsigned short* argv = handle->tty.wr.ansi_csi_argv;
+ int i;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ char fg_color = -1, bg_color = -1;
+ char fg_bright = -1, bg_bright = -1;
+ char inverse = -1;
+
+ if (argc == 0) {
+ /* Reset mode */
+ fg_color = uv_tty_default_fg_color;
+ bg_color = uv_tty_default_bg_color;
+ fg_bright = uv_tty_default_fg_bright;
+ bg_bright = uv_tty_default_bg_bright;
+ inverse = uv_tty_default_inverse;
+ }
+
+ for (i = 0; i < argc; i++) {
+ short arg = argv[i];
+
+ if (arg == 0) {
+ /* Reset mode */
+ fg_color = uv_tty_default_fg_color;
+ bg_color = uv_tty_default_bg_color;
+ fg_bright = uv_tty_default_fg_bright;
+ bg_bright = uv_tty_default_bg_bright;
+ inverse = uv_tty_default_inverse;
+
+ } else if (arg == 1) {
+ /* Foreground bright on */
+ fg_bright = 1;
+
+ } else if (arg == 2) {
+ /* Both bright off */
+ fg_bright = 0;
+ bg_bright = 0;
+
+ } else if (arg == 5) {
+ /* Background bright on */
+ bg_bright = 1;
+
+ } else if (arg == 7) {
+ /* Inverse: on */
+ inverse = 1;
+
+ } else if (arg == 21 || arg == 22) {
+ /* Foreground bright off */
+ fg_bright = 0;
+
+ } else if (arg == 25) {
+ /* Background bright off */
+ bg_bright = 0;
+
+ } else if (arg == 27) {
+ /* Inverse: off */
+ inverse = 0;
+
+ } else if (arg >= 30 && arg <= 37) {
+ /* Set foreground color */
+ fg_color = arg - 30;
+
+ } else if (arg == 39) {
+ /* Default text color */
+ fg_color = uv_tty_default_fg_color;
+ fg_bright = uv_tty_default_fg_bright;
+
+ } else if (arg >= 40 && arg <= 47) {
+ /* Set background color */
+ bg_color = arg - 40;
+
+ } else if (arg == 49) {
+ /* Default background color */
+ bg_color = uv_tty_default_bg_color;
+ bg_bright = uv_tty_default_bg_bright;
+
+ } else if (arg >= 90 && arg <= 97) {
+ /* Set bold foreground color */
+ fg_bright = 1;
+ fg_color = arg - 90;
+
+ } else if (arg >= 100 && arg <= 107) {
+ /* Set bold background color */
+ bg_bright = 1;
+ bg_color = arg - 100;
+
+ }
+ }
+
+ if (fg_color == -1 && bg_color == -1 && fg_bright == -1 &&
+ bg_bright == -1 && inverse == -1) {
+ /* Nothing changed */
+ return 0;
+ }
+
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
+ FLIP_FGBG;
+ }
+
+ if (fg_color != -1) {
+ info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ if (fg_color & 1) info.wAttributes |= FOREGROUND_RED;
+ if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN;
+ if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE;
+ }
+
+ if (fg_bright != -1) {
+ if (fg_bright) {
+ info.wAttributes |= FOREGROUND_INTENSITY;
+ } else {
+ info.wAttributes &= ~FOREGROUND_INTENSITY;
+ }
+ }
+
+ if (bg_color != -1) {
+ info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
+ if (bg_color & 1) info.wAttributes |= BACKGROUND_RED;
+ if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN;
+ if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE;
+ }
+
+ if (bg_bright != -1) {
+ if (bg_bright) {
+ info.wAttributes |= BACKGROUND_INTENSITY;
+ } else {
+ info.wAttributes &= ~BACKGROUND_INTENSITY;
+ }
+ }
+
+ if (inverse != -1) {
+ if (inverse) {
+ info.wAttributes |= COMMON_LVB_REVERSE_VIDEO;
+ } else {
+ info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO;
+ }
+ }
+
+ if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
+ FLIP_FGBG;
+ }
+
+ if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
+ DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ uv_tty_update_virtual_window(&info);
+
+ handle->tty.wr.saved_position.X = info.dwCursorPosition.X;
+ handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
+ handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
+
+ if (save_attributes) {
+ handle->tty.wr.saved_attributes = info.wAttributes &
+ (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
+ handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES;
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_restore_state(uv_tty_t* handle,
+ unsigned char restore_attributes, DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ WORD new_attributes;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
+ if (uv_tty_move_caret(handle,
+ handle->tty.wr.saved_position.X,
+ 0,
+ handle->tty.wr.saved_position.Y,
+ 0,
+ error) != 0) {
+ return -1;
+ }
+ }
+
+ if (restore_attributes &&
+ (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) {
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ new_attributes = info.wAttributes;
+ new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
+ new_attributes |= handle->tty.wr.saved_attributes;
+
+ if (!SetConsoleTextAttribute(handle->handle, new_attributes)) {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
+ BOOL visible,
+ DWORD* error) {
+ CONSOLE_CURSOR_INFO cursor_info;
+
+ if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ cursor_info.bVisible = visible;
+
+ if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+static int uv_tty_write_bufs(uv_tty_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ DWORD* error) {
+ /* We can only write 8k characters at a time. Windows can't handle */
+ /* much more characters in a single console write anyway. */
+ WCHAR utf16_buf[MAX_CONSOLE_CHAR];
+ WCHAR* utf16_buffer;
+ DWORD utf16_buf_used = 0;
+ unsigned int i, len, max_len, pos;
+ int allocate = 0;
+
+#define FLUSH_TEXT() \
+ do { \
+ pos = 0; \
+ do { \
+ len = utf16_buf_used - pos; \
+ if (len > MAX_CONSOLE_CHAR) \
+ len = MAX_CONSOLE_CHAR; \
+ uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \
+ pos += len; \
+ } while (pos < utf16_buf_used); \
+ if (allocate) { \
+ uv__free(utf16_buffer); \
+ allocate = 0; \
+ utf16_buffer = utf16_buf; \
+ } \
+ utf16_buf_used = 0; \
+ } while (0)
+
+#define ENSURE_BUFFER_SPACE(wchars_needed) \
+ if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
+ FLUSH_TEXT(); \
+ }
+
+ /* Cache for fast access */
+ unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
+ unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
+ unsigned char previous_eol = handle->tty.wr.previous_eol;
+ unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
+
+ /* Store the error here. If we encounter an error, stop trying to do i/o */
+ /* but keep parsing the buffer so we leave the parser in a consistent */
+ /* state. */
+ *error = ERROR_SUCCESS;
+
+ utf16_buffer = utf16_buf;
+
+ uv_sem_wait(&uv_tty_output_lock);
+
+ for (i = 0; i < nbufs; i++) {
+ uv_buf_t buf = bufs[i];
+ unsigned int j;
+
+ if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) {
+ utf16_buf_used = MultiByteToWideChar(CP_UTF8,
+ 0,
+ buf.base,
+ buf.len,
+ NULL,
+ 0);
+
+ if (utf16_buf_used == 0) {
+ *error = GetLastError();
+ break;
+ }
+
+ max_len = (utf16_buf_used + 1) * sizeof(WCHAR);
+ allocate = max_len > MAX_CONSOLE_CHAR;
+ if (allocate)
+ utf16_buffer = uv__malloc(max_len);
+ if (!MultiByteToWideChar(CP_UTF8,
+ 0,
+ buf.base,
+ buf.len,
+ utf16_buffer,
+ utf16_buf_used)) {
+ if (allocate)
+ uv__free(utf16_buffer);
+ *error = GetLastError();
+ break;
+ }
+
+ FLUSH_TEXT();
+
+ continue;
+ }
+
+ for (j = 0; j < buf.len; j++) {
+ unsigned char c = buf.base[j];
+
+ /* Run the character through the utf8 decoder We happily accept non */
+ /* shortest form encodings and invalid code points - there's no real */
+ /* harm that can be done. */
+ if (utf8_bytes_left == 0) {
+ /* Read utf-8 start byte */
+ DWORD first_zero_bit;
+ unsigned char not_c = ~c;
+#ifdef _MSC_VER /* msvc */
+ if (_BitScanReverse(&first_zero_bit, not_c)) {
+#else /* assume gcc */
+ if (c != 0) {
+ first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c);
+#endif
+ if (first_zero_bit == 7) {
+ /* Ascii - pass right through */
+ utf8_codepoint = (unsigned int) c;
+
+ } else if (first_zero_bit <= 5) {
+ /* Multibyte sequence */
+ utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c;
+ utf8_bytes_left = (char) (6 - first_zero_bit);
+
+ } else {
+ /* Invalid continuation */
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ }
+
+ } else {
+ /* 0xff -- invalid */
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ }
+
+ } else if ((c & 0xc0) == 0x80) {
+ /* Valid continuation of utf-8 multibyte sequence */
+ utf8_bytes_left--;
+ utf8_codepoint <<= 6;
+ utf8_codepoint |= ((unsigned int) c & 0x3f);
+
+ } else {
+ /* Start byte where continuation was expected. */
+ utf8_bytes_left = 0;
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ /* Patch buf offset so this character will be parsed again as a */
+ /* start byte. */
+ j--;
+ }
+
+ /* Maybe we need to parse more bytes to find a character. */
+ if (utf8_bytes_left != 0) {
+ continue;
+ }
+
+ /* Parse vt100/ansi escape codes */
+ if (ansi_parser_state == ANSI_NORMAL) {
+ switch (utf8_codepoint) {
+ case '\033':
+ ansi_parser_state = ANSI_ESCAPE_SEEN;
+ continue;
+
+ case 0233:
+ ansi_parser_state = ANSI_CSI;
+ handle->tty.wr.ansi_csi_argc = 0;
+ continue;
+ }
+
+ } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) {
+ switch (utf8_codepoint) {
+ case '[':
+ ansi_parser_state = ANSI_CSI;
+ handle->tty.wr.ansi_csi_argc = 0;
+ continue;
+
+ case '^':
+ case '_':
+ case 'P':
+ case ']':
+ /* Not supported, but we'll have to parse until we see a stop */
+ /* code, e.g. ESC \ or BEL. */
+ ansi_parser_state = ANSI_ST_CONTROL;
+ continue;
+
+ case '\033':
+ /* Ignore double escape. */
+ continue;
+
+ case 'c':
+ /* Full console reset. */
+ FLUSH_TEXT();
+ uv_tty_reset(handle, error);
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ case '7':
+ /* Save the cursor position and text attributes. */
+ FLUSH_TEXT();
+ uv_tty_save_state(handle, 1, error);
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ case '8':
+ /* Restore the cursor position and text attributes */
+ FLUSH_TEXT();
+ uv_tty_restore_state(handle, 1, error);
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ default:
+ if (utf8_codepoint >= '@' && utf8_codepoint <= '_') {
+ /* Single-char control. */
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+ } else {
+ /* Invalid - proceed as normal, */
+ ansi_parser_state = ANSI_NORMAL;
+ }
+ }
+
+ } else if (ansi_parser_state & ANSI_CSI) {
+ if (!(ansi_parser_state & ANSI_IGNORE)) {
+ if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
+ /* Parsing a numerical argument */
+
+ if (!(ansi_parser_state & ANSI_IN_ARG)) {
+ /* We were not currently parsing a number */
+
+ /* Check for too many arguments */
+ if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+
+ ansi_parser_state |= ANSI_IN_ARG;
+ handle->tty.wr.ansi_csi_argc++;
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
+ (unsigned short) utf8_codepoint - '0';
+ continue;
+ } else {
+ /* We were already parsing a number. Parse next digit. */
+ uint32_t value = 10 *
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
+
+ /* Check for overflow. */
+ if (value > UINT16_MAX) {
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
+ (unsigned short) value + (utf8_codepoint - '0');
+ continue;
+ }
+
+ } else if (utf8_codepoint == ';') {
+ /* Denotes the end of an argument. */
+ if (ansi_parser_state & ANSI_IN_ARG) {
+ ansi_parser_state &= ~ANSI_IN_ARG;
+ continue;
+
+ } else {
+ /* If ANSI_IN_ARG is not set, add another argument and */
+ /* default it to 0. */
+ /* Check for too many arguments */
+ if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+
+ handle->tty.wr.ansi_csi_argc++;
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
+ continue;
+ }
+
+ } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
+ handle->tty.wr.ansi_csi_argc == 0) {
+ /* Ignores '?' if it is the first character after CSI[ */
+ /* This is an extension character from the VT100 codeset */
+ /* that is supported and used by most ANSI terminals today. */
+ continue;
+
+ } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
+ (handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) {
+ int x, y, d;
+
+ /* Command byte */
+ switch (utf8_codepoint) {
+ case 'A':
+ /* cursor up */
+ FLUSH_TEXT();
+ y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ uv_tty_move_caret(handle, 0, 1, y, 1, error);
+ break;
+
+ case 'B':
+ /* cursor down */
+ FLUSH_TEXT();
+ y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ uv_tty_move_caret(handle, 0, 1, y, 1, error);
+ break;
+
+ case 'C':
+ /* cursor forward */
+ FLUSH_TEXT();
+ x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ uv_tty_move_caret(handle, x, 1, 0, 1, error);
+ break;
+
+ case 'D':
+ /* cursor back */
+ FLUSH_TEXT();
+ x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ uv_tty_move_caret(handle, x, 1, 0, 1, error);
+ break;
+
+ case 'E':
+ /* cursor next line */
+ FLUSH_TEXT();
+ y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ uv_tty_move_caret(handle, 0, 0, y, 1, error);
+ break;
+
+ case 'F':
+ /* cursor previous line */
+ FLUSH_TEXT();
+ y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ uv_tty_move_caret(handle, 0, 0, y, 1, error);
+ break;
+
+ case 'G':
+ /* cursor horizontal move absolute */
+ FLUSH_TEXT();
+ x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
+ ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
+ uv_tty_move_caret(handle, x, 0, 0, 1, error);
+ break;
+
+ case 'H':
+ case 'f':
+ /* cursor move absolute */
+ FLUSH_TEXT();
+ y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
+ ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
+ x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1])
+ ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
+ uv_tty_move_caret(handle, x, 0, y, 0, error);
+ break;
+
+ case 'J':
+ /* Erase screen */
+ FLUSH_TEXT();
+ d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
+ if (d >= 0 && d <= 2) {
+ uv_tty_clear(handle, d, 1, error);
+ }
+ break;
+
+ case 'K':
+ /* Erase line */
+ FLUSH_TEXT();
+ d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
+ if (d >= 0 && d <= 2) {
+ uv_tty_clear(handle, d, 0, error);
+ }
+ break;
+
+ case 'm':
+ /* Set style */
+ FLUSH_TEXT();
+ uv_tty_set_style(handle, error);
+ break;
+
+ case 's':
+ /* Save the cursor position. */
+ FLUSH_TEXT();
+ uv_tty_save_state(handle, 0, error);
+ break;
+
+ case 'u':
+ /* Restore the cursor position */
+ FLUSH_TEXT();
+ uv_tty_restore_state(handle, 0, error);
+ break;
+
+ case 'l':
+ /* Hide the cursor */
+ if (handle->tty.wr.ansi_csi_argc == 1 &&
+ handle->tty.wr.ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 0, error);
+ }
+ break;
+
+ case 'h':
+ /* Show the cursor */
+ if (handle->tty.wr.ansi_csi_argc == 1 &&
+ handle->tty.wr.ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 1, error);
+ }
+ break;
+ }
+
+ /* Sequence ended - go back to normal state. */
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ } else {
+ /* We don't support commands that use private mode characters or */
+ /* intermediaries. Ignore the rest of the sequence. */
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+ } else {
+ /* We're ignoring this command. Stop only on command character. */
+ if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
+ ansi_parser_state = ANSI_NORMAL;
+ }
+ continue;
+ }
+
+ } else if (ansi_parser_state & ANSI_ST_CONTROL) {
+ /* Unsupported control code */
+ /* Ignore everything until we see BEL or ESC \ */
+ if (ansi_parser_state & ANSI_IN_STRING) {
+ if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
+ if (utf8_codepoint == '"') {
+ ansi_parser_state &= ~ANSI_IN_STRING;
+ } else if (utf8_codepoint == '\\') {
+ ansi_parser_state |= ANSI_BACKSLASH_SEEN;
+ }
+ } else {
+ ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
+ }
+ } else {
+ if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' &&
+ (ansi_parser_state & ANSI_ESCAPE_SEEN))) {
+ /* End of sequence */
+ ansi_parser_state = ANSI_NORMAL;
+ } else if (utf8_codepoint == '\033') {
+ /* Escape character */
+ ansi_parser_state |= ANSI_ESCAPE_SEEN;
+ } else if (utf8_codepoint == '"') {
+ /* String starting */
+ ansi_parser_state |= ANSI_IN_STRING;
+ ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
+ ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
+ } else {
+ ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
+ }
+ }
+ continue;
+ } else {
+ /* Inconsistent state */
+ abort();
+ }
+
+ /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */
+ /* windows console doesn't really support UTF-16, so just emit the */
+ /* replacement character. */
+ if (utf8_codepoint > 0xffff) {
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ }
+
+ if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) {
+ /* EOL conversion - emit \r\n when we see \n. */
+
+ if (utf8_codepoint == 0x0a && previous_eol != 0x0d) {
+ /* \n was not preceded by \r; print \r\n. */
+ ENSURE_BUFFER_SPACE(2);
+ utf16_buf[utf16_buf_used++] = L'\r';
+ utf16_buf[utf16_buf_used++] = L'\n';
+ } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
+ /* \n was followed by \r; do not print the \r, since */
+ /* the source was either \r\n\r (so the second \r is */
+ /* redundant) or was \n\r (so the \n was processed */
+ /* by the last case and an \r automatically inserted). */
+ } else {
+ /* \r without \n; print \r as-is. */
+ ENSURE_BUFFER_SPACE(1);
+ utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
+ }
+
+ previous_eol = (char) utf8_codepoint;
+
+ } else if (utf8_codepoint <= 0xffff) {
+ /* Encode character into utf-16 buffer. */
+ ENSURE_BUFFER_SPACE(1);
+ utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
+ previous_eol = 0;
+ }
+ }
+ }
+
+ /* Flush remaining characters */
+ FLUSH_TEXT();
+
+ /* Copy cached values back to struct. */
+ handle->tty.wr.utf8_bytes_left = utf8_bytes_left;
+ handle->tty.wr.utf8_codepoint = utf8_codepoint;
+ handle->tty.wr.previous_eol = previous_eol;
+ handle->tty.wr.ansi_parser_state = ansi_parser_state;
+
+ uv_sem_post(&uv_tty_output_lock);
+
+ if (*error == STATUS_SUCCESS) {
+ return 0;
+ } else {
+ return -1;
+ }
+
+#undef FLUSH_TEXT
+}
+
+
+int uv_tty_write(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_tty_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ DWORD error;
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_WRITE;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+
+ req->u.io.queued_bytes = 0;
+
+ if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ SET_REQ_ERROR(req, error);
+ }
+
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+
+ return 0;
+}
+
+
+int uv__tty_try_write(uv_tty_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ DWORD error;
+
+ if (handle->stream.conn.write_reqs_pending > 0)
+ return UV_EAGAIN;
+
+ if (uv_tty_write_bufs(handle, bufs, nbufs, &error))
+ return uv_translate_sys_error(error);
+
+ return uv__count_bufs(bufs, nbufs);
+}
+
+
+void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_write_t* req) {
+ int err;
+
+ handle->write_queue_size -= req->u.io.queued_bytes;
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (req->cb) {
+ err = GET_REQ_ERROR(req);
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ handle->stream.conn.write_reqs_pending--;
+ if (handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_tty_close(uv_tty_t* handle) {
+ assert(handle->u.fd == -1 || handle->u.fd > 2);
+ if (handle->u.fd == -1)
+ CloseHandle(handle->handle);
+ else
+ close(handle->u.fd);
+
+ if (handle->flags & UV_HANDLE_READING)
+ uv_tty_read_stop(handle);
+
+ handle->u.fd = -1;
+ handle->handle = INVALID_HANDLE_VALUE;
+ handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+ uv__handle_closing(handle);
+
+ if (handle->reqs_pending == 0) {
+ uv_want_endgame(handle->loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
+ if (!(handle->flags & UV_HANDLE_TTY_READABLE) &&
+ handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
+
+ /* TTY shutdown is really just a no-op */
+ if (handle->stream.conn.shutdown_req->cb) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
+ } else {
+ handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
+ }
+ }
+
+ handle->stream.conn.shutdown_req = NULL;
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ /* The wait handle used for raw reading should be unregistered when the */
+ /* wait callback runs. */
+ assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
+ handle->tty.rd.read_raw_wait == NULL);
+
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+/* TODO: remove me */
+void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* raw_req) {
+ abort();
+}
+
+
+/* TODO: remove me */
+void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_connect_t* req) {
+ abort();
+}
+
+
+int uv_tty_reset_mode(void) {
+ /* Not necessary to do anything. */
+ return 0;
+}
+
+/* Determine whether or not this version of windows supports
+ * proper ANSI color codes. Should be supported as of windows
+ * 10 version 1511, build number 10.0.10586.
+ */
+static void uv__determine_vterm_state(HANDLE handle) {
+ DWORD dwMode = 0;
+
+ if (!GetConsoleMode(handle, &dwMode)) {
+ uv__vterm_state = UV_UNSUPPORTED;
+ return;
+ }
+
+ dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+ if (!SetConsoleMode(handle, dwMode)) {
+ uv__vterm_state = UV_UNSUPPORTED;
+ return;
+ }
+
+ uv__vterm_state = UV_SUPPORTED;
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+
+/*
+ * Threshold of active udp streams for which to preallocate udp read buffers.
+ */
+const unsigned int uv_active_udp_streams_threshold = 0;
+
+/* A zero-size buffer for use by uv_udp_read */
+static char uv_zero_[] = "";
+
+int uv_udp_getsockname(const uv_udp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ int result;
+
+ if (handle->socket == INVALID_SOCKET) {
+ return UV_EINVAL;
+ }
+
+ result = getsockname(handle->socket, name, namelen);
+ if (result != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
+ int family) {
+ DWORD yes = 1;
+ WSAPROTOCOL_INFOW info;
+ int opt_len;
+
+ if (handle->socket != INVALID_SOCKET)
+ return UV_EBUSY;
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) {
+ return GetLastError();
+ }
+
+ /* Associate it with the I/O completion port. */
+ /* Use uv_handle_t pointer as completion key. */
+ if (CreateIoCompletionPort((HANDLE)socket,
+ loop->iocp,
+ (ULONG_PTR)socket,
+ 0) == NULL) {
+ return GetLastError();
+ }
+
+ if (pSetFileCompletionNotificationModes) {
+ /* All known Windows that support SetFileCompletionNotificationModes */
+ /* have a bug that makes it impossible to use this function in */
+ /* conjunction with datagram sockets. We can work around that but only */
+ /* if the user is using the default UDP driver (AFD) and has no other */
+ /* LSPs stacked on top. Here we check whether that is the case. */
+ opt_len = (int) sizeof info;
+ if (getsockopt(socket,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &info,
+ &opt_len) == SOCKET_ERROR) {
+ return GetLastError();
+ }
+
+ if (info.ProtocolChain.ChainLen == 1) {
+ if (pSetFileCompletionNotificationModes((HANDLE)socket,
+ FILE_SKIP_SET_EVENT_ON_HANDLE |
+ FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
+ handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
+ handle->func_wsarecv = uv_wsarecv_workaround;
+ handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
+ } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
+ return GetLastError();
+ }
+ }
+ }
+
+ handle->socket = socket;
+
+ if (family == AF_INET6) {
+ handle->flags |= UV_HANDLE_IPV6;
+ } else {
+ assert(!(handle->flags & UV_HANDLE_IPV6));
+ }
+
+ return 0;
+}
+
+
+int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
+ int domain;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return UV_EINVAL;
+
+ if (flags & ~0xFF)
+ return UV_EINVAL;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
+ handle->socket = INVALID_SOCKET;
+ handle->reqs_pending = 0;
+ handle->activecnt = 0;
+ handle->func_wsarecv = WSARecv;
+ handle->func_wsarecvfrom = WSARecvFrom;
+ handle->send_queue_size = 0;
+ handle->send_queue_count = 0;
+ uv_req_init(loop, (uv_req_t*) &(handle->recv_req));
+ handle->recv_req.type = UV_UDP_RECV;
+ handle->recv_req.data = handle;
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init.
+ */
+
+ if (domain != AF_UNSPEC) {
+ SOCKET sock;
+ DWORD err;
+
+ sock = socket(domain, SOCK_DGRAM, 0);
+ if (sock == INVALID_SOCKET) {
+ err = WSAGetLastError();
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+
+ err = uv_udp_set_socket(handle->loop, handle, sock, domain);
+ if (err) {
+ closesocket(sock);
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
+ return uv_udp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
+void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
+ uv_udp_recv_stop(handle);
+ closesocket(handle->socket);
+ handle->socket = INVALID_SOCKET;
+
+ uv__handle_closing(handle);
+
+ if (handle->reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+static int uv_udp_maybe_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int r;
+ int err;
+ DWORD no = 0;
+
+ if (handle->flags & UV_HANDLE_BOUND)
+ return 0;
+
+ if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) {
+ /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (handle->socket == INVALID_SOCKET) {
+ SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0);
+ if (sock == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family);
+ if (err) {
+ closesocket(sock);
+ return err;
+ }
+ }
+
+ if (flags & UV_UDP_REUSEADDR) {
+ DWORD yes = 1;
+ /* Set SO_REUSEADDR on the socket. */
+ if (setsockopt(handle->socket,
+ SOL_SOCKET,
+ SO_REUSEADDR,
+ (char*) &yes,
+ sizeof yes) == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ return err;
+ }
+ }
+
+ if (addr->sa_family == AF_INET6)
+ handle->flags |= UV_HANDLE_IPV6;
+
+ if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
+ /* On windows IPV6ONLY is on by default. */
+ /* If the user doesn't specify it libuv turns it off. */
+
+ /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
+ /* available, or when run on XP/2003 which have no support for dualstack */
+ /* sockets. For now we're silently ignoring the error. */
+ setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ (char*) &no,
+ sizeof no);
+ }
+
+ r = bind(handle->socket, addr, addrlen);
+ if (r == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+}
+
+
+static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
+ uv_req_t* req;
+ uv_buf_t buf;
+ DWORD bytes, flags;
+ int result;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ req = &handle->recv_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ /*
+ * Preallocate a read buffer if the number of active streams is below
+ * the threshold.
+ */
+ if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
+ handle->flags &= ~UV_HANDLE_ZERO_READ;
+
+ handle->recv_buffer = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
+ if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) {
+ handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
+ return;
+ }
+ assert(handle->recv_buffer.base != NULL);
+
+ buf = handle->recv_buffer;
+ memset(&handle->recv_from, 0, sizeof handle->recv_from);
+ handle->recv_from_len = sizeof handle->recv_from;
+ flags = 0;
+
+ result = handle->func_wsarecvfrom(handle->socket,
+ (WSABUF*) &buf,
+ 1,
+ &bytes,
+ &flags,
+ (struct sockaddr*) &handle->recv_from,
+ &handle->recv_from_len,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->u.io.overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, req);
+ handle->reqs_pending++;
+ }
+
+ } else {
+ handle->flags |= UV_HANDLE_ZERO_READ;
+
+ buf.base = (char*) uv_zero_;
+ buf.len = 0;
+ flags = MSG_PEEK;
+
+ result = handle->func_wsarecv(handle->socket,
+ (WSABUF*) &buf,
+ 1,
+ &bytes,
+ &flags,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->u.io.overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, req);
+ handle->reqs_pending++;
+ }
+ }
+}
+
+
+int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ uv_loop_t* loop = handle->loop;
+ int err;
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return WSAEALREADY;
+ }
+
+ err = uv_udp_maybe_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip4_any_,
+ sizeof(uv_addr_ip4_any_),
+ 0);
+ if (err)
+ return err;
+
+ handle->flags |= UV_HANDLE_READING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ loop->active_udp_streams++;
+
+ handle->recv_cb = recv_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* recv request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
+ uv_udp_queue_recv(loop, handle);
+
+ return 0;
+}
+
+
+int uv__udp_recv_stop(uv_udp_t* handle) {
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ handle->loop->active_udp_streams--;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv__send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ DWORD result, bytes;
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_UDP_SEND;
+ req->handle = handle;
+ req->cb = cb;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ result = WSASendTo(handle->socket,
+ (WSABUF*)bufs,
+ nbufs,
+ &bytes,
+ 0,
+ addr,
+ addrlen,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ handle->reqs_pending++;
+ handle->send_queue_size += req->u.io.queued_bytes;
+ handle->send_queue_count++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
+ handle->reqs_pending++;
+ handle->send_queue_size += req->u.io.queued_bytes;
+ handle->send_queue_count++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ } else {
+ /* Send failed due to an error. */
+ return WSAGetLastError();
+ }
+
+ return 0;
+}
+
+
+void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
+ uv_req_t* req) {
+ uv_buf_t buf;
+ int partial;
+
+ assert(handle->type == UV_UDP);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!REQ_SUCCESS(req)) {
+ DWORD err = GET_REQ_SOCK_ERROR(req);
+ if (err == WSAEMSGSIZE) {
+ /* Not a real error, it just indicates that the received packet */
+ /* was bigger than the receive buffer. */
+ } else if (err == WSAECONNRESET || err == WSAENETRESET) {
+ /* A previous sendto operation failed; ignore this error. If */
+ /* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */
+ /* MSG_PEEK flag to clear out the error queue. For nonzero reads, */
+ /* immediately queue a new receive. */
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+ goto done;
+ }
+ } else {
+ /* A real error occurred. Report the error to the user only if we're */
+ /* currently reading. */
+ if (handle->flags & UV_HANDLE_READING) {
+ uv_udp_recv_stop(handle);
+ buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
+ uv_buf_init(NULL, 0) : handle->recv_buffer;
+ handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
+ }
+ goto done;
+ }
+ }
+
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+ /* Successful read */
+ partial = !REQ_SUCCESS(req);
+ handle->recv_cb(handle,
+ req->u.io.overlapped.InternalHigh,
+ &handle->recv_buffer,
+ (const struct sockaddr*) &handle->recv_from,
+ partial ? UV_UDP_PARTIAL : 0);
+ } else if (handle->flags & UV_HANDLE_READING) {
+ DWORD bytes, err, flags;
+ struct sockaddr_storage from;
+ int from_len;
+
+ /* Do a nonblocking receive */
+ /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
+ buf = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
+ if (buf.base == NULL || buf.len == 0) {
+ handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
+ goto done;
+ }
+ assert(buf.base != NULL);
+
+ memset(&from, 0, sizeof from);
+ from_len = sizeof from;
+
+ flags = 0;
+
+ if (WSARecvFrom(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ (struct sockaddr*) &from,
+ &from_len,
+ NULL,
+ NULL) != SOCKET_ERROR) {
+
+ /* Message received */
+ handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
+ } else {
+ err = WSAGetLastError();
+ if (err == WSAEMSGSIZE) {
+ /* Message truncated */
+ handle->recv_cb(handle,
+ bytes,
+ &buf,
+ (const struct sockaddr*) &from,
+ UV_UDP_PARTIAL);
+ } else if (err == WSAEWOULDBLOCK) {
+ /* Kernel buffer empty */
+ handle->recv_cb(handle, 0, &buf, NULL, 0);
+ } else if (err == WSAECONNRESET || err == WSAENETRESET) {
+ /* WSAECONNRESET/WSANETRESET is ignored because this just indicates
+ * that a previous sendto operation failed.
+ */
+ handle->recv_cb(handle, 0, &buf, NULL, 0);
+ } else {
+ /* Any other error that we want to report back to the user. */
+ uv_udp_recv_stop(handle);
+ handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
+ }
+ }
+ }
+
+done:
+ /* Post another read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_udp_queue_recv(loop, handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
+ uv_udp_send_t* req) {
+ int err;
+
+ assert(handle->type == UV_UDP);
+
+ assert(handle->send_queue_size >= req->u.io.queued_bytes);
+ assert(handle->send_queue_count >= 1);
+ handle->send_queue_size -= req->u.io.queued_bytes;
+ handle->send_queue_count--;
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (req->cb) {
+ err = 0;
+ if (!REQ_SUCCESS(req)) {
+ err = GET_REQ_SOCK_ERROR(req);
+ }
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+static int uv__udp_set_membership4(uv_udp_t* handle,
+ const struct sockaddr_in* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int err;
+ int optname;
+ struct ip_mreq mreq;
+
+ if (handle->flags & UV_HANDLE_IPV6)
+ return UV_EINVAL;
+
+ /* If the socket is unbound, bind to inaddr_any. */
+ err = uv_udp_maybe_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip4_any_,
+ sizeof(uv_addr_ip4_any_),
+ UV_UDP_REUSEADDR);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ memset(&mreq, 0, sizeof mreq);
+
+ if (interface_addr) {
+ err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
+ if (err)
+ return err;
+ } else {
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ }
+
+ mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IP_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IP_DROP_MEMBERSHIP;
+ break;
+ default:
+ return UV_EINVAL;
+ }
+
+ if (setsockopt(handle->socket,
+ IPPROTO_IP,
+ optname,
+ (char*) &mreq,
+ sizeof mreq) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv__udp_set_membership6(uv_udp_t* handle,
+ const struct sockaddr_in6* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int optname;
+ int err;
+ struct ipv6_mreq mreq;
+ struct sockaddr_in6 addr6;
+
+ if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
+ return UV_EINVAL;
+
+ err = uv_udp_maybe_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip6_any_,
+ sizeof(uv_addr_ip6_any_),
+ UV_UDP_REUSEADDR);
+
+ if (err)
+ return uv_translate_sys_error(err);
+
+ memset(&mreq, 0, sizeof(mreq));
+
+ if (interface_addr) {
+ if (uv_ip6_addr(interface_addr, 0, &addr6))
+ return UV_EINVAL;
+ mreq.ipv6mr_interface = addr6.sin6_scope_id;
+ } else {
+ mreq.ipv6mr_interface = 0;
+ }
+
+ mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IPV6_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IPV6_DROP_MEMBERSHIP;
+ break;
+ default:
+ return UV_EINVAL;
+ }
+
+ if (setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ optname,
+ (char*) &mreq,
+ sizeof mreq) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_udp_set_membership(uv_udp_t* handle,
+ const char* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+
+ if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0)
+ return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
+ else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0)
+ return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
+ else
+ return UV_EINVAL;
+}
+
+
+int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
+ struct sockaddr_storage addr_st;
+ struct sockaddr_in* addr4;
+ struct sockaddr_in6* addr6;
+
+ addr4 = (struct sockaddr_in*) &addr_st;
+ addr6 = (struct sockaddr_in6*) &addr_st;
+
+ if (!interface_addr) {
+ memset(&addr_st, 0, sizeof addr_st);
+ if (handle->flags & UV_HANDLE_IPV6) {
+ addr_st.ss_family = AF_INET6;
+ addr6->sin6_scope_id = 0;
+ } else {
+ addr_st.ss_family = AF_INET;
+ addr4->sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
+ /* nothing, address was parsed */
+ } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
+ /* nothing, address was parsed */
+ } else {
+ return UV_EINVAL;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND))
+ return UV_EBADF;
+
+ if (addr_st.ss_family == AF_INET) {
+ if (setsockopt(handle->socket,
+ IPPROTO_IP,
+ IP_MULTICAST_IF,
+ (char*) &addr4->sin_addr,
+ sizeof(addr4->sin_addr)) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+ } else if (addr_st.ss_family == AF_INET6) {
+ if (setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ IPV6_MULTICAST_IF,
+ (char*) &addr6->sin6_scope_id,
+ sizeof(addr6->sin6_scope_id)) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+ } else {
+ assert(0 && "unexpected address family");
+ abort();
+ }
+
+ return 0;
+}
+
+
+int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
+ BOOL optval = (BOOL) value;
+
+ if (!(handle->flags & UV_HANDLE_BOUND))
+ return UV_EBADF;
+
+ if (setsockopt(handle->socket,
+ SOL_SOCKET,
+ SO_BROADCAST,
+ (char*) &optval,
+ sizeof optval)) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
+ WSAPROTOCOL_INFOW protocol_info;
+ int opt_len;
+ int err;
+
+ /* Detect the address family of the socket. */
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(sock,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ err = uv_udp_set_socket(handle->loop,
+ handle,
+ sock,
+ protocol_info.iAddressFamily);
+ return uv_translate_sys_error(err);
+}
+
+
+#define SOCKOPT_SETTER(name, option4, option6, validate) \
+ int uv_udp_set_##name(uv_udp_t* handle, int value) { \
+ DWORD optval = (DWORD) value; \
+ \
+ if (!(validate(value))) { \
+ return UV_EINVAL; \
+ } \
+ \
+ if (!(handle->flags & UV_HANDLE_BOUND)) \
+ return UV_EBADF; \
+ \
+ if (!(handle->flags & UV_HANDLE_IPV6)) { \
+ /* Set IPv4 socket option */ \
+ if (setsockopt(handle->socket, \
+ IPPROTO_IP, \
+ option4, \
+ (char*) &optval, \
+ sizeof optval)) { \
+ return uv_translate_sys_error(WSAGetLastError()); \
+ } \
+ } else { \
+ /* Set IPv6 socket option */ \
+ if (setsockopt(handle->socket, \
+ IPPROTO_IPV6, \
+ option6, \
+ (char*) &optval, \
+ sizeof optval)) { \
+ return uv_translate_sys_error(WSAGetLastError()); \
+ } \
+ } \
+ return 0; \
+ }
+
+#define VALIDATE_TTL(value) ((value) >= 1 && (value) <= 255)
+#define VALIDATE_MULTICAST_TTL(value) ((value) >= -1 && (value) <= 255)
+#define VALIDATE_MULTICAST_LOOP(value) (1)
+
+SOCKOPT_SETTER(ttl,
+ IP_TTL,
+ IPV6_HOPLIMIT,
+ VALIDATE_TTL)
+SOCKOPT_SETTER(multicast_ttl,
+ IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS,
+ VALIDATE_MULTICAST_TTL)
+SOCKOPT_SETTER(multicast_loop,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP,
+ VALIDATE_MULTICAST_LOOP)
+
+#undef SOCKOPT_SETTER
+#undef VALIDATE_TTL
+#undef VALIDATE_MULTICAST_TTL
+#undef VALIDATE_MULTICAST_LOOP
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+
+ err = uv_udp_maybe_bind(handle, addr, addrlen, flags);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb send_cb) {
+ const struct sockaddr* bind_addr;
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ if (addrlen == sizeof(uv_addr_ip4_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
+ } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
+ } else {
+ abort();
+ }
+ err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
+ if (err)
+ return uv_translate_sys_error(err);
+ }
+
+ err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
+
+
+int uv__udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen) {
+ return UV_ENOSYS;
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <direct.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <wchar.h>
+
+#include "uv.h"
+#include "internal.h"
+
+#include <winsock2.h>
+#include <winperf.h>
+#include <iphlpapi.h>
+#include <psapi.h>
+#include <tlhelp32.h>
+#include <windows.h>
+#include <userenv.h>
+
+
+/*
+ * Max title length; the only thing MSDN tells us about the maximum length
+ * of the console title is that it is smaller than 64K. However in practice
+ * it is much smaller, and there is no way to figure out what the exact length
+ * of the title is or can be, at least not on XP. To make it even more
+ * annoying, GetConsoleTitle fails when the buffer to be read into is bigger
+ * than the actual maximum length. So we make a conservative guess here;
+ * just don't put the novel you're writing in the title, unless the plot
+ * survives truncation.
+ */
+#define MAX_TITLE_LENGTH 8192
+
+/* The number of nanoseconds in one second. */
+#define UV__NANOSEC 1000000000
+
+/* Max user name length, from iphlpapi.h */
+#ifndef UNLEN
+# define UNLEN 256
+#endif
+
+/* Cached copy of the process title, plus a mutex guarding it. */
+static char *process_title;
+static CRITICAL_SECTION process_title_lock;
+
+/* Cached copy of the process id, written once. */
+static DWORD current_pid = 0;
+
+
+/* Interval (in seconds) of the high-resolution clock. */
+static double hrtime_interval_ = 0;
+
+
+/*
+ * One-time initialization code for functionality defined in util.c.
+ */
+void uv__util_init() {
+ LARGE_INTEGER perf_frequency;
+
+ /* Initialize process title access mutex. */
+ InitializeCriticalSection(&process_title_lock);
+
+ /* Retrieve high-resolution timer frequency
+ * and precompute its reciprocal.
+ */
+ if (QueryPerformanceFrequency(&perf_frequency)) {
+ hrtime_interval_ = 1.0 / perf_frequency.QuadPart;
+ } else {
+ hrtime_interval_= 0;
+ }
+}
+
+
+int uv_exepath(char* buffer, size_t* size_ptr) {
+ int utf8_len, utf16_buffer_len, utf16_len;
+ WCHAR* utf16_buffer;
+ int err;
+
+ if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) {
+ return UV_EINVAL;
+ }
+
+ if (*size_ptr > 32768) {
+ /* Windows paths can never be longer than this. */
+ utf16_buffer_len = 32768;
+ } else {
+ utf16_buffer_len = (int) *size_ptr;
+ }
+
+ utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len);
+ if (!utf16_buffer) {
+ return UV_ENOMEM;
+ }
+
+ /* Get the path as UTF-16. */
+ utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
+ if (utf16_len <= 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ /* utf16_len contains the length, *not* including the terminating null. */
+ utf16_buffer[utf16_len] = L'\0';
+
+ /* Convert to UTF-8 */
+ utf8_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ buffer,
+ (int) *size_ptr,
+ NULL,
+ NULL);
+ if (utf8_len == 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ uv__free(utf16_buffer);
+
+ /* utf8_len *does* include the terminating null at this point, but the */
+ /* returned size shouldn't. */
+ *size_ptr = utf8_len - 1;
+ return 0;
+
+ error:
+ uv__free(utf16_buffer);
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_cwd(char* buffer, size_t* size) {
+ DWORD utf16_len;
+ WCHAR utf16_buffer[MAX_PATH];
+ int r;
+
+ if (buffer == NULL || size == NULL) {
+ return UV_EINVAL;
+ }
+
+ utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
+ if (utf16_len == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (utf16_len > MAX_PATH) {
+ /* This should be impossible; however the CRT has a code path to deal */
+ /* with this scenario, so I added a check anyway. */
+ return UV_EIO;
+ }
+
+ /* utf16_len contains the length, *not* including the terminating null. */
+ utf16_buffer[utf16_len] = L'\0';
+
+ /* The returned directory should not have a trailing slash, unless it */
+ /* points at a drive root, like c:\. Remove it if needed.*/
+ if (utf16_buffer[utf16_len - 1] == L'\\' &&
+ !(utf16_len == 3 && utf16_buffer[1] == L':')) {
+ utf16_len--;
+ utf16_buffer[utf16_len] = L'\0';
+ }
+
+ /* Check how much space we need */
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (r == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (r > (int) *size) {
+ *size = r;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ buffer,
+ *size > INT_MAX ? INT_MAX : (int) *size,
+ NULL,
+ NULL);
+ if (r == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ *size = r - 1;
+ return 0;
+}
+
+
+int uv_chdir(const char* dir) {
+ WCHAR utf16_buffer[MAX_PATH];
+ size_t utf16_len;
+ WCHAR drive_letter, env_var[4];
+
+ if (dir == NULL) {
+ return UV_EINVAL;
+ }
+
+ if (MultiByteToWideChar(CP_UTF8,
+ 0,
+ dir,
+ -1,
+ utf16_buffer,
+ MAX_PATH) == 0) {
+ DWORD error = GetLastError();
+ /* The maximum length of the current working directory is 260 chars, */
+ /* including terminating null. If it doesn't fit, the path name must be */
+ /* too long. */
+ if (error == ERROR_INSUFFICIENT_BUFFER) {
+ return UV_ENAMETOOLONG;
+ } else {
+ return uv_translate_sys_error(error);
+ }
+ }
+
+ if (!SetCurrentDirectoryW(utf16_buffer)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Windows stores the drive-local path in an "hidden" environment variable, */
+ /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */
+ /* update this, so we'll have to do it. */
+ utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
+ if (utf16_len == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (utf16_len > MAX_PATH) {
+ return UV_EIO;
+ }
+
+ /* The returned directory should not have a trailing slash, unless it */
+ /* points at a drive root, like c:\. Remove it if needed. */
+ if (utf16_buffer[utf16_len - 1] == L'\\' &&
+ !(utf16_len == 3 && utf16_buffer[1] == L':')) {
+ utf16_len--;
+ utf16_buffer[utf16_len] = L'\0';
+ }
+
+ if (utf16_len < 2 || utf16_buffer[1] != L':') {
+ /* Doesn't look like a drive letter could be there - probably an UNC */
+ /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */
+ drive_letter = 0;
+ } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
+ drive_letter = utf16_buffer[0];
+ } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') {
+ /* Convert to uppercase. */
+ drive_letter = utf16_buffer[0] - L'a' + L'A';
+ } else {
+ /* Not valid. */
+ drive_letter = 0;
+ }
+
+ if (drive_letter != 0) {
+ /* Construct the environment variable name and set it. */
+ env_var[0] = L'=';
+ env_var[1] = drive_letter;
+ env_var[2] = L':';
+ env_var[3] = L'\0';
+
+ if (!SetEnvironmentVariableW(env_var, utf16_buffer)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+ }
+
+ return 0;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ /* Can't be implemented */
+ avg[0] = avg[1] = avg[2] = 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ MEMORYSTATUSEX memory_status;
+ memory_status.dwLength = sizeof(memory_status);
+
+ if (!GlobalMemoryStatusEx(&memory_status)) {
+ return -1;
+ }
+
+ return (uint64_t)memory_status.ullAvailPhys;
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ MEMORYSTATUSEX memory_status;
+ memory_status.dwLength = sizeof(memory_status);
+
+ if (!GlobalMemoryStatusEx(&memory_status)) {
+ return -1;
+ }
+
+ return (uint64_t)memory_status.ullTotalPhys;
+}
+
+
+int uv_parent_pid() {
+ int parent_pid = -1;
+ HANDLE handle;
+ PROCESSENTRY32 pe;
+ DWORD current_pid = GetCurrentProcessId();
+
+ pe.dwSize = sizeof(PROCESSENTRY32);
+ handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+
+ if (Process32First(handle, &pe)) {
+ do {
+ if (pe.th32ProcessID == current_pid) {
+ parent_pid = pe.th32ParentProcessID;
+ break;
+ }
+ } while( Process32Next(handle, &pe));
+ }
+
+ CloseHandle(handle);
+ return parent_pid;
+}
+
+
+int uv_current_pid() {
+ if (current_pid == 0) {
+ current_pid = GetCurrentProcessId();
+ }
+ return current_pid;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ int err;
+ int length;
+ WCHAR* title_w = NULL;
+
+ uv__once_init();
+
+ /* Find out how big the buffer for the wide-char title must be */
+ length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
+ if (!length) {
+ err = GetLastError();
+ goto done;
+ }
+
+ /* Convert to wide-char string */
+ title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length);
+ if (!title_w) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length);
+ if (!length) {
+ err = GetLastError();
+ goto done;
+ }
+
+ /* If the title must be truncated insert a \0 terminator there */
+ if (length > MAX_TITLE_LENGTH) {
+ title_w[MAX_TITLE_LENGTH - 1] = L'\0';
+ }
+
+ if (!SetConsoleTitleW(title_w)) {
+ err = GetLastError();
+ goto done;
+ }
+
+ EnterCriticalSection(&process_title_lock);
+ uv__free(process_title);
+ process_title = uv__strdup(title);
+ LeaveCriticalSection(&process_title_lock);
+
+ err = 0;
+
+done:
+ uv__free(title_w);
+ return uv_translate_sys_error(err);
+}
+
+
+static int uv__get_process_title() {
+ WCHAR title_w[MAX_TITLE_LENGTH];
+
+ if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {
+ return -1;
+ }
+
+ if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0)
+ return -1;
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ size_t len;
+
+ if (buffer == NULL || size == 0)
+ return UV_EINVAL;
+
+ uv__once_init();
+
+ EnterCriticalSection(&process_title_lock);
+ /*
+ * If the process_title was never read before nor explicitly set,
+ * we must query it with getConsoleTitleW
+ */
+ if (!process_title && uv__get_process_title() == -1) {
+ LeaveCriticalSection(&process_title_lock);
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ assert(process_title);
+ len = strlen(process_title) + 1;
+
+ if (size < len) {
+ LeaveCriticalSection(&process_title_lock);
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, process_title, len);
+ LeaveCriticalSection(&process_title_lock);
+
+ return 0;
+}
+
+
+uint64_t uv_hrtime(void) {
+ uv__once_init();
+ return uv__hrtime(UV__NANOSEC);
+}
+
+uint64_t uv__hrtime(double scale) {
+ LARGE_INTEGER counter;
+
+ /* If the performance interval is zero, there's no support. */
+ if (hrtime_interval_ == 0) {
+ return 0;
+ }
+
+ if (!QueryPerformanceCounter(&counter)) {
+ return 0;
+ }
+
+ /* Because we have no guarantee about the order of magnitude of the
+ * performance counter interval, integer math could cause this computation
+ * to overflow. Therefore we resort to floating point math.
+ */
+ return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale);
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ HANDLE current_process;
+ PROCESS_MEMORY_COUNTERS pmc;
+
+ current_process = GetCurrentProcess();
+
+ if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ *rss = pmc.WorkingSetSize;
+
+ return 0;
+}
+
+
+int uv_uptime(double* uptime) {
+ BYTE stack_buffer[4096];
+ BYTE* malloced_buffer = NULL;
+ BYTE* buffer = (BYTE*) stack_buffer;
+ size_t buffer_size = sizeof(stack_buffer);
+ DWORD data_size;
+
+ PERF_DATA_BLOCK* data_block;
+ PERF_OBJECT_TYPE* object_type;
+ PERF_COUNTER_DEFINITION* counter_definition;
+
+ DWORD i;
+
+ for (;;) {
+ LONG result;
+
+ data_size = (DWORD) buffer_size;
+ result = RegQueryValueExW(HKEY_PERFORMANCE_DATA,
+ L"2",
+ NULL,
+ NULL,
+ buffer,
+ &data_size);
+ if (result == ERROR_SUCCESS) {
+ break;
+ } else if (result != ERROR_MORE_DATA) {
+ *uptime = 0;
+ return uv_translate_sys_error(result);
+ }
+
+ buffer_size *= 2;
+ /* Don't let the buffer grow infinitely. */
+ if (buffer_size > 1 << 20) {
+ goto internalError;
+ }
+
+ uv__free(malloced_buffer);
+
+ buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size);
+ if (malloced_buffer == NULL) {
+ *uptime = 0;
+ return UV_ENOMEM;
+ }
+ }
+
+ if (data_size < sizeof(*data_block))
+ goto internalError;
+
+ data_block = (PERF_DATA_BLOCK*) buffer;
+
+ if (wmemcmp(data_block->Signature, L"PERF", 4) != 0)
+ goto internalError;
+
+ if (data_size < data_block->HeaderLength + sizeof(*object_type))
+ goto internalError;
+
+ object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength);
+
+ if (object_type->NumInstances != PERF_NO_INSTANCES)
+ goto internalError;
+
+ counter_definition = (PERF_COUNTER_DEFINITION*) (buffer +
+ data_block->HeaderLength + object_type->HeaderLength);
+ for (i = 0; i < object_type->NumCounters; i++) {
+ if ((BYTE*) counter_definition + sizeof(*counter_definition) >
+ buffer + data_size) {
+ break;
+ }
+
+ if (counter_definition->CounterNameTitleIndex == 674 &&
+ counter_definition->CounterSize == sizeof(uint64_t)) {
+ if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size ||
+ !(counter_definition->CounterType & PERF_OBJECT_TIMER)) {
+ goto internalError;
+ } else {
+ BYTE* address = (BYTE*) object_type + object_type->DefinitionLength +
+ counter_definition->CounterOffset;
+ uint64_t value = *((uint64_t*) address);
+ *uptime = (double) (object_type->PerfTime.QuadPart - value) /
+ (double) object_type->PerfFreq.QuadPart;
+ uv__free(malloced_buffer);
+ return 0;
+ }
+ }
+
+ counter_definition = (PERF_COUNTER_DEFINITION*)
+ ((BYTE*) counter_definition + counter_definition->ByteLength);
+ }
+
+ /* If we get here, the uptime value was not found. */
+ uv__free(malloced_buffer);
+ *uptime = 0;
+ return UV_ENOSYS;
+
+ internalError:
+ uv__free(malloced_buffer);
+ *uptime = 0;
+ return UV_EIO;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
+ uv_cpu_info_t* cpu_infos;
+ SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
+ DWORD sppi_size;
+ SYSTEM_INFO system_info;
+ DWORD cpu_count, r, i;
+ NTSTATUS status;
+ ULONG result_size;
+ int err;
+ uv_cpu_info_t* cpu_info;
+
+ cpu_infos = NULL;
+ cpu_count = 0;
+ sppi = NULL;
+
+ uv__once_init();
+
+ GetSystemInfo(&system_info);
+ cpu_count = system_info.dwNumberOfProcessors;
+
+ cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos);
+ if (cpu_infos == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ sppi_size = cpu_count * sizeof(*sppi);
+ sppi = uv__malloc(sppi_size);
+ if (sppi == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
+ sppi,
+ sppi_size,
+ &result_size);
+ if (!NT_SUCCESS(status)) {
+ err = pRtlNtStatusToDosError(status);
+ goto error;
+ }
+
+ assert(result_size == sppi_size);
+
+ for (i = 0; i < cpu_count; i++) {
+ WCHAR key_name[128];
+ HKEY processor_key;
+ DWORD cpu_speed;
+ DWORD cpu_speed_size = sizeof(cpu_speed);
+ WCHAR cpu_brand[256];
+ DWORD cpu_brand_size = sizeof(cpu_brand);
+ size_t len;
+
+ len = _snwprintf(key_name,
+ ARRAY_SIZE(key_name),
+ L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
+ i);
+
+ assert(len > 0 && len < ARRAY_SIZE(key_name));
+
+ r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ key_name,
+ 0,
+ KEY_QUERY_VALUE,
+ &processor_key);
+ if (r != ERROR_SUCCESS) {
+ err = GetLastError();
+ goto error;
+ }
+
+ if (RegQueryValueExW(processor_key,
+ L"~MHz",
+ NULL,
+ NULL,
+ (BYTE*) &cpu_speed,
+ &cpu_speed_size) != ERROR_SUCCESS) {
+ err = GetLastError();
+ RegCloseKey(processor_key);
+ goto error;
+ }
+
+ if (RegQueryValueExW(processor_key,
+ L"ProcessorNameString",
+ NULL,
+ NULL,
+ (BYTE*) &cpu_brand,
+ &cpu_brand_size) != ERROR_SUCCESS) {
+ err = GetLastError();
+ RegCloseKey(processor_key);
+ goto error;
+ }
+
+ RegCloseKey(processor_key);
+
+ cpu_info = &cpu_infos[i];
+ cpu_info->speed = cpu_speed;
+ cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
+ cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
+ sppi[i].IdleTime.QuadPart) / 10000;
+ cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
+ cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
+ cpu_info->cpu_times.nice = 0;
+
+ uv__convert_utf16_to_utf8(cpu_brand,
+ cpu_brand_size / sizeof(WCHAR),
+ &(cpu_info->model));
+ }
+
+ uv__free(sppi);
+
+ *cpu_count_ptr = cpu_count;
+ *cpu_infos_ptr = cpu_infos;
+
+ return 0;
+
+ error:
+ /* This is safe because the cpu_infos array is zeroed on allocation. */
+ for (i = 0; i < cpu_count; i++)
+ uv__free(cpu_infos[i].model);
+
+ uv__free(cpu_infos);
+ uv__free(sppi);
+
+ return uv_translate_sys_error(err);
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+static int is_windows_version_or_greater(DWORD os_major,
+ DWORD os_minor,
+ WORD service_pack_major,
+ WORD service_pack_minor) {
+ OSVERSIONINFOEX osvi;
+ DWORDLONG condition_mask = 0;
+ int op = VER_GREATER_EQUAL;
+
+ /* Initialize the OSVERSIONINFOEX structure. */
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ osvi.dwMajorVersion = os_major;
+ osvi.dwMinorVersion = os_minor;
+ osvi.wServicePackMajor = service_pack_major;
+ osvi.wServicePackMinor = service_pack_minor;
+
+ /* Initialize the condition mask. */
+ VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
+ VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
+ VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
+ VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
+
+ /* Perform the test. */
+ return (int) VerifyVersionInfo(
+ &osvi,
+ VER_MAJORVERSION | VER_MINORVERSION |
+ VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
+ condition_mask);
+}
+
+
+static int address_prefix_match(int family,
+ struct sockaddr* address,
+ struct sockaddr* prefix_address,
+ int prefix_len) {
+ uint8_t* address_data;
+ uint8_t* prefix_address_data;
+ int i;
+
+ assert(address->sa_family == family);
+ assert(prefix_address->sa_family == family);
+
+ if (family == AF_INET6) {
+ address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr);
+ prefix_address_data =
+ (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
+ } else {
+ address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr);
+ prefix_address_data =
+ (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr);
+ }
+
+ for (i = 0; i < prefix_len >> 3; i++) {
+ if (address_data[i] != prefix_address_data[i])
+ return 0;
+ }
+
+ if (prefix_len % 8)
+ return prefix_address_data[i] ==
+ (address_data[i] & (0xff << (8 - prefix_len % 8)));
+
+ return 1;
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
+ int* count_ptr) {
+ IP_ADAPTER_ADDRESSES* win_address_buf;
+ ULONG win_address_buf_size;
+ IP_ADAPTER_ADDRESSES* adapter;
+
+ uv_interface_address_t* uv_address_buf;
+ char* name_buf;
+ size_t uv_address_buf_size;
+ uv_interface_address_t* uv_address;
+
+ int count;
+
+ int is_vista_or_greater;
+ ULONG flags;
+
+ is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
+ if (is_vista_or_greater) {
+ flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+ GAA_FLAG_SKIP_DNS_SERVER;
+ } else {
+ /* We need at least XP SP1. */
+ if (!is_windows_version_or_greater(5, 1, 1, 0))
+ return UV_ENOTSUP;
+
+ flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+ GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
+ }
+
+
+ /* Fetch the size of the adapters reported by windows, and then get the */
+ /* list itself. */
+ win_address_buf_size = 0;
+ win_address_buf = NULL;
+
+ for (;;) {
+ ULONG r;
+
+ /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */
+ /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */
+ /* win_address_buf_size. */
+ r = GetAdaptersAddresses(AF_UNSPEC,
+ flags,
+ NULL,
+ win_address_buf,
+ &win_address_buf_size);
+
+ if (r == ERROR_SUCCESS)
+ break;
+
+ uv__free(win_address_buf);
+
+ switch (r) {
+ case ERROR_BUFFER_OVERFLOW:
+ /* This happens when win_address_buf is NULL or too small to hold */
+ /* all adapters. */
+ win_address_buf = uv__malloc(win_address_buf_size);
+ if (win_address_buf == NULL)
+ return UV_ENOMEM;
+
+ continue;
+
+ case ERROR_NO_DATA: {
+ /* No adapters were found. */
+ uv_address_buf = uv__malloc(1);
+ if (uv_address_buf == NULL)
+ return UV_ENOMEM;
+
+ *count_ptr = 0;
+ *addresses_ptr = uv_address_buf;
+
+ return 0;
+ }
+
+ case ERROR_ADDRESS_NOT_ASSOCIATED:
+ return UV_EAGAIN;
+
+ case ERROR_INVALID_PARAMETER:
+ /* MSDN says:
+ * "This error is returned for any of the following conditions: the
+ * SizePointer parameter is NULL, the Address parameter is not
+ * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for
+ * the parameters requested is greater than ULONG_MAX."
+ * Since the first two conditions are not met, it must be that the
+ * adapter data is too big.
+ */
+ return UV_ENOBUFS;
+
+ default:
+ /* Other (unspecified) errors can happen, but we don't have any */
+ /* special meaning for them. */
+ assert(r != ERROR_SUCCESS);
+ return uv_translate_sys_error(r);
+ }
+ }
+
+ /* Count the number of enabled interfaces and compute how much space is */
+ /* needed to store their info. */
+ count = 0;
+ uv_address_buf_size = 0;
+
+ for (adapter = win_address_buf;
+ adapter != NULL;
+ adapter = adapter->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
+ int name_size;
+
+ /* Interfaces that are not 'up' should not be reported. Also skip */
+ /* interfaces that have no associated unicast address, as to avoid */
+ /* allocating space for the name for this interface. */
+ if (adapter->OperStatus != IfOperStatusUp ||
+ adapter->FirstUnicastAddress == NULL)
+ continue;
+
+ /* Compute the size of the interface name. */
+ name_size = WideCharToMultiByte(CP_UTF8,
+ 0,
+ adapter->FriendlyName,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ FALSE);
+ if (name_size <= 0) {
+ uv__free(win_address_buf);
+ return uv_translate_sys_error(GetLastError());
+ }
+ uv_address_buf_size += name_size;
+
+ /* Count the number of addresses associated with this interface, and */
+ /* compute the size. */
+ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
+ adapter->FirstUnicastAddress;
+ unicast_address != NULL;
+ unicast_address = unicast_address->Next) {
+ count++;
+ uv_address_buf_size += sizeof(uv_interface_address_t);
+ }
+ }
+
+ /* Allocate space to store interface data plus adapter names. */
+ uv_address_buf = uv__malloc(uv_address_buf_size);
+ if (uv_address_buf == NULL) {
+ uv__free(win_address_buf);
+ return UV_ENOMEM;
+ }
+
+ /* Compute the start of the uv_interface_address_t array, and the place in */
+ /* the buffer where the interface names will be stored. */
+ uv_address = uv_address_buf;
+ name_buf = (char*) (uv_address_buf + count);
+
+ /* Fill out the output buffer. */
+ for (adapter = win_address_buf;
+ adapter != NULL;
+ adapter = adapter->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
+ int name_size;
+ size_t max_name_size;
+
+ if (adapter->OperStatus != IfOperStatusUp ||
+ adapter->FirstUnicastAddress == NULL)
+ continue;
+
+ /* Convert the interface name to UTF8. */
+ max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
+ if (max_name_size > (size_t) INT_MAX)
+ max_name_size = INT_MAX;
+ name_size = WideCharToMultiByte(CP_UTF8,
+ 0,
+ adapter->FriendlyName,
+ -1,
+ name_buf,
+ (int) max_name_size,
+ NULL,
+ FALSE);
+ if (name_size <= 0) {
+ uv__free(win_address_buf);
+ uv__free(uv_address_buf);
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Add an uv_interface_address_t element for every unicast address. */
+ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
+ adapter->FirstUnicastAddress;
+ unicast_address != NULL;
+ unicast_address = unicast_address->Next) {
+ struct sockaddr* sa;
+ ULONG prefix_len;
+
+ sa = unicast_address->Address.lpSockaddr;
+
+ /* XP has no OnLinkPrefixLength field. */
+ if (is_vista_or_greater) {
+ prefix_len =
+ ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
+ } else {
+ /* Prior to Windows Vista the FirstPrefix pointed to the list with
+ * single prefix for each IP address assigned to the adapter.
+ * Order of FirstPrefix does not match order of FirstUnicastAddress,
+ * so we need to find corresponding prefix.
+ */
+ IP_ADAPTER_PREFIX* prefix;
+ prefix_len = 0;
+
+ for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
+ /* We want the longest matching prefix. */
+ if (prefix->Address.lpSockaddr->sa_family != sa->sa_family ||
+ prefix->PrefixLength <= prefix_len)
+ continue;
+
+ if (address_prefix_match(sa->sa_family, sa,
+ prefix->Address.lpSockaddr, prefix->PrefixLength)) {
+ prefix_len = prefix->PrefixLength;
+ }
+ }
+
+ /* If there is no matching prefix information, return a single-host
+ * subnet mask (e.g. 255.255.255.255 for IPv4).
+ */
+ if (!prefix_len)
+ prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
+ }
+
+ memset(uv_address, 0, sizeof *uv_address);
+
+ uv_address->name = name_buf;
+
+ if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
+ memcpy(uv_address->phys_addr,
+ adapter->PhysicalAddress,
+ sizeof(uv_address->phys_addr));
+ }
+
+ uv_address->is_internal =
+ (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
+
+ if (sa->sa_family == AF_INET6) {
+ uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
+
+ uv_address->netmask.netmask6.sin6_family = AF_INET6;
+ memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
+ /* This check ensures that we don't write past the size of the data. */
+ if (prefix_len % 8) {
+ uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
+ 0xff << (8 - prefix_len % 8);
+ }
+
+ } else {
+ uv_address->address.address4 = *((struct sockaddr_in *) sa);
+
+ uv_address->netmask.netmask4.sin_family = AF_INET;
+ uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
+ htonl(0xffffffff << (32 - prefix_len)) : 0;
+ }
+
+ uv_address++;
+ }
+
+ name_buf += name_size;
+ }
+
+ uv__free(win_address_buf);
+
+ *addresses_ptr = uv_address_buf;
+ *count_ptr = count;
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ uv__free(addresses);
+}
+
+
+int uv_getrusage(uv_rusage_t *uv_rusage) {
+ FILETIME createTime, exitTime, kernelTime, userTime;
+ SYSTEMTIME kernelSystemTime, userSystemTime;
+ PROCESS_MEMORY_COUNTERS memCounters;
+ IO_COUNTERS ioCounters;
+ int ret;
+
+ ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ ret = FileTimeToSystemTime(&userTime, &userSystemTime);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ ret = GetProcessMemoryInfo(GetCurrentProcess(),
+ &memCounters,
+ sizeof(memCounters));
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ memset(uv_rusage, 0, sizeof(*uv_rusage));
+
+ uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
+ userSystemTime.wMinute * 60 +
+ userSystemTime.wSecond;
+ uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
+
+ uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 +
+ kernelSystemTime.wMinute * 60 +
+ kernelSystemTime.wSecond;
+ uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000;
+
+ uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
+ uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
+
+ uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
+ uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
+
+ return 0;
+}
+
+
+int uv_os_homedir(char* buffer, size_t* size) {
+ uv_passwd_t pwd;
+ wchar_t path[MAX_PATH];
+ DWORD bufsize;
+ size_t len;
+ int r;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ /* Check if the USERPROFILE environment variable is set first */
+ len = GetEnvironmentVariableW(L"USERPROFILE", path, MAX_PATH);
+
+ if (len == 0) {
+ r = GetLastError();
+
+ /* Don't return an error if USERPROFILE was not found */
+ if (r != ERROR_ENVVAR_NOT_FOUND)
+ return uv_translate_sys_error(r);
+ } else if (len > MAX_PATH) {
+ /* This should not be possible */
+ return UV_EIO;
+ } else {
+ /* Check how much space we need */
+ bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
+
+ if (bufsize == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (bufsize > *size) {
+ *size = bufsize;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ path,
+ -1,
+ buffer,
+ *size,
+ NULL,
+ NULL);
+
+ if (bufsize == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ *size = bufsize - 1;
+ return 0;
+ }
+
+ /* USERPROFILE is not set, so call uv__getpwuid_r() */
+ r = uv__getpwuid_r(&pwd);
+
+ if (r != 0) {
+ return r;
+ }
+
+ len = strlen(pwd.homedir);
+
+ if (len >= *size) {
+ *size = len + 1;
+ uv_os_free_passwd(&pwd);
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, pwd.homedir, len + 1);
+ *size = len;
+ uv_os_free_passwd(&pwd);
+
+ return 0;
+}
+
+
+int uv_os_tmpdir(char* buffer, size_t* size) {
+ wchar_t path[MAX_PATH + 1];
+ DWORD bufsize;
+ size_t len;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ len = GetTempPathW(MAX_PATH + 1, path);
+
+ if (len == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (len > MAX_PATH + 1) {
+ /* This should not be possible */
+ return UV_EIO;
+ }
+
+ /* The returned directory should not have a trailing slash, unless it */
+ /* points at a drive root, like c:\. Remove it if needed.*/
+ if (path[len - 1] == L'\\' &&
+ !(len == 3 && path[1] == L':')) {
+ len--;
+ path[len] = L'\0';
+ }
+
+ /* Check how much space we need */
+ bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
+
+ if (bufsize == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (bufsize > *size) {
+ *size = bufsize;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ path,
+ -1,
+ buffer,
+ *size,
+ NULL,
+ NULL);
+
+ if (bufsize == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ *size = bufsize - 1;
+ return 0;
+}
+
+
+void uv_os_free_passwd(uv_passwd_t* pwd) {
+ if (pwd == NULL)
+ return;
+
+ uv__free(pwd->username);
+ uv__free(pwd->homedir);
+ pwd->username = NULL;
+ pwd->homedir = NULL;
+}
+
+
+/*
+ * Converts a UTF-16 string into a UTF-8 one. The resulting string is
+ * null-terminated.
+ *
+ * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
+ * be specified.
+ */
+int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) {
+ DWORD bufsize;
+
+ if (utf16 == NULL)
+ return UV_EINVAL;
+
+ /* Check how much space we need */
+ bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16,
+ utf16len,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+
+ if (bufsize == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ /* Allocate the destination buffer adding an extra byte for the terminating
+ * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so
+ * we do it ourselves always, just in case. */
+ *utf8 = uv__malloc(bufsize + 1);
+
+ if (*utf8 == NULL)
+ return UV_ENOMEM;
+
+ /* Convert to UTF-8 */
+ bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16,
+ utf16len,
+ *utf8,
+ bufsize,
+ NULL,
+ NULL);
+
+ if (bufsize == 0) {
+ uv__free(*utf8);
+ *utf8 = NULL;
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ (*utf8)[bufsize] = '\0';
+ return 0;
+}
+
+
+int uv__getpwuid_r(uv_passwd_t* pwd) {
+ HANDLE token;
+ wchar_t username[UNLEN + 1];
+ wchar_t path[MAX_PATH];
+ DWORD bufsize;
+ int r;
+
+ if (pwd == NULL)
+ return UV_EINVAL;
+
+ /* Get the home directory using GetUserProfileDirectoryW() */
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ bufsize = sizeof(path);
+ if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
+ r = GetLastError();
+ CloseHandle(token);
+
+ /* This should not be possible */
+ if (r == ERROR_INSUFFICIENT_BUFFER)
+ return UV_ENOMEM;
+
+ return uv_translate_sys_error(r);
+ }
+
+ CloseHandle(token);
+
+ /* Get the username using GetUserNameW() */
+ bufsize = sizeof(username);
+ if (!GetUserNameW(username, &bufsize)) {
+ r = GetLastError();
+
+ /* This should not be possible */
+ if (r == ERROR_INSUFFICIENT_BUFFER)
+ return UV_ENOMEM;
+
+ return uv_translate_sys_error(r);
+ }
+
+ pwd->homedir = NULL;
+ r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
+
+ if (r != 0)
+ return r;
+
+ pwd->username = NULL;
+ r = uv__convert_utf16_to_utf8(username, -1, &pwd->username);
+
+ if (r != 0) {
+ uv__free(pwd->homedir);
+ return r;
+ }
+
+ pwd->shell = NULL;
+ pwd->uid = -1;
+ pwd->gid = -1;
+
+ return 0;
+}
+
+
+int uv_os_get_passwd(uv_passwd_t* pwd) {
+ return uv__getpwuid_r(pwd);
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/* Ntdll function pointers */
+sRtlNtStatusToDosError pRtlNtStatusToDosError;
+sNtDeviceIoControlFile pNtDeviceIoControlFile;
+sNtQueryInformationFile pNtQueryInformationFile;
+sNtSetInformationFile pNtSetInformationFile;
+sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
+sNtQueryDirectoryFile pNtQueryDirectoryFile;
+sNtQuerySystemInformation pNtQuerySystemInformation;
+
+
+/* Kernel32 function pointers */
+sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
+sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
+sCreateSymbolicLinkW pCreateSymbolicLinkW;
+sCancelIoEx pCancelIoEx;
+sInitializeConditionVariable pInitializeConditionVariable;
+sSleepConditionVariableCS pSleepConditionVariableCS;
+sSleepConditionVariableSRW pSleepConditionVariableSRW;
+sWakeAllConditionVariable pWakeAllConditionVariable;
+sWakeConditionVariable pWakeConditionVariable;
+sCancelSynchronousIo pCancelSynchronousIo;
+sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
+
+
+/* Powrprof.dll function pointer */
+sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
+
+
+void uv_winapi_init() {
+ HMODULE ntdll_module;
+ HMODULE kernel32_module;
+ HMODULE powrprof_module;
+
+ ntdll_module = GetModuleHandleA("ntdll.dll");
+ if (ntdll_module == NULL) {
+ uv_fatal_error(GetLastError(), "GetModuleHandleA");
+ }
+
+ pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
+ ntdll_module,
+ "RtlNtStatusToDosError");
+ if (pRtlNtStatusToDosError == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtDeviceIoControlFile = (sNtDeviceIoControlFile) GetProcAddress(
+ ntdll_module,
+ "NtDeviceIoControlFile");
+ if (pNtDeviceIoControlFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress(
+ ntdll_module,
+ "NtQueryInformationFile");
+ if (pNtQueryInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress(
+ ntdll_module,
+ "NtSetInformationFile");
+ if (pNtSetInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQueryVolumeInformationFile = (sNtQueryVolumeInformationFile)
+ GetProcAddress(ntdll_module, "NtQueryVolumeInformationFile");
+ if (pNtQueryVolumeInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQueryDirectoryFile = (sNtQueryDirectoryFile)
+ GetProcAddress(ntdll_module, "NtQueryDirectoryFile");
+ if (pNtQueryVolumeInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress(
+ ntdll_module,
+ "NtQuerySystemInformation");
+ if (pNtQuerySystemInformation == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ kernel32_module = GetModuleHandleA("kernel32.dll");
+ if (kernel32_module == NULL) {
+ uv_fatal_error(GetLastError(), "GetModuleHandleA");
+ }
+
+ pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress(
+ kernel32_module,
+ "GetQueuedCompletionStatusEx");
+
+ pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes)
+ GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes");
+
+ pCreateSymbolicLinkW = (sCreateSymbolicLinkW)
+ GetProcAddress(kernel32_module, "CreateSymbolicLinkW");
+
+ pCancelIoEx = (sCancelIoEx)
+ GetProcAddress(kernel32_module, "CancelIoEx");
+
+ pInitializeConditionVariable = (sInitializeConditionVariable)
+ GetProcAddress(kernel32_module, "InitializeConditionVariable");
+
+ pSleepConditionVariableCS = (sSleepConditionVariableCS)
+ GetProcAddress(kernel32_module, "SleepConditionVariableCS");
+
+ pSleepConditionVariableSRW = (sSleepConditionVariableSRW)
+ GetProcAddress(kernel32_module, "SleepConditionVariableSRW");
+
+ pWakeAllConditionVariable = (sWakeAllConditionVariable)
+ GetProcAddress(kernel32_module, "WakeAllConditionVariable");
+
+ pWakeConditionVariable = (sWakeConditionVariable)
+ GetProcAddress(kernel32_module, "WakeConditionVariable");
+
+ pCancelSynchronousIo = (sCancelSynchronousIo)
+ GetProcAddress(kernel32_module, "CancelSynchronousIo");
+
+ pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW)
+ GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW");
+
+
+ powrprof_module = LoadLibraryA("powrprof.dll");
+ if (powrprof_module != NULL) {
+ pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
+ GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
+ }
+
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef UV_WIN_WINAPI_H_
+#define UV_WIN_WINAPI_H_
+
+#include <windows.h>
+
+
+/*
+ * Ntdll headers
+ */
+#ifndef STATUS_SEVERITY_SUCCESS
+# define STATUS_SEVERITY_SUCCESS 0x0
+#endif
+
+#ifndef STATUS_SEVERITY_INFORMATIONAL
+# define STATUS_SEVERITY_INFORMATIONAL 0x1
+#endif
+
+#ifndef STATUS_SEVERITY_WARNING
+# define STATUS_SEVERITY_WARNING 0x2
+#endif
+
+#ifndef STATUS_SEVERITY_ERROR
+# define STATUS_SEVERITY_ERROR 0x3
+#endif
+
+#ifndef FACILITY_NTWIN32
+# define FACILITY_NTWIN32 0x7
+#endif
+
+#ifndef NT_SUCCESS
+# define NT_SUCCESS(status) (((NTSTATUS) (status)) >= 0)
+#endif
+
+#ifndef NT_INFORMATION
+# define NT_INFORMATION(status) ((((ULONG) (status)) >> 30) == 1)
+#endif
+
+#ifndef NT_WARNING
+# define NT_WARNING(status) ((((ULONG) (status)) >> 30) == 2)
+#endif
+
+#ifndef NT_ERROR
+# define NT_ERROR(status) ((((ULONG) (status)) >> 30) == 3)
+#endif
+
+#ifndef STATUS_SUCCESS
+# define STATUS_SUCCESS ((NTSTATUS) 0x00000000L)
+#endif
+
+#ifndef STATUS_WAIT_0
+# define STATUS_WAIT_0 ((NTSTATUS) 0x00000000L)
+#endif
+
+#ifndef STATUS_WAIT_1
+# define STATUS_WAIT_1 ((NTSTATUS) 0x00000001L)
+#endif
+
+#ifndef STATUS_WAIT_2
+# define STATUS_WAIT_2 ((NTSTATUS) 0x00000002L)
+#endif
+
+#ifndef STATUS_WAIT_3
+# define STATUS_WAIT_3 ((NTSTATUS) 0x00000003L)
+#endif
+
+#ifndef STATUS_WAIT_63
+# define STATUS_WAIT_63 ((NTSTATUS) 0x0000003FL)
+#endif
+
+#ifndef STATUS_ABANDONED
+# define STATUS_ABANDONED ((NTSTATUS) 0x00000080L)
+#endif
+
+#ifndef STATUS_ABANDONED_WAIT_0
+# define STATUS_ABANDONED_WAIT_0 ((NTSTATUS) 0x00000080L)
+#endif
+
+#ifndef STATUS_ABANDONED_WAIT_63
+# define STATUS_ABANDONED_WAIT_63 ((NTSTATUS) 0x000000BFL)
+#endif
+
+#ifndef STATUS_USER_APC
+# define STATUS_USER_APC ((NTSTATUS) 0x000000C0L)
+#endif
+
+#ifndef STATUS_KERNEL_APC
+# define STATUS_KERNEL_APC ((NTSTATUS) 0x00000100L)
+#endif
+
+#ifndef STATUS_ALERTED
+# define STATUS_ALERTED ((NTSTATUS) 0x00000101L)
+#endif
+
+#ifndef STATUS_TIMEOUT
+# define STATUS_TIMEOUT ((NTSTATUS) 0x00000102L)
+#endif
+
+#ifndef STATUS_PENDING
+# define STATUS_PENDING ((NTSTATUS) 0x00000103L)
+#endif
+
+#ifndef STATUS_REPARSE
+# define STATUS_REPARSE ((NTSTATUS) 0x00000104L)
+#endif
+
+#ifndef STATUS_MORE_ENTRIES
+# define STATUS_MORE_ENTRIES ((NTSTATUS) 0x00000105L)
+#endif
+
+#ifndef STATUS_NOT_ALL_ASSIGNED
+# define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS) 0x00000106L)
+#endif
+
+#ifndef STATUS_SOME_NOT_MAPPED
+# define STATUS_SOME_NOT_MAPPED ((NTSTATUS) 0x00000107L)
+#endif
+
+#ifndef STATUS_OPLOCK_BREAK_IN_PROGRESS
+# define STATUS_OPLOCK_BREAK_IN_PROGRESS ((NTSTATUS) 0x00000108L)
+#endif
+
+#ifndef STATUS_VOLUME_MOUNTED
+# define STATUS_VOLUME_MOUNTED ((NTSTATUS) 0x00000109L)
+#endif
+
+#ifndef STATUS_RXACT_COMMITTED
+# define STATUS_RXACT_COMMITTED ((NTSTATUS) 0x0000010AL)
+#endif
+
+#ifndef STATUS_NOTIFY_CLEANUP
+# define STATUS_NOTIFY_CLEANUP ((NTSTATUS) 0x0000010BL)
+#endif
+
+#ifndef STATUS_NOTIFY_ENUM_DIR
+# define STATUS_NOTIFY_ENUM_DIR ((NTSTATUS) 0x0000010CL)
+#endif
+
+#ifndef STATUS_NO_QUOTAS_FOR_ACCOUNT
+# define STATUS_NO_QUOTAS_FOR_ACCOUNT ((NTSTATUS) 0x0000010DL)
+#endif
+
+#ifndef STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED
+# define STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED ((NTSTATUS) 0x0000010EL)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_TRANSITION
+# define STATUS_PAGE_FAULT_TRANSITION ((NTSTATUS) 0x00000110L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_DEMAND_ZERO
+# define STATUS_PAGE_FAULT_DEMAND_ZERO ((NTSTATUS) 0x00000111L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_COPY_ON_WRITE
+# define STATUS_PAGE_FAULT_COPY_ON_WRITE ((NTSTATUS) 0x00000112L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_GUARD_PAGE
+# define STATUS_PAGE_FAULT_GUARD_PAGE ((NTSTATUS) 0x00000113L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_PAGING_FILE
+# define STATUS_PAGE_FAULT_PAGING_FILE ((NTSTATUS) 0x00000114L)
+#endif
+
+#ifndef STATUS_CACHE_PAGE_LOCKED
+# define STATUS_CACHE_PAGE_LOCKED ((NTSTATUS) 0x00000115L)
+#endif
+
+#ifndef STATUS_CRASH_DUMP
+# define STATUS_CRASH_DUMP ((NTSTATUS) 0x00000116L)
+#endif
+
+#ifndef STATUS_BUFFER_ALL_ZEROS
+# define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS) 0x00000117L)
+#endif
+
+#ifndef STATUS_REPARSE_OBJECT
+# define STATUS_REPARSE_OBJECT ((NTSTATUS) 0x00000118L)
+#endif
+
+#ifndef STATUS_RESOURCE_REQUIREMENTS_CHANGED
+# define STATUS_RESOURCE_REQUIREMENTS_CHANGED ((NTSTATUS) 0x00000119L)
+#endif
+
+#ifndef STATUS_TRANSLATION_COMPLETE
+# define STATUS_TRANSLATION_COMPLETE ((NTSTATUS) 0x00000120L)
+#endif
+
+#ifndef STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY
+# define STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY ((NTSTATUS) 0x00000121L)
+#endif
+
+#ifndef STATUS_NOTHING_TO_TERMINATE
+# define STATUS_NOTHING_TO_TERMINATE ((NTSTATUS) 0x00000122L)
+#endif
+
+#ifndef STATUS_PROCESS_NOT_IN_JOB
+# define STATUS_PROCESS_NOT_IN_JOB ((NTSTATUS) 0x00000123L)
+#endif
+
+#ifndef STATUS_PROCESS_IN_JOB
+# define STATUS_PROCESS_IN_JOB ((NTSTATUS) 0x00000124L)
+#endif
+
+#ifndef STATUS_VOLSNAP_HIBERNATE_READY
+# define STATUS_VOLSNAP_HIBERNATE_READY ((NTSTATUS) 0x00000125L)
+#endif
+
+#ifndef STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY
+# define STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY ((NTSTATUS) 0x00000126L)
+#endif
+
+#ifndef STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED
+# define STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED ((NTSTATUS) 0x00000127L)
+#endif
+
+#ifndef STATUS_INTERRUPT_STILL_CONNECTED
+# define STATUS_INTERRUPT_STILL_CONNECTED ((NTSTATUS) 0x00000128L)
+#endif
+
+#ifndef STATUS_PROCESS_CLONED
+# define STATUS_PROCESS_CLONED ((NTSTATUS) 0x00000129L)
+#endif
+
+#ifndef STATUS_FILE_LOCKED_WITH_ONLY_READERS
+# define STATUS_FILE_LOCKED_WITH_ONLY_READERS ((NTSTATUS) 0x0000012AL)
+#endif
+
+#ifndef STATUS_FILE_LOCKED_WITH_WRITERS
+# define STATUS_FILE_LOCKED_WITH_WRITERS ((NTSTATUS) 0x0000012BL)
+#endif
+
+#ifndef STATUS_RESOURCEMANAGER_READ_ONLY
+# define STATUS_RESOURCEMANAGER_READ_ONLY ((NTSTATUS) 0x00000202L)
+#endif
+
+#ifndef STATUS_RING_PREVIOUSLY_EMPTY
+# define STATUS_RING_PREVIOUSLY_EMPTY ((NTSTATUS) 0x00000210L)
+#endif
+
+#ifndef STATUS_RING_PREVIOUSLY_FULL
+# define STATUS_RING_PREVIOUSLY_FULL ((NTSTATUS) 0x00000211L)
+#endif
+
+#ifndef STATUS_RING_PREVIOUSLY_ABOVE_QUOTA
+# define STATUS_RING_PREVIOUSLY_ABOVE_QUOTA ((NTSTATUS) 0x00000212L)
+#endif
+
+#ifndef STATUS_RING_NEWLY_EMPTY
+# define STATUS_RING_NEWLY_EMPTY ((NTSTATUS) 0x00000213L)
+#endif
+
+#ifndef STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT
+# define STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT ((NTSTATUS) 0x00000214L)
+#endif
+
+#ifndef STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE
+# define STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE ((NTSTATUS) 0x00000215L)
+#endif
+
+#ifndef STATUS_OPLOCK_HANDLE_CLOSED
+# define STATUS_OPLOCK_HANDLE_CLOSED ((NTSTATUS) 0x00000216L)
+#endif
+
+#ifndef STATUS_WAIT_FOR_OPLOCK
+# define STATUS_WAIT_FOR_OPLOCK ((NTSTATUS) 0x00000367L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_EXISTS
+# define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS) 0x40000000L)
+#endif
+
+#ifndef STATUS_THREAD_WAS_SUSPENDED
+# define STATUS_THREAD_WAS_SUSPENDED ((NTSTATUS) 0x40000001L)
+#endif
+
+#ifndef STATUS_WORKING_SET_LIMIT_RANGE
+# define STATUS_WORKING_SET_LIMIT_RANGE ((NTSTATUS) 0x40000002L)
+#endif
+
+#ifndef STATUS_IMAGE_NOT_AT_BASE
+# define STATUS_IMAGE_NOT_AT_BASE ((NTSTATUS) 0x40000003L)
+#endif
+
+#ifndef STATUS_RXACT_STATE_CREATED
+# define STATUS_RXACT_STATE_CREATED ((NTSTATUS) 0x40000004L)
+#endif
+
+#ifndef STATUS_SEGMENT_NOTIFICATION
+# define STATUS_SEGMENT_NOTIFICATION ((NTSTATUS) 0x40000005L)
+#endif
+
+#ifndef STATUS_LOCAL_USER_SESSION_KEY
+# define STATUS_LOCAL_USER_SESSION_KEY ((NTSTATUS) 0x40000006L)
+#endif
+
+#ifndef STATUS_BAD_CURRENT_DIRECTORY
+# define STATUS_BAD_CURRENT_DIRECTORY ((NTSTATUS) 0x40000007L)
+#endif
+
+#ifndef STATUS_SERIAL_MORE_WRITES
+# define STATUS_SERIAL_MORE_WRITES ((NTSTATUS) 0x40000008L)
+#endif
+
+#ifndef STATUS_REGISTRY_RECOVERED
+# define STATUS_REGISTRY_RECOVERED ((NTSTATUS) 0x40000009L)
+#endif
+
+#ifndef STATUS_FT_READ_RECOVERY_FROM_BACKUP
+# define STATUS_FT_READ_RECOVERY_FROM_BACKUP ((NTSTATUS) 0x4000000AL)
+#endif
+
+#ifndef STATUS_FT_WRITE_RECOVERY
+# define STATUS_FT_WRITE_RECOVERY ((NTSTATUS) 0x4000000BL)
+#endif
+
+#ifndef STATUS_SERIAL_COUNTER_TIMEOUT
+# define STATUS_SERIAL_COUNTER_TIMEOUT ((NTSTATUS) 0x4000000CL)
+#endif
+
+#ifndef STATUS_NULL_LM_PASSWORD
+# define STATUS_NULL_LM_PASSWORD ((NTSTATUS) 0x4000000DL)
+#endif
+
+#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH
+# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH ((NTSTATUS) 0x4000000EL)
+#endif
+
+#ifndef STATUS_RECEIVE_PARTIAL
+# define STATUS_RECEIVE_PARTIAL ((NTSTATUS) 0x4000000FL)
+#endif
+
+#ifndef STATUS_RECEIVE_EXPEDITED
+# define STATUS_RECEIVE_EXPEDITED ((NTSTATUS) 0x40000010L)
+#endif
+
+#ifndef STATUS_RECEIVE_PARTIAL_EXPEDITED
+# define STATUS_RECEIVE_PARTIAL_EXPEDITED ((NTSTATUS) 0x40000011L)
+#endif
+
+#ifndef STATUS_EVENT_DONE
+# define STATUS_EVENT_DONE ((NTSTATUS) 0x40000012L)
+#endif
+
+#ifndef STATUS_EVENT_PENDING
+# define STATUS_EVENT_PENDING ((NTSTATUS) 0x40000013L)
+#endif
+
+#ifndef STATUS_CHECKING_FILE_SYSTEM
+# define STATUS_CHECKING_FILE_SYSTEM ((NTSTATUS) 0x40000014L)
+#endif
+
+#ifndef STATUS_FATAL_APP_EXIT
+# define STATUS_FATAL_APP_EXIT ((NTSTATUS) 0x40000015L)
+#endif
+
+#ifndef STATUS_PREDEFINED_HANDLE
+# define STATUS_PREDEFINED_HANDLE ((NTSTATUS) 0x40000016L)
+#endif
+
+#ifndef STATUS_WAS_UNLOCKED
+# define STATUS_WAS_UNLOCKED ((NTSTATUS) 0x40000017L)
+#endif
+
+#ifndef STATUS_SERVICE_NOTIFICATION
+# define STATUS_SERVICE_NOTIFICATION ((NTSTATUS) 0x40000018L)
+#endif
+
+#ifndef STATUS_WAS_LOCKED
+# define STATUS_WAS_LOCKED ((NTSTATUS) 0x40000019L)
+#endif
+
+#ifndef STATUS_LOG_HARD_ERROR
+# define STATUS_LOG_HARD_ERROR ((NTSTATUS) 0x4000001AL)
+#endif
+
+#ifndef STATUS_ALREADY_WIN32
+# define STATUS_ALREADY_WIN32 ((NTSTATUS) 0x4000001BL)
+#endif
+
+#ifndef STATUS_WX86_UNSIMULATE
+# define STATUS_WX86_UNSIMULATE ((NTSTATUS) 0x4000001CL)
+#endif
+
+#ifndef STATUS_WX86_CONTINUE
+# define STATUS_WX86_CONTINUE ((NTSTATUS) 0x4000001DL)
+#endif
+
+#ifndef STATUS_WX86_SINGLE_STEP
+# define STATUS_WX86_SINGLE_STEP ((NTSTATUS) 0x4000001EL)
+#endif
+
+#ifndef STATUS_WX86_BREAKPOINT
+# define STATUS_WX86_BREAKPOINT ((NTSTATUS) 0x4000001FL)
+#endif
+
+#ifndef STATUS_WX86_EXCEPTION_CONTINUE
+# define STATUS_WX86_EXCEPTION_CONTINUE ((NTSTATUS) 0x40000020L)
+#endif
+
+#ifndef STATUS_WX86_EXCEPTION_LASTCHANCE
+# define STATUS_WX86_EXCEPTION_LASTCHANCE ((NTSTATUS) 0x40000021L)
+#endif
+
+#ifndef STATUS_WX86_EXCEPTION_CHAIN
+# define STATUS_WX86_EXCEPTION_CHAIN ((NTSTATUS) 0x40000022L)
+#endif
+
+#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
+# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE ((NTSTATUS) 0x40000023L)
+#endif
+
+#ifndef STATUS_NO_YIELD_PERFORMED
+# define STATUS_NO_YIELD_PERFORMED ((NTSTATUS) 0x40000024L)
+#endif
+
+#ifndef STATUS_TIMER_RESUME_IGNORED
+# define STATUS_TIMER_RESUME_IGNORED ((NTSTATUS) 0x40000025L)
+#endif
+
+#ifndef STATUS_ARBITRATION_UNHANDLED
+# define STATUS_ARBITRATION_UNHANDLED ((NTSTATUS) 0x40000026L)
+#endif
+
+#ifndef STATUS_CARDBUS_NOT_SUPPORTED
+# define STATUS_CARDBUS_NOT_SUPPORTED ((NTSTATUS) 0x40000027L)
+#endif
+
+#ifndef STATUS_WX86_CREATEWX86TIB
+# define STATUS_WX86_CREATEWX86TIB ((NTSTATUS) 0x40000028L)
+#endif
+
+#ifndef STATUS_MP_PROCESSOR_MISMATCH
+# define STATUS_MP_PROCESSOR_MISMATCH ((NTSTATUS) 0x40000029L)
+#endif
+
+#ifndef STATUS_HIBERNATED
+# define STATUS_HIBERNATED ((NTSTATUS) 0x4000002AL)
+#endif
+
+#ifndef STATUS_RESUME_HIBERNATION
+# define STATUS_RESUME_HIBERNATION ((NTSTATUS) 0x4000002BL)
+#endif
+
+#ifndef STATUS_FIRMWARE_UPDATED
+# define STATUS_FIRMWARE_UPDATED ((NTSTATUS) 0x4000002CL)
+#endif
+
+#ifndef STATUS_DRIVERS_LEAKING_LOCKED_PAGES
+# define STATUS_DRIVERS_LEAKING_LOCKED_PAGES ((NTSTATUS) 0x4000002DL)
+#endif
+
+#ifndef STATUS_MESSAGE_RETRIEVED
+# define STATUS_MESSAGE_RETRIEVED ((NTSTATUS) 0x4000002EL)
+#endif
+
+#ifndef STATUS_SYSTEM_POWERSTATE_TRANSITION
+# define STATUS_SYSTEM_POWERSTATE_TRANSITION ((NTSTATUS) 0x4000002FL)
+#endif
+
+#ifndef STATUS_ALPC_CHECK_COMPLETION_LIST
+# define STATUS_ALPC_CHECK_COMPLETION_LIST ((NTSTATUS) 0x40000030L)
+#endif
+
+#ifndef STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION
+# define STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION ((NTSTATUS) 0x40000031L)
+#endif
+
+#ifndef STATUS_ACCESS_AUDIT_BY_POLICY
+# define STATUS_ACCESS_AUDIT_BY_POLICY ((NTSTATUS) 0x40000032L)
+#endif
+
+#ifndef STATUS_ABANDON_HIBERFILE
+# define STATUS_ABANDON_HIBERFILE ((NTSTATUS) 0x40000033L)
+#endif
+
+#ifndef STATUS_BIZRULES_NOT_ENABLED
+# define STATUS_BIZRULES_NOT_ENABLED ((NTSTATUS) 0x40000034L)
+#endif
+
+#ifndef STATUS_GUARD_PAGE_VIOLATION
+# define STATUS_GUARD_PAGE_VIOLATION ((NTSTATUS) 0x80000001L)
+#endif
+
+#ifndef STATUS_DATATYPE_MISALIGNMENT
+# define STATUS_DATATYPE_MISALIGNMENT ((NTSTATUS) 0x80000002L)
+#endif
+
+#ifndef STATUS_BREAKPOINT
+# define STATUS_BREAKPOINT ((NTSTATUS) 0x80000003L)
+#endif
+
+#ifndef STATUS_SINGLE_STEP
+# define STATUS_SINGLE_STEP ((NTSTATUS) 0x80000004L)
+#endif
+
+#ifndef STATUS_BUFFER_OVERFLOW
+# define STATUS_BUFFER_OVERFLOW ((NTSTATUS) 0x80000005L)
+#endif
+
+#ifndef STATUS_NO_MORE_FILES
+# define STATUS_NO_MORE_FILES ((NTSTATUS) 0x80000006L)
+#endif
+
+#ifndef STATUS_WAKE_SYSTEM_DEBUGGER
+# define STATUS_WAKE_SYSTEM_DEBUGGER ((NTSTATUS) 0x80000007L)
+#endif
+
+#ifndef STATUS_HANDLES_CLOSED
+# define STATUS_HANDLES_CLOSED ((NTSTATUS) 0x8000000AL)
+#endif
+
+#ifndef STATUS_NO_INHERITANCE
+# define STATUS_NO_INHERITANCE ((NTSTATUS) 0x8000000BL)
+#endif
+
+#ifndef STATUS_GUID_SUBSTITUTION_MADE
+# define STATUS_GUID_SUBSTITUTION_MADE ((NTSTATUS) 0x8000000CL)
+#endif
+
+#ifndef STATUS_PARTIAL_COPY
+# define STATUS_PARTIAL_COPY ((NTSTATUS) 0x8000000DL)
+#endif
+
+#ifndef STATUS_DEVICE_PAPER_EMPTY
+# define STATUS_DEVICE_PAPER_EMPTY ((NTSTATUS) 0x8000000EL)
+#endif
+
+#ifndef STATUS_DEVICE_POWERED_OFF
+# define STATUS_DEVICE_POWERED_OFF ((NTSTATUS) 0x8000000FL)
+#endif
+
+#ifndef STATUS_DEVICE_OFF_LINE
+# define STATUS_DEVICE_OFF_LINE ((NTSTATUS) 0x80000010L)
+#endif
+
+#ifndef STATUS_DEVICE_BUSY
+# define STATUS_DEVICE_BUSY ((NTSTATUS) 0x80000011L)
+#endif
+
+#ifndef STATUS_NO_MORE_EAS
+# define STATUS_NO_MORE_EAS ((NTSTATUS) 0x80000012L)
+#endif
+
+#ifndef STATUS_INVALID_EA_NAME
+# define STATUS_INVALID_EA_NAME ((NTSTATUS) 0x80000013L)
+#endif
+
+#ifndef STATUS_EA_LIST_INCONSISTENT
+# define STATUS_EA_LIST_INCONSISTENT ((NTSTATUS) 0x80000014L)
+#endif
+
+#ifndef STATUS_INVALID_EA_FLAG
+# define STATUS_INVALID_EA_FLAG ((NTSTATUS) 0x80000015L)
+#endif
+
+#ifndef STATUS_VERIFY_REQUIRED
+# define STATUS_VERIFY_REQUIRED ((NTSTATUS) 0x80000016L)
+#endif
+
+#ifndef STATUS_EXTRANEOUS_INFORMATION
+# define STATUS_EXTRANEOUS_INFORMATION ((NTSTATUS) 0x80000017L)
+#endif
+
+#ifndef STATUS_RXACT_COMMIT_NECESSARY
+# define STATUS_RXACT_COMMIT_NECESSARY ((NTSTATUS) 0x80000018L)
+#endif
+
+#ifndef STATUS_NO_MORE_ENTRIES
+# define STATUS_NO_MORE_ENTRIES ((NTSTATUS) 0x8000001AL)
+#endif
+
+#ifndef STATUS_FILEMARK_DETECTED
+# define STATUS_FILEMARK_DETECTED ((NTSTATUS) 0x8000001BL)
+#endif
+
+#ifndef STATUS_MEDIA_CHANGED
+# define STATUS_MEDIA_CHANGED ((NTSTATUS) 0x8000001CL)
+#endif
+
+#ifndef STATUS_BUS_RESET
+# define STATUS_BUS_RESET ((NTSTATUS) 0x8000001DL)
+#endif
+
+#ifndef STATUS_END_OF_MEDIA
+# define STATUS_END_OF_MEDIA ((NTSTATUS) 0x8000001EL)
+#endif
+
+#ifndef STATUS_BEGINNING_OF_MEDIA
+# define STATUS_BEGINNING_OF_MEDIA ((NTSTATUS) 0x8000001FL)
+#endif
+
+#ifndef STATUS_MEDIA_CHECK
+# define STATUS_MEDIA_CHECK ((NTSTATUS) 0x80000020L)
+#endif
+
+#ifndef STATUS_SETMARK_DETECTED
+# define STATUS_SETMARK_DETECTED ((NTSTATUS) 0x80000021L)
+#endif
+
+#ifndef STATUS_NO_DATA_DETECTED
+# define STATUS_NO_DATA_DETECTED ((NTSTATUS) 0x80000022L)
+#endif
+
+#ifndef STATUS_REDIRECTOR_HAS_OPEN_HANDLES
+# define STATUS_REDIRECTOR_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000023L)
+#endif
+
+#ifndef STATUS_SERVER_HAS_OPEN_HANDLES
+# define STATUS_SERVER_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000024L)
+#endif
+
+#ifndef STATUS_ALREADY_DISCONNECTED
+# define STATUS_ALREADY_DISCONNECTED ((NTSTATUS) 0x80000025L)
+#endif
+
+#ifndef STATUS_LONGJUMP
+# define STATUS_LONGJUMP ((NTSTATUS) 0x80000026L)
+#endif
+
+#ifndef STATUS_CLEANER_CARTRIDGE_INSTALLED
+# define STATUS_CLEANER_CARTRIDGE_INSTALLED ((NTSTATUS) 0x80000027L)
+#endif
+
+#ifndef STATUS_PLUGPLAY_QUERY_VETOED
+# define STATUS_PLUGPLAY_QUERY_VETOED ((NTSTATUS) 0x80000028L)
+#endif
+
+#ifndef STATUS_UNWIND_CONSOLIDATE
+# define STATUS_UNWIND_CONSOLIDATE ((NTSTATUS) 0x80000029L)
+#endif
+
+#ifndef STATUS_REGISTRY_HIVE_RECOVERED
+# define STATUS_REGISTRY_HIVE_RECOVERED ((NTSTATUS) 0x8000002AL)
+#endif
+
+#ifndef STATUS_DLL_MIGHT_BE_INSECURE
+# define STATUS_DLL_MIGHT_BE_INSECURE ((NTSTATUS) 0x8000002BL)
+#endif
+
+#ifndef STATUS_DLL_MIGHT_BE_INCOMPATIBLE
+# define STATUS_DLL_MIGHT_BE_INCOMPATIBLE ((NTSTATUS) 0x8000002CL)
+#endif
+
+#ifndef STATUS_STOPPED_ON_SYMLINK
+# define STATUS_STOPPED_ON_SYMLINK ((NTSTATUS) 0x8000002DL)
+#endif
+
+#ifndef STATUS_CANNOT_GRANT_REQUESTED_OPLOCK
+# define STATUS_CANNOT_GRANT_REQUESTED_OPLOCK ((NTSTATUS) 0x8000002EL)
+#endif
+
+#ifndef STATUS_NO_ACE_CONDITION
+# define STATUS_NO_ACE_CONDITION ((NTSTATUS) 0x8000002FL)
+#endif
+
+#ifndef STATUS_UNSUCCESSFUL
+# define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L)
+#endif
+
+#ifndef STATUS_NOT_IMPLEMENTED
+# define STATUS_NOT_IMPLEMENTED ((NTSTATUS) 0xC0000002L)
+#endif
+
+#ifndef STATUS_INVALID_INFO_CLASS
+# define STATUS_INVALID_INFO_CLASS ((NTSTATUS) 0xC0000003L)
+#endif
+
+#ifndef STATUS_INFO_LENGTH_MISMATCH
+# define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004L)
+#endif
+
+#ifndef STATUS_ACCESS_VIOLATION
+# define STATUS_ACCESS_VIOLATION ((NTSTATUS) 0xC0000005L)
+#endif
+
+#ifndef STATUS_IN_PAGE_ERROR
+# define STATUS_IN_PAGE_ERROR ((NTSTATUS) 0xC0000006L)
+#endif
+
+#ifndef STATUS_PAGEFILE_QUOTA
+# define STATUS_PAGEFILE_QUOTA ((NTSTATUS) 0xC0000007L)
+#endif
+
+#ifndef STATUS_INVALID_HANDLE
+# define STATUS_INVALID_HANDLE ((NTSTATUS) 0xC0000008L)
+#endif
+
+#ifndef STATUS_BAD_INITIAL_STACK
+# define STATUS_BAD_INITIAL_STACK ((NTSTATUS) 0xC0000009L)
+#endif
+
+#ifndef STATUS_BAD_INITIAL_PC
+# define STATUS_BAD_INITIAL_PC ((NTSTATUS) 0xC000000AL)
+#endif
+
+#ifndef STATUS_INVALID_CID
+# define STATUS_INVALID_CID ((NTSTATUS) 0xC000000BL)
+#endif
+
+#ifndef STATUS_TIMER_NOT_CANCELED
+# define STATUS_TIMER_NOT_CANCELED ((NTSTATUS) 0xC000000CL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER
+# define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xC000000DL)
+#endif
+
+#ifndef STATUS_NO_SUCH_DEVICE
+# define STATUS_NO_SUCH_DEVICE ((NTSTATUS) 0xC000000EL)
+#endif
+
+#ifndef STATUS_NO_SUCH_FILE
+# define STATUS_NO_SUCH_FILE ((NTSTATUS) 0xC000000FL)
+#endif
+
+#ifndef STATUS_INVALID_DEVICE_REQUEST
+# define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xC0000010L)
+#endif
+
+#ifndef STATUS_END_OF_FILE
+# define STATUS_END_OF_FILE ((NTSTATUS) 0xC0000011L)
+#endif
+
+#ifndef STATUS_WRONG_VOLUME
+# define STATUS_WRONG_VOLUME ((NTSTATUS) 0xC0000012L)
+#endif
+
+#ifndef STATUS_NO_MEDIA_IN_DEVICE
+# define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xC0000013L)
+#endif
+
+#ifndef STATUS_UNRECOGNIZED_MEDIA
+# define STATUS_UNRECOGNIZED_MEDIA ((NTSTATUS) 0xC0000014L)
+#endif
+
+#ifndef STATUS_NONEXISTENT_SECTOR
+# define STATUS_NONEXISTENT_SECTOR ((NTSTATUS) 0xC0000015L)
+#endif
+
+#ifndef STATUS_MORE_PROCESSING_REQUIRED
+# define STATUS_MORE_PROCESSING_REQUIRED ((NTSTATUS) 0xC0000016L)
+#endif
+
+#ifndef STATUS_NO_MEMORY
+# define STATUS_NO_MEMORY ((NTSTATUS) 0xC0000017L)
+#endif
+
+#ifndef STATUS_CONFLICTING_ADDRESSES
+# define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS) 0xC0000018L)
+#endif
+
+#ifndef STATUS_NOT_MAPPED_VIEW
+# define STATUS_NOT_MAPPED_VIEW ((NTSTATUS) 0xC0000019L)
+#endif
+
+#ifndef STATUS_UNABLE_TO_FREE_VM
+# define STATUS_UNABLE_TO_FREE_VM ((NTSTATUS) 0xC000001AL)
+#endif
+
+#ifndef STATUS_UNABLE_TO_DELETE_SECTION
+# define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS) 0xC000001BL)
+#endif
+
+#ifndef STATUS_INVALID_SYSTEM_SERVICE
+# define STATUS_INVALID_SYSTEM_SERVICE ((NTSTATUS) 0xC000001CL)
+#endif
+
+#ifndef STATUS_ILLEGAL_INSTRUCTION
+# define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS) 0xC000001DL)
+#endif
+
+#ifndef STATUS_INVALID_LOCK_SEQUENCE
+# define STATUS_INVALID_LOCK_SEQUENCE ((NTSTATUS) 0xC000001EL)
+#endif
+
+#ifndef STATUS_INVALID_VIEW_SIZE
+# define STATUS_INVALID_VIEW_SIZE ((NTSTATUS) 0xC000001FL)
+#endif
+
+#ifndef STATUS_INVALID_FILE_FOR_SECTION
+# define STATUS_INVALID_FILE_FOR_SECTION ((NTSTATUS) 0xC0000020L)
+#endif
+
+#ifndef STATUS_ALREADY_COMMITTED
+# define STATUS_ALREADY_COMMITTED ((NTSTATUS) 0xC0000021L)
+#endif
+
+#ifndef STATUS_ACCESS_DENIED
+# define STATUS_ACCESS_DENIED ((NTSTATUS) 0xC0000022L)
+#endif
+
+#ifndef STATUS_BUFFER_TOO_SMALL
+# define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xC0000023L)
+#endif
+
+#ifndef STATUS_OBJECT_TYPE_MISMATCH
+# define STATUS_OBJECT_TYPE_MISMATCH ((NTSTATUS) 0xC0000024L)
+#endif
+
+#ifndef STATUS_NONCONTINUABLE_EXCEPTION
+# define STATUS_NONCONTINUABLE_EXCEPTION ((NTSTATUS) 0xC0000025L)
+#endif
+
+#ifndef STATUS_INVALID_DISPOSITION
+# define STATUS_INVALID_DISPOSITION ((NTSTATUS) 0xC0000026L)
+#endif
+
+#ifndef STATUS_UNWIND
+# define STATUS_UNWIND ((NTSTATUS) 0xC0000027L)
+#endif
+
+#ifndef STATUS_BAD_STACK
+# define STATUS_BAD_STACK ((NTSTATUS) 0xC0000028L)
+#endif
+
+#ifndef STATUS_INVALID_UNWIND_TARGET
+# define STATUS_INVALID_UNWIND_TARGET ((NTSTATUS) 0xC0000029L)
+#endif
+
+#ifndef STATUS_NOT_LOCKED
+# define STATUS_NOT_LOCKED ((NTSTATUS) 0xC000002AL)
+#endif
+
+#ifndef STATUS_PARITY_ERROR
+# define STATUS_PARITY_ERROR ((NTSTATUS) 0xC000002BL)
+#endif
+
+#ifndef STATUS_UNABLE_TO_DECOMMIT_VM
+# define STATUS_UNABLE_TO_DECOMMIT_VM ((NTSTATUS) 0xC000002CL)
+#endif
+
+#ifndef STATUS_NOT_COMMITTED
+# define STATUS_NOT_COMMITTED ((NTSTATUS) 0xC000002DL)
+#endif
+
+#ifndef STATUS_INVALID_PORT_ATTRIBUTES
+# define STATUS_INVALID_PORT_ATTRIBUTES ((NTSTATUS) 0xC000002EL)
+#endif
+
+#ifndef STATUS_PORT_MESSAGE_TOO_LONG
+# define STATUS_PORT_MESSAGE_TOO_LONG ((NTSTATUS) 0xC000002FL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_MIX
+# define STATUS_INVALID_PARAMETER_MIX ((NTSTATUS) 0xC0000030L)
+#endif
+
+#ifndef STATUS_INVALID_QUOTA_LOWER
+# define STATUS_INVALID_QUOTA_LOWER ((NTSTATUS) 0xC0000031L)
+#endif
+
+#ifndef STATUS_DISK_CORRUPT_ERROR
+# define STATUS_DISK_CORRUPT_ERROR ((NTSTATUS) 0xC0000032L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_INVALID
+# define STATUS_OBJECT_NAME_INVALID ((NTSTATUS) 0xC0000033L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_NOT_FOUND
+# define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xC0000034L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_COLLISION
+# define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS) 0xC0000035L)
+#endif
+
+#ifndef STATUS_PORT_DISCONNECTED
+# define STATUS_PORT_DISCONNECTED ((NTSTATUS) 0xC0000037L)
+#endif
+
+#ifndef STATUS_DEVICE_ALREADY_ATTACHED
+# define STATUS_DEVICE_ALREADY_ATTACHED ((NTSTATUS) 0xC0000038L)
+#endif
+
+#ifndef STATUS_OBJECT_PATH_INVALID
+# define STATUS_OBJECT_PATH_INVALID ((NTSTATUS) 0xC0000039L)
+#endif
+
+#ifndef STATUS_OBJECT_PATH_NOT_FOUND
+# define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xC000003AL)
+#endif
+
+#ifndef STATUS_OBJECT_PATH_SYNTAX_BAD
+# define STATUS_OBJECT_PATH_SYNTAX_BAD ((NTSTATUS) 0xC000003BL)
+#endif
+
+#ifndef STATUS_DATA_OVERRUN
+# define STATUS_DATA_OVERRUN ((NTSTATUS) 0xC000003CL)
+#endif
+
+#ifndef STATUS_DATA_LATE_ERROR
+# define STATUS_DATA_LATE_ERROR ((NTSTATUS) 0xC000003DL)
+#endif
+
+#ifndef STATUS_DATA_ERROR
+# define STATUS_DATA_ERROR ((NTSTATUS) 0xC000003EL)
+#endif
+
+#ifndef STATUS_CRC_ERROR
+# define STATUS_CRC_ERROR ((NTSTATUS) 0xC000003FL)
+#endif
+
+#ifndef STATUS_SECTION_TOO_BIG
+# define STATUS_SECTION_TOO_BIG ((NTSTATUS) 0xC0000040L)
+#endif
+
+#ifndef STATUS_PORT_CONNECTION_REFUSED
+# define STATUS_PORT_CONNECTION_REFUSED ((NTSTATUS) 0xC0000041L)
+#endif
+
+#ifndef STATUS_INVALID_PORT_HANDLE
+# define STATUS_INVALID_PORT_HANDLE ((NTSTATUS) 0xC0000042L)
+#endif
+
+#ifndef STATUS_SHARING_VIOLATION
+# define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xC0000043L)
+#endif
+
+#ifndef STATUS_QUOTA_EXCEEDED
+# define STATUS_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000044L)
+#endif
+
+#ifndef STATUS_INVALID_PAGE_PROTECTION
+# define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS) 0xC0000045L)
+#endif
+
+#ifndef STATUS_MUTANT_NOT_OWNED
+# define STATUS_MUTANT_NOT_OWNED ((NTSTATUS) 0xC0000046L)
+#endif
+
+#ifndef STATUS_SEMAPHORE_LIMIT_EXCEEDED
+# define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000047L)
+#endif
+
+#ifndef STATUS_PORT_ALREADY_SET
+# define STATUS_PORT_ALREADY_SET ((NTSTATUS) 0xC0000048L)
+#endif
+
+#ifndef STATUS_SECTION_NOT_IMAGE
+# define STATUS_SECTION_NOT_IMAGE ((NTSTATUS) 0xC0000049L)
+#endif
+
+#ifndef STATUS_SUSPEND_COUNT_EXCEEDED
+# define STATUS_SUSPEND_COUNT_EXCEEDED ((NTSTATUS) 0xC000004AL)
+#endif
+
+#ifndef STATUS_THREAD_IS_TERMINATING
+# define STATUS_THREAD_IS_TERMINATING ((NTSTATUS) 0xC000004BL)
+#endif
+
+#ifndef STATUS_BAD_WORKING_SET_LIMIT
+# define STATUS_BAD_WORKING_SET_LIMIT ((NTSTATUS) 0xC000004CL)
+#endif
+
+#ifndef STATUS_INCOMPATIBLE_FILE_MAP
+# define STATUS_INCOMPATIBLE_FILE_MAP ((NTSTATUS) 0xC000004DL)
+#endif
+
+#ifndef STATUS_SECTION_PROTECTION
+# define STATUS_SECTION_PROTECTION ((NTSTATUS) 0xC000004EL)
+#endif
+
+#ifndef STATUS_EAS_NOT_SUPPORTED
+# define STATUS_EAS_NOT_SUPPORTED ((NTSTATUS) 0xC000004FL)
+#endif
+
+#ifndef STATUS_EA_TOO_LARGE
+# define STATUS_EA_TOO_LARGE ((NTSTATUS) 0xC0000050L)
+#endif
+
+#ifndef STATUS_NONEXISTENT_EA_ENTRY
+# define STATUS_NONEXISTENT_EA_ENTRY ((NTSTATUS) 0xC0000051L)
+#endif
+
+#ifndef STATUS_NO_EAS_ON_FILE
+# define STATUS_NO_EAS_ON_FILE ((NTSTATUS) 0xC0000052L)
+#endif
+
+#ifndef STATUS_EA_CORRUPT_ERROR
+# define STATUS_EA_CORRUPT_ERROR ((NTSTATUS) 0xC0000053L)
+#endif
+
+#ifndef STATUS_FILE_LOCK_CONFLICT
+# define STATUS_FILE_LOCK_CONFLICT ((NTSTATUS) 0xC0000054L)
+#endif
+
+#ifndef STATUS_LOCK_NOT_GRANTED
+# define STATUS_LOCK_NOT_GRANTED ((NTSTATUS) 0xC0000055L)
+#endif
+
+#ifndef STATUS_DELETE_PENDING
+# define STATUS_DELETE_PENDING ((NTSTATUS) 0xC0000056L)
+#endif
+
+#ifndef STATUS_CTL_FILE_NOT_SUPPORTED
+# define STATUS_CTL_FILE_NOT_SUPPORTED ((NTSTATUS) 0xC0000057L)
+#endif
+
+#ifndef STATUS_UNKNOWN_REVISION
+# define STATUS_UNKNOWN_REVISION ((NTSTATUS) 0xC0000058L)
+#endif
+
+#ifndef STATUS_REVISION_MISMATCH
+# define STATUS_REVISION_MISMATCH ((NTSTATUS) 0xC0000059L)
+#endif
+
+#ifndef STATUS_INVALID_OWNER
+# define STATUS_INVALID_OWNER ((NTSTATUS) 0xC000005AL)
+#endif
+
+#ifndef STATUS_INVALID_PRIMARY_GROUP
+# define STATUS_INVALID_PRIMARY_GROUP ((NTSTATUS) 0xC000005BL)
+#endif
+
+#ifndef STATUS_NO_IMPERSONATION_TOKEN
+# define STATUS_NO_IMPERSONATION_TOKEN ((NTSTATUS) 0xC000005CL)
+#endif
+
+#ifndef STATUS_CANT_DISABLE_MANDATORY
+# define STATUS_CANT_DISABLE_MANDATORY ((NTSTATUS) 0xC000005DL)
+#endif
+
+#ifndef STATUS_NO_LOGON_SERVERS
+# define STATUS_NO_LOGON_SERVERS ((NTSTATUS) 0xC000005EL)
+#endif
+
+#ifndef STATUS_NO_SUCH_LOGON_SESSION
+# define STATUS_NO_SUCH_LOGON_SESSION ((NTSTATUS) 0xC000005FL)
+#endif
+
+#ifndef STATUS_NO_SUCH_PRIVILEGE
+# define STATUS_NO_SUCH_PRIVILEGE ((NTSTATUS) 0xC0000060L)
+#endif
+
+#ifndef STATUS_PRIVILEGE_NOT_HELD
+# define STATUS_PRIVILEGE_NOT_HELD ((NTSTATUS) 0xC0000061L)
+#endif
+
+#ifndef STATUS_INVALID_ACCOUNT_NAME
+# define STATUS_INVALID_ACCOUNT_NAME ((NTSTATUS) 0xC0000062L)
+#endif
+
+#ifndef STATUS_USER_EXISTS
+# define STATUS_USER_EXISTS ((NTSTATUS) 0xC0000063L)
+#endif
+
+#ifndef STATUS_NO_SUCH_USER
+# define STATUS_NO_SUCH_USER ((NTSTATUS) 0xC0000064L)
+#endif
+
+#ifndef STATUS_GROUP_EXISTS
+# define STATUS_GROUP_EXISTS ((NTSTATUS) 0xC0000065L)
+#endif
+
+#ifndef STATUS_NO_SUCH_GROUP
+# define STATUS_NO_SUCH_GROUP ((NTSTATUS) 0xC0000066L)
+#endif
+
+#ifndef STATUS_MEMBER_IN_GROUP
+# define STATUS_MEMBER_IN_GROUP ((NTSTATUS) 0xC0000067L)
+#endif
+
+#ifndef STATUS_MEMBER_NOT_IN_GROUP
+# define STATUS_MEMBER_NOT_IN_GROUP ((NTSTATUS) 0xC0000068L)
+#endif
+
+#ifndef STATUS_LAST_ADMIN
+# define STATUS_LAST_ADMIN ((NTSTATUS) 0xC0000069L)
+#endif
+
+#ifndef STATUS_WRONG_PASSWORD
+# define STATUS_WRONG_PASSWORD ((NTSTATUS) 0xC000006AL)
+#endif
+
+#ifndef STATUS_ILL_FORMED_PASSWORD
+# define STATUS_ILL_FORMED_PASSWORD ((NTSTATUS) 0xC000006BL)
+#endif
+
+#ifndef STATUS_PASSWORD_RESTRICTION
+# define STATUS_PASSWORD_RESTRICTION ((NTSTATUS) 0xC000006CL)
+#endif
+
+#ifndef STATUS_LOGON_FAILURE
+# define STATUS_LOGON_FAILURE ((NTSTATUS) 0xC000006DL)
+#endif
+
+#ifndef STATUS_ACCOUNT_RESTRICTION
+# define STATUS_ACCOUNT_RESTRICTION ((NTSTATUS) 0xC000006EL)
+#endif
+
+#ifndef STATUS_INVALID_LOGON_HOURS
+# define STATUS_INVALID_LOGON_HOURS ((NTSTATUS) 0xC000006FL)
+#endif
+
+#ifndef STATUS_INVALID_WORKSTATION
+# define STATUS_INVALID_WORKSTATION ((NTSTATUS) 0xC0000070L)
+#endif
+
+#ifndef STATUS_PASSWORD_EXPIRED
+# define STATUS_PASSWORD_EXPIRED ((NTSTATUS) 0xC0000071L)
+#endif
+
+#ifndef STATUS_ACCOUNT_DISABLED
+# define STATUS_ACCOUNT_DISABLED ((NTSTATUS) 0xC0000072L)
+#endif
+
+#ifndef STATUS_NONE_MAPPED
+# define STATUS_NONE_MAPPED ((NTSTATUS) 0xC0000073L)
+#endif
+
+#ifndef STATUS_TOO_MANY_LUIDS_REQUESTED
+# define STATUS_TOO_MANY_LUIDS_REQUESTED ((NTSTATUS) 0xC0000074L)
+#endif
+
+#ifndef STATUS_LUIDS_EXHAUSTED
+# define STATUS_LUIDS_EXHAUSTED ((NTSTATUS) 0xC0000075L)
+#endif
+
+#ifndef STATUS_INVALID_SUB_AUTHORITY
+# define STATUS_INVALID_SUB_AUTHORITY ((NTSTATUS) 0xC0000076L)
+#endif
+
+#ifndef STATUS_INVALID_ACL
+# define STATUS_INVALID_ACL ((NTSTATUS) 0xC0000077L)
+#endif
+
+#ifndef STATUS_INVALID_SID
+# define STATUS_INVALID_SID ((NTSTATUS) 0xC0000078L)
+#endif
+
+#ifndef STATUS_INVALID_SECURITY_DESCR
+# define STATUS_INVALID_SECURITY_DESCR ((NTSTATUS) 0xC0000079L)
+#endif
+
+#ifndef STATUS_PROCEDURE_NOT_FOUND
+# define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS) 0xC000007AL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_FORMAT
+# define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS) 0xC000007BL)
+#endif
+
+#ifndef STATUS_NO_TOKEN
+# define STATUS_NO_TOKEN ((NTSTATUS) 0xC000007CL)
+#endif
+
+#ifndef STATUS_BAD_INHERITANCE_ACL
+# define STATUS_BAD_INHERITANCE_ACL ((NTSTATUS) 0xC000007DL)
+#endif
+
+#ifndef STATUS_RANGE_NOT_LOCKED
+# define STATUS_RANGE_NOT_LOCKED ((NTSTATUS) 0xC000007EL)
+#endif
+
+#ifndef STATUS_DISK_FULL
+# define STATUS_DISK_FULL ((NTSTATUS) 0xC000007FL)
+#endif
+
+#ifndef STATUS_SERVER_DISABLED
+# define STATUS_SERVER_DISABLED ((NTSTATUS) 0xC0000080L)
+#endif
+
+#ifndef STATUS_SERVER_NOT_DISABLED
+# define STATUS_SERVER_NOT_DISABLED ((NTSTATUS) 0xC0000081L)
+#endif
+
+#ifndef STATUS_TOO_MANY_GUIDS_REQUESTED
+# define STATUS_TOO_MANY_GUIDS_REQUESTED ((NTSTATUS) 0xC0000082L)
+#endif
+
+#ifndef STATUS_GUIDS_EXHAUSTED
+# define STATUS_GUIDS_EXHAUSTED ((NTSTATUS) 0xC0000083L)
+#endif
+
+#ifndef STATUS_INVALID_ID_AUTHORITY
+# define STATUS_INVALID_ID_AUTHORITY ((NTSTATUS) 0xC0000084L)
+#endif
+
+#ifndef STATUS_AGENTS_EXHAUSTED
+# define STATUS_AGENTS_EXHAUSTED ((NTSTATUS) 0xC0000085L)
+#endif
+
+#ifndef STATUS_INVALID_VOLUME_LABEL
+# define STATUS_INVALID_VOLUME_LABEL ((NTSTATUS) 0xC0000086L)
+#endif
+
+#ifndef STATUS_SECTION_NOT_EXTENDED
+# define STATUS_SECTION_NOT_EXTENDED ((NTSTATUS) 0xC0000087L)
+#endif
+
+#ifndef STATUS_NOT_MAPPED_DATA
+# define STATUS_NOT_MAPPED_DATA ((NTSTATUS) 0xC0000088L)
+#endif
+
+#ifndef STATUS_RESOURCE_DATA_NOT_FOUND
+# define STATUS_RESOURCE_DATA_NOT_FOUND ((NTSTATUS) 0xC0000089L)
+#endif
+
+#ifndef STATUS_RESOURCE_TYPE_NOT_FOUND
+# define STATUS_RESOURCE_TYPE_NOT_FOUND ((NTSTATUS) 0xC000008AL)
+#endif
+
+#ifndef STATUS_RESOURCE_NAME_NOT_FOUND
+# define STATUS_RESOURCE_NAME_NOT_FOUND ((NTSTATUS) 0xC000008BL)
+#endif
+
+#ifndef STATUS_ARRAY_BOUNDS_EXCEEDED
+# define STATUS_ARRAY_BOUNDS_EXCEEDED ((NTSTATUS) 0xC000008CL)
+#endif
+
+#ifndef STATUS_FLOAT_DENORMAL_OPERAND
+# define STATUS_FLOAT_DENORMAL_OPERAND ((NTSTATUS) 0xC000008DL)
+#endif
+
+#ifndef STATUS_FLOAT_DIVIDE_BY_ZERO
+# define STATUS_FLOAT_DIVIDE_BY_ZERO ((NTSTATUS) 0xC000008EL)
+#endif
+
+#ifndef STATUS_FLOAT_INEXACT_RESULT
+# define STATUS_FLOAT_INEXACT_RESULT ((NTSTATUS) 0xC000008FL)
+#endif
+
+#ifndef STATUS_FLOAT_INVALID_OPERATION
+# define STATUS_FLOAT_INVALID_OPERATION ((NTSTATUS) 0xC0000090L)
+#endif
+
+#ifndef STATUS_FLOAT_OVERFLOW
+# define STATUS_FLOAT_OVERFLOW ((NTSTATUS) 0xC0000091L)
+#endif
+
+#ifndef STATUS_FLOAT_STACK_CHECK
+# define STATUS_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000092L)
+#endif
+
+#ifndef STATUS_FLOAT_UNDERFLOW
+# define STATUS_FLOAT_UNDERFLOW ((NTSTATUS) 0xC0000093L)
+#endif
+
+#ifndef STATUS_INTEGER_DIVIDE_BY_ZERO
+# define STATUS_INTEGER_DIVIDE_BY_ZERO ((NTSTATUS) 0xC0000094L)
+#endif
+
+#ifndef STATUS_INTEGER_OVERFLOW
+# define STATUS_INTEGER_OVERFLOW ((NTSTATUS) 0xC0000095L)
+#endif
+
+#ifndef STATUS_PRIVILEGED_INSTRUCTION
+# define STATUS_PRIVILEGED_INSTRUCTION ((NTSTATUS) 0xC0000096L)
+#endif
+
+#ifndef STATUS_TOO_MANY_PAGING_FILES
+# define STATUS_TOO_MANY_PAGING_FILES ((NTSTATUS) 0xC0000097L)
+#endif
+
+#ifndef STATUS_FILE_INVALID
+# define STATUS_FILE_INVALID ((NTSTATUS) 0xC0000098L)
+#endif
+
+#ifndef STATUS_ALLOTTED_SPACE_EXCEEDED
+# define STATUS_ALLOTTED_SPACE_EXCEEDED ((NTSTATUS) 0xC0000099L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_RESOURCES
+# define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS) 0xC000009AL)
+#endif
+
+#ifndef STATUS_DFS_EXIT_PATH_FOUND
+# define STATUS_DFS_EXIT_PATH_FOUND ((NTSTATUS) 0xC000009BL)
+#endif
+
+#ifndef STATUS_DEVICE_DATA_ERROR
+# define STATUS_DEVICE_DATA_ERROR ((NTSTATUS) 0xC000009CL)
+#endif
+
+#ifndef STATUS_DEVICE_NOT_CONNECTED
+# define STATUS_DEVICE_NOT_CONNECTED ((NTSTATUS) 0xC000009DL)
+#endif
+
+#ifndef STATUS_DEVICE_POWER_FAILURE
+# define STATUS_DEVICE_POWER_FAILURE ((NTSTATUS) 0xC000009EL)
+#endif
+
+#ifndef STATUS_FREE_VM_NOT_AT_BASE
+# define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS) 0xC000009FL)
+#endif
+
+#ifndef STATUS_MEMORY_NOT_ALLOCATED
+# define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS) 0xC00000A0L)
+#endif
+
+#ifndef STATUS_WORKING_SET_QUOTA
+# define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xC00000A1L)
+#endif
+
+#ifndef STATUS_MEDIA_WRITE_PROTECTED
+# define STATUS_MEDIA_WRITE_PROTECTED ((NTSTATUS) 0xC00000A2L)
+#endif
+
+#ifndef STATUS_DEVICE_NOT_READY
+# define STATUS_DEVICE_NOT_READY ((NTSTATUS) 0xC00000A3L)
+#endif
+
+#ifndef STATUS_INVALID_GROUP_ATTRIBUTES
+# define STATUS_INVALID_GROUP_ATTRIBUTES ((NTSTATUS) 0xC00000A4L)
+#endif
+
+#ifndef STATUS_BAD_IMPERSONATION_LEVEL
+# define STATUS_BAD_IMPERSONATION_LEVEL ((NTSTATUS) 0xC00000A5L)
+#endif
+
+#ifndef STATUS_CANT_OPEN_ANONYMOUS
+# define STATUS_CANT_OPEN_ANONYMOUS ((NTSTATUS) 0xC00000A6L)
+#endif
+
+#ifndef STATUS_BAD_VALIDATION_CLASS
+# define STATUS_BAD_VALIDATION_CLASS ((NTSTATUS) 0xC00000A7L)
+#endif
+
+#ifndef STATUS_BAD_TOKEN_TYPE
+# define STATUS_BAD_TOKEN_TYPE ((NTSTATUS) 0xC00000A8L)
+#endif
+
+#ifndef STATUS_BAD_MASTER_BOOT_RECORD
+# define STATUS_BAD_MASTER_BOOT_RECORD ((NTSTATUS) 0xC00000A9L)
+#endif
+
+#ifndef STATUS_INSTRUCTION_MISALIGNMENT
+# define STATUS_INSTRUCTION_MISALIGNMENT ((NTSTATUS) 0xC00000AAL)
+#endif
+
+#ifndef STATUS_INSTANCE_NOT_AVAILABLE
+# define STATUS_INSTANCE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ABL)
+#endif
+
+#ifndef STATUS_PIPE_NOT_AVAILABLE
+# define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ACL)
+#endif
+
+#ifndef STATUS_INVALID_PIPE_STATE
+# define STATUS_INVALID_PIPE_STATE ((NTSTATUS) 0xC00000ADL)
+#endif
+
+#ifndef STATUS_PIPE_BUSY
+# define STATUS_PIPE_BUSY ((NTSTATUS) 0xC00000AEL)
+#endif
+
+#ifndef STATUS_ILLEGAL_FUNCTION
+# define STATUS_ILLEGAL_FUNCTION ((NTSTATUS) 0xC00000AFL)
+#endif
+
+#ifndef STATUS_PIPE_DISCONNECTED
+# define STATUS_PIPE_DISCONNECTED ((NTSTATUS) 0xC00000B0L)
+#endif
+
+#ifndef STATUS_PIPE_CLOSING
+# define STATUS_PIPE_CLOSING ((NTSTATUS) 0xC00000B1L)
+#endif
+
+#ifndef STATUS_PIPE_CONNECTED
+# define STATUS_PIPE_CONNECTED ((NTSTATUS) 0xC00000B2L)
+#endif
+
+#ifndef STATUS_PIPE_LISTENING
+# define STATUS_PIPE_LISTENING ((NTSTATUS) 0xC00000B3L)
+#endif
+
+#ifndef STATUS_INVALID_READ_MODE
+# define STATUS_INVALID_READ_MODE ((NTSTATUS) 0xC00000B4L)
+#endif
+
+#ifndef STATUS_IO_TIMEOUT
+# define STATUS_IO_TIMEOUT ((NTSTATUS) 0xC00000B5L)
+#endif
+
+#ifndef STATUS_FILE_FORCED_CLOSED
+# define STATUS_FILE_FORCED_CLOSED ((NTSTATUS) 0xC00000B6L)
+#endif
+
+#ifndef STATUS_PROFILING_NOT_STARTED
+# define STATUS_PROFILING_NOT_STARTED ((NTSTATUS) 0xC00000B7L)
+#endif
+
+#ifndef STATUS_PROFILING_NOT_STOPPED
+# define STATUS_PROFILING_NOT_STOPPED ((NTSTATUS) 0xC00000B8L)
+#endif
+
+#ifndef STATUS_COULD_NOT_INTERPRET
+# define STATUS_COULD_NOT_INTERPRET ((NTSTATUS) 0xC00000B9L)
+#endif
+
+#ifndef STATUS_FILE_IS_A_DIRECTORY
+# define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS) 0xC00000BAL)
+#endif
+
+#ifndef STATUS_NOT_SUPPORTED
+# define STATUS_NOT_SUPPORTED ((NTSTATUS) 0xC00000BBL)
+#endif
+
+#ifndef STATUS_REMOTE_NOT_LISTENING
+# define STATUS_REMOTE_NOT_LISTENING ((NTSTATUS) 0xC00000BCL)
+#endif
+
+#ifndef STATUS_DUPLICATE_NAME
+# define STATUS_DUPLICATE_NAME ((NTSTATUS) 0xC00000BDL)
+#endif
+
+#ifndef STATUS_BAD_NETWORK_PATH
+# define STATUS_BAD_NETWORK_PATH ((NTSTATUS) 0xC00000BEL)
+#endif
+
+#ifndef STATUS_NETWORK_BUSY
+# define STATUS_NETWORK_BUSY ((NTSTATUS) 0xC00000BFL)
+#endif
+
+#ifndef STATUS_DEVICE_DOES_NOT_EXIST
+# define STATUS_DEVICE_DOES_NOT_EXIST ((NTSTATUS) 0xC00000C0L)
+#endif
+
+#ifndef STATUS_TOO_MANY_COMMANDS
+# define STATUS_TOO_MANY_COMMANDS ((NTSTATUS) 0xC00000C1L)
+#endif
+
+#ifndef STATUS_ADAPTER_HARDWARE_ERROR
+# define STATUS_ADAPTER_HARDWARE_ERROR ((NTSTATUS) 0xC00000C2L)
+#endif
+
+#ifndef STATUS_INVALID_NETWORK_RESPONSE
+# define STATUS_INVALID_NETWORK_RESPONSE ((NTSTATUS) 0xC00000C3L)
+#endif
+
+#ifndef STATUS_UNEXPECTED_NETWORK_ERROR
+# define STATUS_UNEXPECTED_NETWORK_ERROR ((NTSTATUS) 0xC00000C4L)
+#endif
+
+#ifndef STATUS_BAD_REMOTE_ADAPTER
+# define STATUS_BAD_REMOTE_ADAPTER ((NTSTATUS) 0xC00000C5L)
+#endif
+
+#ifndef STATUS_PRINT_QUEUE_FULL
+# define STATUS_PRINT_QUEUE_FULL ((NTSTATUS) 0xC00000C6L)
+#endif
+
+#ifndef STATUS_NO_SPOOL_SPACE
+# define STATUS_NO_SPOOL_SPACE ((NTSTATUS) 0xC00000C7L)
+#endif
+
+#ifndef STATUS_PRINT_CANCELLED
+# define STATUS_PRINT_CANCELLED ((NTSTATUS) 0xC00000C8L)
+#endif
+
+#ifndef STATUS_NETWORK_NAME_DELETED
+# define STATUS_NETWORK_NAME_DELETED ((NTSTATUS) 0xC00000C9L)
+#endif
+
+#ifndef STATUS_NETWORK_ACCESS_DENIED
+# define STATUS_NETWORK_ACCESS_DENIED ((NTSTATUS) 0xC00000CAL)
+#endif
+
+#ifndef STATUS_BAD_DEVICE_TYPE
+# define STATUS_BAD_DEVICE_TYPE ((NTSTATUS) 0xC00000CBL)
+#endif
+
+#ifndef STATUS_BAD_NETWORK_NAME
+# define STATUS_BAD_NETWORK_NAME ((NTSTATUS) 0xC00000CCL)
+#endif
+
+#ifndef STATUS_TOO_MANY_NAMES
+# define STATUS_TOO_MANY_NAMES ((NTSTATUS) 0xC00000CDL)
+#endif
+
+#ifndef STATUS_TOO_MANY_SESSIONS
+# define STATUS_TOO_MANY_SESSIONS ((NTSTATUS) 0xC00000CEL)
+#endif
+
+#ifndef STATUS_SHARING_PAUSED
+# define STATUS_SHARING_PAUSED ((NTSTATUS) 0xC00000CFL)
+#endif
+
+#ifndef STATUS_REQUEST_NOT_ACCEPTED
+# define STATUS_REQUEST_NOT_ACCEPTED ((NTSTATUS) 0xC00000D0L)
+#endif
+
+#ifndef STATUS_REDIRECTOR_PAUSED
+# define STATUS_REDIRECTOR_PAUSED ((NTSTATUS) 0xC00000D1L)
+#endif
+
+#ifndef STATUS_NET_WRITE_FAULT
+# define STATUS_NET_WRITE_FAULT ((NTSTATUS) 0xC00000D2L)
+#endif
+
+#ifndef STATUS_PROFILING_AT_LIMIT
+# define STATUS_PROFILING_AT_LIMIT ((NTSTATUS) 0xC00000D3L)
+#endif
+
+#ifndef STATUS_NOT_SAME_DEVICE
+# define STATUS_NOT_SAME_DEVICE ((NTSTATUS) 0xC00000D4L)
+#endif
+
+#ifndef STATUS_FILE_RENAMED
+# define STATUS_FILE_RENAMED ((NTSTATUS) 0xC00000D5L)
+#endif
+
+#ifndef STATUS_VIRTUAL_CIRCUIT_CLOSED
+# define STATUS_VIRTUAL_CIRCUIT_CLOSED ((NTSTATUS) 0xC00000D6L)
+#endif
+
+#ifndef STATUS_NO_SECURITY_ON_OBJECT
+# define STATUS_NO_SECURITY_ON_OBJECT ((NTSTATUS) 0xC00000D7L)
+#endif
+
+#ifndef STATUS_CANT_WAIT
+# define STATUS_CANT_WAIT ((NTSTATUS) 0xC00000D8L)
+#endif
+
+#ifndef STATUS_PIPE_EMPTY
+# define STATUS_PIPE_EMPTY ((NTSTATUS) 0xC00000D9L)
+#endif
+
+#ifndef STATUS_CANT_ACCESS_DOMAIN_INFO
+# define STATUS_CANT_ACCESS_DOMAIN_INFO ((NTSTATUS) 0xC00000DAL)
+#endif
+
+#ifndef STATUS_CANT_TERMINATE_SELF
+# define STATUS_CANT_TERMINATE_SELF ((NTSTATUS) 0xC00000DBL)
+#endif
+
+#ifndef STATUS_INVALID_SERVER_STATE
+# define STATUS_INVALID_SERVER_STATE ((NTSTATUS) 0xC00000DCL)
+#endif
+
+#ifndef STATUS_INVALID_DOMAIN_STATE
+# define STATUS_INVALID_DOMAIN_STATE ((NTSTATUS) 0xC00000DDL)
+#endif
+
+#ifndef STATUS_INVALID_DOMAIN_ROLE
+# define STATUS_INVALID_DOMAIN_ROLE ((NTSTATUS) 0xC00000DEL)
+#endif
+
+#ifndef STATUS_NO_SUCH_DOMAIN
+# define STATUS_NO_SUCH_DOMAIN ((NTSTATUS) 0xC00000DFL)
+#endif
+
+#ifndef STATUS_DOMAIN_EXISTS
+# define STATUS_DOMAIN_EXISTS ((NTSTATUS) 0xC00000E0L)
+#endif
+
+#ifndef STATUS_DOMAIN_LIMIT_EXCEEDED
+# define STATUS_DOMAIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00000E1L)
+#endif
+
+#ifndef STATUS_OPLOCK_NOT_GRANTED
+# define STATUS_OPLOCK_NOT_GRANTED ((NTSTATUS) 0xC00000E2L)
+#endif
+
+#ifndef STATUS_INVALID_OPLOCK_PROTOCOL
+# define STATUS_INVALID_OPLOCK_PROTOCOL ((NTSTATUS) 0xC00000E3L)
+#endif
+
+#ifndef STATUS_INTERNAL_DB_CORRUPTION
+# define STATUS_INTERNAL_DB_CORRUPTION ((NTSTATUS) 0xC00000E4L)
+#endif
+
+#ifndef STATUS_INTERNAL_ERROR
+# define STATUS_INTERNAL_ERROR ((NTSTATUS) 0xC00000E5L)
+#endif
+
+#ifndef STATUS_GENERIC_NOT_MAPPED
+# define STATUS_GENERIC_NOT_MAPPED ((NTSTATUS) 0xC00000E6L)
+#endif
+
+#ifndef STATUS_BAD_DESCRIPTOR_FORMAT
+# define STATUS_BAD_DESCRIPTOR_FORMAT ((NTSTATUS) 0xC00000E7L)
+#endif
+
+#ifndef STATUS_INVALID_USER_BUFFER
+# define STATUS_INVALID_USER_BUFFER ((NTSTATUS) 0xC00000E8L)
+#endif
+
+#ifndef STATUS_UNEXPECTED_IO_ERROR
+# define STATUS_UNEXPECTED_IO_ERROR ((NTSTATUS) 0xC00000E9L)
+#endif
+
+#ifndef STATUS_UNEXPECTED_MM_CREATE_ERR
+# define STATUS_UNEXPECTED_MM_CREATE_ERR ((NTSTATUS) 0xC00000EAL)
+#endif
+
+#ifndef STATUS_UNEXPECTED_MM_MAP_ERROR
+# define STATUS_UNEXPECTED_MM_MAP_ERROR ((NTSTATUS) 0xC00000EBL)
+#endif
+
+#ifndef STATUS_UNEXPECTED_MM_EXTEND_ERR
+# define STATUS_UNEXPECTED_MM_EXTEND_ERR ((NTSTATUS) 0xC00000ECL)
+#endif
+
+#ifndef STATUS_NOT_LOGON_PROCESS
+# define STATUS_NOT_LOGON_PROCESS ((NTSTATUS) 0xC00000EDL)
+#endif
+
+#ifndef STATUS_LOGON_SESSION_EXISTS
+# define STATUS_LOGON_SESSION_EXISTS ((NTSTATUS) 0xC00000EEL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_1
+# define STATUS_INVALID_PARAMETER_1 ((NTSTATUS) 0xC00000EFL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_2
+# define STATUS_INVALID_PARAMETER_2 ((NTSTATUS) 0xC00000F0L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_3
+# define STATUS_INVALID_PARAMETER_3 ((NTSTATUS) 0xC00000F1L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_4
+# define STATUS_INVALID_PARAMETER_4 ((NTSTATUS) 0xC00000F2L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_5
+# define STATUS_INVALID_PARAMETER_5 ((NTSTATUS) 0xC00000F3L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_6
+# define STATUS_INVALID_PARAMETER_6 ((NTSTATUS) 0xC00000F4L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_7
+# define STATUS_INVALID_PARAMETER_7 ((NTSTATUS) 0xC00000F5L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_8
+# define STATUS_INVALID_PARAMETER_8 ((NTSTATUS) 0xC00000F6L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_9
+# define STATUS_INVALID_PARAMETER_9 ((NTSTATUS) 0xC00000F7L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_10
+# define STATUS_INVALID_PARAMETER_10 ((NTSTATUS) 0xC00000F8L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_11
+# define STATUS_INVALID_PARAMETER_11 ((NTSTATUS) 0xC00000F9L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_12
+# define STATUS_INVALID_PARAMETER_12 ((NTSTATUS) 0xC00000FAL)
+#endif
+
+#ifndef STATUS_REDIRECTOR_NOT_STARTED
+# define STATUS_REDIRECTOR_NOT_STARTED ((NTSTATUS) 0xC00000FBL)
+#endif
+
+#ifndef STATUS_REDIRECTOR_STARTED
+# define STATUS_REDIRECTOR_STARTED ((NTSTATUS) 0xC00000FCL)
+#endif
+
+#ifndef STATUS_STACK_OVERFLOW
+# define STATUS_STACK_OVERFLOW ((NTSTATUS) 0xC00000FDL)
+#endif
+
+#ifndef STATUS_NO_SUCH_PACKAGE
+# define STATUS_NO_SUCH_PACKAGE ((NTSTATUS) 0xC00000FEL)
+#endif
+
+#ifndef STATUS_BAD_FUNCTION_TABLE
+# define STATUS_BAD_FUNCTION_TABLE ((NTSTATUS) 0xC00000FFL)
+#endif
+
+#ifndef STATUS_VARIABLE_NOT_FOUND
+# define STATUS_VARIABLE_NOT_FOUND ((NTSTATUS) 0xC0000100L)
+#endif
+
+#ifndef STATUS_DIRECTORY_NOT_EMPTY
+# define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS) 0xC0000101L)
+#endif
+
+#ifndef STATUS_FILE_CORRUPT_ERROR
+# define STATUS_FILE_CORRUPT_ERROR ((NTSTATUS) 0xC0000102L)
+#endif
+
+#ifndef STATUS_NOT_A_DIRECTORY
+# define STATUS_NOT_A_DIRECTORY ((NTSTATUS) 0xC0000103L)
+#endif
+
+#ifndef STATUS_BAD_LOGON_SESSION_STATE
+# define STATUS_BAD_LOGON_SESSION_STATE ((NTSTATUS) 0xC0000104L)
+#endif
+
+#ifndef STATUS_LOGON_SESSION_COLLISION
+# define STATUS_LOGON_SESSION_COLLISION ((NTSTATUS) 0xC0000105L)
+#endif
+
+#ifndef STATUS_NAME_TOO_LONG
+# define STATUS_NAME_TOO_LONG ((NTSTATUS) 0xC0000106L)
+#endif
+
+#ifndef STATUS_FILES_OPEN
+# define STATUS_FILES_OPEN ((NTSTATUS) 0xC0000107L)
+#endif
+
+#ifndef STATUS_CONNECTION_IN_USE
+# define STATUS_CONNECTION_IN_USE ((NTSTATUS) 0xC0000108L)
+#endif
+
+#ifndef STATUS_MESSAGE_NOT_FOUND
+# define STATUS_MESSAGE_NOT_FOUND ((NTSTATUS) 0xC0000109L)
+#endif
+
+#ifndef STATUS_PROCESS_IS_TERMINATING
+# define STATUS_PROCESS_IS_TERMINATING ((NTSTATUS) 0xC000010AL)
+#endif
+
+#ifndef STATUS_INVALID_LOGON_TYPE
+# define STATUS_INVALID_LOGON_TYPE ((NTSTATUS) 0xC000010BL)
+#endif
+
+#ifndef STATUS_NO_GUID_TRANSLATION
+# define STATUS_NO_GUID_TRANSLATION ((NTSTATUS) 0xC000010CL)
+#endif
+
+#ifndef STATUS_CANNOT_IMPERSONATE
+# define STATUS_CANNOT_IMPERSONATE ((NTSTATUS) 0xC000010DL)
+#endif
+
+#ifndef STATUS_IMAGE_ALREADY_LOADED
+# define STATUS_IMAGE_ALREADY_LOADED ((NTSTATUS) 0xC000010EL)
+#endif
+
+#ifndef STATUS_ABIOS_NOT_PRESENT
+# define STATUS_ABIOS_NOT_PRESENT ((NTSTATUS) 0xC000010FL)
+#endif
+
+#ifndef STATUS_ABIOS_LID_NOT_EXIST
+# define STATUS_ABIOS_LID_NOT_EXIST ((NTSTATUS) 0xC0000110L)
+#endif
+
+#ifndef STATUS_ABIOS_LID_ALREADY_OWNED
+# define STATUS_ABIOS_LID_ALREADY_OWNED ((NTSTATUS) 0xC0000111L)
+#endif
+
+#ifndef STATUS_ABIOS_NOT_LID_OWNER
+# define STATUS_ABIOS_NOT_LID_OWNER ((NTSTATUS) 0xC0000112L)
+#endif
+
+#ifndef STATUS_ABIOS_INVALID_COMMAND
+# define STATUS_ABIOS_INVALID_COMMAND ((NTSTATUS) 0xC0000113L)
+#endif
+
+#ifndef STATUS_ABIOS_INVALID_LID
+# define STATUS_ABIOS_INVALID_LID ((NTSTATUS) 0xC0000114L)
+#endif
+
+#ifndef STATUS_ABIOS_SELECTOR_NOT_AVAILABLE
+# define STATUS_ABIOS_SELECTOR_NOT_AVAILABLE ((NTSTATUS) 0xC0000115L)
+#endif
+
+#ifndef STATUS_ABIOS_INVALID_SELECTOR
+# define STATUS_ABIOS_INVALID_SELECTOR ((NTSTATUS) 0xC0000116L)
+#endif
+
+#ifndef STATUS_NO_LDT
+# define STATUS_NO_LDT ((NTSTATUS) 0xC0000117L)
+#endif
+
+#ifndef STATUS_INVALID_LDT_SIZE
+# define STATUS_INVALID_LDT_SIZE ((NTSTATUS) 0xC0000118L)
+#endif
+
+#ifndef STATUS_INVALID_LDT_OFFSET
+# define STATUS_INVALID_LDT_OFFSET ((NTSTATUS) 0xC0000119L)
+#endif
+
+#ifndef STATUS_INVALID_LDT_DESCRIPTOR
+# define STATUS_INVALID_LDT_DESCRIPTOR ((NTSTATUS) 0xC000011AL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_NE_FORMAT
+# define STATUS_INVALID_IMAGE_NE_FORMAT ((NTSTATUS) 0xC000011BL)
+#endif
+
+#ifndef STATUS_RXACT_INVALID_STATE
+# define STATUS_RXACT_INVALID_STATE ((NTSTATUS) 0xC000011CL)
+#endif
+
+#ifndef STATUS_RXACT_COMMIT_FAILURE
+# define STATUS_RXACT_COMMIT_FAILURE ((NTSTATUS) 0xC000011DL)
+#endif
+
+#ifndef STATUS_MAPPED_FILE_SIZE_ZERO
+# define STATUS_MAPPED_FILE_SIZE_ZERO ((NTSTATUS) 0xC000011EL)
+#endif
+
+#ifndef STATUS_TOO_MANY_OPENED_FILES
+# define STATUS_TOO_MANY_OPENED_FILES ((NTSTATUS) 0xC000011FL)
+#endif
+
+#ifndef STATUS_CANCELLED
+# define STATUS_CANCELLED ((NTSTATUS) 0xC0000120L)
+#endif
+
+#ifndef STATUS_CANNOT_DELETE
+# define STATUS_CANNOT_DELETE ((NTSTATUS) 0xC0000121L)
+#endif
+
+#ifndef STATUS_INVALID_COMPUTER_NAME
+# define STATUS_INVALID_COMPUTER_NAME ((NTSTATUS) 0xC0000122L)
+#endif
+
+#ifndef STATUS_FILE_DELETED
+# define STATUS_FILE_DELETED ((NTSTATUS) 0xC0000123L)
+#endif
+
+#ifndef STATUS_SPECIAL_ACCOUNT
+# define STATUS_SPECIAL_ACCOUNT ((NTSTATUS) 0xC0000124L)
+#endif
+
+#ifndef STATUS_SPECIAL_GROUP
+# define STATUS_SPECIAL_GROUP ((NTSTATUS) 0xC0000125L)
+#endif
+
+#ifndef STATUS_SPECIAL_USER
+# define STATUS_SPECIAL_USER ((NTSTATUS) 0xC0000126L)
+#endif
+
+#ifndef STATUS_MEMBERS_PRIMARY_GROUP
+# define STATUS_MEMBERS_PRIMARY_GROUP ((NTSTATUS) 0xC0000127L)
+#endif
+
+#ifndef STATUS_FILE_CLOSED
+# define STATUS_FILE_CLOSED ((NTSTATUS) 0xC0000128L)
+#endif
+
+#ifndef STATUS_TOO_MANY_THREADS
+# define STATUS_TOO_MANY_THREADS ((NTSTATUS) 0xC0000129L)
+#endif
+
+#ifndef STATUS_THREAD_NOT_IN_PROCESS
+# define STATUS_THREAD_NOT_IN_PROCESS ((NTSTATUS) 0xC000012AL)
+#endif
+
+#ifndef STATUS_TOKEN_ALREADY_IN_USE
+# define STATUS_TOKEN_ALREADY_IN_USE ((NTSTATUS) 0xC000012BL)
+#endif
+
+#ifndef STATUS_PAGEFILE_QUOTA_EXCEEDED
+# define STATUS_PAGEFILE_QUOTA_EXCEEDED ((NTSTATUS) 0xC000012CL)
+#endif
+
+#ifndef STATUS_COMMITMENT_LIMIT
+# define STATUS_COMMITMENT_LIMIT ((NTSTATUS) 0xC000012DL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_LE_FORMAT
+# define STATUS_INVALID_IMAGE_LE_FORMAT ((NTSTATUS) 0xC000012EL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_NOT_MZ
+# define STATUS_INVALID_IMAGE_NOT_MZ ((NTSTATUS) 0xC000012FL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_PROTECT
+# define STATUS_INVALID_IMAGE_PROTECT ((NTSTATUS) 0xC0000130L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_WIN_16
+# define STATUS_INVALID_IMAGE_WIN_16 ((NTSTATUS) 0xC0000131L)
+#endif
+
+#ifndef STATUS_LOGON_SERVER_CONFLICT
+# define STATUS_LOGON_SERVER_CONFLICT ((NTSTATUS) 0xC0000132L)
+#endif
+
+#ifndef STATUS_TIME_DIFFERENCE_AT_DC
+# define STATUS_TIME_DIFFERENCE_AT_DC ((NTSTATUS) 0xC0000133L)
+#endif
+
+#ifndef STATUS_SYNCHRONIZATION_REQUIRED
+# define STATUS_SYNCHRONIZATION_REQUIRED ((NTSTATUS) 0xC0000134L)
+#endif
+
+#ifndef STATUS_DLL_NOT_FOUND
+# define STATUS_DLL_NOT_FOUND ((NTSTATUS) 0xC0000135L)
+#endif
+
+#ifndef STATUS_OPEN_FAILED
+# define STATUS_OPEN_FAILED ((NTSTATUS) 0xC0000136L)
+#endif
+
+#ifndef STATUS_IO_PRIVILEGE_FAILED
+# define STATUS_IO_PRIVILEGE_FAILED ((NTSTATUS) 0xC0000137L)
+#endif
+
+#ifndef STATUS_ORDINAL_NOT_FOUND
+# define STATUS_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000138L)
+#endif
+
+#ifndef STATUS_ENTRYPOINT_NOT_FOUND
+# define STATUS_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000139L)
+#endif
+
+#ifndef STATUS_CONTROL_C_EXIT
+# define STATUS_CONTROL_C_EXIT ((NTSTATUS) 0xC000013AL)
+#endif
+
+#ifndef STATUS_LOCAL_DISCONNECT
+# define STATUS_LOCAL_DISCONNECT ((NTSTATUS) 0xC000013BL)
+#endif
+
+#ifndef STATUS_REMOTE_DISCONNECT
+# define STATUS_REMOTE_DISCONNECT ((NTSTATUS) 0xC000013CL)
+#endif
+
+#ifndef STATUS_REMOTE_RESOURCES
+# define STATUS_REMOTE_RESOURCES ((NTSTATUS) 0xC000013DL)
+#endif
+
+#ifndef STATUS_LINK_FAILED
+# define STATUS_LINK_FAILED ((NTSTATUS) 0xC000013EL)
+#endif
+
+#ifndef STATUS_LINK_TIMEOUT
+# define STATUS_LINK_TIMEOUT ((NTSTATUS) 0xC000013FL)
+#endif
+
+#ifndef STATUS_INVALID_CONNECTION
+# define STATUS_INVALID_CONNECTION ((NTSTATUS) 0xC0000140L)
+#endif
+
+#ifndef STATUS_INVALID_ADDRESS
+# define STATUS_INVALID_ADDRESS ((NTSTATUS) 0xC0000141L)
+#endif
+
+#ifndef STATUS_DLL_INIT_FAILED
+# define STATUS_DLL_INIT_FAILED ((NTSTATUS) 0xC0000142L)
+#endif
+
+#ifndef STATUS_MISSING_SYSTEMFILE
+# define STATUS_MISSING_SYSTEMFILE ((NTSTATUS) 0xC0000143L)
+#endif
+
+#ifndef STATUS_UNHANDLED_EXCEPTION
+# define STATUS_UNHANDLED_EXCEPTION ((NTSTATUS) 0xC0000144L)
+#endif
+
+#ifndef STATUS_APP_INIT_FAILURE
+# define STATUS_APP_INIT_FAILURE ((NTSTATUS) 0xC0000145L)
+#endif
+
+#ifndef STATUS_PAGEFILE_CREATE_FAILED
+# define STATUS_PAGEFILE_CREATE_FAILED ((NTSTATUS) 0xC0000146L)
+#endif
+
+#ifndef STATUS_NO_PAGEFILE
+# define STATUS_NO_PAGEFILE ((NTSTATUS) 0xC0000147L)
+#endif
+
+#ifndef STATUS_INVALID_LEVEL
+# define STATUS_INVALID_LEVEL ((NTSTATUS) 0xC0000148L)
+#endif
+
+#ifndef STATUS_WRONG_PASSWORD_CORE
+# define STATUS_WRONG_PASSWORD_CORE ((NTSTATUS) 0xC0000149L)
+#endif
+
+#ifndef STATUS_ILLEGAL_FLOAT_CONTEXT
+# define STATUS_ILLEGAL_FLOAT_CONTEXT ((NTSTATUS) 0xC000014AL)
+#endif
+
+#ifndef STATUS_PIPE_BROKEN
+# define STATUS_PIPE_BROKEN ((NTSTATUS) 0xC000014BL)
+#endif
+
+#ifndef STATUS_REGISTRY_CORRUPT
+# define STATUS_REGISTRY_CORRUPT ((NTSTATUS) 0xC000014CL)
+#endif
+
+#ifndef STATUS_REGISTRY_IO_FAILED
+# define STATUS_REGISTRY_IO_FAILED ((NTSTATUS) 0xC000014DL)
+#endif
+
+#ifndef STATUS_NO_EVENT_PAIR
+# define STATUS_NO_EVENT_PAIR ((NTSTATUS) 0xC000014EL)
+#endif
+
+#ifndef STATUS_UNRECOGNIZED_VOLUME
+# define STATUS_UNRECOGNIZED_VOLUME ((NTSTATUS) 0xC000014FL)
+#endif
+
+#ifndef STATUS_SERIAL_NO_DEVICE_INITED
+# define STATUS_SERIAL_NO_DEVICE_INITED ((NTSTATUS) 0xC0000150L)
+#endif
+
+#ifndef STATUS_NO_SUCH_ALIAS
+# define STATUS_NO_SUCH_ALIAS ((NTSTATUS) 0xC0000151L)
+#endif
+
+#ifndef STATUS_MEMBER_NOT_IN_ALIAS
+# define STATUS_MEMBER_NOT_IN_ALIAS ((NTSTATUS) 0xC0000152L)
+#endif
+
+#ifndef STATUS_MEMBER_IN_ALIAS
+# define STATUS_MEMBER_IN_ALIAS ((NTSTATUS) 0xC0000153L)
+#endif
+
+#ifndef STATUS_ALIAS_EXISTS
+# define STATUS_ALIAS_EXISTS ((NTSTATUS) 0xC0000154L)
+#endif
+
+#ifndef STATUS_LOGON_NOT_GRANTED
+# define STATUS_LOGON_NOT_GRANTED ((NTSTATUS) 0xC0000155L)
+#endif
+
+#ifndef STATUS_TOO_MANY_SECRETS
+# define STATUS_TOO_MANY_SECRETS ((NTSTATUS) 0xC0000156L)
+#endif
+
+#ifndef STATUS_SECRET_TOO_LONG
+# define STATUS_SECRET_TOO_LONG ((NTSTATUS) 0xC0000157L)
+#endif
+
+#ifndef STATUS_INTERNAL_DB_ERROR
+# define STATUS_INTERNAL_DB_ERROR ((NTSTATUS) 0xC0000158L)
+#endif
+
+#ifndef STATUS_FULLSCREEN_MODE
+# define STATUS_FULLSCREEN_MODE ((NTSTATUS) 0xC0000159L)
+#endif
+
+#ifndef STATUS_TOO_MANY_CONTEXT_IDS
+# define STATUS_TOO_MANY_CONTEXT_IDS ((NTSTATUS) 0xC000015AL)
+#endif
+
+#ifndef STATUS_LOGON_TYPE_NOT_GRANTED
+# define STATUS_LOGON_TYPE_NOT_GRANTED ((NTSTATUS) 0xC000015BL)
+#endif
+
+#ifndef STATUS_NOT_REGISTRY_FILE
+# define STATUS_NOT_REGISTRY_FILE ((NTSTATUS) 0xC000015CL)
+#endif
+
+#ifndef STATUS_NT_CROSS_ENCRYPTION_REQUIRED
+# define STATUS_NT_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000015DL)
+#endif
+
+#ifndef STATUS_DOMAIN_CTRLR_CONFIG_ERROR
+# define STATUS_DOMAIN_CTRLR_CONFIG_ERROR ((NTSTATUS) 0xC000015EL)
+#endif
+
+#ifndef STATUS_FT_MISSING_MEMBER
+# define STATUS_FT_MISSING_MEMBER ((NTSTATUS) 0xC000015FL)
+#endif
+
+#ifndef STATUS_ILL_FORMED_SERVICE_ENTRY
+# define STATUS_ILL_FORMED_SERVICE_ENTRY ((NTSTATUS) 0xC0000160L)
+#endif
+
+#ifndef STATUS_ILLEGAL_CHARACTER
+# define STATUS_ILLEGAL_CHARACTER ((NTSTATUS) 0xC0000161L)
+#endif
+
+#ifndef STATUS_UNMAPPABLE_CHARACTER
+# define STATUS_UNMAPPABLE_CHARACTER ((NTSTATUS) 0xC0000162L)
+#endif
+
+#ifndef STATUS_UNDEFINED_CHARACTER
+# define STATUS_UNDEFINED_CHARACTER ((NTSTATUS) 0xC0000163L)
+#endif
+
+#ifndef STATUS_FLOPPY_VOLUME
+# define STATUS_FLOPPY_VOLUME ((NTSTATUS) 0xC0000164L)
+#endif
+
+#ifndef STATUS_FLOPPY_ID_MARK_NOT_FOUND
+# define STATUS_FLOPPY_ID_MARK_NOT_FOUND ((NTSTATUS) 0xC0000165L)
+#endif
+
+#ifndef STATUS_FLOPPY_WRONG_CYLINDER
+# define STATUS_FLOPPY_WRONG_CYLINDER ((NTSTATUS) 0xC0000166L)
+#endif
+
+#ifndef STATUS_FLOPPY_UNKNOWN_ERROR
+# define STATUS_FLOPPY_UNKNOWN_ERROR ((NTSTATUS) 0xC0000167L)
+#endif
+
+#ifndef STATUS_FLOPPY_BAD_REGISTERS
+# define STATUS_FLOPPY_BAD_REGISTERS ((NTSTATUS) 0xC0000168L)
+#endif
+
+#ifndef STATUS_DISK_RECALIBRATE_FAILED
+# define STATUS_DISK_RECALIBRATE_FAILED ((NTSTATUS) 0xC0000169L)
+#endif
+
+#ifndef STATUS_DISK_OPERATION_FAILED
+# define STATUS_DISK_OPERATION_FAILED ((NTSTATUS) 0xC000016AL)
+#endif
+
+#ifndef STATUS_DISK_RESET_FAILED
+# define STATUS_DISK_RESET_FAILED ((NTSTATUS) 0xC000016BL)
+#endif
+
+#ifndef STATUS_SHARED_IRQ_BUSY
+# define STATUS_SHARED_IRQ_BUSY ((NTSTATUS) 0xC000016CL)
+#endif
+
+#ifndef STATUS_FT_ORPHANING
+# define STATUS_FT_ORPHANING ((NTSTATUS) 0xC000016DL)
+#endif
+
+#ifndef STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT
+# define STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT ((NTSTATUS) 0xC000016EL)
+#endif
+
+#ifndef STATUS_PARTITION_FAILURE
+# define STATUS_PARTITION_FAILURE ((NTSTATUS) 0xC0000172L)
+#endif
+
+#ifndef STATUS_INVALID_BLOCK_LENGTH
+# define STATUS_INVALID_BLOCK_LENGTH ((NTSTATUS) 0xC0000173L)
+#endif
+
+#ifndef STATUS_DEVICE_NOT_PARTITIONED
+# define STATUS_DEVICE_NOT_PARTITIONED ((NTSTATUS) 0xC0000174L)
+#endif
+
+#ifndef STATUS_UNABLE_TO_LOCK_MEDIA
+# define STATUS_UNABLE_TO_LOCK_MEDIA ((NTSTATUS) 0xC0000175L)
+#endif
+
+#ifndef STATUS_UNABLE_TO_UNLOAD_MEDIA
+# define STATUS_UNABLE_TO_UNLOAD_MEDIA ((NTSTATUS) 0xC0000176L)
+#endif
+
+#ifndef STATUS_EOM_OVERFLOW
+# define STATUS_EOM_OVERFLOW ((NTSTATUS) 0xC0000177L)
+#endif
+
+#ifndef STATUS_NO_MEDIA
+# define STATUS_NO_MEDIA ((NTSTATUS) 0xC0000178L)
+#endif
+
+#ifndef STATUS_NO_SUCH_MEMBER
+# define STATUS_NO_SUCH_MEMBER ((NTSTATUS) 0xC000017AL)
+#endif
+
+#ifndef STATUS_INVALID_MEMBER
+# define STATUS_INVALID_MEMBER ((NTSTATUS) 0xC000017BL)
+#endif
+
+#ifndef STATUS_KEY_DELETED
+# define STATUS_KEY_DELETED ((NTSTATUS) 0xC000017CL)
+#endif
+
+#ifndef STATUS_NO_LOG_SPACE
+# define STATUS_NO_LOG_SPACE ((NTSTATUS) 0xC000017DL)
+#endif
+
+#ifndef STATUS_TOO_MANY_SIDS
+# define STATUS_TOO_MANY_SIDS ((NTSTATUS) 0xC000017EL)
+#endif
+
+#ifndef STATUS_LM_CROSS_ENCRYPTION_REQUIRED
+# define STATUS_LM_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000017FL)
+#endif
+
+#ifndef STATUS_KEY_HAS_CHILDREN
+# define STATUS_KEY_HAS_CHILDREN ((NTSTATUS) 0xC0000180L)
+#endif
+
+#ifndef STATUS_CHILD_MUST_BE_VOLATILE
+# define STATUS_CHILD_MUST_BE_VOLATILE ((NTSTATUS) 0xC0000181L)
+#endif
+
+#ifndef STATUS_DEVICE_CONFIGURATION_ERROR
+# define STATUS_DEVICE_CONFIGURATION_ERROR ((NTSTATUS) 0xC0000182L)
+#endif
+
+#ifndef STATUS_DRIVER_INTERNAL_ERROR
+# define STATUS_DRIVER_INTERNAL_ERROR ((NTSTATUS) 0xC0000183L)
+#endif
+
+#ifndef STATUS_INVALID_DEVICE_STATE
+# define STATUS_INVALID_DEVICE_STATE ((NTSTATUS) 0xC0000184L)
+#endif
+
+#ifndef STATUS_IO_DEVICE_ERROR
+# define STATUS_IO_DEVICE_ERROR ((NTSTATUS) 0xC0000185L)
+#endif
+
+#ifndef STATUS_DEVICE_PROTOCOL_ERROR
+# define STATUS_DEVICE_PROTOCOL_ERROR ((NTSTATUS) 0xC0000186L)
+#endif
+
+#ifndef STATUS_BACKUP_CONTROLLER
+# define STATUS_BACKUP_CONTROLLER ((NTSTATUS) 0xC0000187L)
+#endif
+
+#ifndef STATUS_LOG_FILE_FULL
+# define STATUS_LOG_FILE_FULL ((NTSTATUS) 0xC0000188L)
+#endif
+
+#ifndef STATUS_TOO_LATE
+# define STATUS_TOO_LATE ((NTSTATUS) 0xC0000189L)
+#endif
+
+#ifndef STATUS_NO_TRUST_LSA_SECRET
+# define STATUS_NO_TRUST_LSA_SECRET ((NTSTATUS) 0xC000018AL)
+#endif
+
+#ifndef STATUS_NO_TRUST_SAM_ACCOUNT
+# define STATUS_NO_TRUST_SAM_ACCOUNT ((NTSTATUS) 0xC000018BL)
+#endif
+
+#ifndef STATUS_TRUSTED_DOMAIN_FAILURE
+# define STATUS_TRUSTED_DOMAIN_FAILURE ((NTSTATUS) 0xC000018CL)
+#endif
+
+#ifndef STATUS_TRUSTED_RELATIONSHIP_FAILURE
+# define STATUS_TRUSTED_RELATIONSHIP_FAILURE ((NTSTATUS) 0xC000018DL)
+#endif
+
+#ifndef STATUS_EVENTLOG_FILE_CORRUPT
+# define STATUS_EVENTLOG_FILE_CORRUPT ((NTSTATUS) 0xC000018EL)
+#endif
+
+#ifndef STATUS_EVENTLOG_CANT_START
+# define STATUS_EVENTLOG_CANT_START ((NTSTATUS) 0xC000018FL)
+#endif
+
+#ifndef STATUS_TRUST_FAILURE
+# define STATUS_TRUST_FAILURE ((NTSTATUS) 0xC0000190L)
+#endif
+
+#ifndef STATUS_MUTANT_LIMIT_EXCEEDED
+# define STATUS_MUTANT_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000191L)
+#endif
+
+#ifndef STATUS_NETLOGON_NOT_STARTED
+# define STATUS_NETLOGON_NOT_STARTED ((NTSTATUS) 0xC0000192L)
+#endif
+
+#ifndef STATUS_ACCOUNT_EXPIRED
+# define STATUS_ACCOUNT_EXPIRED ((NTSTATUS) 0xC0000193L)
+#endif
+
+#ifndef STATUS_POSSIBLE_DEADLOCK
+# define STATUS_POSSIBLE_DEADLOCK ((NTSTATUS) 0xC0000194L)
+#endif
+
+#ifndef STATUS_NETWORK_CREDENTIAL_CONFLICT
+# define STATUS_NETWORK_CREDENTIAL_CONFLICT ((NTSTATUS) 0xC0000195L)
+#endif
+
+#ifndef STATUS_REMOTE_SESSION_LIMIT
+# define STATUS_REMOTE_SESSION_LIMIT ((NTSTATUS) 0xC0000196L)
+#endif
+
+#ifndef STATUS_EVENTLOG_FILE_CHANGED
+# define STATUS_EVENTLOG_FILE_CHANGED ((NTSTATUS) 0xC0000197L)
+#endif
+
+#ifndef STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
+# define STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ((NTSTATUS) 0xC0000198L)
+#endif
+
+#ifndef STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
+# define STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT ((NTSTATUS) 0xC0000199L)
+#endif
+
+#ifndef STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
+# define STATUS_NOLOGON_SERVER_TRUST_ACCOUNT ((NTSTATUS) 0xC000019AL)
+#endif
+
+#ifndef STATUS_DOMAIN_TRUST_INCONSISTENT
+# define STATUS_DOMAIN_TRUST_INCONSISTENT ((NTSTATUS) 0xC000019BL)
+#endif
+
+#ifndef STATUS_FS_DRIVER_REQUIRED
+# define STATUS_FS_DRIVER_REQUIRED ((NTSTATUS) 0xC000019CL)
+#endif
+
+#ifndef STATUS_IMAGE_ALREADY_LOADED_AS_DLL
+# define STATUS_IMAGE_ALREADY_LOADED_AS_DLL ((NTSTATUS) 0xC000019DL)
+#endif
+
+#ifndef STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING
+# define STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING ((NTSTATUS) 0xC000019EL)
+#endif
+
+#ifndef STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME
+# define STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME ((NTSTATUS) 0xC000019FL)
+#endif
+
+#ifndef STATUS_SECURITY_STREAM_IS_INCONSISTENT
+# define STATUS_SECURITY_STREAM_IS_INCONSISTENT ((NTSTATUS) 0xC00001A0L)
+#endif
+
+#ifndef STATUS_INVALID_LOCK_RANGE
+# define STATUS_INVALID_LOCK_RANGE ((NTSTATUS) 0xC00001A1L)
+#endif
+
+#ifndef STATUS_INVALID_ACE_CONDITION
+# define STATUS_INVALID_ACE_CONDITION ((NTSTATUS) 0xC00001A2L)
+#endif
+
+#ifndef STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT
+# define STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT ((NTSTATUS) 0xC00001A3L)
+#endif
+
+#ifndef STATUS_NOTIFICATION_GUID_ALREADY_DEFINED
+# define STATUS_NOTIFICATION_GUID_ALREADY_DEFINED ((NTSTATUS) 0xC00001A4L)
+#endif
+
+#ifndef STATUS_NETWORK_OPEN_RESTRICTION
+# define STATUS_NETWORK_OPEN_RESTRICTION ((NTSTATUS) 0xC0000201L)
+#endif
+
+#ifndef STATUS_NO_USER_SESSION_KEY
+# define STATUS_NO_USER_SESSION_KEY ((NTSTATUS) 0xC0000202L)
+#endif
+
+#ifndef STATUS_USER_SESSION_DELETED
+# define STATUS_USER_SESSION_DELETED ((NTSTATUS) 0xC0000203L)
+#endif
+
+#ifndef STATUS_RESOURCE_LANG_NOT_FOUND
+# define STATUS_RESOURCE_LANG_NOT_FOUND ((NTSTATUS) 0xC0000204L)
+#endif
+
+#ifndef STATUS_INSUFF_SERVER_RESOURCES
+# define STATUS_INSUFF_SERVER_RESOURCES ((NTSTATUS) 0xC0000205L)
+#endif
+
+#ifndef STATUS_INVALID_BUFFER_SIZE
+# define STATUS_INVALID_BUFFER_SIZE ((NTSTATUS) 0xC0000206L)
+#endif
+
+#ifndef STATUS_INVALID_ADDRESS_COMPONENT
+# define STATUS_INVALID_ADDRESS_COMPONENT ((NTSTATUS) 0xC0000207L)
+#endif
+
+#ifndef STATUS_INVALID_ADDRESS_WILDCARD
+# define STATUS_INVALID_ADDRESS_WILDCARD ((NTSTATUS) 0xC0000208L)
+#endif
+
+#ifndef STATUS_TOO_MANY_ADDRESSES
+# define STATUS_TOO_MANY_ADDRESSES ((NTSTATUS) 0xC0000209L)
+#endif
+
+#ifndef STATUS_ADDRESS_ALREADY_EXISTS
+# define STATUS_ADDRESS_ALREADY_EXISTS ((NTSTATUS) 0xC000020AL)
+#endif
+
+#ifndef STATUS_ADDRESS_CLOSED
+# define STATUS_ADDRESS_CLOSED ((NTSTATUS) 0xC000020BL)
+#endif
+
+#ifndef STATUS_CONNECTION_DISCONNECTED
+# define STATUS_CONNECTION_DISCONNECTED ((NTSTATUS) 0xC000020CL)
+#endif
+
+#ifndef STATUS_CONNECTION_RESET
+# define STATUS_CONNECTION_RESET ((NTSTATUS) 0xC000020DL)
+#endif
+
+#ifndef STATUS_TOO_MANY_NODES
+# define STATUS_TOO_MANY_NODES ((NTSTATUS) 0xC000020EL)
+#endif
+
+#ifndef STATUS_TRANSACTION_ABORTED
+# define STATUS_TRANSACTION_ABORTED ((NTSTATUS) 0xC000020FL)
+#endif
+
+#ifndef STATUS_TRANSACTION_TIMED_OUT
+# define STATUS_TRANSACTION_TIMED_OUT ((NTSTATUS) 0xC0000210L)
+#endif
+
+#ifndef STATUS_TRANSACTION_NO_RELEASE
+# define STATUS_TRANSACTION_NO_RELEASE ((NTSTATUS) 0xC0000211L)
+#endif
+
+#ifndef STATUS_TRANSACTION_NO_MATCH
+# define STATUS_TRANSACTION_NO_MATCH ((NTSTATUS) 0xC0000212L)
+#endif
+
+#ifndef STATUS_TRANSACTION_RESPONDED
+# define STATUS_TRANSACTION_RESPONDED ((NTSTATUS) 0xC0000213L)
+#endif
+
+#ifndef STATUS_TRANSACTION_INVALID_ID
+# define STATUS_TRANSACTION_INVALID_ID ((NTSTATUS) 0xC0000214L)
+#endif
+
+#ifndef STATUS_TRANSACTION_INVALID_TYPE
+# define STATUS_TRANSACTION_INVALID_TYPE ((NTSTATUS) 0xC0000215L)
+#endif
+
+#ifndef STATUS_NOT_SERVER_SESSION
+# define STATUS_NOT_SERVER_SESSION ((NTSTATUS) 0xC0000216L)
+#endif
+
+#ifndef STATUS_NOT_CLIENT_SESSION
+# define STATUS_NOT_CLIENT_SESSION ((NTSTATUS) 0xC0000217L)
+#endif
+
+#ifndef STATUS_CANNOT_LOAD_REGISTRY_FILE
+# define STATUS_CANNOT_LOAD_REGISTRY_FILE ((NTSTATUS) 0xC0000218L)
+#endif
+
+#ifndef STATUS_DEBUG_ATTACH_FAILED
+# define STATUS_DEBUG_ATTACH_FAILED ((NTSTATUS) 0xC0000219L)
+#endif
+
+#ifndef STATUS_SYSTEM_PROCESS_TERMINATED
+# define STATUS_SYSTEM_PROCESS_TERMINATED ((NTSTATUS) 0xC000021AL)
+#endif
+
+#ifndef STATUS_DATA_NOT_ACCEPTED
+# define STATUS_DATA_NOT_ACCEPTED ((NTSTATUS) 0xC000021BL)
+#endif
+
+#ifndef STATUS_NO_BROWSER_SERVERS_FOUND
+# define STATUS_NO_BROWSER_SERVERS_FOUND ((NTSTATUS) 0xC000021CL)
+#endif
+
+#ifndef STATUS_VDM_HARD_ERROR
+# define STATUS_VDM_HARD_ERROR ((NTSTATUS) 0xC000021DL)
+#endif
+
+#ifndef STATUS_DRIVER_CANCEL_TIMEOUT
+# define STATUS_DRIVER_CANCEL_TIMEOUT ((NTSTATUS) 0xC000021EL)
+#endif
+
+#ifndef STATUS_REPLY_MESSAGE_MISMATCH
+# define STATUS_REPLY_MESSAGE_MISMATCH ((NTSTATUS) 0xC000021FL)
+#endif
+
+#ifndef STATUS_MAPPED_ALIGNMENT
+# define STATUS_MAPPED_ALIGNMENT ((NTSTATUS) 0xC0000220L)
+#endif
+
+#ifndef STATUS_IMAGE_CHECKSUM_MISMATCH
+# define STATUS_IMAGE_CHECKSUM_MISMATCH ((NTSTATUS) 0xC0000221L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA
+# define STATUS_LOST_WRITEBEHIND_DATA ((NTSTATUS) 0xC0000222L)
+#endif
+
+#ifndef STATUS_CLIENT_SERVER_PARAMETERS_INVALID
+# define STATUS_CLIENT_SERVER_PARAMETERS_INVALID ((NTSTATUS) 0xC0000223L)
+#endif
+
+#ifndef STATUS_PASSWORD_MUST_CHANGE
+# define STATUS_PASSWORD_MUST_CHANGE ((NTSTATUS) 0xC0000224L)
+#endif
+
+#ifndef STATUS_NOT_FOUND
+# define STATUS_NOT_FOUND ((NTSTATUS) 0xC0000225L)
+#endif
+
+#ifndef STATUS_NOT_TINY_STREAM
+# define STATUS_NOT_TINY_STREAM ((NTSTATUS) 0xC0000226L)
+#endif
+
+#ifndef STATUS_RECOVERY_FAILURE
+# define STATUS_RECOVERY_FAILURE ((NTSTATUS) 0xC0000227L)
+#endif
+
+#ifndef STATUS_STACK_OVERFLOW_READ
+# define STATUS_STACK_OVERFLOW_READ ((NTSTATUS) 0xC0000228L)
+#endif
+
+#ifndef STATUS_FAIL_CHECK
+# define STATUS_FAIL_CHECK ((NTSTATUS) 0xC0000229L)
+#endif
+
+#ifndef STATUS_DUPLICATE_OBJECTID
+# define STATUS_DUPLICATE_OBJECTID ((NTSTATUS) 0xC000022AL)
+#endif
+
+#ifndef STATUS_OBJECTID_EXISTS
+# define STATUS_OBJECTID_EXISTS ((NTSTATUS) 0xC000022BL)
+#endif
+
+#ifndef STATUS_CONVERT_TO_LARGE
+# define STATUS_CONVERT_TO_LARGE ((NTSTATUS) 0xC000022CL)
+#endif
+
+#ifndef STATUS_RETRY
+# define STATUS_RETRY ((NTSTATUS) 0xC000022DL)
+#endif
+
+#ifndef STATUS_FOUND_OUT_OF_SCOPE
+# define STATUS_FOUND_OUT_OF_SCOPE ((NTSTATUS) 0xC000022EL)
+#endif
+
+#ifndef STATUS_ALLOCATE_BUCKET
+# define STATUS_ALLOCATE_BUCKET ((NTSTATUS) 0xC000022FL)
+#endif
+
+#ifndef STATUS_PROPSET_NOT_FOUND
+# define STATUS_PROPSET_NOT_FOUND ((NTSTATUS) 0xC0000230L)
+#endif
+
+#ifndef STATUS_MARSHALL_OVERFLOW
+# define STATUS_MARSHALL_OVERFLOW ((NTSTATUS) 0xC0000231L)
+#endif
+
+#ifndef STATUS_INVALID_VARIANT
+# define STATUS_INVALID_VARIANT ((NTSTATUS) 0xC0000232L)
+#endif
+
+#ifndef STATUS_DOMAIN_CONTROLLER_NOT_FOUND
+# define STATUS_DOMAIN_CONTROLLER_NOT_FOUND ((NTSTATUS) 0xC0000233L)
+#endif
+
+#ifndef STATUS_ACCOUNT_LOCKED_OUT
+# define STATUS_ACCOUNT_LOCKED_OUT ((NTSTATUS) 0xC0000234L)
+#endif
+
+#ifndef STATUS_HANDLE_NOT_CLOSABLE
+# define STATUS_HANDLE_NOT_CLOSABLE ((NTSTATUS) 0xC0000235L)
+#endif
+
+#ifndef STATUS_CONNECTION_REFUSED
+# define STATUS_CONNECTION_REFUSED ((NTSTATUS) 0xC0000236L)
+#endif
+
+#ifndef STATUS_GRACEFUL_DISCONNECT
+# define STATUS_GRACEFUL_DISCONNECT ((NTSTATUS) 0xC0000237L)
+#endif
+
+#ifndef STATUS_ADDRESS_ALREADY_ASSOCIATED
+# define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS) 0xC0000238L)
+#endif
+
+#ifndef STATUS_ADDRESS_NOT_ASSOCIATED
+# define STATUS_ADDRESS_NOT_ASSOCIATED ((NTSTATUS) 0xC0000239L)
+#endif
+
+#ifndef STATUS_CONNECTION_INVALID
+# define STATUS_CONNECTION_INVALID ((NTSTATUS) 0xC000023AL)
+#endif
+
+#ifndef STATUS_CONNECTION_ACTIVE
+# define STATUS_CONNECTION_ACTIVE ((NTSTATUS) 0xC000023BL)
+#endif
+
+#ifndef STATUS_NETWORK_UNREACHABLE
+# define STATUS_NETWORK_UNREACHABLE ((NTSTATUS) 0xC000023CL)
+#endif
+
+#ifndef STATUS_HOST_UNREACHABLE
+# define STATUS_HOST_UNREACHABLE ((NTSTATUS) 0xC000023DL)
+#endif
+
+#ifndef STATUS_PROTOCOL_UNREACHABLE
+# define STATUS_PROTOCOL_UNREACHABLE ((NTSTATUS) 0xC000023EL)
+#endif
+
+#ifndef STATUS_PORT_UNREACHABLE
+# define STATUS_PORT_UNREACHABLE ((NTSTATUS) 0xC000023FL)
+#endif
+
+#ifndef STATUS_REQUEST_ABORTED
+# define STATUS_REQUEST_ABORTED ((NTSTATUS) 0xC0000240L)
+#endif
+
+#ifndef STATUS_CONNECTION_ABORTED
+# define STATUS_CONNECTION_ABORTED ((NTSTATUS) 0xC0000241L)
+#endif
+
+#ifndef STATUS_BAD_COMPRESSION_BUFFER
+# define STATUS_BAD_COMPRESSION_BUFFER ((NTSTATUS) 0xC0000242L)
+#endif
+
+#ifndef STATUS_USER_MAPPED_FILE
+# define STATUS_USER_MAPPED_FILE ((NTSTATUS) 0xC0000243L)
+#endif
+
+#ifndef STATUS_AUDIT_FAILED
+# define STATUS_AUDIT_FAILED ((NTSTATUS) 0xC0000244L)
+#endif
+
+#ifndef STATUS_TIMER_RESOLUTION_NOT_SET
+# define STATUS_TIMER_RESOLUTION_NOT_SET ((NTSTATUS) 0xC0000245L)
+#endif
+
+#ifndef STATUS_CONNECTION_COUNT_LIMIT
+# define STATUS_CONNECTION_COUNT_LIMIT ((NTSTATUS) 0xC0000246L)
+#endif
+
+#ifndef STATUS_LOGIN_TIME_RESTRICTION
+# define STATUS_LOGIN_TIME_RESTRICTION ((NTSTATUS) 0xC0000247L)
+#endif
+
+#ifndef STATUS_LOGIN_WKSTA_RESTRICTION
+# define STATUS_LOGIN_WKSTA_RESTRICTION ((NTSTATUS) 0xC0000248L)
+#endif
+
+#ifndef STATUS_IMAGE_MP_UP_MISMATCH
+# define STATUS_IMAGE_MP_UP_MISMATCH ((NTSTATUS) 0xC0000249L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_LOGON_INFO
+# define STATUS_INSUFFICIENT_LOGON_INFO ((NTSTATUS) 0xC0000250L)
+#endif
+
+#ifndef STATUS_BAD_DLL_ENTRYPOINT
+# define STATUS_BAD_DLL_ENTRYPOINT ((NTSTATUS) 0xC0000251L)
+#endif
+
+#ifndef STATUS_BAD_SERVICE_ENTRYPOINT
+# define STATUS_BAD_SERVICE_ENTRYPOINT ((NTSTATUS) 0xC0000252L)
+#endif
+
+#ifndef STATUS_LPC_REPLY_LOST
+# define STATUS_LPC_REPLY_LOST ((NTSTATUS) 0xC0000253L)
+#endif
+
+#ifndef STATUS_IP_ADDRESS_CONFLICT1
+# define STATUS_IP_ADDRESS_CONFLICT1 ((NTSTATUS) 0xC0000254L)
+#endif
+
+#ifndef STATUS_IP_ADDRESS_CONFLICT2
+# define STATUS_IP_ADDRESS_CONFLICT2 ((NTSTATUS) 0xC0000255L)
+#endif
+
+#ifndef STATUS_REGISTRY_QUOTA_LIMIT
+# define STATUS_REGISTRY_QUOTA_LIMIT ((NTSTATUS) 0xC0000256L)
+#endif
+
+#ifndef STATUS_PATH_NOT_COVERED
+# define STATUS_PATH_NOT_COVERED ((NTSTATUS) 0xC0000257L)
+#endif
+
+#ifndef STATUS_NO_CALLBACK_ACTIVE
+# define STATUS_NO_CALLBACK_ACTIVE ((NTSTATUS) 0xC0000258L)
+#endif
+
+#ifndef STATUS_LICENSE_QUOTA_EXCEEDED
+# define STATUS_LICENSE_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000259L)
+#endif
+
+#ifndef STATUS_PWD_TOO_SHORT
+# define STATUS_PWD_TOO_SHORT ((NTSTATUS) 0xC000025AL)
+#endif
+
+#ifndef STATUS_PWD_TOO_RECENT
+# define STATUS_PWD_TOO_RECENT ((NTSTATUS) 0xC000025BL)
+#endif
+
+#ifndef STATUS_PWD_HISTORY_CONFLICT
+# define STATUS_PWD_HISTORY_CONFLICT ((NTSTATUS) 0xC000025CL)
+#endif
+
+#ifndef STATUS_PLUGPLAY_NO_DEVICE
+# define STATUS_PLUGPLAY_NO_DEVICE ((NTSTATUS) 0xC000025EL)
+#endif
+
+#ifndef STATUS_UNSUPPORTED_COMPRESSION
+# define STATUS_UNSUPPORTED_COMPRESSION ((NTSTATUS) 0xC000025FL)
+#endif
+
+#ifndef STATUS_INVALID_HW_PROFILE
+# define STATUS_INVALID_HW_PROFILE ((NTSTATUS) 0xC0000260L)
+#endif
+
+#ifndef STATUS_INVALID_PLUGPLAY_DEVICE_PATH
+# define STATUS_INVALID_PLUGPLAY_DEVICE_PATH ((NTSTATUS) 0xC0000261L)
+#endif
+
+#ifndef STATUS_DRIVER_ORDINAL_NOT_FOUND
+# define STATUS_DRIVER_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000262L)
+#endif
+
+#ifndef STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
+# define STATUS_DRIVER_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000263L)
+#endif
+
+#ifndef STATUS_RESOURCE_NOT_OWNED
+# define STATUS_RESOURCE_NOT_OWNED ((NTSTATUS) 0xC0000264L)
+#endif
+
+#ifndef STATUS_TOO_MANY_LINKS
+# define STATUS_TOO_MANY_LINKS ((NTSTATUS) 0xC0000265L)
+#endif
+
+#ifndef STATUS_QUOTA_LIST_INCONSISTENT
+# define STATUS_QUOTA_LIST_INCONSISTENT ((NTSTATUS) 0xC0000266L)
+#endif
+
+#ifndef STATUS_FILE_IS_OFFLINE
+# define STATUS_FILE_IS_OFFLINE ((NTSTATUS) 0xC0000267L)
+#endif
+
+#ifndef STATUS_EVALUATION_EXPIRATION
+# define STATUS_EVALUATION_EXPIRATION ((NTSTATUS) 0xC0000268L)
+#endif
+
+#ifndef STATUS_ILLEGAL_DLL_RELOCATION
+# define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS) 0xC0000269L)
+#endif
+
+#ifndef STATUS_LICENSE_VIOLATION
+# define STATUS_LICENSE_VIOLATION ((NTSTATUS) 0xC000026AL)
+#endif
+
+#ifndef STATUS_DLL_INIT_FAILED_LOGOFF
+# define STATUS_DLL_INIT_FAILED_LOGOFF ((NTSTATUS) 0xC000026BL)
+#endif
+
+#ifndef STATUS_DRIVER_UNABLE_TO_LOAD
+# define STATUS_DRIVER_UNABLE_TO_LOAD ((NTSTATUS) 0xC000026CL)
+#endif
+
+#ifndef STATUS_DFS_UNAVAILABLE
+# define STATUS_DFS_UNAVAILABLE ((NTSTATUS) 0xC000026DL)
+#endif
+
+#ifndef STATUS_VOLUME_DISMOUNTED
+# define STATUS_VOLUME_DISMOUNTED ((NTSTATUS) 0xC000026EL)
+#endif
+
+#ifndef STATUS_WX86_INTERNAL_ERROR
+# define STATUS_WX86_INTERNAL_ERROR ((NTSTATUS) 0xC000026FL)
+#endif
+
+#ifndef STATUS_WX86_FLOAT_STACK_CHECK
+# define STATUS_WX86_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000270L)
+#endif
+
+#ifndef STATUS_VALIDATE_CONTINUE
+# define STATUS_VALIDATE_CONTINUE ((NTSTATUS) 0xC0000271L)
+#endif
+
+#ifndef STATUS_NO_MATCH
+# define STATUS_NO_MATCH ((NTSTATUS) 0xC0000272L)
+#endif
+
+#ifndef STATUS_NO_MORE_MATCHES
+# define STATUS_NO_MORE_MATCHES ((NTSTATUS) 0xC0000273L)
+#endif
+
+#ifndef STATUS_NOT_A_REPARSE_POINT
+# define STATUS_NOT_A_REPARSE_POINT ((NTSTATUS) 0xC0000275L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_TAG_INVALID
+# define STATUS_IO_REPARSE_TAG_INVALID ((NTSTATUS) 0xC0000276L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_TAG_MISMATCH
+# define STATUS_IO_REPARSE_TAG_MISMATCH ((NTSTATUS) 0xC0000277L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_DATA_INVALID
+# define STATUS_IO_REPARSE_DATA_INVALID ((NTSTATUS) 0xC0000278L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_TAG_NOT_HANDLED
+# define STATUS_IO_REPARSE_TAG_NOT_HANDLED ((NTSTATUS) 0xC0000279L)
+#endif
+
+#ifndef STATUS_REPARSE_POINT_NOT_RESOLVED
+# define STATUS_REPARSE_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000280L)
+#endif
+
+#ifndef STATUS_DIRECTORY_IS_A_REPARSE_POINT
+# define STATUS_DIRECTORY_IS_A_REPARSE_POINT ((NTSTATUS) 0xC0000281L)
+#endif
+
+#ifndef STATUS_RANGE_LIST_CONFLICT
+# define STATUS_RANGE_LIST_CONFLICT ((NTSTATUS) 0xC0000282L)
+#endif
+
+#ifndef STATUS_SOURCE_ELEMENT_EMPTY
+# define STATUS_SOURCE_ELEMENT_EMPTY ((NTSTATUS) 0xC0000283L)
+#endif
+
+#ifndef STATUS_DESTINATION_ELEMENT_FULL
+# define STATUS_DESTINATION_ELEMENT_FULL ((NTSTATUS) 0xC0000284L)
+#endif
+
+#ifndef STATUS_ILLEGAL_ELEMENT_ADDRESS
+# define STATUS_ILLEGAL_ELEMENT_ADDRESS ((NTSTATUS) 0xC0000285L)
+#endif
+
+#ifndef STATUS_MAGAZINE_NOT_PRESENT
+# define STATUS_MAGAZINE_NOT_PRESENT ((NTSTATUS) 0xC0000286L)
+#endif
+
+#ifndef STATUS_REINITIALIZATION_NEEDED
+# define STATUS_REINITIALIZATION_NEEDED ((NTSTATUS) 0xC0000287L)
+#endif
+
+#ifndef STATUS_DEVICE_REQUIRES_CLEANING
+# define STATUS_DEVICE_REQUIRES_CLEANING ((NTSTATUS) 0x80000288L)
+#endif
+
+#ifndef STATUS_DEVICE_DOOR_OPEN
+# define STATUS_DEVICE_DOOR_OPEN ((NTSTATUS) 0x80000289L)
+#endif
+
+#ifndef STATUS_ENCRYPTION_FAILED
+# define STATUS_ENCRYPTION_FAILED ((NTSTATUS) 0xC000028AL)
+#endif
+
+#ifndef STATUS_DECRYPTION_FAILED
+# define STATUS_DECRYPTION_FAILED ((NTSTATUS) 0xC000028BL)
+#endif
+
+#ifndef STATUS_RANGE_NOT_FOUND
+# define STATUS_RANGE_NOT_FOUND ((NTSTATUS) 0xC000028CL)
+#endif
+
+#ifndef STATUS_NO_RECOVERY_POLICY
+# define STATUS_NO_RECOVERY_POLICY ((NTSTATUS) 0xC000028DL)
+#endif
+
+#ifndef STATUS_NO_EFS
+# define STATUS_NO_EFS ((NTSTATUS) 0xC000028EL)
+#endif
+
+#ifndef STATUS_WRONG_EFS
+# define STATUS_WRONG_EFS ((NTSTATUS) 0xC000028FL)
+#endif
+
+#ifndef STATUS_NO_USER_KEYS
+# define STATUS_NO_USER_KEYS ((NTSTATUS) 0xC0000290L)
+#endif
+
+#ifndef STATUS_FILE_NOT_ENCRYPTED
+# define STATUS_FILE_NOT_ENCRYPTED ((NTSTATUS) 0xC0000291L)
+#endif
+
+#ifndef STATUS_NOT_EXPORT_FORMAT
+# define STATUS_NOT_EXPORT_FORMAT ((NTSTATUS) 0xC0000292L)
+#endif
+
+#ifndef STATUS_FILE_ENCRYPTED
+# define STATUS_FILE_ENCRYPTED ((NTSTATUS) 0xC0000293L)
+#endif
+
+#ifndef STATUS_WAKE_SYSTEM
+# define STATUS_WAKE_SYSTEM ((NTSTATUS) 0x40000294L)
+#endif
+
+#ifndef STATUS_WMI_GUID_NOT_FOUND
+# define STATUS_WMI_GUID_NOT_FOUND ((NTSTATUS) 0xC0000295L)
+#endif
+
+#ifndef STATUS_WMI_INSTANCE_NOT_FOUND
+# define STATUS_WMI_INSTANCE_NOT_FOUND ((NTSTATUS) 0xC0000296L)
+#endif
+
+#ifndef STATUS_WMI_ITEMID_NOT_FOUND
+# define STATUS_WMI_ITEMID_NOT_FOUND ((NTSTATUS) 0xC0000297L)
+#endif
+
+#ifndef STATUS_WMI_TRY_AGAIN
+# define STATUS_WMI_TRY_AGAIN ((NTSTATUS) 0xC0000298L)
+#endif
+
+#ifndef STATUS_SHARED_POLICY
+# define STATUS_SHARED_POLICY ((NTSTATUS) 0xC0000299L)
+#endif
+
+#ifndef STATUS_POLICY_OBJECT_NOT_FOUND
+# define STATUS_POLICY_OBJECT_NOT_FOUND ((NTSTATUS) 0xC000029AL)
+#endif
+
+#ifndef STATUS_POLICY_ONLY_IN_DS
+# define STATUS_POLICY_ONLY_IN_DS ((NTSTATUS) 0xC000029BL)
+#endif
+
+#ifndef STATUS_VOLUME_NOT_UPGRADED
+# define STATUS_VOLUME_NOT_UPGRADED ((NTSTATUS) 0xC000029CL)
+#endif
+
+#ifndef STATUS_REMOTE_STORAGE_NOT_ACTIVE
+# define STATUS_REMOTE_STORAGE_NOT_ACTIVE ((NTSTATUS) 0xC000029DL)
+#endif
+
+#ifndef STATUS_REMOTE_STORAGE_MEDIA_ERROR
+# define STATUS_REMOTE_STORAGE_MEDIA_ERROR ((NTSTATUS) 0xC000029EL)
+#endif
+
+#ifndef STATUS_NO_TRACKING_SERVICE
+# define STATUS_NO_TRACKING_SERVICE ((NTSTATUS) 0xC000029FL)
+#endif
+
+#ifndef STATUS_SERVER_SID_MISMATCH
+# define STATUS_SERVER_SID_MISMATCH ((NTSTATUS) 0xC00002A0L)
+#endif
+
+#ifndef STATUS_DS_NO_ATTRIBUTE_OR_VALUE
+# define STATUS_DS_NO_ATTRIBUTE_OR_VALUE ((NTSTATUS) 0xC00002A1L)
+#endif
+
+#ifndef STATUS_DS_INVALID_ATTRIBUTE_SYNTAX
+# define STATUS_DS_INVALID_ATTRIBUTE_SYNTAX ((NTSTATUS) 0xC00002A2L)
+#endif
+
+#ifndef STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED
+# define STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED ((NTSTATUS) 0xC00002A3L)
+#endif
+
+#ifndef STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS
+# define STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS ((NTSTATUS) 0xC00002A4L)
+#endif
+
+#ifndef STATUS_DS_BUSY
+# define STATUS_DS_BUSY ((NTSTATUS) 0xC00002A5L)
+#endif
+
+#ifndef STATUS_DS_UNAVAILABLE
+# define STATUS_DS_UNAVAILABLE ((NTSTATUS) 0xC00002A6L)
+#endif
+
+#ifndef STATUS_DS_NO_RIDS_ALLOCATED
+# define STATUS_DS_NO_RIDS_ALLOCATED ((NTSTATUS) 0xC00002A7L)
+#endif
+
+#ifndef STATUS_DS_NO_MORE_RIDS
+# define STATUS_DS_NO_MORE_RIDS ((NTSTATUS) 0xC00002A8L)
+#endif
+
+#ifndef STATUS_DS_INCORRECT_ROLE_OWNER
+# define STATUS_DS_INCORRECT_ROLE_OWNER ((NTSTATUS) 0xC00002A9L)
+#endif
+
+#ifndef STATUS_DS_RIDMGR_INIT_ERROR
+# define STATUS_DS_RIDMGR_INIT_ERROR ((NTSTATUS) 0xC00002AAL)
+#endif
+
+#ifndef STATUS_DS_OBJ_CLASS_VIOLATION
+# define STATUS_DS_OBJ_CLASS_VIOLATION ((NTSTATUS) 0xC00002ABL)
+#endif
+
+#ifndef STATUS_DS_CANT_ON_NON_LEAF
+# define STATUS_DS_CANT_ON_NON_LEAF ((NTSTATUS) 0xC00002ACL)
+#endif
+
+#ifndef STATUS_DS_CANT_ON_RDN
+# define STATUS_DS_CANT_ON_RDN ((NTSTATUS) 0xC00002ADL)
+#endif
+
+#ifndef STATUS_DS_CANT_MOD_OBJ_CLASS
+# define STATUS_DS_CANT_MOD_OBJ_CLASS ((NTSTATUS) 0xC00002AEL)
+#endif
+
+#ifndef STATUS_DS_CROSS_DOM_MOVE_FAILED
+# define STATUS_DS_CROSS_DOM_MOVE_FAILED ((NTSTATUS) 0xC00002AFL)
+#endif
+
+#ifndef STATUS_DS_GC_NOT_AVAILABLE
+# define STATUS_DS_GC_NOT_AVAILABLE ((NTSTATUS) 0xC00002B0L)
+#endif
+
+#ifndef STATUS_DIRECTORY_SERVICE_REQUIRED
+# define STATUS_DIRECTORY_SERVICE_REQUIRED ((NTSTATUS) 0xC00002B1L)
+#endif
+
+#ifndef STATUS_REPARSE_ATTRIBUTE_CONFLICT
+# define STATUS_REPARSE_ATTRIBUTE_CONFLICT ((NTSTATUS) 0xC00002B2L)
+#endif
+
+#ifndef STATUS_CANT_ENABLE_DENY_ONLY
+# define STATUS_CANT_ENABLE_DENY_ONLY ((NTSTATUS) 0xC00002B3L)
+#endif
+
+#ifndef STATUS_FLOAT_MULTIPLE_FAULTS
+# define STATUS_FLOAT_MULTIPLE_FAULTS ((NTSTATUS) 0xC00002B4L)
+#endif
+
+#ifndef STATUS_FLOAT_MULTIPLE_TRAPS
+# define STATUS_FLOAT_MULTIPLE_TRAPS ((NTSTATUS) 0xC00002B5L)
+#endif
+
+#ifndef STATUS_DEVICE_REMOVED
+# define STATUS_DEVICE_REMOVED ((NTSTATUS) 0xC00002B6L)
+#endif
+
+#ifndef STATUS_JOURNAL_DELETE_IN_PROGRESS
+# define STATUS_JOURNAL_DELETE_IN_PROGRESS ((NTSTATUS) 0xC00002B7L)
+#endif
+
+#ifndef STATUS_JOURNAL_NOT_ACTIVE
+# define STATUS_JOURNAL_NOT_ACTIVE ((NTSTATUS) 0xC00002B8L)
+#endif
+
+#ifndef STATUS_NOINTERFACE
+# define STATUS_NOINTERFACE ((NTSTATUS) 0xC00002B9L)
+#endif
+
+#ifndef STATUS_DS_ADMIN_LIMIT_EXCEEDED
+# define STATUS_DS_ADMIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00002C1L)
+#endif
+
+#ifndef STATUS_DRIVER_FAILED_SLEEP
+# define STATUS_DRIVER_FAILED_SLEEP ((NTSTATUS) 0xC00002C2L)
+#endif
+
+#ifndef STATUS_MUTUAL_AUTHENTICATION_FAILED
+# define STATUS_MUTUAL_AUTHENTICATION_FAILED ((NTSTATUS) 0xC00002C3L)
+#endif
+
+#ifndef STATUS_CORRUPT_SYSTEM_FILE
+# define STATUS_CORRUPT_SYSTEM_FILE ((NTSTATUS) 0xC00002C4L)
+#endif
+
+#ifndef STATUS_DATATYPE_MISALIGNMENT_ERROR
+# define STATUS_DATATYPE_MISALIGNMENT_ERROR ((NTSTATUS) 0xC00002C5L)
+#endif
+
+#ifndef STATUS_WMI_READ_ONLY
+# define STATUS_WMI_READ_ONLY ((NTSTATUS) 0xC00002C6L)
+#endif
+
+#ifndef STATUS_WMI_SET_FAILURE
+# define STATUS_WMI_SET_FAILURE ((NTSTATUS) 0xC00002C7L)
+#endif
+
+#ifndef STATUS_COMMITMENT_MINIMUM
+# define STATUS_COMMITMENT_MINIMUM ((NTSTATUS) 0xC00002C8L)
+#endif
+
+#ifndef STATUS_REG_NAT_CONSUMPTION
+# define STATUS_REG_NAT_CONSUMPTION ((NTSTATUS) 0xC00002C9L)
+#endif
+
+#ifndef STATUS_TRANSPORT_FULL
+# define STATUS_TRANSPORT_FULL ((NTSTATUS) 0xC00002CAL)
+#endif
+
+#ifndef STATUS_DS_SAM_INIT_FAILURE
+# define STATUS_DS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002CBL)
+#endif
+
+#ifndef STATUS_ONLY_IF_CONNECTED
+# define STATUS_ONLY_IF_CONNECTED ((NTSTATUS) 0xC00002CCL)
+#endif
+
+#ifndef STATUS_DS_SENSITIVE_GROUP_VIOLATION
+# define STATUS_DS_SENSITIVE_GROUP_VIOLATION ((NTSTATUS) 0xC00002CDL)
+#endif
+
+#ifndef STATUS_PNP_RESTART_ENUMERATION
+# define STATUS_PNP_RESTART_ENUMERATION ((NTSTATUS) 0xC00002CEL)
+#endif
+
+#ifndef STATUS_JOURNAL_ENTRY_DELETED
+# define STATUS_JOURNAL_ENTRY_DELETED ((NTSTATUS) 0xC00002CFL)
+#endif
+
+#ifndef STATUS_DS_CANT_MOD_PRIMARYGROUPID
+# define STATUS_DS_CANT_MOD_PRIMARYGROUPID ((NTSTATUS) 0xC00002D0L)
+#endif
+
+#ifndef STATUS_SYSTEM_IMAGE_BAD_SIGNATURE
+# define STATUS_SYSTEM_IMAGE_BAD_SIGNATURE ((NTSTATUS) 0xC00002D1L)
+#endif
+
+#ifndef STATUS_PNP_REBOOT_REQUIRED
+# define STATUS_PNP_REBOOT_REQUIRED ((NTSTATUS) 0xC00002D2L)
+#endif
+
+#ifndef STATUS_POWER_STATE_INVALID
+# define STATUS_POWER_STATE_INVALID ((NTSTATUS) 0xC00002D3L)
+#endif
+
+#ifndef STATUS_DS_INVALID_GROUP_TYPE
+# define STATUS_DS_INVALID_GROUP_TYPE ((NTSTATUS) 0xC00002D4L)
+#endif
+
+#ifndef STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN
+# define STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D5L)
+#endif
+
+#ifndef STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN
+# define STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D6L)
+#endif
+
+#ifndef STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER
+# define STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D7L)
+#endif
+
+#ifndef STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER
+# define STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC00002D8L)
+#endif
+
+#ifndef STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER
+# define STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D9L)
+#endif
+
+#ifndef STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER
+# define STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER ((NTSTATUS) 0xC00002DAL)
+#endif
+
+#ifndef STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER
+# define STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER ((NTSTATUS) 0xC00002DBL)
+#endif
+
+#ifndef STATUS_DS_HAVE_PRIMARY_MEMBERS
+# define STATUS_DS_HAVE_PRIMARY_MEMBERS ((NTSTATUS) 0xC00002DCL)
+#endif
+
+#ifndef STATUS_WMI_NOT_SUPPORTED
+# define STATUS_WMI_NOT_SUPPORTED ((NTSTATUS) 0xC00002DDL)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_POWER
+# define STATUS_INSUFFICIENT_POWER ((NTSTATUS) 0xC00002DEL)
+#endif
+
+#ifndef STATUS_SAM_NEED_BOOTKEY_PASSWORD
+# define STATUS_SAM_NEED_BOOTKEY_PASSWORD ((NTSTATUS) 0xC00002DFL)
+#endif
+
+#ifndef STATUS_SAM_NEED_BOOTKEY_FLOPPY
+# define STATUS_SAM_NEED_BOOTKEY_FLOPPY ((NTSTATUS) 0xC00002E0L)
+#endif
+
+#ifndef STATUS_DS_CANT_START
+# define STATUS_DS_CANT_START ((NTSTATUS) 0xC00002E1L)
+#endif
+
+#ifndef STATUS_DS_INIT_FAILURE
+# define STATUS_DS_INIT_FAILURE ((NTSTATUS) 0xC00002E2L)
+#endif
+
+#ifndef STATUS_SAM_INIT_FAILURE
+# define STATUS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002E3L)
+#endif
+
+#ifndef STATUS_DS_GC_REQUIRED
+# define STATUS_DS_GC_REQUIRED ((NTSTATUS) 0xC00002E4L)
+#endif
+
+#ifndef STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY
+# define STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY ((NTSTATUS) 0xC00002E5L)
+#endif
+
+#ifndef STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS
+# define STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS ((NTSTATUS) 0xC00002E6L)
+#endif
+
+#ifndef STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED
+# define STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED ((NTSTATUS) 0xC00002E7L)
+#endif
+
+#ifndef STATUS_MULTIPLE_FAULT_VIOLATION
+# define STATUS_MULTIPLE_FAULT_VIOLATION ((NTSTATUS) 0xC00002E8L)
+#endif
+
+#ifndef STATUS_CURRENT_DOMAIN_NOT_ALLOWED
+# define STATUS_CURRENT_DOMAIN_NOT_ALLOWED ((NTSTATUS) 0xC00002E9L)
+#endif
+
+#ifndef STATUS_CANNOT_MAKE
+# define STATUS_CANNOT_MAKE ((NTSTATUS) 0xC00002EAL)
+#endif
+
+#ifndef STATUS_SYSTEM_SHUTDOWN
+# define STATUS_SYSTEM_SHUTDOWN ((NTSTATUS) 0xC00002EBL)
+#endif
+
+#ifndef STATUS_DS_INIT_FAILURE_CONSOLE
+# define STATUS_DS_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002ECL)
+#endif
+
+#ifndef STATUS_DS_SAM_INIT_FAILURE_CONSOLE
+# define STATUS_DS_SAM_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002EDL)
+#endif
+
+#ifndef STATUS_UNFINISHED_CONTEXT_DELETED
+# define STATUS_UNFINISHED_CONTEXT_DELETED ((NTSTATUS) 0xC00002EEL)
+#endif
+
+#ifndef STATUS_NO_TGT_REPLY
+# define STATUS_NO_TGT_REPLY ((NTSTATUS) 0xC00002EFL)
+#endif
+
+#ifndef STATUS_OBJECTID_NOT_FOUND
+# define STATUS_OBJECTID_NOT_FOUND ((NTSTATUS) 0xC00002F0L)
+#endif
+
+#ifndef STATUS_NO_IP_ADDRESSES
+# define STATUS_NO_IP_ADDRESSES ((NTSTATUS) 0xC00002F1L)
+#endif
+
+#ifndef STATUS_WRONG_CREDENTIAL_HANDLE
+# define STATUS_WRONG_CREDENTIAL_HANDLE ((NTSTATUS) 0xC00002F2L)
+#endif
+
+#ifndef STATUS_CRYPTO_SYSTEM_INVALID
+# define STATUS_CRYPTO_SYSTEM_INVALID ((NTSTATUS) 0xC00002F3L)
+#endif
+
+#ifndef STATUS_MAX_REFERRALS_EXCEEDED
+# define STATUS_MAX_REFERRALS_EXCEEDED ((NTSTATUS) 0xC00002F4L)
+#endif
+
+#ifndef STATUS_MUST_BE_KDC
+# define STATUS_MUST_BE_KDC ((NTSTATUS) 0xC00002F5L)
+#endif
+
+#ifndef STATUS_STRONG_CRYPTO_NOT_SUPPORTED
+# define STATUS_STRONG_CRYPTO_NOT_SUPPORTED ((NTSTATUS) 0xC00002F6L)
+#endif
+
+#ifndef STATUS_TOO_MANY_PRINCIPALS
+# define STATUS_TOO_MANY_PRINCIPALS ((NTSTATUS) 0xC00002F7L)
+#endif
+
+#ifndef STATUS_NO_PA_DATA
+# define STATUS_NO_PA_DATA ((NTSTATUS) 0xC00002F8L)
+#endif
+
+#ifndef STATUS_PKINIT_NAME_MISMATCH
+# define STATUS_PKINIT_NAME_MISMATCH ((NTSTATUS) 0xC00002F9L)
+#endif
+
+#ifndef STATUS_SMARTCARD_LOGON_REQUIRED
+# define STATUS_SMARTCARD_LOGON_REQUIRED ((NTSTATUS) 0xC00002FAL)
+#endif
+
+#ifndef STATUS_KDC_INVALID_REQUEST
+# define STATUS_KDC_INVALID_REQUEST ((NTSTATUS) 0xC00002FBL)
+#endif
+
+#ifndef STATUS_KDC_UNABLE_TO_REFER
+# define STATUS_KDC_UNABLE_TO_REFER ((NTSTATUS) 0xC00002FCL)
+#endif
+
+#ifndef STATUS_KDC_UNKNOWN_ETYPE
+# define STATUS_KDC_UNKNOWN_ETYPE ((NTSTATUS) 0xC00002FDL)
+#endif
+
+#ifndef STATUS_SHUTDOWN_IN_PROGRESS
+# define STATUS_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FEL)
+#endif
+
+#ifndef STATUS_SERVER_SHUTDOWN_IN_PROGRESS
+# define STATUS_SERVER_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FFL)
+#endif
+
+#ifndef STATUS_NOT_SUPPORTED_ON_SBS
+# define STATUS_NOT_SUPPORTED_ON_SBS ((NTSTATUS) 0xC0000300L)
+#endif
+
+#ifndef STATUS_WMI_GUID_DISCONNECTED
+# define STATUS_WMI_GUID_DISCONNECTED ((NTSTATUS) 0xC0000301L)
+#endif
+
+#ifndef STATUS_WMI_ALREADY_DISABLED
+# define STATUS_WMI_ALREADY_DISABLED ((NTSTATUS) 0xC0000302L)
+#endif
+
+#ifndef STATUS_WMI_ALREADY_ENABLED
+# define STATUS_WMI_ALREADY_ENABLED ((NTSTATUS) 0xC0000303L)
+#endif
+
+#ifndef STATUS_MFT_TOO_FRAGMENTED
+# define STATUS_MFT_TOO_FRAGMENTED ((NTSTATUS) 0xC0000304L)
+#endif
+
+#ifndef STATUS_COPY_PROTECTION_FAILURE
+# define STATUS_COPY_PROTECTION_FAILURE ((NTSTATUS) 0xC0000305L)
+#endif
+
+#ifndef STATUS_CSS_AUTHENTICATION_FAILURE
+# define STATUS_CSS_AUTHENTICATION_FAILURE ((NTSTATUS) 0xC0000306L)
+#endif
+
+#ifndef STATUS_CSS_KEY_NOT_PRESENT
+# define STATUS_CSS_KEY_NOT_PRESENT ((NTSTATUS) 0xC0000307L)
+#endif
+
+#ifndef STATUS_CSS_KEY_NOT_ESTABLISHED
+# define STATUS_CSS_KEY_NOT_ESTABLISHED ((NTSTATUS) 0xC0000308L)
+#endif
+
+#ifndef STATUS_CSS_SCRAMBLED_SECTOR
+# define STATUS_CSS_SCRAMBLED_SECTOR ((NTSTATUS) 0xC0000309L)
+#endif
+
+#ifndef STATUS_CSS_REGION_MISMATCH
+# define STATUS_CSS_REGION_MISMATCH ((NTSTATUS) 0xC000030AL)
+#endif
+
+#ifndef STATUS_CSS_RESETS_EXHAUSTED
+# define STATUS_CSS_RESETS_EXHAUSTED ((NTSTATUS) 0xC000030BL)
+#endif
+
+#ifndef STATUS_PKINIT_FAILURE
+# define STATUS_PKINIT_FAILURE ((NTSTATUS) 0xC0000320L)
+#endif
+
+#ifndef STATUS_SMARTCARD_SUBSYSTEM_FAILURE
+# define STATUS_SMARTCARD_SUBSYSTEM_FAILURE ((NTSTATUS) 0xC0000321L)
+#endif
+
+#ifndef STATUS_NO_KERB_KEY
+# define STATUS_NO_KERB_KEY ((NTSTATUS) 0xC0000322L)
+#endif
+
+#ifndef STATUS_HOST_DOWN
+# define STATUS_HOST_DOWN ((NTSTATUS) 0xC0000350L)
+#endif
+
+#ifndef STATUS_UNSUPPORTED_PREAUTH
+# define STATUS_UNSUPPORTED_PREAUTH ((NTSTATUS) 0xC0000351L)
+#endif
+
+#ifndef STATUS_EFS_ALG_BLOB_TOO_BIG
+# define STATUS_EFS_ALG_BLOB_TOO_BIG ((NTSTATUS) 0xC0000352L)
+#endif
+
+#ifndef STATUS_PORT_NOT_SET
+# define STATUS_PORT_NOT_SET ((NTSTATUS) 0xC0000353L)
+#endif
+
+#ifndef STATUS_DEBUGGER_INACTIVE
+# define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354L)
+#endif
+
+#ifndef STATUS_DS_VERSION_CHECK_FAILURE
+# define STATUS_DS_VERSION_CHECK_FAILURE ((NTSTATUS) 0xC0000355L)
+#endif
+
+#ifndef STATUS_AUDITING_DISABLED
+# define STATUS_AUDITING_DISABLED ((NTSTATUS) 0xC0000356L)
+#endif
+
+#ifndef STATUS_PRENT4_MACHINE_ACCOUNT
+# define STATUS_PRENT4_MACHINE_ACCOUNT ((NTSTATUS) 0xC0000357L)
+#endif
+
+#ifndef STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER
+# define STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC0000358L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_WIN_32
+# define STATUS_INVALID_IMAGE_WIN_32 ((NTSTATUS) 0xC0000359L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_WIN_64
+# define STATUS_INVALID_IMAGE_WIN_64 ((NTSTATUS) 0xC000035AL)
+#endif
+
+#ifndef STATUS_BAD_BINDINGS
+# define STATUS_BAD_BINDINGS ((NTSTATUS) 0xC000035BL)
+#endif
+
+#ifndef STATUS_NETWORK_SESSION_EXPIRED
+# define STATUS_NETWORK_SESSION_EXPIRED ((NTSTATUS) 0xC000035CL)
+#endif
+
+#ifndef STATUS_APPHELP_BLOCK
+# define STATUS_APPHELP_BLOCK ((NTSTATUS) 0xC000035DL)
+#endif
+
+#ifndef STATUS_ALL_SIDS_FILTERED
+# define STATUS_ALL_SIDS_FILTERED ((NTSTATUS) 0xC000035EL)
+#endif
+
+#ifndef STATUS_NOT_SAFE_MODE_DRIVER
+# define STATUS_NOT_SAFE_MODE_DRIVER ((NTSTATUS) 0xC000035FL)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT
+# define STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT ((NTSTATUS) 0xC0000361L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PATH
+# define STATUS_ACCESS_DISABLED_BY_POLICY_PATH ((NTSTATUS) 0xC0000362L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER
+# define STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER ((NTSTATUS) 0xC0000363L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
+# define STATUS_ACCESS_DISABLED_BY_POLICY_OTHER ((NTSTATUS) 0xC0000364L)
+#endif
+
+#ifndef STATUS_FAILED_DRIVER_ENTRY
+# define STATUS_FAILED_DRIVER_ENTRY ((NTSTATUS) 0xC0000365L)
+#endif
+
+#ifndef STATUS_DEVICE_ENUMERATION_ERROR
+# define STATUS_DEVICE_ENUMERATION_ERROR ((NTSTATUS) 0xC0000366L)
+#endif
+
+#ifndef STATUS_MOUNT_POINT_NOT_RESOLVED
+# define STATUS_MOUNT_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000368L)
+#endif
+
+#ifndef STATUS_INVALID_DEVICE_OBJECT_PARAMETER
+# define STATUS_INVALID_DEVICE_OBJECT_PARAMETER ((NTSTATUS) 0xC0000369L)
+#endif
+
+#ifndef STATUS_MCA_OCCURED
+# define STATUS_MCA_OCCURED ((NTSTATUS) 0xC000036AL)
+#endif
+
+#ifndef STATUS_DRIVER_BLOCKED_CRITICAL
+# define STATUS_DRIVER_BLOCKED_CRITICAL ((NTSTATUS) 0xC000036BL)
+#endif
+
+#ifndef STATUS_DRIVER_BLOCKED
+# define STATUS_DRIVER_BLOCKED ((NTSTATUS) 0xC000036CL)
+#endif
+
+#ifndef STATUS_DRIVER_DATABASE_ERROR
+# define STATUS_DRIVER_DATABASE_ERROR ((NTSTATUS) 0xC000036DL)
+#endif
+
+#ifndef STATUS_SYSTEM_HIVE_TOO_LARGE
+# define STATUS_SYSTEM_HIVE_TOO_LARGE ((NTSTATUS) 0xC000036EL)
+#endif
+
+#ifndef STATUS_INVALID_IMPORT_OF_NON_DLL
+# define STATUS_INVALID_IMPORT_OF_NON_DLL ((NTSTATUS) 0xC000036FL)
+#endif
+
+#ifndef STATUS_DS_SHUTTING_DOWN
+# define STATUS_DS_SHUTTING_DOWN ((NTSTATUS) 0x40000370L)
+#endif
+
+#ifndef STATUS_NO_SECRETS
+# define STATUS_NO_SECRETS ((NTSTATUS) 0xC0000371L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY
+# define STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY ((NTSTATUS) 0xC0000372L)
+#endif
+
+#ifndef STATUS_FAILED_STACK_SWITCH
+# define STATUS_FAILED_STACK_SWITCH ((NTSTATUS) 0xC0000373L)
+#endif
+
+#ifndef STATUS_HEAP_CORRUPTION
+# define STATUS_HEAP_CORRUPTION ((NTSTATUS) 0xC0000374L)
+#endif
+
+#ifndef STATUS_SMARTCARD_WRONG_PIN
+# define STATUS_SMARTCARD_WRONG_PIN ((NTSTATUS) 0xC0000380L)
+#endif
+
+#ifndef STATUS_SMARTCARD_CARD_BLOCKED
+# define STATUS_SMARTCARD_CARD_BLOCKED ((NTSTATUS) 0xC0000381L)
+#endif
+
+#ifndef STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED
+# define STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED ((NTSTATUS) 0xC0000382L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_CARD
+# define STATUS_SMARTCARD_NO_CARD ((NTSTATUS) 0xC0000383L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_KEY_CONTAINER
+# define STATUS_SMARTCARD_NO_KEY_CONTAINER ((NTSTATUS) 0xC0000384L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_CERTIFICATE
+# define STATUS_SMARTCARD_NO_CERTIFICATE ((NTSTATUS) 0xC0000385L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_KEYSET
+# define STATUS_SMARTCARD_NO_KEYSET ((NTSTATUS) 0xC0000386L)
+#endif
+
+#ifndef STATUS_SMARTCARD_IO_ERROR
+# define STATUS_SMARTCARD_IO_ERROR ((NTSTATUS) 0xC0000387L)
+#endif
+
+#ifndef STATUS_DOWNGRADE_DETECTED
+# define STATUS_DOWNGRADE_DETECTED ((NTSTATUS) 0xC0000388L)
+#endif
+
+#ifndef STATUS_SMARTCARD_CERT_REVOKED
+# define STATUS_SMARTCARD_CERT_REVOKED ((NTSTATUS) 0xC0000389L)
+#endif
+
+#ifndef STATUS_ISSUING_CA_UNTRUSTED
+# define STATUS_ISSUING_CA_UNTRUSTED ((NTSTATUS) 0xC000038AL)
+#endif
+
+#ifndef STATUS_REVOCATION_OFFLINE_C
+# define STATUS_REVOCATION_OFFLINE_C ((NTSTATUS) 0xC000038BL)
+#endif
+
+#ifndef STATUS_PKINIT_CLIENT_FAILURE
+# define STATUS_PKINIT_CLIENT_FAILURE ((NTSTATUS) 0xC000038CL)
+#endif
+
+#ifndef STATUS_SMARTCARD_CERT_EXPIRED
+# define STATUS_SMARTCARD_CERT_EXPIRED ((NTSTATUS) 0xC000038DL)
+#endif
+
+#ifndef STATUS_DRIVER_FAILED_PRIOR_UNLOAD
+# define STATUS_DRIVER_FAILED_PRIOR_UNLOAD ((NTSTATUS) 0xC000038EL)
+#endif
+
+#ifndef STATUS_SMARTCARD_SILENT_CONTEXT
+# define STATUS_SMARTCARD_SILENT_CONTEXT ((NTSTATUS) 0xC000038FL)
+#endif
+
+#ifndef STATUS_PER_USER_TRUST_QUOTA_EXCEEDED
+# define STATUS_PER_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000401L)
+#endif
+
+#ifndef STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED
+# define STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000402L)
+#endif
+
+#ifndef STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED
+# define STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000403L)
+#endif
+
+#ifndef STATUS_DS_NAME_NOT_UNIQUE
+# define STATUS_DS_NAME_NOT_UNIQUE ((NTSTATUS) 0xC0000404L)
+#endif
+
+#ifndef STATUS_DS_DUPLICATE_ID_FOUND
+# define STATUS_DS_DUPLICATE_ID_FOUND ((NTSTATUS) 0xC0000405L)
+#endif
+
+#ifndef STATUS_DS_GROUP_CONVERSION_ERROR
+# define STATUS_DS_GROUP_CONVERSION_ERROR ((NTSTATUS) 0xC0000406L)
+#endif
+
+#ifndef STATUS_VOLSNAP_PREPARE_HIBERNATE
+# define STATUS_VOLSNAP_PREPARE_HIBERNATE ((NTSTATUS) 0xC0000407L)
+#endif
+
+#ifndef STATUS_USER2USER_REQUIRED
+# define STATUS_USER2USER_REQUIRED ((NTSTATUS) 0xC0000408L)
+#endif
+
+#ifndef STATUS_STACK_BUFFER_OVERRUN
+# define STATUS_STACK_BUFFER_OVERRUN ((NTSTATUS) 0xC0000409L)
+#endif
+
+#ifndef STATUS_NO_S4U_PROT_SUPPORT
+# define STATUS_NO_S4U_PROT_SUPPORT ((NTSTATUS) 0xC000040AL)
+#endif
+
+#ifndef STATUS_CROSSREALM_DELEGATION_FAILURE
+# define STATUS_CROSSREALM_DELEGATION_FAILURE ((NTSTATUS) 0xC000040BL)
+#endif
+
+#ifndef STATUS_REVOCATION_OFFLINE_KDC
+# define STATUS_REVOCATION_OFFLINE_KDC ((NTSTATUS) 0xC000040CL)
+#endif
+
+#ifndef STATUS_ISSUING_CA_UNTRUSTED_KDC
+# define STATUS_ISSUING_CA_UNTRUSTED_KDC ((NTSTATUS) 0xC000040DL)
+#endif
+
+#ifndef STATUS_KDC_CERT_EXPIRED
+# define STATUS_KDC_CERT_EXPIRED ((NTSTATUS) 0xC000040EL)
+#endif
+
+#ifndef STATUS_KDC_CERT_REVOKED
+# define STATUS_KDC_CERT_REVOKED ((NTSTATUS) 0xC000040FL)
+#endif
+
+#ifndef STATUS_PARAMETER_QUOTA_EXCEEDED
+# define STATUS_PARAMETER_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000410L)
+#endif
+
+#ifndef STATUS_HIBERNATION_FAILURE
+# define STATUS_HIBERNATION_FAILURE ((NTSTATUS) 0xC0000411L)
+#endif
+
+#ifndef STATUS_DELAY_LOAD_FAILED
+# define STATUS_DELAY_LOAD_FAILED ((NTSTATUS) 0xC0000412L)
+#endif
+
+#ifndef STATUS_AUTHENTICATION_FIREWALL_FAILED
+# define STATUS_AUTHENTICATION_FIREWALL_FAILED ((NTSTATUS) 0xC0000413L)
+#endif
+
+#ifndef STATUS_VDM_DISALLOWED
+# define STATUS_VDM_DISALLOWED ((NTSTATUS) 0xC0000414L)
+#endif
+
+#ifndef STATUS_HUNG_DISPLAY_DRIVER_THREAD
+# define STATUS_HUNG_DISPLAY_DRIVER_THREAD ((NTSTATUS) 0xC0000415L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE
+# define STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE ((NTSTATUS) 0xC0000416L)
+#endif
+
+#ifndef STATUS_INVALID_CRUNTIME_PARAMETER
+# define STATUS_INVALID_CRUNTIME_PARAMETER ((NTSTATUS) 0xC0000417L)
+#endif
+
+#ifndef STATUS_NTLM_BLOCKED
+# define STATUS_NTLM_BLOCKED ((NTSTATUS) 0xC0000418L)
+#endif
+
+#ifndef STATUS_DS_SRC_SID_EXISTS_IN_FOREST
+# define STATUS_DS_SRC_SID_EXISTS_IN_FOREST ((NTSTATUS) 0xC0000419L)
+#endif
+
+#ifndef STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST
+# define STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041AL)
+#endif
+
+#ifndef STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST
+# define STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041BL)
+#endif
+
+#ifndef STATUS_INVALID_USER_PRINCIPAL_NAME
+# define STATUS_INVALID_USER_PRINCIPAL_NAME ((NTSTATUS) 0xC000041CL)
+#endif
+
+#ifndef STATUS_FATAL_USER_CALLBACK_EXCEPTION
+# define STATUS_FATAL_USER_CALLBACK_EXCEPTION ((NTSTATUS) 0xC000041DL)
+#endif
+
+#ifndef STATUS_ASSERTION_FAILURE
+# define STATUS_ASSERTION_FAILURE ((NTSTATUS) 0xC0000420L)
+#endif
+
+#ifndef STATUS_VERIFIER_STOP
+# define STATUS_VERIFIER_STOP ((NTSTATUS) 0xC0000421L)
+#endif
+
+#ifndef STATUS_CALLBACK_POP_STACK
+# define STATUS_CALLBACK_POP_STACK ((NTSTATUS) 0xC0000423L)
+#endif
+
+#ifndef STATUS_INCOMPATIBLE_DRIVER_BLOCKED
+# define STATUS_INCOMPATIBLE_DRIVER_BLOCKED ((NTSTATUS) 0xC0000424L)
+#endif
+
+#ifndef STATUS_HIVE_UNLOADED
+# define STATUS_HIVE_UNLOADED ((NTSTATUS) 0xC0000425L)
+#endif
+
+#ifndef STATUS_COMPRESSION_DISABLED
+# define STATUS_COMPRESSION_DISABLED ((NTSTATUS) 0xC0000426L)
+#endif
+
+#ifndef STATUS_FILE_SYSTEM_LIMITATION
+# define STATUS_FILE_SYSTEM_LIMITATION ((NTSTATUS) 0xC0000427L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_HASH
+# define STATUS_INVALID_IMAGE_HASH ((NTSTATUS) 0xC0000428L)
+#endif
+
+#ifndef STATUS_NOT_CAPABLE
+# define STATUS_NOT_CAPABLE ((NTSTATUS) 0xC0000429L)
+#endif
+
+#ifndef STATUS_REQUEST_OUT_OF_SEQUENCE
+# define STATUS_REQUEST_OUT_OF_SEQUENCE ((NTSTATUS) 0xC000042AL)
+#endif
+
+#ifndef STATUS_IMPLEMENTATION_LIMIT
+# define STATUS_IMPLEMENTATION_LIMIT ((NTSTATUS) 0xC000042BL)
+#endif
+
+#ifndef STATUS_ELEVATION_REQUIRED
+# define STATUS_ELEVATION_REQUIRED ((NTSTATUS) 0xC000042CL)
+#endif
+
+#ifndef STATUS_NO_SECURITY_CONTEXT
+# define STATUS_NO_SECURITY_CONTEXT ((NTSTATUS) 0xC000042DL)
+#endif
+
+#ifndef STATUS_PKU2U_CERT_FAILURE
+# define STATUS_PKU2U_CERT_FAILURE ((NTSTATUS) 0xC000042FL)
+#endif
+
+#ifndef STATUS_BEYOND_VDL
+# define STATUS_BEYOND_VDL ((NTSTATUS) 0xC0000432L)
+#endif
+
+#ifndef STATUS_ENCOUNTERED_WRITE_IN_PROGRESS
+# define STATUS_ENCOUNTERED_WRITE_IN_PROGRESS ((NTSTATUS) 0xC0000433L)
+#endif
+
+#ifndef STATUS_PTE_CHANGED
+# define STATUS_PTE_CHANGED ((NTSTATUS) 0xC0000434L)
+#endif
+
+#ifndef STATUS_PURGE_FAILED
+# define STATUS_PURGE_FAILED ((NTSTATUS) 0xC0000435L)
+#endif
+
+#ifndef STATUS_CRED_REQUIRES_CONFIRMATION
+# define STATUS_CRED_REQUIRES_CONFIRMATION ((NTSTATUS) 0xC0000440L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE
+# define STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE ((NTSTATUS) 0xC0000441L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER
+# define STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER ((NTSTATUS) 0xC0000442L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE
+# define STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE ((NTSTATUS) 0xC0000443L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE
+# define STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE ((NTSTATUS) 0xC0000444L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_FILE_NOT_CSE
+# define STATUS_CS_ENCRYPTION_FILE_NOT_CSE ((NTSTATUS) 0xC0000445L)
+#endif
+
+#ifndef STATUS_INVALID_LABEL
+# define STATUS_INVALID_LABEL ((NTSTATUS) 0xC0000446L)
+#endif
+
+#ifndef STATUS_DRIVER_PROCESS_TERMINATED
+# define STATUS_DRIVER_PROCESS_TERMINATED ((NTSTATUS) 0xC0000450L)
+#endif
+
+#ifndef STATUS_AMBIGUOUS_SYSTEM_DEVICE
+# define STATUS_AMBIGUOUS_SYSTEM_DEVICE ((NTSTATUS) 0xC0000451L)
+#endif
+
+#ifndef STATUS_SYSTEM_DEVICE_NOT_FOUND
+# define STATUS_SYSTEM_DEVICE_NOT_FOUND ((NTSTATUS) 0xC0000452L)
+#endif
+
+#ifndef STATUS_RESTART_BOOT_APPLICATION
+# define STATUS_RESTART_BOOT_APPLICATION ((NTSTATUS) 0xC0000453L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_NVRAM_RESOURCES
+# define STATUS_INSUFFICIENT_NVRAM_RESOURCES ((NTSTATUS) 0xC0000454L)
+#endif
+
+#ifndef STATUS_INVALID_TASK_NAME
+# define STATUS_INVALID_TASK_NAME ((NTSTATUS) 0xC0000500L)
+#endif
+
+#ifndef STATUS_INVALID_TASK_INDEX
+# define STATUS_INVALID_TASK_INDEX ((NTSTATUS) 0xC0000501L)
+#endif
+
+#ifndef STATUS_THREAD_ALREADY_IN_TASK
+# define STATUS_THREAD_ALREADY_IN_TASK ((NTSTATUS) 0xC0000502L)
+#endif
+
+#ifndef STATUS_CALLBACK_BYPASS
+# define STATUS_CALLBACK_BYPASS ((NTSTATUS) 0xC0000503L)
+#endif
+
+#ifndef STATUS_FAIL_FAST_EXCEPTION
+# define STATUS_FAIL_FAST_EXCEPTION ((NTSTATUS) 0xC0000602L)
+#endif
+
+#ifndef STATUS_IMAGE_CERT_REVOKED
+# define STATUS_IMAGE_CERT_REVOKED ((NTSTATUS) 0xC0000603L)
+#endif
+
+#ifndef STATUS_PORT_CLOSED
+# define STATUS_PORT_CLOSED ((NTSTATUS) 0xC0000700L)
+#endif
+
+#ifndef STATUS_MESSAGE_LOST
+# define STATUS_MESSAGE_LOST ((NTSTATUS) 0xC0000701L)
+#endif
+
+#ifndef STATUS_INVALID_MESSAGE
+# define STATUS_INVALID_MESSAGE ((NTSTATUS) 0xC0000702L)
+#endif
+
+#ifndef STATUS_REQUEST_CANCELED
+# define STATUS_REQUEST_CANCELED ((NTSTATUS) 0xC0000703L)
+#endif
+
+#ifndef STATUS_RECURSIVE_DISPATCH
+# define STATUS_RECURSIVE_DISPATCH ((NTSTATUS) 0xC0000704L)
+#endif
+
+#ifndef STATUS_LPC_RECEIVE_BUFFER_EXPECTED
+# define STATUS_LPC_RECEIVE_BUFFER_EXPECTED ((NTSTATUS) 0xC0000705L)
+#endif
+
+#ifndef STATUS_LPC_INVALID_CONNECTION_USAGE
+# define STATUS_LPC_INVALID_CONNECTION_USAGE ((NTSTATUS) 0xC0000706L)
+#endif
+
+#ifndef STATUS_LPC_REQUESTS_NOT_ALLOWED
+# define STATUS_LPC_REQUESTS_NOT_ALLOWED ((NTSTATUS) 0xC0000707L)
+#endif
+
+#ifndef STATUS_RESOURCE_IN_USE
+# define STATUS_RESOURCE_IN_USE ((NTSTATUS) 0xC0000708L)
+#endif
+
+#ifndef STATUS_HARDWARE_MEMORY_ERROR
+# define STATUS_HARDWARE_MEMORY_ERROR ((NTSTATUS) 0xC0000709L)
+#endif
+
+#ifndef STATUS_THREADPOOL_HANDLE_EXCEPTION
+# define STATUS_THREADPOOL_HANDLE_EXCEPTION ((NTSTATUS) 0xC000070AL)
+#endif
+
+#ifndef STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070BL)
+#endif
+
+#ifndef STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070CL)
+#endif
+
+#ifndef STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070DL)
+#endif
+
+#ifndef STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070EL)
+#endif
+
+#ifndef STATUS_THREADPOOL_RELEASED_DURING_OPERATION
+# define STATUS_THREADPOOL_RELEASED_DURING_OPERATION ((NTSTATUS) 0xC000070FL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING
+# define STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000710L)
+#endif
+
+#ifndef STATUS_APC_RETURNED_WHILE_IMPERSONATING
+# define STATUS_APC_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000711L)
+#endif
+
+#ifndef STATUS_PROCESS_IS_PROTECTED
+# define STATUS_PROCESS_IS_PROTECTED ((NTSTATUS) 0xC0000712L)
+#endif
+
+#ifndef STATUS_MCA_EXCEPTION
+# define STATUS_MCA_EXCEPTION ((NTSTATUS) 0xC0000713L)
+#endif
+
+#ifndef STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE
+# define STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE ((NTSTATUS) 0xC0000714L)
+#endif
+
+#ifndef STATUS_SYMLINK_CLASS_DISABLED
+# define STATUS_SYMLINK_CLASS_DISABLED ((NTSTATUS) 0xC0000715L)
+#endif
+
+#ifndef STATUS_INVALID_IDN_NORMALIZATION
+# define STATUS_INVALID_IDN_NORMALIZATION ((NTSTATUS) 0xC0000716L)
+#endif
+
+#ifndef STATUS_NO_UNICODE_TRANSLATION
+# define STATUS_NO_UNICODE_TRANSLATION ((NTSTATUS) 0xC0000717L)
+#endif
+
+#ifndef STATUS_ALREADY_REGISTERED
+# define STATUS_ALREADY_REGISTERED ((NTSTATUS) 0xC0000718L)
+#endif
+
+#ifndef STATUS_CONTEXT_MISMATCH
+# define STATUS_CONTEXT_MISMATCH ((NTSTATUS) 0xC0000719L)
+#endif
+
+#ifndef STATUS_PORT_ALREADY_HAS_COMPLETION_LIST
+# define STATUS_PORT_ALREADY_HAS_COMPLETION_LIST ((NTSTATUS) 0xC000071AL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_THREAD_PRIORITY
+# define STATUS_CALLBACK_RETURNED_THREAD_PRIORITY ((NTSTATUS) 0xC000071BL)
+#endif
+
+#ifndef STATUS_INVALID_THREAD
+# define STATUS_INVALID_THREAD ((NTSTATUS) 0xC000071CL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_TRANSACTION
+# define STATUS_CALLBACK_RETURNED_TRANSACTION ((NTSTATUS) 0xC000071DL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_LDR_LOCK
+# define STATUS_CALLBACK_RETURNED_LDR_LOCK ((NTSTATUS) 0xC000071EL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_LANG
+# define STATUS_CALLBACK_RETURNED_LANG ((NTSTATUS) 0xC000071FL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_PRI_BACK
+# define STATUS_CALLBACK_RETURNED_PRI_BACK ((NTSTATUS) 0xC0000720L)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_THREAD_AFFINITY
+# define STATUS_CALLBACK_RETURNED_THREAD_AFFINITY ((NTSTATUS) 0xC0000721L)
+#endif
+
+#ifndef STATUS_DISK_REPAIR_DISABLED
+# define STATUS_DISK_REPAIR_DISABLED ((NTSTATUS) 0xC0000800L)
+#endif
+
+#ifndef STATUS_DS_DOMAIN_RENAME_IN_PROGRESS
+# define STATUS_DS_DOMAIN_RENAME_IN_PROGRESS ((NTSTATUS) 0xC0000801L)
+#endif
+
+#ifndef STATUS_DISK_QUOTA_EXCEEDED
+# define STATUS_DISK_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000802L)
+#endif
+
+#ifndef STATUS_DATA_LOST_REPAIR
+# define STATUS_DATA_LOST_REPAIR ((NTSTATUS) 0x80000803L)
+#endif
+
+#ifndef STATUS_CONTENT_BLOCKED
+# define STATUS_CONTENT_BLOCKED ((NTSTATUS) 0xC0000804L)
+#endif
+
+#ifndef STATUS_BAD_CLUSTERS
+# define STATUS_BAD_CLUSTERS ((NTSTATUS) 0xC0000805L)
+#endif
+
+#ifndef STATUS_VOLUME_DIRTY
+# define STATUS_VOLUME_DIRTY ((NTSTATUS) 0xC0000806L)
+#endif
+
+#ifndef STATUS_FILE_CHECKED_OUT
+# define STATUS_FILE_CHECKED_OUT ((NTSTATUS) 0xC0000901L)
+#endif
+
+#ifndef STATUS_CHECKOUT_REQUIRED
+# define STATUS_CHECKOUT_REQUIRED ((NTSTATUS) 0xC0000902L)
+#endif
+
+#ifndef STATUS_BAD_FILE_TYPE
+# define STATUS_BAD_FILE_TYPE ((NTSTATUS) 0xC0000903L)
+#endif
+
+#ifndef STATUS_FILE_TOO_LARGE
+# define STATUS_FILE_TOO_LARGE ((NTSTATUS) 0xC0000904L)
+#endif
+
+#ifndef STATUS_FORMS_AUTH_REQUIRED
+# define STATUS_FORMS_AUTH_REQUIRED ((NTSTATUS) 0xC0000905L)
+#endif
+
+#ifndef STATUS_VIRUS_INFECTED
+# define STATUS_VIRUS_INFECTED ((NTSTATUS) 0xC0000906L)
+#endif
+
+#ifndef STATUS_VIRUS_DELETED
+# define STATUS_VIRUS_DELETED ((NTSTATUS) 0xC0000907L)
+#endif
+
+#ifndef STATUS_BAD_MCFG_TABLE
+# define STATUS_BAD_MCFG_TABLE ((NTSTATUS) 0xC0000908L)
+#endif
+
+#ifndef STATUS_CANNOT_BREAK_OPLOCK
+# define STATUS_CANNOT_BREAK_OPLOCK ((NTSTATUS) 0xC0000909L)
+#endif
+
+#ifndef STATUS_WOW_ASSERTION
+# define STATUS_WOW_ASSERTION ((NTSTATUS) 0xC0009898L)
+#endif
+
+#ifndef STATUS_INVALID_SIGNATURE
+# define STATUS_INVALID_SIGNATURE ((NTSTATUS) 0xC000A000L)
+#endif
+
+#ifndef STATUS_HMAC_NOT_SUPPORTED
+# define STATUS_HMAC_NOT_SUPPORTED ((NTSTATUS) 0xC000A001L)
+#endif
+
+#ifndef STATUS_AUTH_TAG_MISMATCH
+# define STATUS_AUTH_TAG_MISMATCH ((NTSTATUS) 0xC000A002L)
+#endif
+
+#ifndef STATUS_IPSEC_QUEUE_OVERFLOW
+# define STATUS_IPSEC_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A010L)
+#endif
+
+#ifndef STATUS_ND_QUEUE_OVERFLOW
+# define STATUS_ND_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A011L)
+#endif
+
+#ifndef STATUS_HOPLIMIT_EXCEEDED
+# define STATUS_HOPLIMIT_EXCEEDED ((NTSTATUS) 0xC000A012L)
+#endif
+
+#ifndef STATUS_PROTOCOL_NOT_SUPPORTED
+# define STATUS_PROTOCOL_NOT_SUPPORTED ((NTSTATUS) 0xC000A013L)
+#endif
+
+#ifndef STATUS_FASTPATH_REJECTED
+# define STATUS_FASTPATH_REJECTED ((NTSTATUS) 0xC000A014L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED
+# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED ((NTSTATUS) 0xC000A080L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR
+# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR ((NTSTATUS) 0xC000A081L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR
+# define STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR ((NTSTATUS) 0xC000A082L)
+#endif
+
+#ifndef STATUS_XML_PARSE_ERROR
+# define STATUS_XML_PARSE_ERROR ((NTSTATUS) 0xC000A083L)
+#endif
+
+#ifndef STATUS_XMLDSIG_ERROR
+# define STATUS_XMLDSIG_ERROR ((NTSTATUS) 0xC000A084L)
+#endif
+
+#ifndef STATUS_WRONG_COMPARTMENT
+# define STATUS_WRONG_COMPARTMENT ((NTSTATUS) 0xC000A085L)
+#endif
+
+#ifndef STATUS_AUTHIP_FAILURE
+# define STATUS_AUTHIP_FAILURE ((NTSTATUS) 0xC000A086L)
+#endif
+
+#ifndef STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS
+# define STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS ((NTSTATUS) 0xC000A087L)
+#endif
+
+#ifndef STATUS_DS_OID_NOT_FOUND
+# define STATUS_DS_OID_NOT_FOUND ((NTSTATUS) 0xC000A088L)
+#endif
+
+#ifndef STATUS_HASH_NOT_SUPPORTED
+# define STATUS_HASH_NOT_SUPPORTED ((NTSTATUS) 0xC000A100L)
+#endif
+
+#ifndef STATUS_HASH_NOT_PRESENT
+# define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L)
+#endif
+
+/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the */
+/* DDK got it wrong! */
+#ifdef NTSTATUS_FROM_WIN32
+# undef NTSTATUS_FROM_WIN32
+#endif
+#define NTSTATUS_FROM_WIN32(error) ((NTSTATUS) (error) <= 0 ? \
+ ((NTSTATUS) (error)) : ((NTSTATUS) (((error) & 0x0000FFFF) | \
+ (FACILITY_NTWIN32 << 16) | ERROR_SEVERITY_WARNING)))
+
+#ifndef JOB_OBJECT_LIMIT_PROCESS_MEMORY
+# define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100
+#endif
+#ifndef JOB_OBJECT_LIMIT_JOB_MEMORY
+# define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200
+#endif
+#ifndef JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
+# define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400
+#endif
+#ifndef JOB_OBJECT_LIMIT_BREAKAWAY_OK
+# define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800
+#endif
+#ifndef JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
+# define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000
+#endif
+#ifndef JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
+# define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000
+#endif
+
+/* from winternl.h */
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+} UNICODE_STRING, *PUNICODE_STRING;
+
+typedef const UNICODE_STRING *PCUNICODE_STRING;
+
+/* from ntifs.h */
+#ifndef DEVICE_TYPE
+# define DEVICE_TYPE DWORD
+#endif
+
+/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does
+ * not.
+ */
+#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
+ typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ };
+ } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+#endif
+
+typedef struct _IO_STATUS_BLOCK {
+ union {
+ NTSTATUS Status;
+ PVOID Pointer;
+ };
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef enum _FILE_INFORMATION_CLASS {
+ FileDirectoryInformation = 1,
+ FileFullDirectoryInformation,
+ FileBothDirectoryInformation,
+ FileBasicInformation,
+ FileStandardInformation,
+ FileInternalInformation,
+ FileEaInformation,
+ FileAccessInformation,
+ FileNameInformation,
+ FileRenameInformation,
+ FileLinkInformation,
+ FileNamesInformation,
+ FileDispositionInformation,
+ FilePositionInformation,
+ FileFullEaInformation,
+ FileModeInformation,
+ FileAlignmentInformation,
+ FileAllInformation,
+ FileAllocationInformation,
+ FileEndOfFileInformation,
+ FileAlternateNameInformation,
+ FileStreamInformation,
+ FilePipeInformation,
+ FilePipeLocalInformation,
+ FilePipeRemoteInformation,
+ FileMailslotQueryInformation,
+ FileMailslotSetInformation,
+ FileCompressionInformation,
+ FileObjectIdInformation,
+ FileCompletionInformation,
+ FileMoveClusterInformation,
+ FileQuotaInformation,
+ FileReparsePointInformation,
+ FileNetworkOpenInformation,
+ FileAttributeTagInformation,
+ FileTrackingInformation,
+ FileIdBothDirectoryInformation,
+ FileIdFullDirectoryInformation,
+ FileValidDataLengthInformation,
+ FileShortNameInformation,
+ FileIoCompletionNotificationInformation,
+ FileIoStatusBlockRangeInformation,
+ FileIoPriorityHintInformation,
+ FileSfioReserveInformation,
+ FileSfioVolumeInformation,
+ FileHardLinkInformation,
+ FileProcessIdsUsingFileInformation,
+ FileNormalizedNameInformation,
+ FileNetworkPhysicalNameInformation,
+ FileIdGlobalTxDirectoryInformation,
+ FileIsRemoteDeviceInformation,
+ FileAttributeCacheInformation,
+ FileNumaNodeInformation,
+ FileStandardLinkInformation,
+ FileRemoteProtocolInformation,
+ FileMaximumInformation
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef struct _FILE_DIRECTORY_INFORMATION {
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
+
+typedef struct _FILE_BOTH_DIR_INFORMATION {
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG FileNameLength;
+ ULONG EaSize;
+ CCHAR ShortNameLength;
+ WCHAR ShortName[12];
+ WCHAR FileName[1];
+} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
+
+typedef struct _FILE_BASIC_INFORMATION {
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ DWORD FileAttributes;
+} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
+
+typedef struct _FILE_STANDARD_INFORMATION {
+ LARGE_INTEGER AllocationSize;
+ LARGE_INTEGER EndOfFile;
+ ULONG NumberOfLinks;
+ BOOLEAN DeletePending;
+ BOOLEAN Directory;
+} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
+
+typedef struct _FILE_INTERNAL_INFORMATION {
+ LARGE_INTEGER IndexNumber;
+} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION;
+
+typedef struct _FILE_EA_INFORMATION {
+ ULONG EaSize;
+} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION;
+
+typedef struct _FILE_ACCESS_INFORMATION {
+ ACCESS_MASK AccessFlags;
+} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION;
+
+typedef struct _FILE_POSITION_INFORMATION {
+ LARGE_INTEGER CurrentByteOffset;
+} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION;
+
+typedef struct _FILE_MODE_INFORMATION {
+ ULONG Mode;
+} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION;
+
+typedef struct _FILE_ALIGNMENT_INFORMATION {
+ ULONG AlignmentRequirement;
+} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION;
+
+typedef struct _FILE_NAME_INFORMATION {
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
+
+typedef struct _FILE_END_OF_FILE_INFORMATION {
+ LARGE_INTEGER EndOfFile;
+} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION;
+
+typedef struct _FILE_ALL_INFORMATION {
+ FILE_BASIC_INFORMATION BasicInformation;
+ FILE_STANDARD_INFORMATION StandardInformation;
+ FILE_INTERNAL_INFORMATION InternalInformation;
+ FILE_EA_INFORMATION EaInformation;
+ FILE_ACCESS_INFORMATION AccessInformation;
+ FILE_POSITION_INFORMATION PositionInformation;
+ FILE_MODE_INFORMATION ModeInformation;
+ FILE_ALIGNMENT_INFORMATION AlignmentInformation;
+ FILE_NAME_INFORMATION NameInformation;
+} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION;
+
+typedef struct _FILE_DISPOSITION_INFORMATION {
+ BOOLEAN DeleteFile;
+} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;
+
+typedef struct _FILE_PIPE_LOCAL_INFORMATION {
+ ULONG NamedPipeType;
+ ULONG NamedPipeConfiguration;
+ ULONG MaximumInstances;
+ ULONG CurrentInstances;
+ ULONG InboundQuota;
+ ULONG ReadDataAvailable;
+ ULONG OutboundQuota;
+ ULONG WriteQuotaAvailable;
+ ULONG NamedPipeState;
+ ULONG NamedPipeEnd;
+} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
+
+#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010
+#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
+
+typedef enum _FS_INFORMATION_CLASS {
+ FileFsVolumeInformation = 1,
+ FileFsLabelInformation = 2,
+ FileFsSizeInformation = 3,
+ FileFsDeviceInformation = 4,
+ FileFsAttributeInformation = 5,
+ FileFsControlInformation = 6,
+ FileFsFullSizeInformation = 7,
+ FileFsObjectIdInformation = 8,
+ FileFsDriverPathInformation = 9,
+ FileFsVolumeFlagsInformation = 10,
+ FileFsSectorSizeInformation = 11
+} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
+
+typedef struct _FILE_FS_VOLUME_INFORMATION {
+ LARGE_INTEGER VolumeCreationTime;
+ ULONG VolumeSerialNumber;
+ ULONG VolumeLabelLength;
+ BOOLEAN SupportsObjects;
+ WCHAR VolumeLabel[1];
+} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION;
+
+typedef struct _FILE_FS_LABEL_INFORMATION {
+ ULONG VolumeLabelLength;
+ WCHAR VolumeLabel[1];
+} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION;
+
+typedef struct _FILE_FS_SIZE_INFORMATION {
+ LARGE_INTEGER TotalAllocationUnits;
+ LARGE_INTEGER AvailableAllocationUnits;
+ ULONG SectorsPerAllocationUnit;
+ ULONG BytesPerSector;
+} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;
+
+typedef struct _FILE_FS_DEVICE_INFORMATION {
+ DEVICE_TYPE DeviceType;
+ ULONG Characteristics;
+} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION;
+
+typedef struct _FILE_FS_ATTRIBUTE_INFORMATION {
+ ULONG FileSystemAttributes;
+ LONG MaximumComponentNameLength;
+ ULONG FileSystemNameLength;
+ WCHAR FileSystemName[1];
+} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION;
+
+typedef struct _FILE_FS_CONTROL_INFORMATION {
+ LARGE_INTEGER FreeSpaceStartFiltering;
+ LARGE_INTEGER FreeSpaceThreshold;
+ LARGE_INTEGER FreeSpaceStopFiltering;
+ LARGE_INTEGER DefaultQuotaThreshold;
+ LARGE_INTEGER DefaultQuotaLimit;
+ ULONG FileSystemControlFlags;
+} FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION;
+
+typedef struct _FILE_FS_FULL_SIZE_INFORMATION {
+ LARGE_INTEGER TotalAllocationUnits;
+ LARGE_INTEGER CallerAvailableAllocationUnits;
+ LARGE_INTEGER ActualAvailableAllocationUnits;
+ ULONG SectorsPerAllocationUnit;
+ ULONG BytesPerSector;
+} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION;
+
+typedef struct _FILE_FS_OBJECTID_INFORMATION {
+ UCHAR ObjectId[16];
+ UCHAR ExtendedInfo[48];
+} FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION;
+
+typedef struct _FILE_FS_DRIVER_PATH_INFORMATION {
+ BOOLEAN DriverInPath;
+ ULONG DriverNameLength;
+ WCHAR DriverName[1];
+} FILE_FS_DRIVER_PATH_INFORMATION, *PFILE_FS_DRIVER_PATH_INFORMATION;
+
+typedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION {
+ ULONG Flags;
+} FILE_FS_VOLUME_FLAGS_INFORMATION, *PFILE_FS_VOLUME_FLAGS_INFORMATION;
+
+typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION {
+ ULONG LogicalBytesPerSector;
+ ULONG PhysicalBytesPerSectorForAtomicity;
+ ULONG PhysicalBytesPerSectorForPerformance;
+ ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity;
+ ULONG Flags;
+ ULONG ByteOffsetForSectorAlignment;
+ ULONG ByteOffsetForPartitionAlignment;
+} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION;
+
+typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
+ LARGE_INTEGER IdleTime;
+ LARGE_INTEGER KernelTime;
+ LARGE_INTEGER UserTime;
+ LARGE_INTEGER DpcTime;
+ LARGE_INTEGER InterruptTime;
+ ULONG InterruptCount;
+} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
+
+#ifndef SystemProcessorPerformanceInformation
+# define SystemProcessorPerformanceInformation 8
+#endif
+
+#ifndef FILE_DEVICE_FILE_SYSTEM
+# define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#endif
+
+#ifndef FILE_DEVICE_NETWORK
+# define FILE_DEVICE_NETWORK 0x00000012
+#endif
+
+#ifndef METHOD_BUFFERED
+# define METHOD_BUFFERED 0
+#endif
+
+#ifndef METHOD_IN_DIRECT
+# define METHOD_IN_DIRECT 1
+#endif
+
+#ifndef METHOD_OUT_DIRECT
+# define METHOD_OUT_DIRECT 2
+#endif
+
+#ifndef METHOD_NEITHER
+#define METHOD_NEITHER 3
+#endif
+
+#ifndef METHOD_DIRECT_TO_HARDWARE
+# define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT
+#endif
+
+#ifndef METHOD_DIRECT_FROM_HARDWARE
+# define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT
+#endif
+
+#ifndef FILE_ANY_ACCESS
+# define FILE_ANY_ACCESS 0
+#endif
+
+#ifndef FILE_SPECIAL_ACCESS
+# define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS)
+#endif
+
+#ifndef FILE_READ_ACCESS
+# define FILE_READ_ACCESS 0x0001
+#endif
+
+#ifndef FILE_WRITE_ACCESS
+# define FILE_WRITE_ACCESS 0x0002
+#endif
+
+#ifndef CTL_CODE
+# define CTL_CODE(device_type, function, method, access) \
+ (((device_type) << 16) | ((access) << 14) | ((function) << 2) | (method))
+#endif
+
+#ifndef FSCTL_SET_REPARSE_POINT
+# define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
+ 41, \
+ METHOD_BUFFERED, \
+ FILE_SPECIAL_ACCESS)
+#endif
+
+#ifndef FSCTL_GET_REPARSE_POINT
+# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
+ 42, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+#endif
+
+#ifndef FSCTL_DELETE_REPARSE_POINT
+# define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
+ 43, \
+ METHOD_BUFFERED, \
+ FILE_SPECIAL_ACCESS)
+#endif
+
+#ifndef IO_REPARSE_TAG_SYMLINK
+# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
+#endif
+
+typedef VOID (NTAPI *PIO_APC_ROUTINE)
+ (PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ ULONG Reserved);
+
+typedef ULONG (NTAPI *sRtlNtStatusToDosError)
+ (NTSTATUS Status);
+
+typedef NTSTATUS (NTAPI *sNtDeviceIoControlFile)
+ (HANDLE FileHandle,
+ HANDLE Event,
+ PIO_APC_ROUTINE ApcRoutine,
+ PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ ULONG IoControlCode,
+ PVOID InputBuffer,
+ ULONG InputBufferLength,
+ PVOID OutputBuffer,
+ ULONG OutputBufferLength);
+
+typedef NTSTATUS (NTAPI *sNtQueryInformationFile)
+ (HANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ FILE_INFORMATION_CLASS FileInformationClass);
+
+typedef NTSTATUS (NTAPI *sNtSetInformationFile)
+ (HANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ FILE_INFORMATION_CLASS FileInformationClass);
+
+typedef NTSTATUS (NTAPI *sNtQueryVolumeInformationFile)
+ (HANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FsInformation,
+ ULONG Length,
+ FS_INFORMATION_CLASS FsInformationClass);
+
+typedef NTSTATUS (NTAPI *sNtQuerySystemInformation)
+ (UINT SystemInformationClass,
+ PVOID SystemInformation,
+ ULONG SystemInformationLength,
+ PULONG ReturnLength);
+
+typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
+ (HANDLE FileHandle,
+ HANDLE Event,
+ PIO_APC_ROUTINE ApcRoutine,
+ PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ FILE_INFORMATION_CLASS FileInformationClass,
+ BOOLEAN ReturnSingleEntry,
+ PUNICODE_STRING FileName,
+ BOOLEAN RestartScan
+ );
+
+/*
+ * Kernel32 headers
+ */
+#ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
+# define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1
+#endif
+
+#ifndef FILE_SKIP_SET_EVENT_ON_HANDLE
+# define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2
+#endif
+
+#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
+# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
+#endif
+
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+ typedef struct _OVERLAPPED_ENTRY {
+ ULONG_PTR lpCompletionKey;
+ LPOVERLAPPED lpOverlapped;
+ ULONG_PTR Internal;
+ DWORD dwNumberOfBytesTransferred;
+ } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY;
+#endif
+
+/* from wincon.h */
+#ifndef ENABLE_INSERT_MODE
+# define ENABLE_INSERT_MODE 0x20
+#endif
+
+#ifndef ENABLE_QUICK_EDIT_MODE
+# define ENABLE_QUICK_EDIT_MODE 0x40
+#endif
+
+#ifndef ENABLE_EXTENDED_FLAGS
+# define ENABLE_EXTENDED_FLAGS 0x80
+#endif
+
+/* from winerror.h */
+#ifndef ERROR_SYMLINK_NOT_SUPPORTED
+# define ERROR_SYMLINK_NOT_SUPPORTED 1464
+#endif
+
+#ifndef ERROR_MUI_FILE_NOT_FOUND
+# define ERROR_MUI_FILE_NOT_FOUND 15100
+#endif
+
+#ifndef ERROR_MUI_INVALID_FILE
+# define ERROR_MUI_INVALID_FILE 15101
+#endif
+
+#ifndef ERROR_MUI_INVALID_RC_CONFIG
+# define ERROR_MUI_INVALID_RC_CONFIG 15102
+#endif
+
+#ifndef ERROR_MUI_INVALID_LOCALE_NAME
+# define ERROR_MUI_INVALID_LOCALE_NAME 15103
+#endif
+
+#ifndef ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME
+# define ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME 15104
+#endif
+
+#ifndef ERROR_MUI_FILE_NOT_LOADED
+# define ERROR_MUI_FILE_NOT_LOADED 15105
+#endif
+
+typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
+ (HANDLE CompletionPort,
+ LPOVERLAPPED_ENTRY lpCompletionPortEntries,
+ ULONG ulCount,
+ PULONG ulNumEntriesRemoved,
+ DWORD dwMilliseconds,
+ BOOL fAlertable);
+
+typedef BOOL (WINAPI* sSetFileCompletionNotificationModes)
+ (HANDLE FileHandle,
+ UCHAR Flags);
+
+typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW)
+ (LPCWSTR lpSymlinkFileName,
+ LPCWSTR lpTargetFileName,
+ DWORD dwFlags);
+
+typedef BOOL (WINAPI* sCancelIoEx)
+ (HANDLE hFile,
+ LPOVERLAPPED lpOverlapped);
+
+typedef VOID (WINAPI* sInitializeConditionVariable)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef BOOL (WINAPI* sSleepConditionVariableCS)
+ (PCONDITION_VARIABLE ConditionVariable,
+ PCRITICAL_SECTION CriticalSection,
+ DWORD dwMilliseconds);
+
+typedef BOOL (WINAPI* sSleepConditionVariableSRW)
+ (PCONDITION_VARIABLE ConditionVariable,
+ PSRWLOCK SRWLock,
+ DWORD dwMilliseconds,
+ ULONG Flags);
+
+typedef VOID (WINAPI* sWakeAllConditionVariable)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef VOID (WINAPI* sWakeConditionVariable)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef BOOL (WINAPI* sCancelSynchronousIo)
+ (HANDLE hThread);
+
+typedef DWORD (WINAPI* sGetFinalPathNameByHandleW)
+ (HANDLE hFile,
+ LPWSTR lpszFilePath,
+ DWORD cchFilePath,
+ DWORD dwFlags);
+
+/* from powerbase.h */
+#ifndef DEVICE_NOTIFY_CALLBACK
+# define DEVICE_NOTIFY_CALLBACK 2
+#endif
+
+#ifndef PBT_APMRESUMEAUTOMATIC
+# define PBT_APMRESUMEAUTOMATIC 18
+#endif
+
+#ifndef PBT_APMRESUMESUSPEND
+# define PBT_APMRESUMESUSPEND 7
+#endif
+
+typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE(
+ PVOID Context,
+ ULONG Type,
+ PVOID Setting
+);
+typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE;
+
+typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS {
+ _PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback;
+ PVOID Context;
+} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS;
+
+typedef PVOID _HPOWERNOTIFY;
+typedef _HPOWERNOTIFY *_PHPOWERNOTIFY;
+
+typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification)
+ (DWORD Flags,
+ HANDLE Recipient,
+ _PHPOWERNOTIFY RegistrationHandle);
+
+
+/* Ntdll function pointers */
+extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
+extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
+extern sNtQueryInformationFile pNtQueryInformationFile;
+extern sNtSetInformationFile pNtSetInformationFile;
+extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
+extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
+extern sNtQuerySystemInformation pNtQuerySystemInformation;
+
+
+/* Kernel32 function pointers */
+extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
+extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
+extern sCreateSymbolicLinkW pCreateSymbolicLinkW;
+extern sCancelIoEx pCancelIoEx;
+extern sInitializeConditionVariable pInitializeConditionVariable;
+extern sSleepConditionVariableCS pSleepConditionVariableCS;
+extern sSleepConditionVariableSRW pSleepConditionVariableSRW;
+extern sWakeAllConditionVariable pWakeAllConditionVariable;
+extern sWakeConditionVariable pWakeConditionVariable;
+extern sCancelSynchronousIo pCancelSynchronousIo;
+extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
+
+
+/* Powrprof.dll function pointer */
+extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
+
+#endif /* UV_WIN_WINAPI_H_ */
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/* Whether there are any non-IFS LSPs stacked on TCP */
+int uv_tcp_non_ifs_lsp_ipv4;
+int uv_tcp_non_ifs_lsp_ipv6;
+
+/* Ip address used to bind to any port at any interface */
+struct sockaddr_in uv_addr_ip4_any_;
+struct sockaddr_in6 uv_addr_ip6_any_;
+
+
+/*
+ * Retrieves the pointer to a winsock extension function.
+ */
+static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
+ void **target) {
+ int result;
+ DWORD bytes;
+
+ result = WSAIoctl(socket,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &guid,
+ sizeof(guid),
+ (void*)target,
+ sizeof(*target),
+ &bytes,
+ NULL,
+ NULL);
+
+ if (result == SOCKET_ERROR) {
+ *target = NULL;
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+
+BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
+ const GUID wsaid_acceptex = WSAID_ACCEPTEX;
+ return uv_get_extension_function(socket, wsaid_acceptex, (void**)target);
+}
+
+
+BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
+ const GUID wsaid_connectex = WSAID_CONNECTEX;
+ return uv_get_extension_function(socket, wsaid_connectex, (void**)target);
+}
+
+
+static int error_means_no_support(DWORD error) {
+ return error == WSAEPROTONOSUPPORT || error == WSAESOCKTNOSUPPORT ||
+ error == WSAEPFNOSUPPORT || error == WSAEAFNOSUPPORT;
+}
+
+
+void uv_winsock_init() {
+ WSADATA wsa_data;
+ int errorno;
+ SOCKET dummy;
+ WSAPROTOCOL_INFOW protocol_info;
+ int opt_len;
+
+ /* Initialize winsock */
+ errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ if (errorno != 0) {
+ uv_fatal_error(errorno, "WSAStartup");
+ }
+
+ /* Set implicit binding address used by connectEx */
+ if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) {
+ abort();
+ }
+
+ /* TODO: IPv6 support in libtuv is incomplete, disable this for now.
+ if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) {
+ abort();
+ }
+ */
+
+ /* Detect non-IFS LSPs */
+ dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+
+ if (dummy != INVALID_SOCKET) {
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(dummy,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "getsockopt");
+
+ if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
+ uv_tcp_non_ifs_lsp_ipv4 = 1;
+
+ if (closesocket(dummy) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "closesocket");
+
+ } else if (!error_means_no_support(WSAGetLastError())) {
+ /* Any error other than "socket type not supported" is fatal. */
+ uv_fatal_error(WSAGetLastError(), "socket");
+ }
+
+ /* Detect IPV6 support and non-IFS LSPs */
+ dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
+
+ if (dummy != INVALID_SOCKET) {
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(dummy,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "getsockopt");
+
+ if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
+ uv_tcp_non_ifs_lsp_ipv6 = 1;
+
+ if (closesocket(dummy) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "closesocket");
+
+ } else if (!error_means_no_support(WSAGetLastError())) {
+ /* Any error other than "socket type not supported" is fatal. */
+ uv_fatal_error(WSAGetLastError(), "socket");
+ }
+}
+
+
+int uv_ntstatus_to_winsock_error(NTSTATUS status) {
+ switch (status) {
+ case STATUS_SUCCESS:
+ return ERROR_SUCCESS;
+
+ case STATUS_PENDING:
+ return ERROR_IO_PENDING;
+
+ case STATUS_INVALID_HANDLE:
+ case STATUS_OBJECT_TYPE_MISMATCH:
+ return WSAENOTSOCK;
+
+ case STATUS_INSUFFICIENT_RESOURCES:
+ case STATUS_PAGEFILE_QUOTA:
+ case STATUS_COMMITMENT_LIMIT:
+ case STATUS_WORKING_SET_QUOTA:
+ case STATUS_NO_MEMORY:
+ case STATUS_QUOTA_EXCEEDED:
+ case STATUS_TOO_MANY_PAGING_FILES:
+ case STATUS_REMOTE_RESOURCES:
+ return WSAENOBUFS;
+
+ case STATUS_TOO_MANY_ADDRESSES:
+ case STATUS_SHARING_VIOLATION:
+ case STATUS_ADDRESS_ALREADY_EXISTS:
+ return WSAEADDRINUSE;
+
+ case STATUS_LINK_TIMEOUT:
+ case STATUS_IO_TIMEOUT:
+ case STATUS_TIMEOUT:
+ return WSAETIMEDOUT;
+
+ case STATUS_GRACEFUL_DISCONNECT:
+ return WSAEDISCON;
+
+ case STATUS_REMOTE_DISCONNECT:
+ case STATUS_CONNECTION_RESET:
+ case STATUS_LINK_FAILED:
+ case STATUS_CONNECTION_DISCONNECTED:
+ case STATUS_PORT_UNREACHABLE:
+ case STATUS_HOPLIMIT_EXCEEDED:
+ return WSAECONNRESET;
+
+ case STATUS_LOCAL_DISCONNECT:
+ case STATUS_TRANSACTION_ABORTED:
+ case STATUS_CONNECTION_ABORTED:
+ return WSAECONNABORTED;
+
+ case STATUS_BAD_NETWORK_PATH:
+ case STATUS_NETWORK_UNREACHABLE:
+ case STATUS_PROTOCOL_UNREACHABLE:
+ return WSAENETUNREACH;
+
+ case STATUS_HOST_UNREACHABLE:
+ return WSAEHOSTUNREACH;
+
+ case STATUS_CANCELLED:
+ case STATUS_REQUEST_ABORTED:
+ return WSAEINTR;
+
+ case STATUS_BUFFER_OVERFLOW:
+ case STATUS_INVALID_BUFFER_SIZE:
+ return WSAEMSGSIZE;
+
+ case STATUS_BUFFER_TOO_SMALL:
+ case STATUS_ACCESS_VIOLATION:
+ return WSAEFAULT;
+
+ case STATUS_DEVICE_NOT_READY:
+ case STATUS_REQUEST_NOT_ACCEPTED:
+ return WSAEWOULDBLOCK;
+
+ case STATUS_INVALID_NETWORK_RESPONSE:
+ case STATUS_NETWORK_BUSY:
+ case STATUS_NO_SUCH_DEVICE:
+ case STATUS_NO_SUCH_FILE:
+ case STATUS_OBJECT_PATH_NOT_FOUND:
+ case STATUS_OBJECT_NAME_NOT_FOUND:
+ case STATUS_UNEXPECTED_NETWORK_ERROR:
+ return WSAENETDOWN;
+
+ case STATUS_INVALID_CONNECTION:
+ return WSAENOTCONN;
+
+ case STATUS_REMOTE_NOT_LISTENING:
+ case STATUS_CONNECTION_REFUSED:
+ return WSAECONNREFUSED;
+
+ case STATUS_PIPE_DISCONNECTED:
+ return WSAESHUTDOWN;
+
+ case STATUS_CONFLICTING_ADDRESSES:
+ case STATUS_INVALID_ADDRESS:
+ case STATUS_INVALID_ADDRESS_COMPONENT:
+ return WSAEADDRNOTAVAIL;
+
+ case STATUS_NOT_SUPPORTED:
+ case STATUS_NOT_IMPLEMENTED:
+ return WSAEOPNOTSUPP;
+
+ case STATUS_ACCESS_DENIED:
+ return WSAEACCES;
+
+ default:
+ if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
+ (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
+ /* It's a windows error that has been previously mapped to an */
+ /* ntstatus code. */
+ return (DWORD) (status & 0xffff);
+ } else {
+ /* The default fallback for unmappable ntstatus codes. */
+ return WSAEINVAL;
+ }
+ }
+}
+
+
+/*
+ * This function provides a workaround for a bug in the winsock implementation
+ * of WSARecv. The problem is that when SetFileCompletionNotificationModes is
+ * used to avoid IOCP notifications of completed reads, WSARecv does not
+ * reliably indicate whether we can expect a completion package to be posted
+ * when the receive buffer is smaller than the received datagram.
+ *
+ * However it is desirable to use SetFileCompletionNotificationModes because
+ * it yields a massive performance increase.
+ *
+ * This function provides a workaround for that bug, but it only works for the
+ * specific case that we need it for. E.g. it assumes that the "avoid iocp"
+ * bit has been set, and supports only overlapped operation. It also requires
+ * the user to use the default msafd driver, doesn't work when other LSPs are
+ * stacked on top of it.
+ */
+int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
+ NTSTATUS status;
+ void* apc_context;
+ IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ AFD_RECV_INFO info;
+ DWORD error;
+
+ if (overlapped == NULL || completion_routine != NULL) {
+ WSASetLastError(WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ info.BufferArray = buffers;
+ info.BufferCount = buffer_count;
+ info.AfdFlags = AFD_OVERLAPPED;
+ info.TdiFlags = TDI_RECEIVE_NORMAL;
+
+ if (*flags & MSG_PEEK) {
+ info.TdiFlags |= TDI_RECEIVE_PEEK;
+ }
+
+ if (*flags & MSG_PARTIAL) {
+ info.TdiFlags |= TDI_RECEIVE_PARTIAL;
+ }
+
+ if (!((intptr_t) overlapped->hEvent & 1)) {
+ apc_context = (void*) overlapped;
+ } else {
+ apc_context = NULL;
+ }
+
+ iosb->Status = STATUS_PENDING;
+ iosb->Pointer = 0;
+
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ overlapped->hEvent,
+ NULL,
+ apc_context,
+ iosb,
+ IOCTL_AFD_RECEIVE,
+ &info,
+ sizeof(info),
+ NULL,
+ 0);
+
+ *flags = 0;
+ *bytes = (DWORD) iosb->Information;
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ case STATUS_BUFFER_OVERFLOW:
+ error = WSAEMSGSIZE;
+ break;
+
+ case STATUS_RECEIVE_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL | MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL;
+ break;
+
+ default:
+ error = uv_ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
+
+
+/* See description of uv_wsarecv_workaround. */
+int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
+ int* addr_len, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
+ NTSTATUS status;
+ void* apc_context;
+ IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ AFD_RECV_DATAGRAM_INFO info;
+ DWORD error;
+
+ if (overlapped == NULL || addr == NULL || addr_len == NULL ||
+ completion_routine != NULL) {
+ WSASetLastError(WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ info.BufferArray = buffers;
+ info.BufferCount = buffer_count;
+ info.AfdFlags = AFD_OVERLAPPED;
+ info.TdiFlags = TDI_RECEIVE_NORMAL;
+ info.Address = addr;
+ info.AddressLength = addr_len;
+
+ if (*flags & MSG_PEEK) {
+ info.TdiFlags |= TDI_RECEIVE_PEEK;
+ }
+
+ if (*flags & MSG_PARTIAL) {
+ info.TdiFlags |= TDI_RECEIVE_PARTIAL;
+ }
+
+ if (!((intptr_t) overlapped->hEvent & 1)) {
+ apc_context = (void*) overlapped;
+ } else {
+ apc_context = NULL;
+ }
+
+ iosb->Status = STATUS_PENDING;
+ iosb->Pointer = 0;
+
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ overlapped->hEvent,
+ NULL,
+ apc_context,
+ iosb,
+ IOCTL_AFD_RECEIVE_DATAGRAM,
+ &info,
+ sizeof(info),
+ NULL,
+ 0);
+
+ *flags = 0;
+ *bytes = (DWORD) iosb->Information;
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ case STATUS_BUFFER_OVERFLOW:
+ error = WSAEMSGSIZE;
+ break;
+
+ case STATUS_RECEIVE_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL | MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL;
+ break;
+
+ default:
+ error = uv_ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
+
+
+int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
+ AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
+ IO_STATUS_BLOCK iosb;
+ IO_STATUS_BLOCK* iosb_ptr;
+ HANDLE event = NULL;
+ void* apc_context;
+ NTSTATUS status;
+ DWORD error;
+
+ if (overlapped != NULL) {
+ /* Overlapped operation. */
+ iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ event = overlapped->hEvent;
+
+ /* Do not report iocp completion if hEvent is tagged. */
+ if ((uintptr_t) event & 1) {
+ event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
+ apc_context = NULL;
+ } else {
+ apc_context = overlapped;
+ }
+
+ } else {
+ /* Blocking operation. */
+ iosb_ptr = &iosb;
+ event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (event == NULL) {
+ return SOCKET_ERROR;
+ }
+ apc_context = NULL;
+ }
+
+ iosb_ptr->Status = STATUS_PENDING;
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ event,
+ NULL,
+ apc_context,
+ iosb_ptr,
+ IOCTL_AFD_POLL,
+ info_in,
+ sizeof *info_in,
+ info_out,
+ sizeof *info_out);
+
+ if (overlapped == NULL) {
+ /* If this is a blocking operation, wait for the event to become */
+ /* signaled, and then grab the real status from the io status block. */
+ if (status == STATUS_PENDING) {
+ DWORD r = WaitForSingleObject(event, INFINITE);
+
+ if (r == WAIT_FAILED) {
+ DWORD saved_error = GetLastError();
+ CloseHandle(event);
+ WSASetLastError(saved_error);
+ return SOCKET_ERROR;
+ }
+
+ status = iosb.Status;
+ }
+
+ CloseHandle(event);
+ }
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ default:
+ error = uv_ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef UV_WIN_WINSOCK_H_
+#define UV_WIN_WINSOCK_H_
+
+#include <winsock2.h>
+#include <iptypes.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+
+#include "winapi.h"
+
+
+/*
+ * MinGW is missing these too
+ */
+#ifndef SO_UPDATE_CONNECT_CONTEXT
+# define SO_UPDATE_CONNECT_CONTEXT 0x7010
+#endif
+
+#ifndef TCP_KEEPALIVE
+# define TCP_KEEPALIVE 3
+#endif
+
+#ifndef IPV6_V6ONLY
+# define IPV6_V6ONLY 27
+#endif
+
+#ifndef IPV6_HOPLIMIT
+# define IPV6_HOPLIMIT 21
+#endif
+
+#ifndef SIO_BASE_HANDLE
+# define SIO_BASE_HANDLE 0x48000022
+#endif
+
+/*
+ * TDI defines that are only in the DDK.
+ * We only need receive flags so far.
+ */
+#ifndef TDI_RECEIVE_NORMAL
+ #define TDI_RECEIVE_BROADCAST 0x00000004
+ #define TDI_RECEIVE_MULTICAST 0x00000008
+ #define TDI_RECEIVE_PARTIAL 0x00000010
+ #define TDI_RECEIVE_NORMAL 0x00000020
+ #define TDI_RECEIVE_EXPEDITED 0x00000040
+ #define TDI_RECEIVE_PEEK 0x00000080
+ #define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100
+ #define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200
+ #define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400
+ #define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800
+ #define TDI_RECEIVE_CONTROL_INFO 0x00001000
+ #define TDI_RECEIVE_FORCE_INDICATION 0x00002000
+ #define TDI_RECEIVE_NO_PUSH 0x00004000
+#endif
+
+/*
+ * The "Auxiliary Function Driver" is the windows kernel-mode driver that does
+ * TCP, UDP etc. Winsock is just a layer that dispatches requests to it.
+ * Having these definitions allows us to bypass winsock and make an AFD kernel
+ * call directly, avoiding a bug in winsock's recvfrom implementation.
+ */
+
+#define AFD_NO_FAST_IO 0x00000001
+#define AFD_OVERLAPPED 0x00000002
+#define AFD_IMMEDIATE 0x00000004
+
+#define AFD_POLL_RECEIVE_BIT 0
+#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT)
+#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1
+#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT)
+#define AFD_POLL_SEND_BIT 2
+#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT)
+#define AFD_POLL_DISCONNECT_BIT 3
+#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT)
+#define AFD_POLL_ABORT_BIT 4
+#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT)
+#define AFD_POLL_LOCAL_CLOSE_BIT 5
+#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT)
+#define AFD_POLL_CONNECT_BIT 6
+#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT)
+#define AFD_POLL_ACCEPT_BIT 7
+#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT)
+#define AFD_POLL_CONNECT_FAIL_BIT 8
+#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT)
+#define AFD_POLL_QOS_BIT 9
+#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT)
+#define AFD_POLL_GROUP_QOS_BIT 10
+#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT)
+
+#define AFD_NUM_POLL_EVENTS 11
+#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1)
+
+typedef struct _AFD_RECV_DATAGRAM_INFO {
+ LPWSABUF BufferArray;
+ ULONG BufferCount;
+ ULONG AfdFlags;
+ ULONG TdiFlags;
+ struct sockaddr* Address;
+ int* AddressLength;
+} AFD_RECV_DATAGRAM_INFO, *PAFD_RECV_DATAGRAM_INFO;
+
+typedef struct _AFD_RECV_INFO {
+ LPWSABUF BufferArray;
+ ULONG BufferCount;
+ ULONG AfdFlags;
+ ULONG TdiFlags;
+} AFD_RECV_INFO, *PAFD_RECV_INFO;
+
+
+#define _AFD_CONTROL_CODE(operation, method) \
+ ((FSCTL_AFD_BASE) << 12 | (operation << 2) | method)
+
+#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK
+
+#define AFD_RECEIVE 5
+#define AFD_RECEIVE_DATAGRAM 6
+#define AFD_POLL 9
+
+#define IOCTL_AFD_RECEIVE \
+ _AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER)
+
+#define IOCTL_AFD_RECEIVE_DATAGRAM \
+ _AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER)
+
+#define IOCTL_AFD_POLL \
+ _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED)
+
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP {
+ /* FIXME: __C89_NAMELESS was removed */
+ /* __C89_NAMELESS */ union {
+ ULONGLONG Alignment;
+ /* __C89_NAMELESS */ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next;
+ SOCKET_ADDRESS Address;
+ IP_PREFIX_ORIGIN PrefixOrigin;
+ IP_SUFFIX_ORIGIN SuffixOrigin;
+ IP_DAD_STATE DadState;
+ ULONG ValidLifetime;
+ ULONG PreferredLifetime;
+ ULONG LeaseLifetime;
+} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP;
+
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next;
+ SOCKET_ADDRESS Address;
+ IP_PREFIX_ORIGIN PrefixOrigin;
+ IP_SUFFIX_ORIGIN SuffixOrigin;
+ IP_DAD_STATE DadState;
+ ULONG ValidLifetime;
+ ULONG PreferredLifetime;
+ ULONG LeaseLifetime;
+ UINT8 OnLinkPrefixLength;
+} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH;
+
+#endif
+
+#endif /* UV_WIN_WINSOCK_H_ */
TUV_ASSERT(r == 0);
break;
-/*
- case PIPE:
+#ifdef TUV_FEATURE_PIPE
+ case TEST_PIPE:
stream = (uv_stream_t*)malloc(sizeof(uv_pipe_t));
TUV_ASSERT(stream != NULL);
- r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);
+ r = uv_pipe_init(&loop, (uv_pipe_t*)stream, 0);
TUV_ASSERT(r == 0);
break;
-*/
+#endif
default:
TUV_ASSERT(0 && "Bad serverType");
extern "C" {
#endif
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#if defined(__NUTTX__) || defined(__TUV_RAW__)
#define EMBED_LOW_MEMORY
int run_helper_##name(void); \
int run_helper_##name(void)
+#ifdef _WIN32
+# define TEST_PIPENAME "\\\\?\\pipe\\uv-test"
+# define TEST_PIPENAME_2 "\\\\?\\pipe\\uv-test2"
+# define TEST_PIPENAME_3 "\\\\?\\pipe\\uv-test3"
+#else
+# define TEST_PIPENAME "/tmp/uv-test-sock"
+# define TEST_PIPENAME_2 "/tmp/uv-test-sock2"
+# define TEST_PIPENAME_3 "/tmp/uv-test-sock3"
+#endif
/* Have our own assert, so we are sure it does not get optimized away in
* a release build.
#else
+int ipc_helper(int listen_after_write);
+int ipc_helper_tcp_connection(void);
+// int ipc_send_recv_helper(void);
+int ipc_helper_bind_twice(void);
+// int stdio_over_pipes_helper(void);
+int spawn_stdin_stdout(void);
+
+static int maybe_run_test(int argc, char **argv);
static pthread_t tid = 0;
return run_test_part(task->task_name, task->process_name);
}
-int main(int argc, char *argv[]) {
- int result;
- InitDebugSettings();
+int main(int argc, char **argv) {
+ if (platform_init(argc, argv))
+ return 1;
- platform_init(argc, argv);
+ InitDebugSettings();
- if (argc>2) {
- return run_test_part(argv[1], argv[2]);
+ switch (argc) {
+ case 1: return run_tests();
+ case 2: return maybe_run_test(argc, argv);
+ case 3: return run_test_part(argv[1], argv[2]);
+ default:
+ ReleaseDebugSettings();
+
+ fprintf(stderr, "Too many arguments.\n");
+ fflush(stderr);
+ return 1;
}
- result = run_tests();
+
ReleaseDebugSettings();
- return result;
+ return 0;
+}
+
+static int maybe_run_test(int argc, char **argv) {
+#if TUV_FEATURE_PROCESS
+ if (strcmp(argv[1], "ipc_helper_listen_before_write") == 0) {
+ return ipc_helper(0);
+ }
+
+ if (strcmp(argv[1], "ipc_helper_listen_after_write") == 0) {
+ return ipc_helper(1);
+ }
+
+ // if (strcmp(argv[1], "ipc_send_recv_helper") == 0) {
+ // return ipc_send_recv_helper();
+ // }
+
+ if (strcmp(argv[1], "ipc_helper_tcp_connection") == 0) {
+ return ipc_helper_tcp_connection();
+ }
+
+ if (strcmp(argv[1], "ipc_helper_bind_twice") == 0) {
+ return ipc_helper_bind_twice();
+ }
+
+ // if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) {
+ // return stdio_over_pipes_helper();
+ // }
+
+ if (strcmp(argv[1], "spawn_helper1") == 0) {
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper2") == 0) {
+ printf("hello world\n");
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper3") == 0) {
+ char buffer[256];
+ TUV_ASSERT(buffer == fgets(buffer, sizeof(buffer) - 1, stdin));
+ buffer[sizeof(buffer) - 1] = '\0';
+ fputs(buffer, stdout);
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper4") == 0) {
+ /* Never surrender, never return! */
+ while (1) uv_sleep(10000);
+ }
+
+ if (strcmp(argv[1], "spawn_helper5") == 0) {
+ const char out[] = "fourth stdio!\n";
+#ifdef _WIN32
+ DWORD bytes;
+ WriteFile((HANDLE) _get_osfhandle(3), out, sizeof(out) - 1, &bytes, NULL);
+#else
+ {
+ ssize_t r;
+
+ do
+ r = write(3, out, sizeof(out) - 1);
+ while (r == -1 && errno == EINTR);
+
+ fsync(3);
+ }
+#endif
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper6") == 0) {
+ int r;
+
+ r = fprintf(stdout, "hello world\n");
+ TUV_ASSERT(r > 0);
+
+ r = fprintf(stderr, "hello errworld\n");
+ TUV_ASSERT(r > 0);
+
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper7") == 0) {
+ int r;
+ char *test;
+ /* Test if the test value from the parent is still set */
+ test = getenv("ENV_TEST");
+ TUV_ASSERT(test != NULL);
+
+ r = fprintf(stdout, "%s", test);
+ TUV_ASSERT(r > 0);
+
+ return 1;
+ }
+
+#ifndef _WIN32
+ if (strcmp(argv[1], "spawn_helper8") == 0) {
+ int fd;
+ TUV_ASSERT(sizeof(fd) == read(0, &fd, sizeof(fd)));
+ TUV_ASSERT(fd > 2);
+ TUV_ASSERT(-1 == write(fd, "x", 1));
+
+ return 1;
+ }
+#endif /* !_WIN32 */
+
+ if (strcmp(argv[1], "spawn_helper9") == 0) {
+ return spawn_stdin_stdout();
+ }
+
+#ifndef _WIN32
+ if (strcmp(argv[1], "spawn_helper_setuid_setgid") == 0) {
+ uv_uid_t uid = atoi(argv[2]);
+ uv_gid_t gid = atoi(argv[3]);
+
+ TUV_ASSERT(uid == getuid());
+ TUV_ASSERT(gid == getgid());
+
+ return 1;
+ }
+#endif /* !_WIN32 */
+
+#endif /* TUV_FEATURE_PROCESS */
+ // return run_test(argv[1], 0, 1);
+ return 1;
}
#endif
// shutdown_eof should be last of tcp test, it'll stop "echo_sevrer"
+#if defined(__linux__) && defined(TUV_FEATURE_PIPE)
+#define TEST_LIST_EXT_PIPE(TE) \
+ TE(pipe_bind_error_addrinuse, 5000) \
+ TE(pipe_bind_error_addrnotavail, 5000) \
+ TE(pipe_bind_error_inval, 5000) \
+ TE(pipe_listen_without_bind, 5000) \
+/*TE(pipe_close_stdout_read_stdin, 5000)*/ \
+ TE(pipe_connect_bad_name, 5000) \
+/*TE(pipe_connect_to_file, 5000)*/ \
+/*TE(pipe_connect_multiple, 5000)*/ \
+/*TE(pipe_connect_on_prepare, 5000)*/ \
+ TE(pipe_getsockname, 5000) \
+ TE(pipe_getsockname_abstract, 5000) \
+ TE(pipe_getsockname_blocking, 5000) \
+ TE(pipe_pending_instances, 5000) \
+ TE(pipe_sendmsg, 5000) \
+ TE(pipe_server_close, 5000) \
+ TE(pipe_set_non_blocking, 5000)
+#else
+#define TEST_LIST_EXT_PIPE(TE)
+#endif
+
+#if defined(__linux__) && defined(TUV_FEATURE_SIGNAL)
+#define TEST_LIST_EXT_SIGNAL(TE) \
+ TE(we_get_signal, 5000) \
+ TE(we_get_signals, 5000)
+#else
+#define TEST_LIST_EXT_SIGNAL(TE)
+#endif
+
+#if defined(__linux__) && defined(TUV_FEATURE_PROCESS)
+#define TEST_LIST_EXT_PROCESS(TE) \
+/*TE(ipc_listen_before_write, 5000)*/ \
+/*TE(ipc_listen_after_write, 5000)*/ \
+/*TE(ipc_tcp_connection, 5000)*/ \
+/*TE(spawn_fails_check_for_waitpid_cleanup, 5000) */ \
+/*TE(spawn_exit_code, 5000) */ \
+ TE(spawn_stdout, 5000) \
+/*TE(spawn_stdout_to_file, 5000) */ \
+/*TE(spawn_stdout_and_stderr_to_file, 5000) */ \
+/*TE(spawn_stdout_and_stderr_to_file2, 5000) */ \
+/*TE(spawn_stdout_and_stderr_to_file_swap, 5000) */ \
+/*TE(spawn_stdin, 5000) */ \
+/*TE(spawn_stdio_greater_than_3, 5000) */ \
+/*TE(spawn_ignored_stdio, 5000) */ \
+/*TE(spawn_and_kill, 5000) */ \
+/*TE(spawn_preserve_env, 5000) */ \
+/*TE(spawn_detached, 5000) */ \
+/*TE(spawn_and_kill_with_std, 5000) */ \
+/*TE(spawn_and_ping, 5000) */ \
+/*TE(spawn_same_stdout_stderr, 5000) */ \
+/*TE(spawn_closed_process_io, 5000) */ \
+/*TE(spawn_fails, 5000) */ \
+/*TE(kill, 5000) */ \
+/*TE(spawn_setuid_fails, 5000) */ \
+/*TE(spawn_setgid_fails, 5000) */ \
+/*TE(spawn_setuid_fails, 5000) */ \
+/*TE(spawn_setgid_fails, 5000) */ \
+/*TE(spawn_auto_unref, 5000) */ \
+/*TE(spawn_fs_open, 5000) */ \
+/*TE(closed_fd_events, 5000) */ \
+/*TE(spawn_reads_child_path, 5000) */ \
+/*TE(spawn_inherit_streams, 5000) */
+#else
+#define TEST_LIST_EXT_PROCESS(TE)
+#endif
+
#if defined(__linux__)
#define TEST_LIST_EXT(TE) \
TE(condvar_1, 5000) \
TE(getaddrinfo_basic, 5000) \
TE(getaddrinfo_basic_sync, 5000) \
TE(getaddrinfo_concurrent, 5000) \
+ \
+ TEST_LIST_EXT_PIPE(TE) \
+ TEST_LIST_EXT_PROCESS(TE) \
+ TEST_LIST_EXT_SIGNAL(TE)
#elif defined(__TUV_RAW__)
#define TEST_LIST_EXT(TE) \
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include "uv.h"
+#include "runner.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static uv_pipe_t channel;
+static uv_tcp_t tcp_server;
+static uv_tcp_t tcp_server2;
+static uv_tcp_t tcp_connection;
+
+static int exit_cb_called;
+static int read_cb_called;
+static int tcp_write_cb_called;
+static int tcp_read_cb_called;
+static int on_pipe_read_called;
+static int local_conn_accepted;
+static int remote_conn_accepted;
+static int tcp_server_listening;
+static uv_write_t write_req;
+static uv_write_t conn_notify_req;
+static int close_cb_called;
+static int connection_accepted;
+static int tcp_conn_read_cb_called;
+static int tcp_conn_write_cb_called;
+
+typedef struct {
+ uv_connect_t conn_req;
+ uv_write_t tcp_write_req;
+ uv_tcp_t conn;
+} tcp_conn;
+
+#define CONN_COUNT 100
+#define BACKLOG 128
+
+
+static void close_server_conn_cb(uv_handle_t* handle) {
+ free(handle);
+}
+
+
+static void on_connection(uv_stream_t* server, int status) {
+ uv_tcp_t* conn;
+ int r;
+
+ if (!local_conn_accepted) {
+ /* Accept the connection and close it. Also and close the server. */
+ TUV_ASSERT(status == 0);
+ TUV_ASSERT((uv_stream_t*)&tcp_server == server);
+
+ conn = malloc(sizeof(*conn));
+ TUV_ASSERT(conn);
+ r = uv_tcp_init(server->loop, conn);
+ TUV_ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)conn);
+ TUV_ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)conn, close_server_conn_cb);
+ uv_close((uv_handle_t*)server, NULL);
+ local_conn_accepted = 1;
+ }
+}
+
+
+static void exit_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ printf("exit_cb\n");
+ exit_cb_called++;
+ TUV_ASSERT(exit_status == 0);
+ uv_close((uv_handle_t*)process, NULL);
+}
+
+
+static void on_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+static void close_client_conn_cb(uv_handle_t* handle) {
+ tcp_conn* p = (tcp_conn*)handle->data;
+ free(p);
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ uv_close((uv_handle_t*)req->handle, close_client_conn_cb);
+}
+
+
+static void make_many_connections(void) {
+ tcp_conn* conn;
+ struct sockaddr_in addr;
+ int r, i;
+
+ for (i = 0; i < CONN_COUNT; i++) {
+ conn = malloc(sizeof(*conn));
+ TUV_ASSERT(conn);
+
+ r = uv_tcp_init(uv_default_loop(), &conn->conn);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_connect(&conn->conn_req,
+ (uv_tcp_t*) &conn->conn,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ TUV_ASSERT(r == 0);
+
+ conn->conn.data = conn;
+ }
+}
+
+
+static void on_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ int r;
+ uv_pipe_t* pipe;
+ uv_handle_type pending;
+ uv_buf_t outbuf;
+
+ pipe = (uv_pipe_t*) handle;
+
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ free(buf->base);
+ return;
+ }
+
+ printf("error recving on channel: %s\n", uv_strerror(nread));
+ abort();
+ }
+
+ fprintf(stderr, "got %d bytes\n", (int)nread);
+
+ pending = uv_pipe_pending_type(pipe);
+ if (!tcp_server_listening) {
+ TUV_ASSERT(1 == uv_pipe_pending_count(pipe));
+ TUV_ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
+ read_cb_called++;
+
+ /* Accept the pending TCP server, and start listening on it. */
+ TUV_ASSERT(pending == UV_TCP);
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ TUV_ASSERT(r == 0);
+
+ r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server);
+ TUV_ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, on_connection);
+ TUV_ASSERT(r == 0);
+
+ tcp_server_listening = 1;
+
+ /* Make sure that the expected data is correctly multiplexed. */
+ TUV_ASSERT(memcmp("hello\n", buf->base, nread) == 0);
+
+ outbuf = uv_buf_init("world\n", 6);
+ r = uv_write(&write_req, (uv_stream_t*)pipe, &outbuf, 1, NULL);
+ TUV_ASSERT(r == 0);
+
+ /* Create a bunch of connections to get both servers to accept. */
+ make_many_connections();
+ } else if (memcmp("accepted_connection\n", buf->base, nread) == 0) {
+ /* Remote server has accepted a connection. Close the channel. */
+ TUV_ASSERT(0 == uv_pipe_pending_count(pipe));
+ TUV_ASSERT(pending == UV_UNKNOWN_HANDLE);
+ remote_conn_accepted = 1;
+ uv_close((uv_handle_t*)&channel, NULL);
+ }
+
+ free(buf->base);
+}
+
+#ifdef _WIN32
+static void on_read_listen_after_bound_twice(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ int r;
+ uv_pipe_t* pipe;
+ uv_handle_type pending;
+
+ pipe = (uv_pipe_t*) handle;
+
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ free(buf->base);
+ return;
+ }
+
+ printf("error recving on channel: %s\n", uv_strerror(nread));
+ abort();
+ }
+
+ fprintf(stderr, "got %d bytes\n", (int)nread);
+
+ TUV_ASSERT(uv_pipe_pending_count(pipe) > 0);
+ pending = uv_pipe_pending_type(pipe);
+ TUV_ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
+ read_cb_called++;
+
+ if (read_cb_called == 1) {
+ /* Accept the first TCP server, and start listening on it. */
+ TUV_ASSERT(pending == UV_TCP);
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ TUV_ASSERT(r == 0);
+
+ r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server);
+ TUV_ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, on_connection);
+ TUV_ASSERT(r == 0);
+ } else if (read_cb_called == 2) {
+ /* Accept the second TCP server, and start listening on it. */
+ TUV_ASSERT(pending == UV_TCP);
+ r = uv_tcp_init(uv_default_loop(), &tcp_server2);
+ TUV_ASSERT(r == 0);
+
+ r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server2);
+ TUV_ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server2, BACKLOG, on_connection);
+ TUV_ASSERT(r == UV_EADDRINUSE);
+
+ uv_close((uv_handle_t*)&tcp_server, NULL);
+ uv_close((uv_handle_t*)&tcp_server2, NULL);
+ TUV_ASSERT(0 == uv_pipe_pending_count(pipe));
+ uv_close((uv_handle_t*)&channel, NULL);
+ }
+
+ free(buf->base);
+}
+#endif
+
+void spawn_helper(uv_pipe_t* channel,
+ uv_process_t* process,
+ const char* helper) {
+ uv_process_options_t options;
+ size_t exepath_size;
+ char exepath[1024];
+ char* args[3];
+ int r;
+ uv_stdio_container_t stdio[1];
+
+ r = uv_pipe_init(uv_default_loop(), channel, 1);
+ TUV_ASSERT(r == 0);
+ TUV_ASSERT(channel->ipc);
+
+ exepath_size = sizeof(exepath);
+ r = uv_exepath(exepath, &exepath_size);
+ TUV_ASSERT(r == 0);
+
+ exepath[exepath_size] = '\0';
+ args[0] = exepath;
+ args[1] = (char*)helper;
+ args[2] = NULL;
+
+ memset(&options, 0, sizeof(options));
+ options.file = exepath;
+ options.args = args;
+ options.exit_cb = exit_cb;
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE |
+ UV_READABLE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)channel;
+ options.stdio_count = 1;
+
+ r = uv_spawn(uv_default_loop(), process, &options);
+ TUV_ASSERT(r == 0);
+}
+
+
+static void on_tcp_write(uv_write_t* req, int status) {
+ TUV_ASSERT(status == 0);
+ TUV_ASSERT(req->handle == (uv_stream_t*)&tcp_connection);
+ tcp_write_cb_called++;
+}
+
+
+static void on_read_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+static void on_tcp_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ TUV_ASSERT(nread > 0);
+ TUV_ASSERT(memcmp("hello again\n", buf->base, nread) == 0);
+ TUV_ASSERT(tcp == (uv_stream_t*)&tcp_connection);
+ free(buf->base);
+
+ tcp_read_cb_called++;
+
+ uv_close((uv_handle_t*)tcp, NULL);
+ uv_close((uv_handle_t*)&channel, NULL);
+}
+
+
+static void on_read_connection(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ int r;
+ uv_buf_t outbuf;
+ uv_pipe_t* pipe;
+ uv_handle_type pending;
+
+ pipe = (uv_pipe_t*) handle;
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ free(buf->base);
+ return;
+ }
+
+ printf("error recving on channel: %s\n", uv_strerror(nread));
+ abort();
+ }
+
+ fprintf(stderr, "got %d bytes\n", (int)nread);
+
+ TUV_ASSERT(1 == uv_pipe_pending_count(pipe));
+ pending = uv_pipe_pending_type(pipe);
+
+ TUV_ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
+ read_cb_called++;
+
+ /* Accept the pending TCP connection */
+ TUV_ASSERT(pending == UV_TCP);
+ r = uv_tcp_init(uv_default_loop(), &tcp_connection);
+ TUV_ASSERT(r == 0);
+
+ r = uv_accept(handle, (uv_stream_t*)&tcp_connection);
+ TUV_ASSERT(r == 0);
+
+ /* Make sure that the expected data is correctly multiplexed. */
+ TUV_ASSERT(memcmp("hello\n", buf->base, nread) == 0);
+
+ /* Write/read to/from the connection */
+ outbuf = uv_buf_init("world\n", 6);
+ r = uv_write(&write_req, (uv_stream_t*)&tcp_connection, &outbuf, 1,
+ on_tcp_write);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&tcp_connection, on_read_alloc, on_tcp_read);
+ TUV_ASSERT(r == 0);
+
+ free(buf->base);
+}
+
+
+static int run_ipc_test(const char* helper, uv_read_cb read_cb) {
+ uv_process_t process;
+ int r;
+
+ spawn_helper(&channel, &process, helper);
+ uv_read_start((uv_stream_t*)&channel, on_alloc, read_cb);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ return 0;
+}
+
+
+TEST_IMPL(ipc_listen_before_write) {
+ int r = run_ipc_test("ipc_helper_listen_before_write", on_read);
+ TUV_ASSERT(local_conn_accepted == 1);
+ TUV_ASSERT(remote_conn_accepted == 1);
+ TUV_ASSERT(read_cb_called == 1);
+ TUV_ASSERT(exit_cb_called == 1);
+ return r;
+}
+
+
+TEST_IMPL(ipc_listen_after_write) {
+ int r = run_ipc_test("ipc_helper_listen_after_write", on_read);
+ TUV_ASSERT(local_conn_accepted == 1);
+ TUV_ASSERT(remote_conn_accepted == 1);
+ TUV_ASSERT(read_cb_called == 1);
+ TUV_ASSERT(exit_cb_called == 1);
+ return r;
+}
+
+
+TEST_IMPL(ipc_tcp_connection) {
+ int r = run_ipc_test("ipc_helper_tcp_connection", on_read_connection);
+ TUV_ASSERT(read_cb_called == 1);
+ TUV_ASSERT(tcp_write_cb_called == 1);
+ TUV_ASSERT(tcp_read_cb_called == 1);
+ TUV_ASSERT(exit_cb_called == 1);
+ return r;
+}
+
+
+#ifdef _WIN32
+TEST_IMPL(listen_with_simultaneous_accepts) {
+ uv_tcp_t server;
+ int r;
+ struct sockaddr_in addr;
+
+ TUV_ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ TUV_ASSERT(r == 0);
+
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_tcp_simultaneous_accepts(&server, 1);
+ TUV_ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
+ TUV_ASSERT(r == 0);
+ TUV_ASSERT(server.reqs_pending == 32);
+
+ return 0;
+}
+
+
+TEST_IMPL(listen_no_simultaneous_accepts) {
+ uv_tcp_t server;
+ int r;
+ struct sockaddr_in addr;
+
+ TUV_ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ TUV_ASSERT(r == 0);
+
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_tcp_simultaneous_accepts(&server, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
+ TUV_ASSERT(r == 0);
+ TUV_ASSERT(server.reqs_pending == 1);
+
+ return 0;
+}
+
+TEST_IMPL(ipc_listen_after_bind_twice) {
+ int r = run_ipc_test("ipc_helper_bind_twice", on_read_listen_after_bound_twice);
+ TUV_ASSERT(read_cb_called == 2);
+ TUV_ASSERT(exit_cb_called == 1);
+ return r;
+}
+#endif
+
+
+/* Everything here runs in a child process. */
+
+static tcp_conn conn;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void conn_notify_write_cb(uv_write_t* req, int status) {
+ uv_close((uv_handle_t*)&tcp_server, close_cb);
+ uv_close((uv_handle_t*)&channel, close_cb);
+}
+
+
+static void tcp_connection_write_cb(uv_write_t* req, int status) {
+ TUV_ASSERT((uv_handle_t*)&conn.conn == (uv_handle_t*)req->handle);
+ uv_close((uv_handle_t*)req->handle, close_cb);
+ uv_close((uv_handle_t*)&channel, close_cb);
+ uv_close((uv_handle_t*)&tcp_server, close_cb);
+ tcp_conn_write_cb_called++;
+}
+
+
+static void on_tcp_child_process_read(uv_stream_t* tcp,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_buf_t outbuf;
+ int r;
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ free(buf->base);
+ return;
+ }
+
+ printf("error recving on tcp connection: %s\n", uv_strerror(nread));
+ abort();
+ }
+
+ TUV_ASSERT(nread > 0);
+ TUV_ASSERT(memcmp("world\n", buf->base, nread) == 0);
+ on_pipe_read_called++;
+ free(buf->base);
+
+ /* Write to the socket */
+ outbuf = uv_buf_init("hello again\n", 12);
+ r = uv_write(&conn.tcp_write_req, tcp, &outbuf, 1, tcp_connection_write_cb);
+ TUV_ASSERT(r == 0);
+
+ tcp_conn_read_cb_called++;
+}
+
+
+static void connect_child_process_cb(uv_connect_t* req, int status) {
+ int r;
+
+ TUV_ASSERT(status == 0);
+ r = uv_read_start(req->handle, on_read_alloc, on_tcp_child_process_read);
+ TUV_ASSERT(r == 0);
+}
+
+
+static void ipc_on_connection(uv_stream_t* server, int status) {
+ int r;
+ uv_buf_t buf;
+
+ if (!connection_accepted) {
+ /*
+ * Accept the connection and close it. Also let the other
+ * side know.
+ */
+ TUV_ASSERT(status == 0);
+ TUV_ASSERT((uv_stream_t*)&tcp_server == server);
+
+ r = uv_tcp_init(server->loop, &conn.conn);
+ TUV_ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)&conn.conn);
+ TUV_ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&conn.conn, close_cb);
+
+ buf = uv_buf_init("accepted_connection\n", 20);
+ r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1,
+ NULL, conn_notify_write_cb);
+ TUV_ASSERT(r == 0);
+
+ connection_accepted = 1;
+ }
+}
+
+
+static void ipc_on_connection_tcp_conn(uv_stream_t* server, int status) {
+ int r;
+ uv_buf_t buf;
+ uv_tcp_t* conn;
+
+ TUV_ASSERT(status == 0);
+ TUV_ASSERT((uv_stream_t*)&tcp_server == server);
+
+ conn = malloc(sizeof(*conn));
+ TUV_ASSERT(conn);
+
+ r = uv_tcp_init(server->loop, conn);
+ TUV_ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)conn);
+ TUV_ASSERT(r == 0);
+
+ /* Send the accepted connection to the other process */
+ buf = uv_buf_init("hello\n", 6);
+ r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1,
+ (uv_stream_t*)conn, NULL);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) conn,
+ on_read_alloc,
+ on_tcp_child_process_read);
+ TUV_ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)conn, close_cb);
+}
+
+
+int ipc_helper(int listen_after_write) {
+ /*
+ * This is launched from test-ipc.c. stdin is a duplex channel that we
+ * over which a handle will be transmitted.
+ */
+ struct sockaddr_in addr;
+ uv_write_t write_req;
+ int r;
+ uv_buf_t buf;
+
+ TUV_ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_pipe_init(uv_default_loop(), &channel, 1);
+ TUV_ASSERT(r == 0);
+
+ uv_pipe_open(&channel, 0);
+
+ TUV_ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
+ TUV_ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
+ TUV_ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
+
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ TUV_ASSERT(r == 0);
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ TUV_ASSERT(r == 0);
+
+ if (!listen_after_write) {
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection);
+ TUV_ASSERT(r == 0);
+ }
+
+ buf = uv_buf_init("hello\n", 6);
+ r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1,
+ (uv_stream_t*)&tcp_server, NULL);
+ TUV_ASSERT(r == 0);
+
+ if (listen_after_write) {
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection);
+ TUV_ASSERT(r == 0);
+ }
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(connection_accepted == 1);
+ TUV_ASSERT(close_cb_called == 3);
+
+ return 0;
+}
+
+
+int ipc_helper_tcp_connection(void) {
+ /*
+ * This is launched from test-ipc.c. stdin is a duplex channel
+ * over which a handle will be transmitted.
+ */
+
+ int r;
+ struct sockaddr_in addr;
+
+ r = uv_pipe_init(uv_default_loop(), &channel, 1);
+ TUV_ASSERT(r == 0);
+
+ uv_pipe_open(&channel, 0);
+
+ TUV_ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
+ TUV_ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
+ TUV_ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
+
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection_tcp_conn);
+ TUV_ASSERT(r == 0);
+
+ /* Make a connection to the server */
+ r = uv_tcp_init(uv_default_loop(), &conn.conn);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_connect(&conn.conn_req,
+ (uv_tcp_t*) &conn.conn,
+ (const struct sockaddr*) &addr,
+ connect_child_process_cb);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(tcp_conn_read_cb_called == 1);
+ TUV_ASSERT(tcp_conn_write_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 4);
+
+ return 0;
+}
+
+int ipc_helper_bind_twice(void) {
+ /*
+ * This is launched from test-ipc.c. stdin is a duplex channel
+ * over which two handles will be transmitted.
+ */
+ struct sockaddr_in addr;
+ uv_write_t write_req;
+ uv_write_t write_req2;
+ int r;
+ uv_buf_t buf;
+
+ TUV_ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_pipe_init(uv_default_loop(), &channel, 1);
+ TUV_ASSERT(r == 0);
+
+ uv_pipe_open(&channel, 0);
+
+ TUV_ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
+ TUV_ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
+ TUV_ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
+
+ buf = uv_buf_init("hello\n", 6);
+
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ TUV_ASSERT(r == 0);
+ r = uv_tcp_init(uv_default_loop(), &tcp_server2);
+ TUV_ASSERT(r == 0);
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ TUV_ASSERT(r == 0);
+ r = uv_tcp_bind(&tcp_server2, (const struct sockaddr*) &addr, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1,
+ (uv_stream_t*)&tcp_server, NULL);
+ TUV_ASSERT(r == 0);
+ r = uv_write2(&write_req2, (uv_stream_t*)&channel, &buf, 1,
+ (uv_stream_t*)&tcp_server2, NULL);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ return 0;
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include "uv.h"
+#include "runner.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#ifdef _WIN32
+# define BAD_PIPENAME "bad-pipe"
+#else
+# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
+#endif
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ TUV_ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+TEST_IMPL(pipe_bind_error_addrinuse) {
+ uv_pipe_t server1, server2;
+ int r;
+ close_cb_called = 0;
+
+ r = uv_pipe_init(uv_default_loop(), &server1, 0);
+ TUV_ASSERT(r == 0);
+ r = uv_pipe_bind(&server1, TEST_PIPENAME);
+ TUV_ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &server2, 0);
+ TUV_ASSERT(r == 0);
+ r = uv_pipe_bind(&server2, TEST_PIPENAME);
+ TUV_ASSERT(r == UV_EADDRINUSE);
+
+ r = uv_listen((uv_stream_t*)&server1, SOMAXCONN, NULL);
+ TUV_ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&server2, SOMAXCONN, NULL);
+ TUV_ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server1, close_cb);
+ uv_close((uv_handle_t*)&server2, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ TUV_ASSERT(close_cb_called == 2);
+
+ return 0;
+}
+
+
+TEST_IMPL(pipe_bind_error_addrnotavail) {
+ uv_pipe_t server;
+ int r;
+ close_cb_called = 0;
+
+ r = uv_pipe_init(uv_default_loop(), &server, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_pipe_bind(&server, BAD_PIPENAME);
+ TUV_ASSERT(r == UV_EACCES);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ TUV_ASSERT(close_cb_called == 1);
+
+ return 0;
+}
+
+
+TEST_IMPL(pipe_bind_error_inval) {
+ uv_pipe_t server;
+ int r;
+ close_cb_called = 0;
+
+ r = uv_pipe_init(uv_default_loop(), &server, 0);
+ TUV_ASSERT(r == 0);
+ r = uv_pipe_bind(&server, TEST_PIPENAME);
+ TUV_ASSERT(r == 0);
+ r = uv_pipe_bind(&server, TEST_PIPENAME_2);
+ TUV_ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ TUV_ASSERT(close_cb_called == 1);
+
+ return 0;
+}
+
+
+TEST_IMPL(pipe_listen_without_bind) {
+ uv_pipe_t server;
+ int r;
+ close_cb_called = 0;
+
+ r = uv_pipe_init(uv_default_loop(), &server, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
+ TUV_ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ TUV_ASSERT(close_cb_called == 1);
+
+ return 0;
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _WIN32
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#include "uv.h"
+#include "runner.h"
+
+void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t* buf)
+{
+ static char buffer[1024];
+
+ buf->base = buffer;
+ buf->len = sizeof(buffer);
+}
+
+void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t* buf)
+{
+ if (nread < 0) {
+ uv_close((uv_handle_t*)stream, NULL);
+ return;
+ }
+}
+
+/*
+ * This test is a reproduction of joyent/libuv#1419 .
+ */
+TEST_IMPL(pipe_close_stdout_read_stdin) {
+ int r = -1;
+ int pid;
+ int fd[2];
+ int status;
+ char buf;
+ uv_pipe_t stdin_pipe;
+
+ r = pipe(fd);
+ TUV_ASSERT(r == 0);
+
+ if ((pid = fork()) == 0) {
+ /*
+ * Make the read side of the pipe our stdin.
+ * The write side will be closed by the parent process.
+ */
+ close(fd[1]);
+ /* block until write end of pipe is closed */
+ read(fd[0], &buf, 1);
+ close(0);
+ r = dup(fd[0]);
+ TUV_ASSERT(r != -1);
+
+ /* Create a stream that reads from the pipe. */
+ r = uv_pipe_init(uv_default_loop(), (uv_pipe_t *)&stdin_pipe, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_pipe_open((uv_pipe_t *)&stdin_pipe, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t *)&stdin_pipe, alloc_buffer, read_stdin);
+ TUV_ASSERT(r == 0);
+
+ /*
+ * Because the other end of the pipe was closed, there should
+ * be no event left to process after one run of the event loop.
+ * Otherwise, it means that events were not processed correctly.
+ */
+ TUV_ASSERT(uv_run(uv_default_loop(), UV_RUN_NOWAIT) == 0);
+ } else {
+ /*
+ * Close both ends of the pipe so that the child
+ * get a POLLHUP event when it tries to read from
+ * the other end.
+ */
+ close(fd[1]);
+ close(fd[0]);
+
+ waitpid(pid, &status, 0);
+ TUV_ASSERT(WIFEXITED(status) && WEXITSTATUS(status) == 0);
+ }
+
+ return 0;
+}
+
+#endif /* ifndef _WIN32 */
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "runner.h"
+
+
+#ifdef _WIN32
+# define BAD_PIPENAME "bad-pipe"
+#else
+# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
+#endif
+
+
+static int close_cb_called = 0;
+static int connect_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ TUV_ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* connect_req, int status) {
+ TUV_ASSERT(status == UV_ENOENT);
+ uv_close((uv_handle_t*)connect_req->handle, close_cb);
+ connect_cb_called++;
+}
+
+
+static void connect_cb_file(uv_connect_t* connect_req, int status) {
+ TUV_ASSERT(status == UV_ENOTSOCK || status == UV_ECONNREFUSED);
+ uv_close((uv_handle_t*)connect_req->handle, close_cb);
+ connect_cb_called++;
+}
+
+
+TEST_IMPL(pipe_connect_bad_name) {
+ uv_pipe_t client;
+ uv_connect_t req;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &client, 0);
+ TUV_ASSERT(r == 0);
+ uv_pipe_connect(&req, &client, BAD_PIPENAME, connect_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ TUV_ASSERT(close_cb_called == 1);
+ TUV_ASSERT(connect_cb_called == 1);
+
+ return 0;
+}
+
+
+TEST_IMPL(pipe_connect_to_file) {
+ const char* path = "test/fixtures/empty_file";
+ uv_pipe_t client;
+ uv_connect_t req;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &client, 0);
+ TUV_ASSERT(r == 0);
+ uv_pipe_connect(&req, &client, path, connect_cb_file);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ TUV_ASSERT(close_cb_called == 1);
+ TUV_ASSERT(connect_cb_called == 1);
+
+ return 0;
+}
--- /dev/null
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "runner.h"
+
+
+static int connection_cb_called = 0;
+static int connect_cb_called = 0;
+
+#define NUM_CLIENTS 4
+
+typedef struct {
+ uv_pipe_t pipe_handle;
+ uv_connect_t conn_req;
+} client_t;
+
+static uv_pipe_t server_handle;
+static client_t clients[NUM_CLIENTS];
+static uv_pipe_t connections[NUM_CLIENTS];
+
+
+static void connection_cb(uv_stream_t* server, int status) {
+ int r;
+ uv_pipe_t* conn;
+ TUV_ASSERT(status == 0);
+
+ conn = &connections[connection_cb_called];
+ r = uv_pipe_init(server->loop, conn, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)conn);
+ TUV_ASSERT(r == 0);
+
+ if (++connection_cb_called == NUM_CLIENTS &&
+ connect_cb_called == NUM_CLIENTS) {
+ uv_stop(server->loop);
+ }
+}
+
+
+static void connect_cb(uv_connect_t* connect_req, int status) {
+ TUV_ASSERT(status == 0);
+ if (++connect_cb_called == NUM_CLIENTS &&
+ connection_cb_called == NUM_CLIENTS) {
+ uv_stop(connect_req->handle->loop);
+ }
+}
+
+
+TEST_IMPL(pipe_connect_multiple) {
+ int i;
+ int r;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+
+ r = uv_pipe_init(loop, &server_handle, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_pipe_bind(&server_handle, TEST_PIPENAME);
+ TUV_ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server_handle, 128, connection_cb);
+ TUV_ASSERT(r == 0);
+
+ for (i = 0; i < NUM_CLIENTS; i++) {
+ r = uv_pipe_init(loop, &clients[i].pipe_handle, 0);
+ TUV_ASSERT(r == 0);
+ uv_pipe_connect(&clients[i].conn_req,
+ &clients[i].pipe_handle,
+ TEST_PIPENAME,
+ connect_cb);
+ }
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ TUV_ASSERT(connection_cb_called == NUM_CLIENTS);
+ TUV_ASSERT(connect_cb_called == NUM_CLIENTS);
+
+ return 0;
+}
--- /dev/null
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "runner.h"
+
+
+#ifdef _WIN32
+# define BAD_PIPENAME "bad-pipe"
+#else
+# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
+#endif
+
+
+static int close_cb_called = 0;
+static int connect_cb_called = 0;
+
+static uv_pipe_t pipe_handle;
+static uv_prepare_t prepare_handle;
+static uv_connect_t conn_req;
+
+
+static void close_cb(uv_handle_t* handle) {
+ TUV_ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* connect_req, int status) {
+ TUV_ASSERT(status == UV_ENOENT);
+ connect_cb_called++;
+ uv_close((uv_handle_t*)&prepare_handle, close_cb);
+ uv_close((uv_handle_t*)&pipe_handle, close_cb);
+}
+
+
+static void prepare_cb(uv_prepare_t* handle) {
+ TUV_ASSERT(handle == &prepare_handle);
+ uv_pipe_connect(&conn_req, &pipe_handle, BAD_PIPENAME, connect_cb);
+}
+
+/*
+TEST_IMPL(pipe_connect_on_prepare) {
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &pipe_handle, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_prepare_init(uv_default_loop(), &prepare_handle);
+ TUV_ASSERT(r == 0);
+ r = uv_prepare_start(&prepare_handle, prepare_cb);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(close_cb_called == 2);
+ TUV_ASSERT(connect_cb_called == 1);
+
+ return 0;
+}
+*/
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include "uv.h"
+#include "runner.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__linux__)
+ #include <sys/socket.h>
+ #include <sys/un.h>
+#endif
+
+#ifndef _WIN32
+# include <unistd.h> /* close */
+#else
+# include <fcntl.h>
+#endif
+
+static uv_pipe_t pipe_client;
+static uv_pipe_t pipe_server;
+static uv_connect_t connect_req;
+
+static int pipe_close_cb_called = 0;
+static int pipe_client_connect_cb_called = 0;
+
+
+static void pipe_close_cb(uv_handle_t* handle) {
+ TUV_ASSERT(handle == (uv_handle_t*) &pipe_client ||
+ handle == (uv_handle_t*) &pipe_server);
+ pipe_close_cb_called++;
+}
+
+
+static void pipe_client_connect_cb(uv_connect_t* req, int status) {
+ char buf[1024];
+ size_t len;
+ int r;
+
+ TUV_ASSERT(req == &connect_req);
+ TUV_ASSERT(status == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_client, buf, &len);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(buf[len - 1] != 0);
+ TUV_ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_client, buf, &len);
+ TUV_ASSERT(r == 0 && len == 0);
+
+ pipe_client_connect_cb_called++;
+
+
+ uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
+ uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
+}
+
+
+static void pipe_server_connection_cb(uv_stream_t* handle, int status) {
+ /* This function *may* be called, depending on whether accept or the
+ * connection callback is called first.
+ */
+ TUV_ASSERT(status == 0);
+}
+
+
+TEST_IMPL(pipe_getsockname) {
+ uv_loop_t* loop;
+ char buf[1024];
+ size_t len;
+ int r;
+ pipe_close_cb_called = 0;
+
+ loop = uv_default_loop();
+ TUV_ASSERT(loop != NULL);
+
+ r = uv_pipe_init(loop, &pipe_server, 0);
+ TUV_ASSERT(r == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_server, buf, &len);
+ TUV_ASSERT(r == UV_EBADF);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_server, buf, &len);
+ TUV_ASSERT(r == UV_EBADF);
+
+ r = uv_pipe_bind(&pipe_server, TEST_PIPENAME);
+ TUV_ASSERT(r == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_server, buf, &len);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(buf[len - 1] != 0);
+ TUV_ASSERT(buf[len] == '\0');
+ TUV_ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_server, buf, &len);
+ TUV_ASSERT(r == UV_ENOTCONN);
+
+ r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
+ TUV_ASSERT(r == 0);
+
+ r = uv_pipe_init(loop, &pipe_client, 0);
+ TUV_ASSERT(r == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_client, buf, &len);
+ TUV_ASSERT(r == UV_EBADF);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_client, buf, &len);
+ TUV_ASSERT(r == UV_EBADF);
+
+ uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_client, buf, &len);
+ TUV_ASSERT(r == 0 && len == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_client, buf, &len);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(buf[len - 1] != 0);
+ TUV_ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+ TUV_ASSERT(pipe_client_connect_cb_called == 1);
+ TUV_ASSERT(pipe_close_cb_called == 2);
+
+ return 0;
+}
+
+
+TEST_IMPL(pipe_getsockname_abstract) {
+#if defined(__linux__)
+ char buf[1024];
+ size_t len;
+ int r;
+ int sock;
+ struct sockaddr_un sun;
+ socklen_t sun_len;
+ char abstract_pipe[] = "\0test-pipe";
+ pipe_close_cb_called = 0;
+
+ sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+ TUV_ASSERT(sock != -1);
+
+ sun_len = sizeof sun;
+ memset(&sun, 0, sun_len);
+ sun.sun_family = AF_UNIX;
+ memcpy(sun.sun_path, abstract_pipe, sizeof abstract_pipe);
+
+ r = bind(sock, (struct sockaddr*)&sun, sun_len);
+ TUV_ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &pipe_server, 0);
+ TUV_ASSERT(r == 0);
+ r = uv_pipe_open(&pipe_server, sock);
+ TUV_ASSERT(r == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_server, buf, &len);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(memcmp(buf, abstract_pipe, sizeof abstract_pipe) == 0);
+
+ uv_close((uv_handle_t*)&pipe_server, pipe_close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ close(sock);
+
+ TUV_ASSERT(pipe_close_cb_called == 1);
+ return 0;
+#else
+ return 0;
+#endif
+}
+
+TEST_IMPL(pipe_getsockname_blocking) {
+#ifdef _WIN32
+ HANDLE readh, writeh;
+ int readfd;
+ char buf1[1024], buf2[1024];
+ size_t len1, len2;
+ int r;
+
+ r = CreatePipe(&readh, &writeh, NULL, 65536);
+ TUV_ASSERT(r != 0);
+
+ r = uv_pipe_init(uv_default_loop(), &pipe_client, 0);
+ TUV_ASSERT(r == 0);
+ readfd = _open_osfhandle((intptr_t)readh, _O_RDONLY);
+ TUV_ASSERT(r != -1);
+ r = uv_pipe_open(&pipe_client, readfd);
+ TUV_ASSERT(r == 0);
+ r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
+ TUV_ASSERT(r == 0);
+ Sleep(100);
+ r = uv_read_stop((uv_stream_t*)&pipe_client);
+ TUV_ASSERT(r == 0);
+
+ len1 = sizeof buf1;
+ r = uv_pipe_getsockname(&pipe_client, buf1, &len1);
+ TUV_ASSERT(r == 0);
+ TUV_ASSERT(len1 == 0); /* It's an annonymous pipe. */
+
+ r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
+ TUV_ASSERT(r == 0);
+ Sleep(100);
+
+ len2 = sizeof buf2;
+ r = uv_pipe_getsockname(&pipe_client, buf2, &len2);
+ TUV_ASSERT(r == 0);
+ TUV_ASSERT(len2 == 0); /* It's an annonymous pipe. */
+
+ r = uv_read_stop((uv_stream_t*)&pipe_client);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(len1 == len2);
+ TUV_ASSERT(memcmp(buf1, buf2, len1) == 0);
+
+ pipe_close_cb_called = 0;
+ uv_close((uv_handle_t*)&pipe_client, pipe_close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ TUV_ASSERT(pipe_close_cb_called == 1);
+
+ CloseHandle(writeh);
+#endif
+
+ return 0;
+}
--- /dev/null
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#include "uv.h"
+#include "runner.h"
+
+
+static void connection_cb(uv_stream_t* server, int status) {
+ TUV_ASSERT(0 && "this will never be called");
+}
+
+
+TEST_IMPL(pipe_pending_instances) {
+ int r;
+ uv_pipe_t pipe_handle;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+
+ r = uv_pipe_init(loop, &pipe_handle, 0);
+ TUV_ASSERT(r == 0);
+
+ uv_pipe_pending_instances(&pipe_handle, 8);
+
+ r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME);
+ TUV_ASSERT(r == 0);
+
+ uv_pipe_pending_instances(&pipe_handle, 16);
+
+ r = uv_listen((uv_stream_t*)&pipe_handle, 128, connection_cb);
+ TUV_ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&pipe_handle, NULL);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ return 0;
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include "uv.h"
+#include "runner.h"
+
+
+#ifndef _WIN32
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+
+/* NOTE: size should be divisible by 2 */
+static uv_pipe_t incoming[4];
+static unsigned int incoming_count;
+static unsigned int close_called;
+
+
+static void set_nonblocking(uv_os_sock_t sock) {
+ int r;
+#ifdef _WIN32
+ unsigned long on = 1;
+ r = ioctlsocket(sock, FIONBIO, &on);
+ TUV_ASSERT(r == 0);
+#else
+ int flags = fcntl(sock, F_GETFL, 0);
+ TUV_ASSERT(flags >= 0);
+ r = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+ TUV_ASSERT(r >= 0);
+#endif
+}
+
+
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_called++;
+}
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ static char base[1];
+
+ buf->base = base;
+ buf->len = sizeof(base);
+}
+
+
+static void read_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_pipe_t* p;
+ uv_pipe_t* inc;
+ uv_handle_type pending;
+ unsigned int i;
+
+ p = (uv_pipe_t*) handle;
+ TUV_ASSERT(nread >= 0);
+
+ while (uv_pipe_pending_count(p) != 0) {
+ pending = uv_pipe_pending_type(p);
+ TUV_ASSERT(pending == UV_NAMED_PIPE);
+
+ TUV_ASSERT(incoming_count < ARRAY_SIZE(incoming));
+ inc = &incoming[incoming_count++];
+ TUV_ASSERT(0 == uv_pipe_init(p->loop, inc, 0));
+ TUV_ASSERT(0 == uv_accept(handle, (uv_stream_t*) inc));
+ }
+
+ if (incoming_count != ARRAY_SIZE(incoming))
+ return;
+
+ TUV_ASSERT(0 == uv_read_stop((uv_stream_t*) p));
+ uv_close((uv_handle_t*) p, close_cb);
+ for (i = 0; i < ARRAY_SIZE(incoming); i++)
+ uv_close((uv_handle_t*) &incoming[i], close_cb);
+}
+
+
+TEST_IMPL(pipe_sendmsg) {
+ uv_pipe_t p;
+ int r;
+ int fds[2];
+ int send_fds[ARRAY_SIZE(incoming)];
+ struct msghdr msg;
+ char scratch[64];
+ struct cmsghdr *cmsg;
+ unsigned int i;
+ uv_buf_t buf;
+
+ TUV_ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
+ for (i = 0; i < ARRAY_SIZE(send_fds); i += 2)
+ TUV_ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, send_fds + i));
+ TUV_ASSERT(i == ARRAY_SIZE(send_fds));
+ TUV_ASSERT(0 == uv_pipe_init(uv_default_loop(), &p, 1));
+ TUV_ASSERT(0 == uv_pipe_open(&p, fds[1]));
+
+ buf = uv_buf_init("X", 1);
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = (struct iovec*) &buf;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+
+ msg.msg_control = (void*) scratch;
+ msg.msg_controllen = CMSG_LEN(sizeof(send_fds));
+ TUV_ASSERT(sizeof(scratch) >= msg.msg_controllen);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = msg.msg_controllen;
+
+ /* silence aliasing warning */
+ {
+ void* pv = CMSG_DATA(cmsg);
+ int* pi = pv;
+ for (i = 0; i < ARRAY_SIZE(send_fds); i++)
+ pi[i] = send_fds[i];
+ }
+
+ set_nonblocking(fds[1]);
+ TUV_ASSERT(0 == uv_read_start((uv_stream_t*) &p, alloc_cb, read_cb));
+
+ do
+ r = sendmsg(fds[0], &msg, 0);
+ while (r == -1 && errno == EINTR);
+ TUV_ASSERT(r == 1);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(ARRAY_SIZE(incoming) == incoming_count);
+ TUV_ASSERT(ARRAY_SIZE(incoming) + 1 == close_called);
+ close(fds[0]);
+
+ return 0;
+}
+
+#else /* !_WIN32 */
+
+TEST_IMPL(pipe_sendmsg) {
+ return 0;
+}
+
+#endif /* _WIN32 */
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <string.h>
+#include <errno.h>
+
+#include "uv.h"
+#include "runner.h"
+
+
+static uv_pipe_t pipe_client;
+static uv_pipe_t pipe_server;
+static uv_connect_t connect_req;
+
+static int pipe_close_cb_called = 0;
+static int pipe_client_connect_cb_called = 0;
+
+
+static void pipe_close_cb(uv_handle_t* handle) {
+ TUV_ASSERT(handle == (uv_handle_t*) &pipe_client ||
+ handle == (uv_handle_t*) &pipe_server);
+ pipe_close_cb_called++;
+}
+
+
+static void pipe_client_connect_cb(uv_connect_t* req, int status) {
+ TUV_ASSERT(req == &connect_req);
+ TUV_ASSERT(status == 0);
+
+ pipe_client_connect_cb_called++;
+
+ uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
+ uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
+}
+
+
+static void pipe_server_connection_cb(uv_stream_t* handle, int status) {
+ /* This function *may* be called, depending on whether accept or the
+ * connection callback is called first.
+ */
+ TUV_ASSERT(status == 0);
+}
+
+
+TEST_IMPL(pipe_server_close) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+ TUV_ASSERT(loop != NULL);
+
+ r = uv_pipe_init(loop, &pipe_server, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_pipe_bind(&pipe_server, TEST_PIPENAME);
+ TUV_ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
+ TUV_ASSERT(r == 0);
+
+ r = uv_pipe_init(loop, &pipe_client, 0);
+ TUV_ASSERT(r == 0);
+
+ uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+ TUV_ASSERT(pipe_client_connect_cb_called == 1);
+ TUV_ASSERT(pipe_close_cb_called == 2);
+
+ return 0;
+}
--- /dev/null
+/* Copyright (c) 2015, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "uv.h"
+#include "runner.h"
+
+#ifdef _WIN32
+
+TEST_IMPL(pipe_set_non_blocking) {
+ RETURN_SKIP("Test not implemented on Windows.");
+}
+
+#else /* !_WIN32 */
+
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+struct thread_ctx {
+ uv_barrier_t barrier;
+ int fd;
+};
+
+static void thread_main(void* arg) {
+ struct thread_ctx* ctx;
+ char buf[4096];
+ ssize_t n;
+
+ ctx = arg;
+ uv_barrier_wait(&ctx->barrier);
+
+ do
+ n = read(ctx->fd, buf, sizeof(buf));
+ while (n > 0 || (n == -1 && errno == EINTR));
+
+ TUV_ASSERT(n == 0);
+}
+
+TEST_IMPL(pipe_set_non_blocking) {
+ struct thread_ctx ctx;
+ uv_pipe_t pipe_handle;
+ uv_thread_t thread;
+ size_t nwritten;
+ char data[4096];
+ uv_buf_t buf;
+ int fd[2];
+ int n;
+
+ TUV_ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
+ TUV_ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fd));
+ TUV_ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
+ TUV_ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &pipe_handle, 1));
+
+ ctx.fd = fd[1];
+ TUV_ASSERT(0 == uv_barrier_init(&ctx.barrier, 2));
+ TUV_ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx));
+ uv_barrier_wait(&ctx.barrier);
+
+ buf.len = sizeof(data);
+ buf.base = data;
+ memset(data, '.', sizeof(data));
+
+ nwritten = 0;
+ while (nwritten < 10 << 20) {
+ /* The stream is in blocking mode so uv_try_write() should always succeed
+ * with the exact number of bytes that we wanted written.
+ */
+ n = uv_try_write((uv_stream_t*) &pipe_handle, &buf, 1);
+ TUV_ASSERT(n == sizeof(data));
+ nwritten += n;
+ }
+
+ uv_close((uv_handle_t*) &pipe_handle, NULL);
+ TUV_ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ TUV_ASSERT(0 == uv_thread_join(&thread));
+ TUV_ASSERT(0 == close(fd[1])); /* fd[0] is closed by uv_close(). */
+ uv_barrier_destroy(&ctx.barrier);
+
+ return 0;
+}
+
+#endif /* !_WIN32 */
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+
+/* This test does not pretend to be cross-platform. */
+#ifndef _WIN32
+
+#include "uv.h"
+#include "runner.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define NSIGNALS 10
+
+#define container_of(ptr, type, member) \
+ ((type *) ((char *) (ptr) - offsetof(type, member)))
+
+struct timer_ctx {
+ unsigned int ncalls;
+ uv_timer_t handle;
+ int signum;
+};
+
+struct signal_ctx {
+ enum { CLOSE, STOP } stop_or_close;
+ unsigned int ncalls;
+ uv_signal_t handle;
+ int signum;
+};
+
+
+static void signal_cb(uv_signal_t* handle, int signum) {
+ struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle);
+ TUV_ASSERT(signum == ctx->signum);
+
+ if (++ctx->ncalls == NSIGNALS) {
+ if (ctx->stop_or_close == STOP)
+ uv_signal_stop(handle);
+ else if (ctx->stop_or_close == CLOSE)
+ uv_close((uv_handle_t*)handle, NULL);
+ else
+ TUV_ASSERT(0);
+ }
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ struct timer_ctx* ctx = container_of(handle, struct timer_ctx, handle);
+
+ raise(ctx->signum);
+
+ if (++ctx->ncalls == NSIGNALS)
+ uv_close((uv_handle_t*)handle, NULL);
+}
+
+
+static void start_watcher(uv_loop_t* loop, int signum, struct signal_ctx* ctx) {
+ ctx->ncalls = 0;
+ ctx->signum = signum;
+ ctx->stop_or_close = CLOSE;
+ TUV_ASSERT(0 == uv_signal_init(loop, &ctx->handle));
+ TUV_ASSERT(0 == uv_signal_start(&ctx->handle, signal_cb, signum));
+}
+
+
+static void start_timer(uv_loop_t* loop, int signum, struct timer_ctx* ctx) {
+ ctx->ncalls = 0;
+ ctx->signum = signum;
+ TUV_ASSERT(0 == uv_timer_init(loop, &ctx->handle));
+ TUV_ASSERT(0 == uv_timer_start(&ctx->handle, timer_cb, 5, 5));
+}
+
+
+TEST_IMPL(we_get_signal) {
+ struct signal_ctx sc;
+ struct timer_ctx tc;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+ start_timer(loop, SIGCHLD, &tc);
+ start_watcher(loop, SIGCHLD, &sc);
+ sc.stop_or_close = STOP; /* stop, don't close the signal handle */
+ TUV_ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ TUV_ASSERT(tc.ncalls == NSIGNALS);
+ TUV_ASSERT(sc.ncalls == NSIGNALS);
+
+ start_timer(loop, SIGCHLD, &tc);
+ TUV_ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ TUV_ASSERT(tc.ncalls == NSIGNALS);
+ TUV_ASSERT(sc.ncalls == NSIGNALS);
+
+ sc.ncalls = 0;
+ sc.stop_or_close = CLOSE; /* now close it when it's done */
+ uv_signal_start(&sc.handle, signal_cb, SIGCHLD);
+
+ start_timer(loop, SIGCHLD, &tc);
+ TUV_ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ TUV_ASSERT(tc.ncalls == NSIGNALS);
+ TUV_ASSERT(sc.ncalls == NSIGNALS);
+
+ return 0;
+}
+
+
+TEST_IMPL(we_get_signals) {
+ struct signal_ctx sc[4];
+ struct timer_ctx tc[2];
+ uv_loop_t* loop;
+ unsigned int i;
+
+ loop = uv_default_loop();
+ start_watcher(loop, SIGUSR1, sc + 0);
+ start_watcher(loop, SIGUSR1, sc + 1);
+ start_watcher(loop, SIGUSR2, sc + 2);
+ start_watcher(loop, SIGUSR2, sc + 3);
+ start_timer(loop, SIGUSR1, tc + 0);
+ start_timer(loop, SIGUSR2, tc + 1);
+ TUV_ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ for (i = 0; i < ARRAY_SIZE(sc); i++)
+ TUV_ASSERT(sc[i].ncalls == NSIGNALS);
+
+ for (i = 0; i < ARRAY_SIZE(tc); i++)
+ TUV_ASSERT(tc[i].ncalls == NSIGNALS);
+
+ return 0;
+}
+
+#endif /* _WIN32 */
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * 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.
+ */
+
+#include "uv.h"
+#include "runner.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+# if defined(__MINGW32__)
+# include <basetyps.h>
+# endif
+# include <shellapi.h>
+# include <wchar.h>
+#else
+# include <unistd.h>
+# include <sys/wait.h>
+#endif
+
+
+static int close_cb_called;
+static int exit_cb_called;
+static uv_process_t process;
+static uv_timer_t timer;
+static uv_process_options_t options;
+static char exepath[1024];
+static size_t exepath_size = 1024;
+static char* args[5];
+static int no_term_signal;
+static int timer_counter;
+
+#define OUTPUT_SIZE 1024
+static char output[OUTPUT_SIZE];
+static int output_used;
+
+
+static void close_cb(uv_handle_t* handle) {
+ printf("close_cb\n");
+ close_cb_called++;
+}
+
+static void exit_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ printf("exit_cb\n");
+ exit_cb_called++;
+ TUV_ASSERT(exit_status == 1);
+ TUV_ASSERT(term_signal == 0);
+ uv_close((uv_handle_t*)process, close_cb);
+}
+
+
+static void fail_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ TUV_ASSERT(0 && "fail_cb called");
+}
+
+
+static void kill_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ int err;
+
+ printf("exit_cb\n");
+ exit_cb_called++;
+#ifdef _WIN32
+ TUV_ASSERT(exit_status == 1);
+#else
+ TUV_ASSERT(exit_status == 0);
+#endif
+ TUV_ASSERT(no_term_signal || term_signal == 15);
+ uv_close((uv_handle_t*)process, close_cb);
+
+ /*
+ * Sending signum == 0 should check if the
+ * child process is still alive, not kill it.
+ * This process should be dead.
+ */
+ err = uv_kill(process->pid, 0);
+ TUV_ASSERT(err == UV_ESRCH);
+}
+
+static void detach_failure_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ printf("detach_cb\n");
+ exit_cb_called++;
+}
+
+static void on_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = output + output_used;
+ buf->len = OUTPUT_SIZE - output_used;
+}
+
+
+static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ if (nread > 0) {
+ output_used += nread;
+ } else if (nread < 0) {
+ TUV_ASSERT(nread == UV_EOF);
+ uv_close((uv_handle_t*)tcp, close_cb);
+ }
+}
+
+
+static void on_read_once(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ uv_read_stop(tcp);
+ on_read(tcp, nread, buf);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ TUV_ASSERT(status == 0);
+ uv_close((uv_handle_t*)req->handle, close_cb);
+}
+
+
+static void init_process_options(char* test, uv_exit_cb exit_cb) {
+ /* Note spawn_helper1 defined in test/run-tests.c */
+ int r = uv_exepath(exepath, &exepath_size);
+ TUV_ASSERT(r == 0);
+ exepath[exepath_size] = '\0';
+ args[0] = exepath;
+ args[1] = test;
+ args[2] = NULL;
+ args[3] = NULL;
+ args[4] = NULL;
+ options.file = exepath;
+ options.args = args;
+ options.exit_cb = exit_cb;
+ options.flags = 0;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_process_kill(&process, /* SIGTERM */ 15);
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+
+static void timer_counter_cb(uv_timer_t* handle) {
+ ++timer_counter;
+}
+
+
+TEST_IMPL(spawn_fails) {
+ int r;
+
+ init_process_options("", fail_cb);
+ options.file = options.args[0] = "program-that-had-better-not-exist";
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == UV_ENOENT || r == UV_EACCES);
+ TUV_ASSERT(0 == uv_is_active((uv_handle_t*) &process));
+ uv_close((uv_handle_t*) &process, NULL);
+ TUV_ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ return 0;
+}
+
+
+#ifndef _WIN32
+TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) {
+ int r;
+ int status;
+ int err;
+
+ init_process_options("", fail_cb);
+ options.file = options.args[0] = "program-that-had-better-not-exist";
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == UV_ENOENT || r == UV_EACCES);
+ TUV_ASSERT(0 == uv_is_active((uv_handle_t*) &process));
+ TUV_ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ /* verify the child is successfully cleaned up within libuv */
+ do
+ err = waitpid(process.pid, &status, 0);
+ while (err == -1 && errno == EINTR);
+
+ TUV_ASSERT(err == -1);
+ TUV_ASSERT(errno == ECHILD);
+
+ uv_close((uv_handle_t*) &process, NULL);
+ TUV_ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ return 0;
+}
+#endif
+
+
+TEST_IMPL(spawn_exit_code) {
+ int r;
+
+ init_process_options("spawn_helper1", exit_cb);
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 1);
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdout) {
+ int r;
+ uv_pipe_t out;
+ uv_stdio_container_t stdio[2];
+
+ init_process_options("spawn_helper2", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
+ printf("output is: %s", output);
+ TUV_ASSERT(strcmp("hello world\n", output) == 0);
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdout_to_file) {
+ int r;
+ uv_file file;
+ uv_fs_t fs_req;
+ uv_stdio_container_t stdio[2];
+ uv_buf_t buf;
+
+ /* Setup. */
+ unlink("stdout_file");
+
+ init_process_options("spawn_helper2", exit_cb);
+
+ r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR, NULL);
+ TUV_ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+
+ file = r;
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_INHERIT_FD;
+ options.stdio[1].data.fd = file;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 1);
+
+ buf = uv_buf_init(output, sizeof(output));
+ r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
+ TUV_ASSERT(r == 12);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, file, NULL);
+ TUV_ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ TUV_ASSERT(strcmp("hello world\n", output) == 0);
+
+ /* Cleanup. */
+ unlink("stdout_file");
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdout_and_stderr_to_file) {
+ int r;
+ uv_file file;
+ uv_fs_t fs_req;
+ uv_stdio_container_t stdio[3];
+ uv_buf_t buf;
+
+ /* Setup. */
+ unlink("stdout_file");
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR, NULL);
+ TUV_ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+
+ file = r;
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_INHERIT_FD;
+ options.stdio[1].data.fd = file;
+ options.stdio[2].flags = UV_INHERIT_FD;
+ options.stdio[2].data.fd = file;
+ options.stdio_count = 3;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 1);
+
+ buf = uv_buf_init(output, sizeof(output));
+ r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
+ TUV_ASSERT(r == 27);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, file, NULL);
+ TUV_ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ TUV_ASSERT(strcmp("hello world\nhello errworld\n", output) == 0);
+
+ /* Cleanup. */
+ unlink("stdout_file");
+
+ return 0;
+}
+
+
+#ifndef _WIN32
+TEST_IMPL(spawn_stdout_and_stderr_to_file2) {
+ int r;
+ uv_file file;
+ uv_fs_t fs_req;
+ uv_stdio_container_t stdio[3];
+ uv_buf_t buf;
+
+ /* Setup. */
+ unlink("stdout_file");
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ /* Replace stderr with our file */
+ r = uv_fs_open(NULL,
+ &fs_req,
+ "stdout_file",
+ O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR,
+ NULL);
+ TUV_ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+ file = dup2(r, STDERR_FILENO);
+ TUV_ASSERT(file != -1);
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_INHERIT_FD;
+ options.stdio[1].data.fd = file;
+ options.stdio[2].flags = UV_INHERIT_FD;
+ options.stdio[2].data.fd = file;
+ options.stdio_count = 3;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 1);
+
+ buf = uv_buf_init(output, sizeof(output));
+ r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
+ TUV_ASSERT(r == 27);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, file, NULL);
+ TUV_ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ TUV_ASSERT(strcmp("hello world\nhello errworld\n", output) == 0);
+
+ /* Cleanup. */
+ unlink("stdout_file");
+
+ return 0;
+}
+#endif
+
+
+#ifndef _WIN32
+TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) {
+ int r;
+ uv_file stdout_file;
+ uv_file stderr_file;
+ uv_fs_t fs_req;
+ uv_stdio_container_t stdio[3];
+ uv_buf_t buf;
+
+ /* Setup. */
+ unlink("stdout_file");
+ unlink("stderr_file");
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ /* open 'stdout_file' and replace STDOUT_FILENO with it */
+ r = uv_fs_open(NULL,
+ &fs_req,
+ "stdout_file",
+ O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR,
+ NULL);
+ TUV_ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+ stdout_file = dup2(r, STDOUT_FILENO);
+ TUV_ASSERT(stdout_file != -1);
+
+ /* open 'stderr_file' and replace STDERR_FILENO with it */
+ r = uv_fs_open(NULL, &fs_req, "stderr_file", O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR, NULL);
+ TUV_ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+ stderr_file = dup2(r, STDERR_FILENO);
+ TUV_ASSERT(stderr_file != -1);
+
+ /* now we're going to swap them: the child process' stdout will be our
+ * stderr_file and vice versa */
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_INHERIT_FD;
+ options.stdio[1].data.fd = stderr_file;
+ options.stdio[2].flags = UV_INHERIT_FD;
+ options.stdio[2].data.fd = stdout_file;
+ options.stdio_count = 3;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 1);
+
+ buf = uv_buf_init(output, sizeof(output));
+
+ /* check the content of stdout_file */
+ r = uv_fs_read(NULL, &fs_req, stdout_file, &buf, 1, 0, NULL);
+ TUV_ASSERT(r >= 15);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, stdout_file, NULL);
+ TUV_ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ TUV_ASSERT(strncmp("hello errworld\n", output, 15) == 0);
+
+ /* check the content of stderr_file */
+ r = uv_fs_read(NULL, &fs_req, stderr_file, &buf, 1, 0, NULL);
+ TUV_ASSERT(r >= 12);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, stderr_file, NULL);
+ TUV_ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ TUV_ASSERT(strncmp("hello world\n", output, 12) == 0);
+
+ /* Cleanup. */
+ unlink("stdout_file");
+ unlink("stderr_file");
+
+ return 0;
+}
+#endif
+
+
+TEST_IMPL(spawn_stdin) {
+ int r;
+ uv_pipe_t out;
+ uv_pipe_t in;
+ uv_write_t write_req;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[2];
+ char buffer[] = "hello-from-spawn_stdin";
+
+ init_process_options("spawn_helper3", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ uv_pipe_init(uv_default_loop(), &in, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)∈
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ buf.base = buffer;
+ buf.len = sizeof(buffer);
+ r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 3); /* Once for process twice for the pipe. */
+ TUV_ASSERT(strcmp(buffer, output) == 0);
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdio_greater_than_3) {
+ int r;
+ uv_pipe_t pipe;
+ uv_stdio_container_t stdio[4];
+
+ init_process_options("spawn_helper5", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &pipe, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_IGNORE;
+ options.stdio[2].flags = UV_IGNORE;
+ options.stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[3].data.stream = (uv_stream_t*)&pipe;
+ options.stdio_count = 4;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &pipe, on_alloc, on_read);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
+ printf("output from stdio[3] is: %s", output);
+ TUV_ASSERT(strcmp("fourth stdio!\n", output) == 0);
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_ignored_stdio) {
+ int r;
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ options.stdio = NULL;
+ options.stdio_count = 0;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 1);
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_and_kill) {
+ int r;
+
+ init_process_options("spawn_helper4", kill_cb);
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ TUV_ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 500, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 2); /* Once for process and once for timer. */
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_preserve_env) {
+ int r;
+ uv_pipe_t out;
+ uv_stdio_container_t stdio[2];
+
+ init_process_options("spawn_helper7", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*) &out;
+ options.stdio_count = 2;
+
+ r = putenv("ENV_TEST=testval");
+ TUV_ASSERT(r == 0);
+
+ /* Explicitly set options.env to NULL to test for env clobbering. */
+ options.env = NULL;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 2);
+
+ printf("output is: %s", output);
+ TUV_ASSERT(strcmp("testval", output) == 0);
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_detached) {
+ int r;
+
+ init_process_options("spawn_helper4", detach_failure_cb);
+
+ options.flags |= UV_PROCESS_DETACHED;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ uv_unref((uv_handle_t*)&process);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 0);
+
+ r = uv_kill(process.pid, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_kill(process.pid, 15);
+ TUV_ASSERT(r == 0);
+
+ return 0;
+}
+
+TEST_IMPL(spawn_and_kill_with_std) {
+ int r;
+ uv_pipe_t in, out, err;
+ uv_write_t write;
+ char message[] = "Nancy's joining me because the message this evening is "
+ "not my message but ours.";
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[3];
+
+ init_process_options("spawn_helper4", kill_cb);
+
+ r = uv_pipe_init(uv_default_loop(), &in, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &out, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &err, 0);
+ TUV_ASSERT(r == 0);
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)∈
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[2].data.stream = (uv_stream_t*)&err;
+ options.stdio_count = 3;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ buf = uv_buf_init(message, sizeof message);
+ r = uv_write(&write, (uv_stream_t*) &in, &buf, 1, write_cb);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &err, on_alloc, on_read);
+ TUV_ASSERT(r == 0);
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ TUV_ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 500, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 5); /* process x 1, timer x 1, stdio x 3. */
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_and_ping) {
+ uv_write_t write_req;
+ uv_pipe_t in, out;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[2];
+ int r;
+
+ init_process_options("spawn_helper3", exit_cb);
+ buf = uv_buf_init("TEST", 4);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ uv_pipe_init(uv_default_loop(), &in, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)∈
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ /* Sending signum == 0 should check if the
+ * child process is still alive, not kill it.
+ */
+ r = uv_process_kill(&process, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(strcmp(output, "TEST") == 0);
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_same_stdout_stderr) {
+ uv_write_t write_req;
+ uv_pipe_t in, out;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[3];
+ int r;
+
+ init_process_options("spawn_helper3", exit_cb);
+ buf = uv_buf_init("TEST", 4);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ uv_pipe_init(uv_default_loop(), &in, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)∈
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ /* Sending signum == 0 should check if the
+ * child process is still alive, not kill it.
+ */
+ r = uv_process_kill(&process, 0);
+ TUV_ASSERT(r == 0);
+
+ r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(strcmp(output, "TEST") == 0);
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_closed_process_io) {
+ uv_pipe_t in;
+ uv_write_t write_req;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[2];
+ static char buffer[] = "hello-from-spawn_stdin\n";
+
+ init_process_options("spawn_helper3", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &in, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*) ∈
+ options.stdio_count = 1;
+
+ close(0); /* Close process stdin. */
+
+ TUV_ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
+
+ buf = uv_buf_init(buffer, sizeof(buffer));
+ TUV_ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));
+
+ TUV_ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 2); /* process, child stdin */
+
+ return 0;
+}
+
+
+TEST_IMPL(kill) {
+ int r;
+
+#ifdef _WIN32
+ no_term_signal = 1;
+#endif
+
+ init_process_options("spawn_helper4", kill_cb);
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ /* Sending signum == 0 should check if the
+ * child process is still alive, not kill it.
+ */
+ r = uv_kill(process.pid, 0);
+ TUV_ASSERT(r == 0);
+
+ /* Kill the process. */
+ r = uv_kill(process.pid, /* SIGTERM */ 15);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 1);
+
+ return 0;
+}
+
+
+#ifdef _WIN32
+TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
+ int r;
+ uv_pipe_t out;
+ char name[64];
+ HANDLE pipe_handle;
+ uv_stdio_container_t stdio[2];
+
+ init_process_options("spawn_helper2", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ /* Create a pipe that'll cause a collision. */
+ snprintf(name,
+ sizeof(name),
+ "\\\\.\\pipe\\uv\\%p-%d",
+ &out,
+ GetCurrentProcessId());
+ pipe_handle = CreateNamedPipeA(name,
+ PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ 10,
+ 65536,
+ 65536,
+ 0,
+ NULL);
+ TUV_ASSERT(pipe_handle != INVALID_HANDLE_VALUE);
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
+ printf("output is: %s", output);
+ TUV_ASSERT(strcmp("hello world\n", output) == 0);
+
+ return 0;
+}
+
+
+#if !defined(USING_UV_SHARED)
+int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr);
+WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target);
+
+TEST_IMPL(argument_escaping) {
+ const WCHAR* test_str[] = {
+ L"",
+ L"HelloWorld",
+ L"Hello World",
+ L"Hello\"World",
+ L"Hello World\\",
+ L"Hello\\\"World",
+ L"Hello\\World",
+ L"Hello\\\\World",
+ L"Hello World\\",
+ L"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\""
+ };
+ const int count = sizeof(test_str) / sizeof(*test_str);
+ WCHAR** test_output;
+ WCHAR* command_line;
+ WCHAR** cracked;
+ size_t total_size = 0;
+ int i;
+ int num_args;
+ int result;
+
+ char* verbatim[] = {
+ "cmd.exe",
+ "/c",
+ "c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"",
+ NULL
+ };
+ WCHAR* verbatim_output;
+ WCHAR* non_verbatim_output;
+
+ test_output = calloc(count, sizeof(WCHAR*));
+ TUV_ASSERT(test_output != NULL);
+ for (i = 0; i < count; ++i) {
+ test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(WCHAR));
+ quote_cmd_arg(test_str[i], test_output[i]);
+ wprintf(L"input : %s\n", test_str[i]);
+ wprintf(L"output: %s\n", test_output[i]);
+ total_size += wcslen(test_output[i]) + 1;
+ }
+ command_line = calloc(total_size + 1, sizeof(WCHAR));
+ TUV_ASSERT(command_line != NULL);
+ for (i = 0; i < count; ++i) {
+ wcscat(command_line, test_output[i]);
+ wcscat(command_line, L" ");
+ }
+ command_line[total_size - 1] = L'\0';
+
+ wprintf(L"command_line: %s\n", command_line);
+
+ cracked = CommandLineToArgvW(command_line, &num_args);
+ for (i = 0; i < num_args; ++i) {
+ wprintf(L"%d: %s\t%s\n", i, test_str[i], cracked[i]);
+ TUV_ASSERT(wcscmp(test_str[i], cracked[i]) == 0);
+ }
+
+ LocalFree(cracked);
+ for (i = 0; i < count; ++i) {
+ free(test_output[i]);
+ }
+
+ result = make_program_args(verbatim, 1, &verbatim_output);
+ TUV_ASSERT(result == 0);
+ result = make_program_args(verbatim, 0, &non_verbatim_output);
+ TUV_ASSERT(result == 0);
+
+ wprintf(L" verbatim_output: %s\n", verbatim_output);
+ wprintf(L"non_verbatim_output: %s\n", non_verbatim_output);
+
+ TUV_ASSERT(wcscmp(verbatim_output,
+ L"cmd.exe /c c:\\path\\to\\node.exe --eval "
+ L"\"require('c:\\\\path\\\\to\\\\test.js')\"") == 0);
+ TUV_ASSERT(wcscmp(non_verbatim_output,
+ L"cmd.exe /c \"c:\\path\\to\\node.exe --eval "
+ L"\\\"require('c:\\\\path\\\\to\\\\test.js')\\\"\"") == 0);
+
+ free(verbatim_output);
+ free(non_verbatim_output);
+
+ return 0;
+}
+
+int make_program_env(char** env_block, WCHAR** dst_ptr);
+
+TEST_IMPL(environment_creation) {
+ int i;
+ char* environment[] = {
+ "FOO=BAR",
+ "SYSTEM=ROOT", /* substring of a supplied var name */
+ "SYSTEMROOTED=OMG", /* supplied var name is a substring */
+ "TEMP=C:\\Temp",
+ "INVALID",
+ "BAZ=QUX",
+ "B_Z=QUX",
+ "B\xe2\x82\xacZ=QUX",
+ "B\xf0\x90\x80\x82Z=QUX",
+ "B\xef\xbd\xa1Z=QUX",
+ "B\xf0\xa3\x91\x96Z=QUX",
+ "BAZ", /* repeat, invalid variable */
+ NULL
+ };
+ WCHAR* wenvironment[] = {
+ L"BAZ=QUX",
+ L"B_Z=QUX",
+ L"B\x20acZ=QUX",
+ L"B\xd800\xdc02Z=QUX",
+ L"B\xd84d\xdc56Z=QUX",
+ L"B\xff61Z=QUX",
+ L"FOO=BAR",
+ L"SYSTEM=ROOT", /* substring of a supplied var name */
+ L"SYSTEMROOTED=OMG", /* supplied var name is a substring */
+ L"TEMP=C:\\Temp",
+ };
+ WCHAR* from_env[] = {
+ /* list should be kept in sync with list
+ * in process.c, minus variables in wenvironment */
+ L"HOMEDRIVE",
+ L"HOMEPATH",
+ L"LOGONSERVER",
+ L"PATH",
+ L"USERDOMAIN",
+ L"USERNAME",
+ L"USERPROFILE",
+ L"SYSTEMDRIVE",
+ L"SYSTEMROOT",
+ L"WINDIR",
+ /* test for behavior in the absence of a
+ * required-environment variable: */
+ L"ZTHIS_ENV_VARIABLE_DOES_NOT_EXIST",
+ };
+ int found_in_loc_env[ARRAY_SIZE(wenvironment)] = {0};
+ int found_in_usr_env[ARRAY_SIZE(from_env)] = {0};
+ WCHAR *expected[ARRAY_SIZE(from_env)];
+ int result;
+ WCHAR* str;
+ WCHAR* prev;
+ WCHAR* env;
+
+ for (i = 0; i < ARRAY_SIZE(from_env); i++) {
+ /* copy expected additions to environment locally */
+ size_t len = GetEnvironmentVariableW(from_env[i], NULL, 0);
+ if (len == 0) {
+ found_in_usr_env[i] = 1;
+ str = malloc(1 * sizeof(WCHAR));
+ *str = 0;
+ expected[i] = str;
+ } else {
+ size_t name_len = wcslen(from_env[i]);
+ str = malloc((name_len+1+len) * sizeof(WCHAR));
+ wmemcpy(str, from_env[i], name_len);
+ expected[i] = str;
+ str += name_len;
+ *str++ = L'=';
+ GetEnvironmentVariableW(from_env[i], str, len);
+ }
+ }
+
+ result = make_program_env(environment, &env);
+ TUV_ASSERT(result == 0);
+
+ for (str = env, prev = NULL; *str; prev = str, str += wcslen(str) + 1) {
+ int found = 0;
+#if 0
+ _cputws(str);
+ putchar('\n');
+#endif
+ for (i = 0; i < ARRAY_SIZE(wenvironment) && !found; i++) {
+ if (!wcscmp(str, wenvironment[i])) {
+ TUV_ASSERT(!found_in_loc_env[i]);
+ found_in_loc_env[i] = 1;
+ found = 1;
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(expected) && !found; i++) {
+ if (!wcscmp(str, expected[i])) {
+ TUV_ASSERT(!found_in_usr_env[i]);
+ found_in_usr_env[i] = 1;
+ found = 1;
+ }
+ }
+ if (prev) { /* verify sort order -- requires Vista */
+#if _WIN32_WINNT >= 0x0600 && \
+ (!defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR))
+ TUV_ASSERT(CompareStringOrdinal(prev, -1, str, -1, TRUE) == 1);
+#endif
+ }
+ TUV_ASSERT(found); /* verify that we expected this variable */
+ }
+
+ /* verify that we found all expected variables */
+ for (i = 0; i < ARRAY_SIZE(wenvironment); i++) {
+ TUV_ASSERT(found_in_loc_env[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(expected); i++) {
+ TUV_ASSERT(found_in_usr_env[i]);
+ }
+
+ return 0;
+}
+#endif
+
+/* Regression test for issue #909 */
+TEST_IMPL(spawn_with_an_odd_path) {
+ int r;
+
+ char newpath[2048];
+ char *path = getenv("PATH");
+ TUV_ASSERT(path != NULL);
+ snprintf(newpath, 2048, ";.;%s", path);
+ SetEnvironmentVariable("PATH", newpath);
+
+ init_process_options("", exit_cb);
+ options.file = options.args[0] = "program-that-had-better-not-exist";
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == UV_ENOENT || r == UV_EACCES);
+ TUV_ASSERT(0 == uv_is_active((uv_handle_t*) &process));
+ uv_close((uv_handle_t*) &process, NULL);
+ TUV_ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ return 0;
+}
+#endif
+
+#ifndef _WIN32
+TEST_IMPL(spawn_setuid_fails) {
+ int r;
+
+ /* if root, become nobody. */
+ uv_uid_t uid = getuid();
+ if (uid == 0) {
+ struct passwd* pw;
+ pw = getpwnam("nobody");
+ TUV_ASSERT(pw != NULL);
+ TUV_ASSERT(0 == setgid(pw->pw_gid));
+ TUV_ASSERT(0 == setuid(pw->pw_uid));
+ }
+
+ init_process_options("spawn_helper1", fail_cb);
+
+ options.flags |= UV_PROCESS_SETUID;
+ options.uid = 0;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == UV_EPERM);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(close_cb_called == 0);
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_setgid_fails) {
+ int r;
+
+ /* if root, become nobody. */
+ uv_uid_t uid = getuid();
+ if (uid == 0) {
+ struct passwd* pw;
+ pw = getpwnam("nobody");
+ TUV_ASSERT(pw != NULL);
+ TUV_ASSERT(0 == setgid(pw->pw_gid));
+ TUV_ASSERT(0 == setuid(pw->pw_uid));
+ }
+
+ init_process_options("spawn_helper1", fail_cb);
+
+ options.flags |= UV_PROCESS_SETGID;
+ options.gid = 0;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == UV_EPERM);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(close_cb_called == 0);
+
+ return 0;
+}
+#endif
+
+
+#ifdef _WIN32
+
+static void exit_cb_unexpected(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ TUV_ASSERT(0 && "should not have been called");
+}
+
+
+TEST_IMPL(spawn_setuid_fails) {
+ int r;
+
+ init_process_options("spawn_helper1", exit_cb_unexpected);
+
+ options.flags |= UV_PROCESS_SETUID;
+ options.uid = (uv_uid_t) -42424242;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == UV_ENOTSUP);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(close_cb_called == 0);
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_setgid_fails) {
+ int r;
+
+ init_process_options("spawn_helper1", exit_cb_unexpected);
+
+ options.flags |= UV_PROCESS_SETGID;
+ options.gid = (uv_gid_t) -42424242;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == UV_ENOTSUP);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(close_cb_called == 0);
+
+ return 0;
+}
+#endif
+
+
+TEST_IMPL(spawn_auto_unref) {
+ init_process_options("spawn_helper1", NULL);
+ TUV_ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
+ TUV_ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ TUV_ASSERT(0 == uv_is_closing((uv_handle_t*) &process));
+ uv_close((uv_handle_t*) &process, NULL);
+ TUV_ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ TUV_ASSERT(1 == uv_is_closing((uv_handle_t*) &process));
+ return 0;
+}
+
+
+#ifndef _WIN32
+TEST_IMPL(spawn_fs_open) {
+ int fd;
+ uv_fs_t fs_req;
+ uv_pipe_t in;
+ uv_write_t write_req;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[1];
+
+ fd = uv_fs_open(NULL, &fs_req, "/dev/null", O_RDWR, 0, NULL);
+ TUV_ASSERT(fd >= 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ init_process_options("spawn_helper8", exit_cb);
+
+ TUV_ASSERT(0 == uv_pipe_init(uv_default_loop(), &in, 0));
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*) ∈
+ options.stdio_count = 1;
+
+ TUV_ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
+
+ buf = uv_buf_init((char*) &fd, sizeof(fd));
+ TUV_ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));
+
+ TUV_ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ TUV_ASSERT(0 == uv_fs_close(NULL, &fs_req, fd, NULL));
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 2); /* One for `in`, one for process */
+
+ return 0;
+}
+#endif /* !_WIN32 */
+
+
+#ifndef _WIN32
+TEST_IMPL(closed_fd_events) {
+ uv_stdio_container_t stdio[3];
+ uv_pipe_t pipe_handle;
+ int fd[2];
+
+ /* create a pipe and share it with a child process */
+ TUV_ASSERT(0 == pipe(fd));
+
+ /* spawn_helper4 blocks indefinitely. */
+ init_process_options("spawn_helper4", exit_cb);
+ options.stdio_count = 3;
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_INHERIT_FD;
+ options.stdio[0].data.fd = fd[0];
+ options.stdio[1].flags = UV_IGNORE;
+ options.stdio[2].flags = UV_IGNORE;
+
+ TUV_ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
+ uv_unref((uv_handle_t*) &process);
+
+ /* read from the pipe with uv */
+ TUV_ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
+ TUV_ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
+ fd[0] = -1;
+
+ TUV_ASSERT(0 == uv_read_start((uv_stream_t*) &pipe_handle, on_alloc, on_read_once));
+
+ TUV_ASSERT(1 == write(fd[1], "", 1));
+
+ TUV_ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+
+ /* should have received just one byte */
+ TUV_ASSERT(output_used == 1);
+
+ /* close the pipe and see if we still get events */
+ uv_close((uv_handle_t*) &pipe_handle, close_cb);
+
+ TUV_ASSERT(1 == write(fd[1], "", 1));
+
+ TUV_ASSERT(0 == uv_timer_init(uv_default_loop(), &timer));
+ TUV_ASSERT(0 == uv_timer_start(&timer, timer_counter_cb, 10, 0));
+
+ /* see if any spurious events interrupt the timer */
+ if (1 == uv_run(uv_default_loop(), UV_RUN_ONCE))
+ /* have to run again to really trigger the timer */
+ TUV_ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+
+ TUV_ASSERT(timer_counter == 1);
+
+ /* cleanup */
+ TUV_ASSERT(0 == uv_process_kill(&process, /* SIGTERM */ 15));
+ TUV_ASSERT(0 == close(fd[1]));
+
+ return 0;
+}
+#endif /* !_WIN32 */
+
+TEST_IMPL(spawn_reads_child_path) {
+ int r;
+ int len;
+ char file[64];
+ char path[1024];
+ char* env[3];
+
+ /* Need to carry over the dynamic linker path when the test runner is
+ * linked against libuv.so, see https://github.com/libuv/libuv/issues/85.
+ */
+#if defined(__APPLE__)
+ static const char dyld_path_var[] = "DYLD_LIBRARY_PATH";
+#elif defined __MVS__
+ static const char dyld_path_var[] = "LIBPATH";
+#else
+ static const char dyld_path_var[] = "LD_LIBRARY_PATH";
+#endif
+
+ /* Set up the process, but make sure that the file to run is relative and */
+ /* requires a lookup into PATH */
+ init_process_options("spawn_helper1", exit_cb);
+
+ /* Set up the PATH env variable */
+ for (len = strlen(exepath);
+ exepath[len - 1] != '/' && exepath[len - 1] != '\\';
+ len--);
+ strcpy(file, exepath + len);
+ exepath[len] = 0;
+ strcpy(path, "PATH=");
+ strcpy(path + 5, exepath);
+
+ env[0] = path;
+ env[1] = getenv(dyld_path_var);
+ env[2] = NULL;
+
+ if (env[1] != NULL) {
+ static char buf[1024 + sizeof(dyld_path_var)];
+ snprintf(buf, sizeof(buf), "%s=%s", dyld_path_var, env[1]);
+ env[1] = buf;
+ }
+
+ options.file = file;
+ options.args[0] = file;
+ options.env = env;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 1);
+
+ return 0;
+}
+
+#ifndef _WIN32
+static int mpipe(int *fds) {
+ if (pipe(fds) == -1)
+ return -1;
+ if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
+ fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
+ close(fds[0]);
+ close(fds[1]);
+ return -1;
+ }
+ return 0;
+}
+#else
+static int mpipe(int *fds) {
+ SECURITY_ATTRIBUTES attr;
+ HANDLE readh, writeh;
+ attr.nLength = sizeof(attr);
+ attr.lpSecurityDescriptor = NULL;
+ attr.bInheritHandle = FALSE;
+ if (!CreatePipe(&readh, &writeh, &attr, 0))
+ return -1;
+ fds[0] = _open_osfhandle((intptr_t)readh, 0);
+ fds[1] = _open_osfhandle((intptr_t)writeh, 0);
+ if (fds[0] == -1 || fds[1] == -1) {
+ CloseHandle(readh);
+ CloseHandle(writeh);
+ return -1;
+ }
+ return 0;
+}
+#endif /* !_WIN32 */
+
+TEST_IMPL(spawn_inherit_streams) {
+ uv_process_t child_req;
+ uv_stdio_container_t child_stdio[2];
+ int fds_stdin[2];
+ int fds_stdout[2];
+ uv_pipe_t pipe_stdin_child;
+ uv_pipe_t pipe_stdout_child;
+ uv_pipe_t pipe_stdin_parent;
+ uv_pipe_t pipe_stdout_parent;
+ unsigned char ubuf[OUTPUT_SIZE - 1];
+ uv_buf_t buf;
+ unsigned int i;
+ int r;
+ uv_write_t write_req;
+ uv_loop_t* loop;
+
+ init_process_options("spawn_helper9", exit_cb);
+
+ loop = uv_default_loop();
+ TUV_ASSERT(uv_pipe_init(loop, &pipe_stdin_child, 0) == 0);
+ TUV_ASSERT(uv_pipe_init(loop, &pipe_stdout_child, 0) == 0);
+ TUV_ASSERT(uv_pipe_init(loop, &pipe_stdin_parent, 0) == 0);
+ TUV_ASSERT(uv_pipe_init(loop, &pipe_stdout_parent, 0) == 0);
+
+ TUV_ASSERT(mpipe(fds_stdin) != -1);
+ TUV_ASSERT(mpipe(fds_stdout) != -1);
+
+ TUV_ASSERT(uv_pipe_open(&pipe_stdin_child, fds_stdin[0]) == 0);
+ TUV_ASSERT(uv_pipe_open(&pipe_stdout_child, fds_stdout[1]) == 0);
+ TUV_ASSERT(uv_pipe_open(&pipe_stdin_parent, fds_stdin[1]) == 0);
+ TUV_ASSERT(uv_pipe_open(&pipe_stdout_parent, fds_stdout[0]) == 0);
+
+ child_stdio[0].flags = UV_INHERIT_STREAM;
+ child_stdio[0].data.stream = (uv_stream_t *)&pipe_stdin_child;
+
+ child_stdio[1].flags = UV_INHERIT_STREAM;
+ child_stdio[1].data.stream = (uv_stream_t *)&pipe_stdout_child;
+
+ options.stdio = child_stdio;
+ options.stdio_count = 2;
+
+ TUV_ASSERT(uv_spawn(loop, &child_req, &options) == 0);
+
+ uv_close((uv_handle_t*)&pipe_stdin_child, NULL);
+ uv_close((uv_handle_t*)&pipe_stdout_child, NULL);
+
+ buf = uv_buf_init((char*)ubuf, sizeof ubuf);
+ for (i = 0; i < sizeof ubuf; ++i)
+ ubuf[i] = i & 255u;
+ memset(output, 0, sizeof ubuf);
+
+ r = uv_write(&write_req,
+ (uv_stream_t*)&pipe_stdin_parent,
+ &buf,
+ 1,
+ write_cb);
+ TUV_ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&pipe_stdout_parent, on_alloc, on_read);
+ TUV_ASSERT(r == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ TUV_ASSERT(r == 0);
+
+ TUV_ASSERT(exit_cb_called == 1);
+ TUV_ASSERT(close_cb_called == 3);
+
+ r = memcmp(ubuf, output, sizeof ubuf);
+ TUV_ASSERT(r == 0);
+
+ return 0;
+}
+
+/* Helper for child process of spawn_inherit_streams */
+#ifndef _WIN32
+int spawn_stdin_stdout(void) {
+ char buf[1024];
+ char* pbuf;
+ for (;;) {
+ ssize_t r, w, c;
+ do {
+ r = read(0, buf, sizeof buf);
+ } while (r == -1 && errno == EINTR);
+ if (r == 0) {
+ return 1;
+ }
+ TUV_ASSERT(r > 0);
+ c = r;
+ pbuf = buf;
+ while (c) {
+ do {
+ w = write(1, pbuf, (size_t)c);
+ } while (w == -1 && errno == EINTR);
+ TUV_ASSERT(w >= 0);
+ pbuf = pbuf + w;
+ c = c - w;
+ }
+ }
+ return 2;
+}
+#else
+int spawn_stdin_stdout(void) {
+ char buf[1024];
+ char* pbuf;
+ HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE);
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ TUV_ASSERT(h_stdin != INVALID_HANDLE_VALUE);
+ TUV_ASSERT(h_stdout != INVALID_HANDLE_VALUE);
+ for (;;) {
+ DWORD n_read;
+ DWORD n_written;
+ DWORD to_write;
+ if (!ReadFile(h_stdin, buf, sizeof buf, &n_read, NULL)) {
+ TUV_ASSERT(GetLastError() == ERROR_BROKEN_PIPE);
+ return 1;
+ }
+ to_write = n_read;
+ pbuf = buf;
+ while (to_write) {
+ TUV_ASSERT(WriteFile(h_stdout, pbuf, to_write, &n_written, NULL));
+ to_write -= n_written;
+ pbuf += n_written;
+ }
+ }
+ return 2;
+}
+#endif /* !_WIN32 */
### Supported platforms
-Current supported platforms are **Linux and NuttX**
+Current supported platforms are **Linux, [NuttX][nuttx-site], [Tizen][tizen-site] and [TizenRT][tizenrt-site]**
OSX 10.10 as development host
* [Build for x86 / Linux](build/Build-for-x86-Linux.md): Ubuntu 14.04 is used as a base platform.
+* [Build for Raspberry Pi 2 / Linux](build/Build-for-RPi2-Linux.md)
* [Build for Raspberry Pi 3 / Tizen](build/Build-for-RPi3-Tizen.md)
* [Build for Stm32f4 / NuttX](build/Build-for-STM32F4-NuttX.md)
-* [Build for Raspberry Pi 2 / Linux](build/Build-for-RPi2-Linux.md)
* [Build for ARTIK053 / TizenRT](build/Build-for-ARTIK053-TizenRT.md)
+* [Build for ARTIK530 / Tizen](build/Build-for-RPi3-Tizen.md)
+* [Build for OpenWrt (non-tested)](build/Build-for-OpenWrt.md)
+* [Build for Windows (experimental)](build/Build-for-Windows.md)
#### H/W boards
* Current supporting
* Raspberry Pi 2
* Raspberry Pi 3
* Samsung ARTIK 053
+ * Samsung ARTIK 530
We will support the correct behavior of APIs for above environments. However, since IoT.js is targeting various kind IoT devices and platforms, single implementation cannot be the best practice for every environments. Therefore embedders should be in charge of optimization for their own environments. For more details on optimization, see the [Optimization Tips](devs/Optimization-Tips.md) page.
### Build script
-There is a script to help you build IoT.js called "[build.py](https://github.com/Samsung/iotjs/blob/master/tools/build.py)" in source repository.
+There is a [script](build/Build-Script.md) to help you build IoT.js called "[build.py](https://github.com/Samsung/iotjs/blob/master/tools/build.py)" in source repository. Run `tools/build.py --help` command to check all of the build options.
+
+#### How to Build
+
+```bash
+ tools/build.py --clean
+```
+
+#### Frequently used build options
+
+`--clean` Clean build directory before build (default: False).
+
+`--no-snapshot` Disable snapshot generation for IoT.js. It is useful for debugging sessions.
+
+`--profile PROFILE` Specify the module profile file for IoT.js. It is used for enable and disable modules. See also ["How to write a new module"](devs/Writing-New-Module.md#profile)
+
+`--run-test [{full,quiet}]` Execute tests after build, optional argument specifies the level of output for the test runner.
+
+`--jerry-debugger` Enable JerryScript debugger, so JavaScript could can be investigated with an available debugger client (eg.: [Python Debugger Console](https://github.com/jerryscript-project/jerryscript/blob/master/jerry-debugger/jerry-client-ws.py) or [IoT.js Code](https://github.com/Samsung/iotjscode/)). See also ["Use JerryScript Debugger"](devs/Use-JerryScript-Debugger.md).
+
+`--js-backtrace {ON,OFF}` Enable/disable backtrace information of JavaScript code (default: ON in debug and OFF in release build).
+[nuttx-site]: http://nuttx.org/
+[tizen-site]: https://www.tizen.org/
+[tizenrt-site]: https://wiki.tizen.org/Tizen_RT
\ No newline at end of file
| buf.copy | O | O | O | O | O |
| buf.equals | O | O | O | O | O |
| buf.fill | O | O | O | O | O |
+| buf.from | O | O | O | O | O |
| buf.slice | O | O | O | O | O |
| buf.toString | O | O | O | O | O |
| buf.write | O | O | O | O | O |
```
+### Buffer.from(array)
+* `array` {Array} Array of numbers.
+* Returns: {Buffer} containing the elements from `array`
+
+Creates a new Buffer from an array of numbers. The numbers are converted to integers first and their modulo 256 remainder is used for constructing the buffer.
+
+**Example**
+
+```js
+var Buffer = require('buffer');
+
+var source = new Buffer[65, 66, 67];
+var buffer = Buffer.from(source);
+
+//prints: ABC
+console.log(buffer.toString());
+```
+
+
+### Buffer.from(string[,encoding])
+* `str` {String} Source string.
+* `encoding` {String} Encoding format.
+* Returns: {Buffer} containing the elements from `str`
+
+Creates a new buffer which contains the CESU-8 representation of the str string argument. If encoding optional argument is present its value must be hex. When this encoding is specified the str argument must be a sequence of hexadecimal digit pairs, and these pairs are converted to bytes.
+
+**Example**
+
+```js
+var Buffer = require('buffer');
+
+var buffer = Buffer.from('4142','hex');
+
+//prints: AB
+console.log(buffer.toString());
+```
+
+
+### Buffer.from(buffer)
+* `buffer` {Buffer} Source buffer.
+* Returns: {Buffer} which is the copy of `buffer`
+Creates a copy of an existing buffer. The buffer data is not shared between the two buffers.
+
+**Example**
+
+```js
+var Buffer = require('buffer');
+
+var source = new Buffer(12);
+var buffer = Buffer.from(source);
+```
+
+
+### Buffer.from(arrayBuffer[, byteOffset[, length]])
+* `arrayBuffer` {ArrayBuffer} Arraybuffer, or a buffer of a TypedArray
+* `byteOffset` {Number} Index of first byte to expose. Default: 0.
+* `length` {Number} Number of bytes to expose. Default: arrayBuffer.length - byteOffset.
+* Returns: {Buffer} containing the data of `arraybuffer` from read `offset` with `length`
+
+**Example**
+
+```js
+var source = new ArrayBuffer(12);
+var buffer = Buffer.from(source, 0, 2);
+
+//prints: 2
+console.log(buffer.length);
+```
+
+```js
+var typed_source = new Uint8Array([65,66]);
+var arr_buff = Buffer.from(typed_source1.buffer, 0, 2);
+
+//prints: AB
+console.log(buff.toString('utf-8'));
+```
+
+
### Buffer.isBuffer(obj)
* `obj` {Object}
* Returns: {boolean}
--- /dev/null
+### Platform Support
+
+The following chart shows the availability of each Crypto module API function on each platform.
+
+| | Linux<br/>(Ubuntu) | Tizen<br/>(Raspberry Pi) | Raspbian<br/>(Raspberry Pi) | Nuttx<br/>(STM32F4-Discovery) | TizenRT<br/>(Artik053) |
+| :---: | :---: | :---: | :---: | :---: | :---: |
+| crypto.createHash | O | O | O | O | O |
+| crypto.createVerify | O | O | O | O | O |
+| crypto.getHashes | O | O | O | O | O |
+
+# Crypto
+
+The module provides limited cryptographic functionality, namely hashing and signature verification.
+To access this module use `require('crypto')`.
+
+### crypto.createVerify(hashType)
+Creates and returns a `Verify` object. This object can not be created with the `new` keyword.
+ - `hashType` {string} Hash type of the signature. {`sha1 | sha256`}
+
+Note: We currently only support `rsa-sha1` and `rsa-sha256` signatures.
+
+### crypto.createHash(hashType)
+Creates and returns a `Hash` object. This object can not be created with the `new` keyword.
+ - `hashType` {string} Type of the hash. {`sha1 | sha256`}
+
+Note: We currently only support `sha1` and `sha256` hashes.
+
+### crypto.getHashes()
+Returns the available hashing methods.
+
+## Class: Verify
+The `Verify` class allows the user to verify a signature against a public key.
+
+### verify.update(data)
+Updates the `Verify` object with the given `data`.
+ - `data` {Buffer | string} Updates the object with the `data`. If there is already `data` in the object, concatenates them.
+
+**Example**
+```js
+var crypto = require('crypto');
+var myVerifyObject = crypto.createVerify('sha256');
+
+myVerifyObject.update('This data should be verified');
+myVerifyObject.update('\nAnd this belongs there too.');
+```
+
+### verify.verify(publicKey, signature)
+Verifies the `signature` against the `publicKey` using the `data` added with `verify.update()`.
+ - `publicKey` {string | Buffer} A valid RSA Public key.
+ - `signature` {string | Buffer} A base64 encoded `rsa-sha1` or `rsa-sha256` signature.
+
+Returns `true` if the verification succeeds, `false` otherwise.
+
+**Example**
+```js
+var crypto = require('crypto');
+
+var myVerifyObject = crypto.createVerify('sha256');
+var myKey = getPublicKeySomehow();
+var myData = getSomeStringToVerify();
+var mySignature = getSignatureSomehow();
+
+
+myVerifyObject.update(myData);
+var success = myVerifyObject.verify(myKey, mySignature);
+
+if (!success) {
+ throw new Error('Invalid signature !');
+}
+```
+
+## Class: Hash
+The `Hash` class creates hashes from the data given.
+
+### hash.update(data)
+Updates the `Hash` object with the given `data`.
+ - `data` {Buffer | String} Updates the object with the `data`. If there is already `data` in the object, concatenates them.
+
+### hash.digest(encoding)
+Returns an `encoded` hash of the input `data` as a `string` or `Buffer`.
+ - `encoding` {string} Encodes the result of the hashing to the given format. Can be {`hex | base64`}. If no `encoding` is given, or the given `encoding` doesn't match the known formats, returns the raw `hash` in a `Buffer`.
+
+Digest can only be called once on a given `Hash` object.
+
+**Example**
+```js
+var crypto = require('crypto');
+
+var myData = 'Some data to hash';
+var myHashObj = crypto.createHash('sha1');
+myHashObj.update(myData);
+var myHash = myHashObj.digest('hex');
+```
| :---: | :---: | :---: | :---: | :---: | :---: |
| fs.close | O | O | O | O | O |
| fs.closeSync | O | O | O | O | O |
+| fs.createReadStream | O | O | O | O | O |
+| fs.createWriteStream | O | O | O | O | O |
| fs.exists | O | O | O | O | O |
| fs.existsSync | O | O | O | O | O |
| fs.fstat | O | O | O | X | X |
```
+## Class: fs.ReadStream
+
+A successful call to `fs.createReadStream()` will return a new `fs.ReadStream`
+object.
+
+`fs.ReadStream` inherits from `stream.Readable`.
+
+
+### Event: 'open'
+* `fd` {integer} File descriptor used by the `fs.ReadStream`.
+
+Emitted when the `fs.ReadStream`'s file descriptor has been opened.
+
+
+### Event: 'ready'
+
+Emitted when the `fs.ReadStream` is ready to be used. Emitted immediately
+after `open`.
+
+
+### Event: 'data'
+* `chunk` {Buffer|string}
+
+Inherited from `stream.Readable`. Emitted when the stream passes the ownership
+of the data to a consumer. Only streams in flowing mode emit this event.
+
+A stream can be switched to flowing mode by calling the readable.resume()
+function or by adding a 'data' event handler.
+
+
+### Event: 'close'
+
+Emitted when the `fs.ReadStream`'s file descriptor has been closed.
+
+
+### ReadStream.bytesRead
+* {integer}
+
+Number of bytes that have been read so far.
+
+
+### ReadStream.path
+* {string}
+
+The path to the file of the `fs.ReadStream`.
+
+
+### fs.createReadStream(path[, options])
+* `path` {string} File path to open for reading.
+* `options` {Object}
+ * `flags` {string} Flags to open file with. **Default:** `'r'`
+ * `encoding` {string} **Default:** `null`
+ * `fd` {integer} File descriptor to be used. **Default:** `null`
+ * `mode` {integer} Permission mode. **Default:** `0666`
+ * `autoClose` {boolean} Should the file be closed automatically. **Default:** `true`
+ * `bufferSize` {integer} Size of buffer in bytes. **Default:** `4096`
+* Returns: `fs.ReadStream`
+
+If `fd` is specified, `path` will be ignored and the specified file
+descriptor will be used instead.
+
+If `autoClose` is `false`, the file will not be closed automatically,
+even if there is an error, it will be the application's responsibility.
+If it is `true` (as by default), the file will be closed automatically
+when end of file is reached or the stream ends.
+
+**Example**
+
+```js
+var fs = require('fs');
+
+var rStream = fs.createReadStream('example.txt');
+rStream.on('data', function(data) {
+ console.log(data.toString());
+});
+```
+
+`fs.ReadStream` inherits from `stream.Readable`, so it is possible to pipe
+it into any `stream.Writable`.
+
+**Example**
+
+```js
+var fs = require('fs');
+
+var readableFileStream = fs.createReadStream('in.txt');
+var writableFileStream = fs.createWriteStream('out.txt');
+
+// The content of in.txt will be copied to out.txt
+readableFileStream.pipe(writableFileStream);
+```
+
+
+## Class: fs.WriteStream
+
+A successful call to `fs.createWriteStream()` will return a new `fs.WriteStream`
+object.
+
+`fs.WriteStream` inherits from `stream.Writable`.
+
+
+### Event: 'open'
+* `fd` {integer} File descriptor used by the `fs.WriteStream`.
+
+Emitted when the `fs.WriteStream`'s file descriptor has been opened.
+
+
+### Event: 'ready'
+
+Emitted when the `fs.WriteStream` is ready to be used. Emitted immediately
+after `open`.
+
+
+### Event: 'close'
+
+Emitted when the `fs.WriteStream`'s file descriptor has been closed.
+
+
+### WriteStream.bytesWritten
+
+The number of bytes written so far. Does not include data that is still queued
+for writing.
+
+
+### WriteStream.path
+
+The path to the file of the `fs.WriteStream`.
+
+
+### fs.createWriteStream
+* `path` {string} File path to be opened for writing.
+* `options` {Object}
+ * `flags` {string} Flags to open the file with. **Default:** `'w'`
+ * `fd` {integer} File descriptor to be used. **Default:** `null`
+ * `mode` {integer} Permission mode. **Default:** `0666`
+ * `autoClose` {boolean} Should the file be closed automatically. **Default:** `true`
+* Returns `fs.WriteStream`
+
+Works similarly to `fs.createReadStream()`, but returns an `fs.WriteStream`.
+
+If `fd` is specified, `path` will be ignored and the specified file
+descriptor will be used instead.
+
+If `autoClose` is `false`, the file will not be closed automatically,
+even if there is an error, it will be the application's responsibility.
+If it is `true` (as by default), the file will be closed automatically
+when end of file is reached or the stream ends.
+
+**Example**
+
+```js
+var fs = require('fs');
+
+var wStream = fs.createWriteStream('example.txt');
+
+wStream.on('ready', function() {
+ wStream.write('test data');
+ // 'test data' will be written into example.txt
+});
+```
+
+
### fs.exists(path, callback)
* `path` {string} File path to be checked.
* `callback` {Function}
| :---: | :---: | :---: | :---: | :---: | :---: |
| gpio.open | X | O | O | O | O |
| gpio.openSync | X | O | O | O | O |
+| gpiopin.setDirectionSync | X | O | O | O | O |
| gpiopin.write | X | O | O | O | O |
| gpiopin.writeSync | X | O | O | O | O |
-| gpiopin.read | X | O | △ | O | O |
+| gpiopin.read | X | O | O | O | O |
| gpiopin.readSync | X | O | O | O | O |
| gpiopin.close | X | O | O | O | O |
| gpiopin.closeSync | X | O | O | O | O |
This class represents an opened and configured GPIO pin.
It allows getting and setting the status of the pin.
+### gpiopin.setDirectionSync(direction)
+ * `direction` {[gpio.DIRECTION](#direction)} Pin direction.
+
+Set the direction of a GPIO pin.
+
+**Example**
+
+```js
+gpio10.setDirectionSync(gpio.DIRECTION.OUT);
+gpio10.writeSync(1);
+
+gpio10.setDirectionSync(gpio.DIRECTION.IN);
+var value = gpio10.readSync();
+```
+
### gpiopin.write(value[, callback])
* `value` {number|boolean}
* `callback` {Function}
--- /dev/null
+### Platform Support
+
+The following chart shows the availability of each HTTP Signature module API function on each platform.
+
+| | Linux<br/>(Ubuntu) | Tizen<br/>(Raspberry Pi) | Raspbian<br/>(Raspberry Pi) | Nuttx<br/>(STM32F4-Discovery) | TizenRT<br/>(Artik053) |
+| :---: | :---: | :---: | :---: | :---: | :---: |
+| httpSignature.parseRequest | O | O | O | O | O |
+| httpSignature.verify | O | O | O | O | O |
+
+# HTTP Signature
+The module makes it possible to verify the signature on HTTP Requests as stated in the RFC Standard (https://tools.ietf.org/html/draft-cavage-http-signatures-10).
+
+### httpSignature.parseRequest(request)
+Parses an `HTTP request` and returns with the parsed object.
+ - `request` {Object} A valid `HTTP Request`
+
+The returned object can be used to later to `verify` the `signature` of the `request`.
+
+### httpSignature.verify(parsedRequest, publicKey)
+Verifies the `parsedRequest`'s `signature` against the given `publicKey`. Returns `true` if the verification succeeds, `false` otherwise.
+ - `parsedRequest` {Object} An `HTTP Request` parsed by `httpSignature.parseRequest()` function.
+ - `publicKey` {Buffer | string} The RSA Public key.
+
+**Example**
+```js
+var httpSign = require('http_signature');
+
+...
+
+function myHTTPListener(req, res) {
+ var parsedRequest = httpSign.parseRequest(req);
+ if (!httpSign.verify(parsedRequest))
+ // Verification failed
+ return res.send(401);
+ }
+
+ // Signature is OK, handle the request normally
+ requestHandler(req, res);
+}
+```
The following shows Http module APIs available for each platform.
| | Linux<br/>(Ubuntu) | Tizen<br/>(Raspberry Pi) | Raspbian<br/>(Raspberry Pi) | NuttX<br/>(STM32F4-Discovery) | TizenRT<br/>(Artik053) |
- | :---: | :---: | :---: | :---: | :---: | :---: |
- | http.createServer | O | O | O | △ ¹ | △ ¹ |
- | http.request | O | O | O | △ ¹ | △ ¹ |
- | http.get | O | O | O | △ ¹ | △ ¹ |
+ | :--- | :---: | :---: | :---: | :---: | :---: |
+ | http.createServer | O | O | O | △ ¹ | △ ¹ |
+ | http.request | O | O | O | △ ¹ | △ ¹ |
+ | http.get | O | O | O | △ ¹ | △ ¹ |
+ | http.METHODS | O | O | O | O | O |
+ | http.Server | O | O | O | △ ¹ | △ ¹ |
+ | http.Server.close | O | O | O | △ ¹ | △ ¹ |
+ | http.Server.listen | O | O | O | △ ¹ | △ ¹ |
+ | http.Server.setTimeout | O | O | O | △ ¹ | △ ¹ |
+ | http.ClientRequest | O | O | O | △ ¹ | △ ¹ |
+ | http.ClientRequest.abort | O | O | O | △ ¹ | △ ¹ |
+ | http.ClientRequest.end | O | O | O | △ ¹ | △ ¹ |
+ | http.ClientRequest.setTimeout | O | O | O | △ ¹ | △ ¹ |
+ | http.ClientRequest.write | O | O | O | △ ¹ | △ ¹ |
+ | http.IncomingMessage | O | O | O | △ ¹ | △ ¹ |
+ | http.IncomingMessage.headers | O | O | O | △ ¹ | △ ¹ |
+ | http.IncomingMessage.method | O | O | O | △ ¹ | △ ¹ |
+ | http.IncomingMessage.httpVersion | O | O | O | △ ¹ | △ ¹ |
+ | http.IncomingMessage.socket | O | O | O | △ ¹ | △ ¹ |
+ | http.IncomingMessage.statusCode | O | O | O | △ ¹ | △ ¹ |
+ | http.IncomingMessage.url | O | O | O | △ ¹ | △ ¹ |
+ | http.IncomingMessage.statusMessage | O | O | O | △ ¹ | △ ¹ |
+ | http.IncomingMessage.setTimeout | O | O | O | △ ¹ | △ ¹ |
+ | http.ServerResponse | O | O | O | △ ¹ | △ ¹ |
+ | http.ServerResponse.end | O | O | O | △ ¹ | △ ¹ |
+ | http.ServerResponse.getHeader | O | O | O | △ ¹ | △ ¹ |
+ | http.ServerResponse.setHeader | O | O | O | △ ¹ | △ ¹ |
+ | http.ServerResponse.setTimeout | O | O | O | △ ¹ | △ ¹ |
+ | http.ServerResponse.write | O | O | O | △ ¹ | △ ¹ |
+ | http.ServerResponse.writeHead | O | O | O | △ ¹ | △ ¹ |
1. On NuttX/STM32F4-Discovery and TizenRT/Artik053, even a couple of sockets/server/requests might not work properly.
IoT.js provides HTTP to support HTTP server and client enabling users to receive/send HTTP request easily.
-### http.createServer([requestListener])
+### http.createServer([options][, requestListener])
+* `options` {Object}
+ * `IncomingMessage` {Function} Specifies the `IncomingMessage` constructor to be used when creating an http incoming message object.
+ Useful when extending the original {http.IncommingMessge}.
+ Default: `http.IncommingMessage`.
+ * `ServerResponse` {Function} Specifies the `ServerResponse` constructor to be used when creating the server response object.
+ Useful when extending the original {http.ServerResponse}.
+ Default: 'http.ServerResponse`.
* `requestListener` {Function}
- * request {http.IncomingMessage}
- * response {http.ServerResponse}
+ * `request` {http.IncomingMessage}
+ * `response` {http.ServerResponse}
* Returns: {http.Server}
-The `requestListener` is a function which is automatically added to the `'request'` event.
+This call only creates the HTTP server instance and does not start the server.
+To start the server and listen for connections use the `server.listen` method.
+
+If a server is no longer needed, all request and response streams should be closed and the `server.close` method
+should be used to stop the server listening for connections.
+
+The `requestListener` is a function which is automatically added to the `'request'` event of the http server.
**Example**
```js
+var console = require('console');
+var http = require('http');
+
var server = http.createServer(function(request, response) {
- ...
+ console.log('Request for path: ' + request.url);
+
+ var message = '<h1>Hello</h1>';
+
+ response.setHeader('Content-Type', 'text/html');
+ response.setHeader('Content-Length', message.length);
+ response.writeHead(200);
+ response.write(message);
+ response.end();
+});
+
+var port = 8081
+server.listen(port, function() {
+ console.log('HTTP server listening on port: ' + port);
});
```
+
### http.request(options[, callback])
* `options` {Object}
* `host` {string} A domain name or IP address of the server to issue the request to. Defaults to 'localhost'.
* `response` {http.IncomingMessage}
* Returns: {http.ClientRequest}
+The function creates a `http.ClientRequest` instance with the `options` defined.
+This can be used to get data form a server or to send data for a server.
+
+In case of data send the `'Content-Length'` header should be specifed so the server can properly handle the request.
+
**Example**
```js
var http = require('http');
+var data_A = 'Data to upload..';
+var data_B = 'more data';
var request = http.request({
method: 'POST',
- port: 80,
- headers: {'Content-Length': 3}
+ port: 8081,
+ headers: { 'Content-Length': data_A.length + data_B.length }
});
-...
+request.write(data_A);
+request.write(data_B);
request.end();
```
-Note that in the example `req.end()` was called. With `http.request()` one must always call `req.end()` to signify that you're done with the request - even if there is no data being written to the request body.
+Note that in the example `request.end()` was called. With `http.request()` one must always call
+`request.end()` to signify that you're done with the request - even if there is no data being written to the request body.
### http.get(options[, callback])
* `options` {Object}
* `response` {http.IncomingMessage}
* Returns: {http.ClientRequest}
-Same as `http.request` except that `http.get` automatically call `req.end()` at the end.
+Same as `http.request` except that `http.get` automatically calls `request.end()` before returning the `http.ClientRequest`
+instance thus calling the `write` method on the return value is invalid.
+
+This method is usefuly when there is no HTTP body to send.
**Example**
http.get({
port: 80,
-}, function(res) {
-...
+}, function(response) {
+ console.log('Got response');
+ response.on('data', function(chunk) {
+ console.log('Chunk: ');
+ console.log(chunk.toString());
+ });
});
```
### http.METHODS
-A list of HTTP methods supported by the parser as `string` properties of an `Object`.
+* {string[]}
+
+A list of HTTP methods supported by the parser as a `string` array.
## Class: http.Server
-This class inherits from `net.Server`.
+This class inherits from `net.Server` and represents a HTTP server.
### Event: 'clientError'
-* `exception` {Error}
-* `socket` {net.Socket}
+Event callback arguments:
+* `exception` {Error} Describes what kind of error occured.
+* `socket` {net.Socket} The socket which triggered the error.
If a client connection emits an 'error' event, it will be forwarded here. Listener of this event is responsible for closing/destroying the underlying socket.
```
### Event: 'close'
-This event is emitted when server is closed.
+This event is emitted when the HTTP server is closed.
+
+**Example**
+
+```js
+var console = require('console');
+var http = require('http');
+
+var server = http.createServer();
+
+server.on('close', function() {
+ console.log('Server closed');
+});
+
+server.listen(8081, function() {
+ console.log('HTTP server listening');
+
+ server.close();
+});
+```
+
+When the example is executed the following will text will be printed:
+
+```
+HTTP server listening
+Server closed
+```
### Event: 'connection'
+Event callback argument:
* `socket` {net.Socket}
-This event is emitted when new TCP connection is established.
+This event is emitted when new TCP connection is established. This event is triggered before
+the `request` event. At this stage no HTTP header or data is processed.
-### Event: 'connect'
+Usually there is no need to listen for this event.
-Emitted each time a client requests an `HTTP CONNECT` method.
### Event: 'request'
-* `request` {http.IncomingMessage}
-* `response` {http.ServerResponse}
+* `request` {http.IncomingMessage} Represents the HTTP request sent by the client.
+* `response` {http.ServerResponse} Represents the HTTP response which will be sent by the server.
+
+After HTTP request headers are parsed, the `'request'` event will be fired.
+
+**Example**
+
+```js
+var console = require('console');
+var http = require('http');
-After request header is parsed, this event will be fired.
+var server = http.createServer();
+
+server.on('request', function(request, response) {
+ console.log('Request for path: ' + request.url);
+
+ var message = '<h1>Hello</h1>';
+
+ response.setHeader('Content-Type', 'text/html');
+ response.setHeader('Content-Length', message.length);
+ response.writeHead(200);
+ response.write(message);
+ response.end();
+});
+var port = 8081
+server.listen(port, function() {
+ console.log('HTTP server listening on port: ' + port);
+});
+```
### server.timeout
+* {number}
+
The number of milliseconds of inactivity before a socket is presumed to have timed out. Default value is 120000 (2 minutes).
### server.listen(port[, hostname][, backlog][, callback])
-* `port` {number}
-* `host` {string}
-* `backlog` {number}
-* `callback` {Function}
+* `port` {number} Port number to listen on.
+* `host` {string} Host IP or name where the server should listen. Default: `'0.0.0.0'`.
+* `backlog` {number} The number of maximum pending connections. Default backlog length is 511 (not 512).
+* `callback` {Function} Callback called when the `'listening'` event is emitted by the underlying `net.Server`.
+* Returns {http.Server} The same server instance which was used to call the `listen` method.
-Wait for new TCP connection with specified port and hostname. If no hostname is provided, server accepts any IP address.
-`backlog` is maximum pending connections. Default backlog length is 511 (not 512).
-`callback` will be called when server has been bound.
+Wait for new TCP connections with specified port and hostname. If no hostname is provided, server listens on all available IP address.
**Example**
```js
+var console = require('console');
var http = require('http');
var server = http.createServer(function(req, res) {
res.end();
});
-server.listen(8080, function() {});
+server.listen(8080, function() {
+ console.log('Started listening');
+});
```
### server.close([callback])
-* `callback` {Function}
+* `callback` {Function} Function which to be registered for the `'close'` event.
+* Returns {http.Server} The same server instance which was used to call the `close` method.
+
+Stop accepting new connections to this server. However, the existing connections are preserved.
+When the server is finally closed after all connections was closed, the `'close'` event is triggered.
-Stop accepting new connection to this server. However, the existing connections are preserved. When server is finally closed after all connections are closed, a callback is called.
+See the `'close`' event.
-### server.setTimeout(ms, cb)
+### server.setTimeout(ms[, callback])
* `ms` {number}
-* `cb` {Function}
+* `callback` {Function} The callback function registered for the `'timeout'` event.
-Registers cb for `'timeout'` event and sets socket's timeout value to ms. This event will be triggered by the underlying socket's 'timeout' event.
+Registers cb for `'timeout'` event and sets socket's timeout value to ms. This event will be triggered by the underlying socket's `'timeout'` event.
-If cb is not provided, the socket will be destroyed automatically after timeout.
-If you provide cb, you should handle the socket's timeout.
+If `callback` is not provided, the socket will be destroyed automatically after timeout.
+If the `callback` function is provided, that function should should handle the socket's timeout.
Default timeout for server is 2 minutes.
});
```
-## Class: http.ServerResponse
-
-### Event: 'close'
-When underlying connection is closed, 'close' event is emitted.
-
-### Event: 'end'
-This event is fired when no more data to be sent.
-
-### Event: 'finish'
-This event is emitted when the response has been sent. It does not guarantee that client has received data yet.
-
-
-### response.end([data][, callback])
-* `data` {Buffer | string}
-* `callback` {Function}
-
-Finishes sending the response.
-
-If `data` is provided, it sends `data` first, and finishes.
-If `callback` is specified, it is called when the response stream is finished.
-
-### response.getHeader(name)
-* `name` {string}
-
-Returns `name` field of response's header
-
-### response.removeHeader(name)
-* `name` {string}
-
-Removes `name` field from response's header
-
-### response.setHeader(name, value)
-* `name` {string}
-* `value` {string}
-
-Sets response's header field(`name`) to `value`. If the field exists, it overwrites the existing value.
-
-### response.setTimeout(ms, cb)
-
-* `ms` {number}
-* `cb` {Function}
-
-Registers cb for 'timeout' event and set socket's timeout value to ms. This event will be triggered by the underlying socket's 'timeout' event.
-
-### response.write(data[, callback])
-* `data` {Buffer | string}
-* `callback` {Function}
-
-Sends `data` as a response body. `callback` will be called when data is flushed.
-
-### response.writeHead(statusCode[, statusMessage][, headers])
-* `statusCode` {number}
-* `statusMessage` {string}
-* `headers` {Object}
-
-Sets response's header. `headers` is a map between field and value in header.
-
## Class: http.ClientRequest
-This object is created internally and returned from http.request(). It represents an in-progress request whose header has already been queued.
+This object is created internally and returned from `http.request()`. It represents an in-progress request whose headers have already been queued.
### Event: 'close'
This event is fired when the underlying socket is closed.
### Event: 'error'
-* `callback` {Function}
+Event callback arguments:
* `err` {Error}
Emitted if something went wrong with making or parsing the request.
This event is emitted after all the data was sent, meaning header and body all finished sending.
### Event: 'response'
-* `response` {http.IncomingMessage}
+Event callback arguments:
+* `response` {http.IncomingMessage} The incoming HTTP response from the server.
+
+This event is emitted when server's HTTP response header is parsed.
+The event is called only once. The developer should attach at least one event handler for this event
+to correctly process any data sent back by the target server.
-This event is emitted when server's response header is parsed. ` http.IncomingMessage` object is passed as argument to handler.
+**Example**
+
+```js
+var http = require('http');
+
+var options = {
+ host: 'localhost',
+ port: 8081,
+ method: 'GET',
+};
+var client_request = http.request(options);
+client_request.on('response', function(response) {
+ console.log('HTTP status: ' + response.statusCode);
+ console.log('Headers:');
+ console.log(response.headers);
+
+ response.on('data', function(chunk) {
+ console.log(chunk.toString());
+ });
+});
+client_request.end();
+```
### Event: 'socket'
+Event callback arguments:
* `socket` {net.Socket}
-This event is emitted when a socket is assigned to this request. `net.Socket` object is passed as argument to handler.
+This event is emitted when a socket is assigned to this request.
After response header is parsed, this event will be fired.
Will abort the outgoing request, dropping any data to be sent/received and destroying the underlying socket.
### request.end([data][, callback])
-* `data` {Buffer | string}
-* `callback` {Function}
+* `data` {Buffer | string} Data to be sent.
+* `callback` {Function} Callback function invoked when all data is processed.
Finishes sending the request.
If `data` is provided, it sends `data` first, and finishes.
If `callback` is specified, it is called when the request stream is finished.
-### request.setTimeout(ms, cb)
+This method must be called to close the request and to make sure all data is sent.
+
+**Example**
+
+```js
+var http = require('http');
+
+var message = 'HTTP Body POST Data';
+var options = {
+ host: 'localhost',
+ port: 8081,
+ method: 'POST',
+ headers: {'Content-Length': message.length},
+};
+var client_request = http.request(options, function(response) {
+ console.log('HTTP status: ' + response.statusCode);
+});
+client_request.end(message);
+```
+
+
+### request.setTimeout(ms[, callback])
* `ms` {number}
-* `cb` {Function}
+* `callback` {Function} The callback function registered for the `'timeout'` event.
-Registers cb for 'timeout' event and set socket's timeout value to ms. This event will be triggered by the underlying socket's 'timeout' event.
+Registers `callback` for 'timeout' event and set socket's timeout value to ms. This event will be triggered by the underlying socket's `'timeout'` event.
-If cb is not provided, the socket will be destroyed automatically after timeout.
-If you provides cb, you should handle the socket's timeout.
+If `callback` is not provided, the socket will be destroyed automatically after timeout.
+If `callback` is provied, the method should handle the socket's timeout.
### request.write(data[, callback])
-* `data` {Buffer | string}
+* `data` {Buffer | string} Data to be sent.
* `callback` {Function}
Sends `data` as a request body. `callback` will be called when data is flushed.
+**Example**
+
+```js
+var http = require('http');
+
+var message = "This is the data";
+var options = {
+ method: 'POST',
+ port: 8383,
+ path: '/',
+ headers: {'Content-Length': message.length},
+};
+
+var client_request = http.request(options);
+client_request.write(message);
+client_request.end();
+```
+
## Class: http.IncomingMessage
-This object is created internally and returned to the callback in http.request(). It represents the response sent by a server to a request.
+This object is created internally and returned to the callback for the http.ClientRequest `'response'` event and
+for the `'request'` event in the http.Server class.
+In case of the `http.ClientRequest` class this `IncomingMessage` will represent the response sent by a server for the given request.
+In case of the `http.Server` class this will represent the request sent by a client for the server.
-http.IncomingMessage inherits [`Stream.readable`](IoT.js-API-Stream.md). See it's documentation to read incoming data from an HTTP request. Notable events are `'data'` (fired when there is data to read), `'close'`, `'end'` (Request has ended) and the method `readable.read()`.
+http.IncomingMessage inherits [`Stream.readable`](IoT.js-API-Stream.md).
+See it's documentation to read incoming data from an HTTP request.
+Notable events are `'data'` (fired when there is data to read), `'close'`, `'end'` (Request has ended) and the method `readable.read()`.
### Event: 'close'
When underlying connection is closed, 'close' event is emitted.
+### Event: 'data'
+Event callback arguments:
+* `chunk` {Buffer} the buffer containing the data.
+
+Raised when there is data to be processed from the underlying socket.
+It is highly possible that this chunk of data is not the whole data,
+thus if the developer needs the whole data in one, each chunk must be
+stored. (See the example for a naive approach.)
+
+The HTTP headers are already parsed before this event is triggered.
+
+Please note that the total size of the data could be bigger
+than the memory available on the device where the code is running.
+
+
+**Example**
+
+```js
+var console = require('console');
+var http = require('http');
+
+var options = {
+ host: 'localhost',
+ port: 8081,
+ method: 'GET',
+ path: '/'
+};
+var client_request = http.request(options, function(response) {
+ var parts = [];
+ response.on('data', function(chunk) {
+ parts.push(chunk);
+ });
+ response.on('end', function() {
+ var body = Buffer.concat(parts);
+ console.log(body.toString());
+ });
+});
+client_request.end();
+```
+
### Event: 'end'
This event is fired when no more data to be received.
-
+At this point it is safe to assume all data was received from the other end.
### message.headers
-HTTP header object.
+A JavaScript object containing all HTTP headers sent by the other end.
### message.method
Requests method as `string`
+### message.httpVersion
+The HTTP version sent by the client. One of the following value: `'1.1'` or `'1.0'`.
+
### message.socket
-Underlying socket
+Underlying network socket (`net.Socket`).
### message.statusCode
HTTP response status code as `number` of 3-digit.
-### message.statusMessage
-HTTP response status message as `string`
-
### message.url
-Requests URL as `string`
+Request URL as `string`. Only contains the URL present in the HTTP request.
+
+Note: only valid if the `IncomingMessage` was constructed by a `http.Server`.
+
+**Example**
+
+If the HTTP request is the following:
+
+```
+GET /page/1?data=a HTTP/1.1 \r\n
+Accept: text/html\r\n
+\r\n
+```
+
+the `message.url` will be: `/page/1?data=a`.
+
+### message.statusMessage
+HTTP response status message as `string`.
### message.setTimeout(ms, cb)
* `cb` {Function}
Registers cb for 'timeout' event set socket's timeout value to ms. This event will be triggered by the underlying socket's 'timeout' event.
+
+
+## Class: http.ServerResponse
+
+Created internally when the `'request'` event is triggered by the `http.Server` class and
+represents the response sent by the server to a client.
+
+### Event: 'close'
+When underlying connection is closed, 'close' event is emitted.
+
+### Event: 'end'
+This event is fired when no more data to be sent.
+
+### Event: 'finish'
+This event is emitted when the response has been sent. It does not guarantee that client has received data yet.
+
+
+### response.end([data][, callback])
+* `data` {Buffer | string} Data which should be sent.
+* `callback` {Function}
+
+Finishes sending the response.
+
+If `data` is provided, it sends `data` first, and finishes.
+If `callback` is specified, it is called when the response stream is finished.
+
+The method should be called to correctly finish up a response.
+Any method which sets headers must be called before this method and before any `write` calls.
+
+**Example**
+
+```js
+var console = require('console');
+var http = require('http');
+
+var server = http.createServer(function(request, response) {
+ console.log('Request for path: ' + request.url);
+
+ var message = '<h1>Hello</h1>';
+
+ response.setHeader('Content-Type', 'text/html');
+ response.setHeader('Content-Length', message.length);
+ response.writeHead(200);
+ response.end(message);
+});
+
+var port = 8081
+server.listen(port, function() {
+ console.log('HTTP server listening on port: ' + port);
+});
+```
+
+### response.getHeader(name)
+* `name` {string} Case-sensitive HTTP header field name.
+
+Returns the value of the `name` HTTP header field.
+
+### response.removeHeader(name)
+* `name` {string} Case-sensitive HTTP header field name.
+
+Remove the HTTP header which has the `name` field name.
+HTTP headers can not be modified after the first `write`, `writeHead` or `end` method call.
+
+### response.setHeader(name, value)
+* `name` {string} The name of the HTTP header field to set.
+* `value` {string} The value of the field.
+
+Sets response's header field(`name`) to `value`. If the field exists, it overwrites the existing value.
+HTTP headers can not be modified after the first `write`, `writeHead` or `end` method call.
+
+### response.setTimeout(ms, cb)
+
+* `ms` {number}
+* `cb` {Function}
+
+Registers cb for 'timeout' event and set socket's timeout value to ms. This event will be triggered by the underlying socket's 'timeout' event.
+
+### response.write(data[, callback])
+* `data` {Buffer | string}
+* `callback` {Function}
+
+Sends `data` as a response body. `callback` will be called when data is flushed.
+
+It is advised to set at least the `Content-Length` HTTP header field correctly before
+any `write` calls. This is so the client could properly handle the server response.
+
+After a `write` method was called there is no possibility to change any headers.
+
+**Example**
+
+```js
+var console = require('console');
+var http = require('http');
+
+var server = http.createServer(function(request, response) {
+ console.log('Request for path: ' + request.url);
+
+ var message = '<h1>Hello</h1>';
+
+ response.setHeader('Content-Type', 'text/html');
+ response.setHeader('Content-Length', message.length);
+ response.writeHead(200);
+ response.write(message);
+ response.end();
+});
+
+var port = 8081
+server.listen(port, function() {
+ console.log('HTTP server listening on port: ' + port);
+});
+```
+
+### response.writeHead(statusCode[, statusMessage][, headers])
+* `statusCode` {number}
+* `statusMessage` {string} Optional. If not set the HTTP status message will be inferred from the status code.
+* `headers` {Object} Optional. An object containing HTTP header field names and values.
+
+Sets response status code, the status message and configures a set of HTTP
+header values.
+
+**Example**
+
+```js
+var console = require('console');
+var http = require('http');
+
+var server = http.createServer(function(request, response) {
+ console.log('Request for path: ' + request.url);
+
+ var message = '<h1>Hello</h1>';
+
+ response.writeHead(200, 'OK', {
+ 'Content-Type': 'text/html',
+ 'Content-Length': message.length,
+ });
+ response.write(message);
+ response.end();
+});
+
+var port = 8081
+server.listen(port, function() {
+ console.log('HTTP server listening on port: ' + port);
+});
+```
IoT.js provides HTTPS to support HTTPS clients enabling users to send HTTPS requests easily.
+### https.createServer([options][, requestListener])
+* `options` {Object} Accepts the same `options` as [tls.createServer](IoT.js-API-TLS.md#tlscreateserveroptions-secureconnectionlistener) and [http.createServer](IoT.js-API-HTTP.md#httpcreateserverrequestlistener) methods.
+* `requestListener` {Function}
+ * request {http.IncomingMessage}
+ * response {http.ServerResponse}
+* Returns: {https.Server}
+
+To create a server the certificates should be specified via the `options` object.
+
+The `requestListener` is a function which is automatically added to the `'request'` event.
+
+**Example**
+
+```js
+var options = {
+ key: fs.readFileSync('server.key'),
+ cert: fs.readFileSync('server.cert')
+};
+var server = https.createServer(options, function(request, response) {
+ ...
+});
+```
+
+
### https.request(options[, callback])
* `options` {Object}
* `host` {string} A domain name or IP address of the server to issue the request to. **Default:** 'localhost'.
* `hostname` {string} Alias for host.
- * `port` {number} Port of remote server. **Default:** 80.
+ * `port` {number} Port of remote server. **Default:** 443.
* `method` {string} A string specifying the HTTPS request method. **Default:** 'GET'.
* `path` {string} Request path. **Default:** '/'. Should include query string if any. E.G. '/index.html?page=12'. An exception is thrown when the request path contains illegal characters. Currently, only spaces are rejected but that may change in the future.
* `headers` {Object} An object containing request headers.
* `key` {string} Optional file path to private keys for client cert in PEM format.
* `rejectUnauthorized` {boolean} Optional Specify whether to verify the Server's certificate against CA certificates. WARNING - Making this `false` may be a security risk. **Default:** `true`
* `callback` {Function}
- * `response` {https.IncomingMessage}
-* Returns: {https.ClientRequest}
+ * `response` {http.IncomingMessage}
+* Returns: {http.ClientRequest}
Example:
```javascript
* `options` {Object}
* `host` {string} A domain name or IP address of the server to issue the request to. **Default:** 'localhost'.
* `hostname` {string} Alias for host.
- * `port` {number} Port of remote server. **Default:** 80.
+ * `port` {number} Port of remote server. **Default:** 443.
* `method` {string} A string specifying the HTTPS request method. **Default:** 'GET'.
* `path` {string} Request path. **Default:** '/'. Should include query string if any. E.G. '/index.html?page=12'. An exception is thrown when the request path contains illegal characters. Currently, only spaces are rejected but that may change in the future.
* `headers` {Object} An object containing request headers.
* `key` {string} Optional file path to private keys for client cert in PEM format.
* `rejectUnauthorized` {boolean} Optional Specify whether to verify the Server's certificate against CA certificates. WARNING - Making this `false` may be a security risk. **Default:** `true`
* `callback` {Function}
- * `response` {https.IncomingMessage}
-* Returns: {https.ClientRequest}
+ * `response` {http.IncomingMessage}
+* Returns: {http.ClientRequest}
Same as `https.request` except that `https.get` automatically call `req.end()` at the end.
...
});
```
-
-
-### https.METHODS
-A list of HTTPS methods supported by the parser as `string` properties of an `Object`.
-
-
-## Class: https.ClientRequest
-
-This object is created internally and returned from https.request(). It represents an in-progress request whose header has already been queued.
-
-See also: [http.ClientRequest](IoT.js-API-HTTP.md#class-httpclientrequest)
-
-## Class: https.IncomingMessage
-
-This object is created internally and returned to the callback in https.request(). It represents the response sent by a server to a request.
-
-See also: [http.IncomingMessage](IoT.js-API-HTTP.md#class-httpincomingmessage)
### Platform Support
-The following chart shows the availability of each TLS module API function on each platform.
+The following chart shows the availability of each MQTT module API function on each platform.
| | Linux<br/>(Ubuntu) | Tizen<br/>(Raspberry Pi) | Raspbian<br/>(Raspberry Pi) | Nuttx<br/>(STM32F4-Discovery) | TizenRT<br/>(Artik053) |
| :---: | :---: | :---: | :---: | :---: | :---: |
-| mqtt.getClient | O | X | X | X | X | X |
-| mqtt.publish | O | X | X | X | X | X |
-| mqtt.subscribe | O | X | X | X | X | X |
-| mqtt.unsubscribe | X | X | X | X | X | X |
-| mqtt.ping | O | X | X | X | X | X |
-| mqtt.connect | O | X | X | X | X | X |
+| mqtt.connect | O | O | O | X | O |
+| mqtt.end | O | O | O | X | O |
+| mqtt.publish | O | O | O | X | O |
+| mqtt.subscribe | O | O | O | X | O |
+| mqtt.unsubscribe | O | O | O | X | O |
# MQTT
## Class: MQTTClient
The `MQTTClient` can subscribe or publish data to a broker. It sends data over a `net.socket`.
-### mqtt.getClient(options)
+### mqtt.connect([url], [options], [callback])
+- `url` {string} host name optionally prefixed by `mqtt://` or `mqtts://`.
- `options` {Object}
- - `clientId` {Buffer | string} Optional. The broker identifies each client by its `clientId`. If not specified, a randomly generated `clientId` is created.
- - `host` {Buffer | string} The address of the broker.
- - `port` {number} The port of the broker.
+ - `clientId` {Buffer | string} Optional. The broker identifies each client by its `clientId`. If not specified, a randomly generated `clientId` is created.
+ - `host` {Buffer | string} The address of the broker.
+ - `port` {number} The port of the broker.
+ - `socket` {net.Socket | TLSSocket} If a `TLSSocket` is given for secure communication it is the user's responsibility to connect it to establish the TLS connection first. Otherwise the client automatically connects the socket to the server.
- `username` {Buffer | string} Optional. Use username when onnecting to a broker.
- `password` {Buffer | string} Optional. Use password authentication when connecting to a broker.
- `keepalive` {number} Keepalive time in seconds. If no data is sent on the connection in the given time window the broker disconnects the client.
- `qos` {number} If `will` is set to `true`, the message will be sent with the given QoS.
- `topic` {Buffer | string} Only processed when `will` is set to `true`. The topic the `message` should be sent to.
- `message` {Buffer | string} Only processed when `will` is set to `true`. The message to be sent to the broker when connecting.
+- `callback` {function} the function which will be executed when the client successfuly connected to the broker.
-Returns an MQTTClient.
+Returns with an MQTTClient object and starts connecting to a broker. Emits a `connect` event after the connection is completed.
-### mqtt.connect(callback)
-- `callback` {function} The function will be executed when the client successfuly connected to the broker.
-
-Connects the client to a broker. Emits a `connect` event.
**Example**
```js
var mqtt = require('mqtt');
var opts = {
- host: '127.0.0.1',
- port: 443,
- keepalive: 10,
- clientId: 'IoT.js Client',
+ port: 443,
+ keepalive: 10,
+ clientId: 'IoT.js Client',
}
-var client = mqtt.getClient(opts);
-client.connect(function () {
- client.disconnect();
+var client = mqtt.connect('mqtt://127.0.0.1', opts, function () {
+ client.end();
});
```
-### mqtt.disconnect()
-Disconnects the client from the broker.
-
-### mqtt.ping()
-Sends a ping request to the server. If the server doesn't respond within 3 seconds, the client closes the connection. Emits a `pingresp` event if the server responded.
-
-**Example**
-```js
-var mqtt = require('mqtt');
-
-var opts = {
- host: '127.0.0.1',
- port: 443,
- keepalive: 10,
- clientId: 'IoT.js Client',
-}
-
-var client = mqtt.getClient(opts);
-client.connect(function () {
- client.ping();
-});
+### mqtt.end([force])
+- `force` {boolean} force network connection abort
-client.on('pingresp', function() {
- client.disconnect();
-});
-```
+Disconnects the client from the broker.
-### mqtt.subscribe(options)
+### mqtt.subscribe(topic, [options], [callback])
+- `topic` {Buffer | string} topic to subscribe to
- `options` {Object}
- - `topic` {Buffer | string} The topic the client subscribes to.
- `qos` {number} Optional. Defaults to 0.
- `retain` {boolean} Optional. If retain is `true` the client receives the messages that were sent to the desired `topic` before it connected. Defaults to `false`.
+- `callback` {function} the function which will be executed when the subscribe is completed.
+
The client subscribes to a given `topic`. If there are messages available on the `topic` the client emits a `data` event with the message received from the broker.
var mqtt = require('mqtt');
var opts = {
- host: '127.0.0.1',
- port: 443,
- keepalive: 10,
- clientId: 'IoT.js Client',
+ host: '127.0.0.1',
+ port: 443,
+ keepalive: 10,
+ clientId: 'IoT.js Client',
}
var subscribe_opts {
- topic: 'hello/#/iotjs',
retain: false,
qos: 2
}
-var client = mqtt.getClient(opts);
-client.connect(function () {
- client.subscribe(subscribe_opts);
+var client = mqtt.connect(opts, function () {
+ client.subscribe('hello/#/iotjs', subscribe_opts, function(error) {
+ if (error) {
+ console.log('Subscribe is failed');
+ } else {
+ console.log('Subscribe is successfully completed');
+ }
+ });
});
-client.on('data', function(data) {
- console.log('I received something: ' + data.toString());
+client.on('message', function(data) {
+ console.log('I received something: ' + data.message.toString());
});
```
-### mqtt.unsubscribe(topic)
-- `options` {Buffer | string} The topic to unsubscribe from.
+### mqtt.unsubscribe(topic, [callback])
+- `topic` {Buffer | string} topic to unsubscribe from
+- `callback` {function} the function which will be executed when the unsubscribe is completed.
Unsubscribes the client from a given topic. If QoS was turned on on the subscription the remaining packets will be sent by the server.
-### mqtt.publish(options)
+### mqtt.publish(topic, message, [options], [callback])
+- `topic` {Buffer | string} topic to publish to
+- `message` {Buffer | string} message to send
- `options` {Object}
- - `topic` {Buffer | string} The topic to send the `message` to.
- - `message` {Buffer | string} The message to be sent.
- `qos` {number} Optional. Defaults to 0.
- `retain` {boolean} Optional. If retain is `true` the broker stores the message for clients subscribing with retain `true` flag, therefore they can receive it later.
+- `callback` {function} the function which will be executed when the publish is completed
+
Publishes a `message` to the broker under the given `topic`.
var mqtt = require('mqtt');
var opts = {
- host: '127.0.0.1',
- port: 443,
- keepalive: 10,
- clientId: 'IoT.js Client',
-}
-
-var publish_opts {
- topic: 'hello/#/iotjs',
- message: 'MQTT now works!',
- retain: false,
- qos: 1
+ host: '127.0.0.1',
+ port: 443,
+ keepalive: 10,
+ clientId: 'IoT.js Client',
}
-var client = mqtt.getClient(opts);
-client.connect(function () {
- client.publish(publish_opts);
+var client = mqtt.connect(opts, function () {
+ client.publish('hello/#/iotjs', 'Hello MQTT clients!', { qos:1 }, function() {
+ console.log('Message has been published');
+ });
});
```
- `topic`: The topic the message was sent from.
- `qos`: The QoS level the message was sent with.
- `packet_id`: The id of the packet if QoS was enabled.
-
-### `pingresp`
-Emitted when we receive a ping response from the server.
-
-### `puback`
-`puback` is emitted if the server has successfully received the QoS 1 packet sent with `publish`.
-
-### `pubcomp`
-If a QoS level 2 package has successfully arrived a `pubcomp` is emitted.
-
-### `suback`
-If a subscription was accepted by the broker to a topic, a `suback` event is emitted.
```
+### readable.pipe(destination[, options])
+* `destination` {Writable|Duplex}
+* `options`
+ * `end` {bool} **Default: `true`**
+* returns: {Writable|Duplex}
+
+Attaches a Writable or Duplex stream to the Readable. Automatically
+switches the Readable stream into flowing mode and pushes all of its
+data into the attached Writable.
+
+**Example**
+```js
+var stream = require('stream');
+var Readable = stream.Readable;
+var Writable = stream.Writable;
+
+var source = new Readable();
+var dest = new Writable();
+
+dest._write = function(chunk, callback, onwrite) {
+ console.log('dest received: ', chunk.toString());
+};
+dest._readyToWrite();
+
+source.pipe(dest);
+source.push('hello'); // the dest._write function will print the data
+```
+
+It is also possible to attach multiple Writable streams to a single
+Readable stream.
+The `readable.pipe()` method returns a reference to the `destination` stream,
+making it possible to set up a chain of piped streams
+(only if `destination` is Duplex).
+
+**Example**
+```js
+var stream = require('stream');
+var Readable = stream.Readable;
+var Writable = stream.Writable;
+
+var source = new Readable();
+var dest = new Duplex();
+var dest2 = new Duplex();
+
+dest._write = function(chunk, callback, onwrite) {
+ console.log('dest received: ', chunk.toString());
+};
+dest._readyToWrite();
+
+dest2._write = function(chunk, callback, onwrite) {
+ console.log('dest2 received: ', chunk.toString());
+};
+dest2._readyToWrite();
+
+source.pipe(dest).pipe(dest2);
+source.push('hello'); // dest and dest2 will receive and print the data
+```
+
+By default, the `end()` method of the `destination` stream is called when the
+Readable emits `end`. This behavior can be disabled by passing the `end`
+option as `false` to the `Readable.pipe()` method.
+
+Note: in case of a stream error, the attached streams will NOT be closed
+automatically. If a stream error occurs, each of the attached streams must
+be closed manually.
+
+
+### readable.unpipe([destination])
+* `destination` {Writable|Duplex}
+* returns: `this`
+
+Detaches a previously attached stream from the Readable.
+If the optional `destination` argument is not specified, all attached streams
+will be detached.
+If `destination` is specified but there is no pipe set up for it, then the
+method simply returns and does nothing.
+
+**Example**
+```js
+var stream = require('stream');
+var Readable = stream.Readable;
+var Writable = stream.Writable;
+
+var source = new Readable();
+var dest = new Writable();
+
+dest._write = function(chunk, callback, onwrite) {
+ console.log('dest received: ', chunk.toString());
+};
+dest._readyToWrite();
+
+source.pipe(dest);
+source.push('hello'); // the dest._write function will print the data
+source.unpipe(dest); // source.unpipe() has the same effect in this case
+source.push(world); // dest will not receive the data anymore
+```
+
+Note: if multiple streams are piped together in a chain, unpiping the first one
+from the readable will not unpipe the rest of them.
+
+**Example**
+```js
+source.pipe(dest).pipe(dest2).pipe(dest3).pipe(dest4);
+// ... some code ...
+source.unpipe(dest);
+// dest will no longer be piped to source, but dest2 will still be
+// piped to dest, etc
+```
+
+
# Class: Stream.Writable
Writable stream is an abstraction for a *destination*
| | Linux<br/>(Ubuntu) | Tizen<br/>(Raspberry Pi) | Raspbian<br/>(Raspberry Pi) | Nuttx<br/>(STM32F4-Discovery) | TizenRT<br/>(Artik053) |
| :---: | :---: | :---: | :---: | :---: | :---: |
-| tls.connect | X | O | O | O | O | O |
-| tls.write | X | O | O | O | O | O |
-| tls.pause | X | O | O | O | O | O |
-| tls.end | X | O | O | O | O | O |
-| tls.resume | X | O | O | O | O | O |
-| tls.pause | X | O | O | O | O | O |
+| tls.connect | O | O | O | O | O | O |
+| tls.createServer | O | O | O | O | O | O |
+| tls.createSecureContext | O | O | O | O | O | O |
+| tls.Server | O | O | O | O | O | O |
+| tls.TLSSocket | O | O | O | O | O | O |
+| tls.TLSSocket.write | O | O | O | O | O | O |
+| tls.TLSSocket.pause | O | O | O | O | O | O |
+| tls.TLSSocket.end | O | O | O | O | O | O |
+| tls.TLSSocket.resume | O | O | O | O | O | O |
+| tls.TLSSocket.pause | O | O | O | O | O | O |
+
+As even a couple of sockets/servers/requests require a considerable size of memory, on NuttX/STM32F4-Discovery and TizenRT/Artik053
+the number of such sockets are limited.
# TLS
Transport Layer Security makes secure communication over sockets possible.
-## Class: tls.TLSSocket
-The `TLSSocket` is responsible for all TLS negotiations and data encryption on a `net.Socket`.
-
-Just like `net.Socket` it uses a `Stream.duplex` interface.
-
-### new tls.TLSSocket(socket[,options])
-- `socket` {net.Socket | stream.Duplex}
-- `options` {Object}
- - `session` {Buffer} Optional, `Buffer` instance containing a TLS session.
-
-Note: `tls.connect()` must be used to create the socket.
-
### tls.connect(options[,callback])
-- `options` {Object}
- - `host` {string} Host the client should connect to, defaults to 'localhost'.
- - `port` {number} Port the client should connect to.
- - `socket` {stream.Duplex} Optional, typically an instance of `net.Socket`. If this options is specified, host and port are ignored. The user passing the options is responsible for it connecting to the server. `tls.connect` won't call `net.connect` on it.
- - `rejectUnauthorized` {boolean} Whether the server certificate should be verified against the list of supplied CAs. An `error` event is emitted if verifications fails; `err.code` contains the MbedTLS error code. Defaults to `false`. NOT READY
- - `servername` {string} Server name for the SNI (Server name Indication) TLS extension. NOT READY
- - `session` {Buffer} A `Buffer` containing a TLS session. NOT READY
- - `minDHSize` {number} The minimum size of the DH parameter in bits to accept a TLS connection. If a server offers a DH parameter with a size less than specified, the TLS connection is destroyed and an error is thrown. Defaults to `1024`.
- - `lookup` {Function} Custom lookup. Defaults to `dns.lookup()`.
-- `callback` {Function} The callback function will be added as a listener for the `secureConnect` event.
+* `options` {Object}
+ * `host` {string} Host the client should connect to, defaults to 'localhost'.
+ * `port` {number} Port the client should connect to.
+ * `socket` {stream.Duplex} Optional, typically an instance of `net.Socket`. If this options is specified, host and port are ignored. The user passing the options is responsible for it connecting to the server. `tls.connect` won't call `net.connect` on it.
+ * `rejectUnauthorized` {boolean} Whether the server certificate should be verified against the list of supplied CAs. An `error` event is emitted if verifications fails; `err.code` contains the MbedTLS error code. Defaults to `false`. NOT READY
+ * `servername` {string} Server name for the SNI (Server name Indication) TLS extension. NOT READY
+ * `session` {Buffer} A `Buffer` containing a TLS session. NOT READY
+ * `minDHSize` {number} The minimum size of the DH parameter in bits to accept a TLS connection. If a server offers a DH parameter with a size less than specified, the TLS connection is destroyed and an error is thrown. Defaults to `1024`.
+ * `lookup` {Function} Custom lookup. Defaults to `dns.lookup()`.
+* `callback` {Function} The callback function will be added as a listener for the `secureConnect` event.
Returns a `tls.TLSSocket` object.
**Example**
+
```js
var tls = require('tls');
```
### tls.connect(port[,host][,options][,callback])
-- `port` {number} Port the client should connect to.
-- `host` {string} Host the client should connect to, defaults to 'localhost'.
-- `options` {Object} See `tls.connect()`.
-- `callback` {Function} See `tls.connect()`.
+* `port` {number} Port the client should connect to.
+* `host` {string} Host the client should connect to, defaults to 'localhost'.
+* `options` {Object} See `tls.connect()`.
+* `callback` {Function} See `tls.connect()`.
Same as tls.connect() except that port and host can be provided as arguments instead of options.
A port or host option, if specified, will take precedence over any port or host argument.
**Example**
+
```js
var tls = require('tls');
});
```
+### tls.createServer([options][, secureConnectionListener])
+* `options` {object} Accepts the same options as the `tls.Server()` and `tls.createSecureContext()`.
+* `secureConnectionListener` {Function}
+ * `socket` {tls.TLSSocket} The connected TLSSocket.
+* Returns {tls.Server}
+
+Create a TLS Server. Behaves the same way as the `new tls.Server(options, secureConnectionListener)`
+call.
+
+**Example**
+
+```js
+
+var fs = require('fs');
+var tls = require('tls');
+var options = {
+ key: fs.readFileSync('server.key'),
+ cert: fs.readFileSync('server.crt')
+};
+var server = tls.createServer(options, function(socket) {
+ console.log('got connection');
+ ...
+});
+
+server.listen(8081);
+```
+
+
+### tls.createSecureContext([options])
+* `options` {object}
+ * `ca` {string | Buffer} Optional trusted CA certificates. No default is provided.
+ * `cert` {string | Buffer} Cert chains in PEM format.
+ * `key` {string | Buffer} Private keys in PEM format.
+* Returns {Object}
+
+The method returns a special object containing the tls context and credential information.
+
+## Class: tls.Server
+
+A server object repesenting a TLS server. Based on the `net.Server`.
+All events, methods and properties are inherited from the `net.Server`.
+
+### new tls.Server([options][, secureConnectionListener])
+
+* `options` {object} Options for the TLS connection.
+ * `secureContext` {object} An special object containing the tls credential information.
+ This should be only created via a `tls.createSecureContext()` call if needed. If not provided
+ a secureContext will be created automatically, using the `options` object. No default value is provided.
+ * Additonal options are from `tls.createSecureContext()`.
+* `secureConnectionListener` {Function}
+ * `socket` {tls.TLSSocket}
+* Returns {tls.Server}
+
+Creates new `tls.Server` object. The `secureConnectionListener` method is automatically set
+as a listener for the `'secureConnection'` event.
+
+To correctly create a TLS Server the server certificates should be provided in the `options`
+object.
+
+**Example**
+
+```js
+var fs = require('fs');
+var tls = require('tls');
+var options = {
+ key: fs.readFileSync('server.key'),
+ cert: fs.readFileSync('server.crt')
+};
+var server = new tls.Server(options, function(socket) {
+ console.log('got connection');
+ ...
+});
+
+server.listen(8081);
+```
+
+## Class: tls.TLSSocket
+The `TLSSocket` is responsible for all TLS negotiations and data encryption on a `net.Socket`.
+
+Just like `net.Socket` it uses a `Stream.duplex` interface.
+
+### new tls.TLSSocket(socket[,options])
+* `socket` {net.Socket | stream.Duplex}
+* `options` {Object}
+ * `isServer` {boolean} The TLSSocket must know if it represents the server or client side of the connection. Default: `false`.
+ * `secureContext` {Object} The TLS context object. If none provided one will be created with the `tls.createSecureContext` method
+ using the given `options` object.
+* Returns {tls.TLSSocket}
+
+Creates a new TLSSocket object for an existing TCP socket.
+
### tlsSocket.address()
Returns an object containing the bound address, family name, and port of the socket.`{port: 443, family: 'IPv4', address: '127.0.0.1'}`
### Event: 'data'
* `callback` {Function}
- * `data` {string} A string from the sender.
+ * `data` {Buffer} A data from the sender.
**Example**
--- /dev/null
+### Platform Support
+
+The following chart shows the availability of each WebSocket module API function on each platform.
+
+| | Linux<br/>(Ubuntu) | Tizen<br/>(Raspberry Pi) | Raspbian<br/>(Raspberry Pi) | Nuttx<br/>(STM32F4-Discovery) | TizenRT<br/>(Artik053) |
+| :---: | :---: | :---: | :---: | :---: | :---: |
+| websocket.connect | O | O | O | X | O |
+| websocket.close | O | O | O | X | O |
+| websocket.ping | O | O | O | X | O |
+| websocket.send | O | O | O | X | O |
+
+# WebSocket
+
+WebSocket provides full-duplex communication over a TCP connection. It is designed to work over HTTP ports 80 and 443.
+
+### Requirements
+WebSocket requires you to enable both the `TLS` and the `WebSocket` module. This can be done by compiling IoT.js with `--cmake-param=-DENABLE_MODULE_WEBSOCKET=ON`. Currently WebSocket only works if TLS is enabled as well.
+
+## Class: Websocket.Server
+Create a new Websocket server instance.
+
+### Websocket.Server(options[, callback])
+Create a new server instance. One of `port` or `server` must be provided or an error is thrown. An HTTP server is automatically created, started, and used if `port` is set. If `secure` is set TLS server is automatically created, started and used. The `tls` module is required or an error is thrown. To use an external HTTP/S server instead, specify only `server`. In this case the HTTP/S server must be started manually.
+
+- `options` {Object}
+ - `port` {Number}
+ - `host` {String} Optional. Defaults to `localhost`.
+ - `server` {Object} Optional.
+ - `path` {String} Optional. Defaults to `/`.
+ - `secure` {Boolean} Optional.
+ - `key` {String} Optional. (Required on `secure` server)
+ - `cert` {String} Optional. (Required on `secure` server)
+- `callback` {Function} Optional. The function which will be executed when the client successfully connected to the server.
+
+Emits a `connection` event when the connection is established.
+
+**Example**
+```js
+var websocket = require('websocket');
+
+var options = {
+ port: 9999
+}
+
+var server = new websocket.Server(options, Listener);
+
+function Listener(ws) {
+ console.log('Client connected: handshake done!');
+ ws.on('message', function (msg) {
+ console.log('Message received: %s', msg.toString());
+ ws.send(msg.toString(), {mask: true, binary: false}); //echo
+ server.close();
+ });
+ ws.on('ping', function (msg) {
+ console.log('Ping received: %s', msg.toString());
+ });
+ ws.on('close', function (msg) {
+ console.log('Client close :\n'
+ 'Reason: ' + msg.reason + ' Code: ' + msg.code);
+ });
+ ws.on('error', function (msg) {
+ console.log('Error: %s', msg.toString());
+ });
+
+server.broadcast('Message to all clients', {mask: false, binary: false});
+};
+
+server.on('error', function (msg) {
+ console.log('Error: %s', msg.toString());
+});
+
+server.on('close', function (msg) {
+ console.log('Server close: \nReason: ' +
+ msg.reason + ' Code: ' + msg.code);
+});
+```
+
+**Example using http server**
+```js
+var websocket = require('websocket');
+var http = require('http');
+
+var httpserver = http.createServer().listen(9999);
+
+options = {
+ server: httpserver
+};
+
+var wss3 = new websocket.Server(options, Listener);
+
+function Listener(ws) {
+ console.log('Client connected: handshake done!');
+};
+```
+
+### server.address()
+
+Returns an object with `port`, `family`, and `address` properties specifying
+the bound address, the family name, and port of the server.
+
+**Example**
+```js
+var websocket = require('websocket');
+
+var options = {
+ port: 9999
+}
+
+var server = new websocket.Server(options, function(ws) {
+});
+
+console.log(server.address());
+```
+
+### server.close([reason], [code])
+You can specify a close message and a close code as well. More info on them can be read here: [https://tools.ietf.org/html/rfc6455#section-7.4.1](https://tools.ietf.org/html/rfc6455#section-7.4.1 "The WebSocket Protocol Status Codes")
+
+- `reason` {String} Optional. Defaults to `Connection successfully closed`.
+- `code` {Number} Optional. Defaults to `1000`.
+
+Close the Websocket server, terminate all clients and emit the `close` event.
+
+**Example**
+```js
+var websocket = require('websocket');
+
+var options = {
+ port: 9999
+}
+
+var server = new websocket.Server(options, Listener);
+
+function Listener(ws) {
+ console.log('Client connected: handshake done!');
+ server.close('Connection successfully closed', 1000);
+};
+```
+
+### server.broadcast(message [, options])
+You can specify a message that will be sent to every clients.
+The `mask` will specify whether the data frame should be masked or not.
+The `binary` will specify that if the data frame mode should be text or binary, default to text.
+More info on them can be read here: [https://tools.ietf.org/html/rfc6455#section-5.6](https://tools.ietf.org/html/rfc6455#section-5.6 "The WebSocket Protocol Data Frames")
+
+- `message` {String}
+- `options` {Object} Optional.
+ - `mask` {Boolean} Optional. Defaults to `true`.
+ - `binary` {Boolean} Optional. Defaults to `false`.
+
+Send message to all clients.
+
+**Example**
+```js
+var websocket = require('websocket');
+
+var options = {
+ port: 9999
+}
+
+var server = new websocket.Server(options, Listener);
+
+function Listener(ws) {
+ console.log('Client connected: handshake done!');
+};
+
+server.broadcast('Message to receive all client',
+ {mask: true, binary: false});
+```
+
+### Event: 'connection'
+
+- `socket` {Websocket}
+
+Emitted when the handshake is complete.
+
+### Event: 'close'
+
+- `message` {Object}
+ - `reason` {String}
+ - `code` {Number}
+
+Emitted when the server close.
+
+### Event: 'error'
+
+- `error` {Error}
+
+Emmitted when an error occurs on the server.
+
+## Class: Websocket
+The `Websocket` client can simultaneously receive and send data. Both `net` and `TLS` sockets are supported, however the latter is recommended, since `websocket` itself doesn't provide a secure enough context to communicate sensitive data.
+
+### websocket.connect([host], [port], [path], [callback])
+Connects to a `websocket` server, host names can be prefixed with `ws://` or `wss://`.
+- `host` {string} Optional. Defaults to `localhost`.
+- `port` {number} Optional. Defaults to `80` if the `host` begins with `ws://` or `443` with `wss://`.
+- `path` {Buffer | string} Optional. Defaults to `/`. If given, the client connects to that `endpoint`.
+- `callback` {function} Optional. The function which will be executed when the client successfully connected to the server.
+
+Emits an `open` event when the connection is established.
+
+**Example**
+```js
+var ws = require('websocket');
+
+var my_websocket = new ws.Websocket();
+
+my_websocket.connect('wss://127.0.0.1', 443, '/my_endpoint', function() {
+ my_websocket.close('Successful connection', 1000);
+});
+
+```
+
+### websocket.close([message], [code], [callback])
+Closes the `websocket` connection with the server. You can specify a close `message` and a close `code` as well. More info on them can be read here: https://tools.ietf.org/html/rfc6455#section-7.4.1
+- `message` {Buffer | string} Optional. This `message` is sent to the server as a close message, mostly for explaining the status `code`.
+- `code` {number} Optional. The `code` indicates the reason why the `websocket` connection was closed. Defaults to 1000.
+- `callback` {function} Optional. The function will be executed when the `websocket` connection is closed.
+
+Emits a `close` event when the connection is closed.
+
+### websocket.ping([message], [mask], [callback])
+Sends a `ping` to the server. If there is no response in the next 30 seconds, the connection is closed.
+- `message` {Buffer | string} Optional. The `message` is used to identify the `ping` frame.
+- `mask` {boolean} Optional. Defaults to `false`. Sets to mask the `message` or not.
+- `callback` {function} Optional. The function to be executed when the server sends a response to the `ping`.
+
+**Example**
+```js
+my_websocket.ping('Ping frame 1', true, function(msg) {
+ console.log('Pong frame successfully received for frame ' + msg);
+});
+
+```
+
+### websocket.send([message], [options], [callback])
+Sends data to the server. It can be either `binary` or `utf8` data.
+- `message` {Buffer | string} The `message` to be sent to the server.
+- `options` {Object}
+ - `mask` {boolean} Optional. Defaults to `false`. If set, the `message` is masked.
+ - `binary` {boolean} Optional. Defaults to `false`. If set, the `message` is expected to be binary data.
+- `callback` {function} Optional. The function to be executed when the `frame` is successfully sent.
+
+**Example**
+```js
+my_websocket.send('My first WebSocket message!', {mask: true, binary: false}, function() {
+ console.log('The data was successfully written to the socket!');
+});
+```
+
+## Events
+
+### `close`
+Having closed the `websocket` connection, with the server, a `close` is emitted.
+
+### `error`
+If an `error` occurs, the `error` event is emitted, with the corresponding error message.
+
+### `message`
+The `message` event is emitted when the client receives data from the server.
+
+### `open`
+Emitted when the client established a `websocket` connection with the server.
./tools/build.py --buildtype=release
```
-## Parameters Candidates
-**NOTE: some parameters are not supported by current version of build.py**
+### Arguments of IoT.js
+The following arguments are related to the IoT.js framework.
---
+---
#### `--buildtype`
* `release` | `debug`
./tools/build.py --buildtype=release
```
---
+---
#### `--builddir`
Specify a directory where build outputs will be generated.
./tools/build.py --builddir=./build
```
---
-#### `--clean`
-With given this option, build.py will clear all the build directory before start new build.
-
-```
-./tools/build.py --clean
-```
-
---
+---
#### `--buildlib`
With given this option, build.py will generate IoT.js output as a library.
./tools/build.py ---buildlib
```
---
-#### `--profile`
-With given this option, build.py will use the specified profile for the build.
+---
+#### `--cmake-param`
+Specify CMake parameters for IoT.js.
+
+"cmake" command for IoT.js will be executed with the given parameter applied.
+
+If you have multiple parameters, supply it with multiple use of this option;
```
-./tools/build.py --profile=./profiles/minimal.profile
+./tools/build.py --cmake-param="..." --cmake-param="..."
```
---
-#### `--target-arch`
-* `arm` | `x86` | `i686` | `x86_64` | `x64`
+---
+#### `--compile-flag`
+Specify C compiler flags for IoT.js.
-Specify target architecture.
+If you have multiple compile flags, supply it with multiple use of this option;
+```
+./tools/build.py --compile-flag="..." --compile-flag="..."
+```
+
+---
+#### `--clean`
+With given this option, build.py will clear all the build directory before start new build.
```
-./tools/build.py --target-arch=arm
+./tools/build.py --clean
```
---
-#### `--target-os`
-* `linux` | `darwin` | `osx` | `nuttx`
-Specify target OS.
+---
+#### `--config`
+Specify build configuration file path.
```
-./tools/build.py --target-os=nuttx --target-arch=arm
+./tools/build.py --config=build.arm.nuttx.stm32f4dis.config
```
---
-#### `--target-board`
-* `stm32f4dis` | empty
+`build.default.config` file is in the source tree for default setting.
-Specify target board.
+If this option is not specified, `build.config` file will be applied. If the file does not exist, it will be copied from `build.default.config`.
+
+Parameters specified by the config file is applied, and then the parameters given by command line overwrite over the settings.
+
+If you need to apply the same set of parameters for each build, making your own config file and trigger build.py with the config file would be more convenient.
+
+---
+#### `-e, --experimental`
+Enable to build experimental features
```
-./tools/build.py --target-os=nuttx --target-arch=arm --target-board=stm32f4dis
+./tools/build.py --experimental
```
---
-#### `--cmake-param`
-Specify CMake parameters for IoT.js.
-"cmake" command for IoT.js will be executed with the given parameter applied.
+---
+#### `--external-include-dir`
+Specify external include directory for IoT.js.
-If you have multiple parameters, supply it with multiple use of this option;
+If you have multiple external include directoies, supply it with multiple use of this option;
+```
+./tools/build.py --external-include-dir="..." --external-include-dir="..."
+```
+---
+#### `--external-lib`
+Specify external library that will be linked with IoT.js.
+
+If you have multiple such libraries, supply it with multiple use of this option;
```
-./tools/build.py --cmake-param="..." --cmake-param="..."
+./tools/build.py --external-lib="libxxx"
```
---
-#### `--compile-flag`
-Specify C compiler flags for IoT.js.
+---
+#### `--external-modules`
+Specify the path of modules.json files which should be processed (format: path1,path2,...).
+See also: ["How to write a new module"](../devs/Writing-New-Module.md)
-If you have multiple compile flags, supply it with multiple use of this option;
```
-./tools/build.py --compile-flag="..." --compile-flag="..."
+./tools/build.py --external-modules=/home/iotjs/my-modules-directory
```
---
+---
#### `--link-flag`
Specify linker flags for IoT.js.
./tools/build.py --link-flag="..." --link-flag="..."
```
---
-#### `--external-include-dir`
-Specify external include directory for IoT.js.
+---
+#### `--no-check-valgrind`
+Disable test execution with valgrind after build.
-If you have multiple external include directoies, supply it with multiple use of this option;
```
-./tools/build.py --external-include-dir="..." --external-include-dir="..."
+./tools/build.py --no-check-valgrind
```
---
-#### `--external-lib`
-Specify external library that will be linked with IoT.js.
+---
+#### `--no-init-submodule`
+With given this option, submoduls will not initialized before start build.
-If you have multiple such libraries, supply it with multiple use of this option;
```
-./tools/build.py --external-lib="libxxx"
+./tools/build.py --no-init-submodule
+```
+
+---
+#### `--no-parallel-build`
+With given this option, compilation process will not run in parallel. In other words, executes `make` without `-j` option.
+
+```
+./tools/build.py --no-parallel-build
```
---
+---
+#### `--nuttx-home`
+To build for nuttx os, nuttx home directory must be given.
+
+```
+./tools/build.py --target-os=nuttx --target-arch=arm --target-board=stm32f4dis --nuttx-home="..."
+```
+
+---
+#### `--profile`
+With given this option, build.py will use the specified profile for the build.
+See also: ["How to write a new module"](../devs/Writing-New-Module.md#profile)
+
+```
+./tools/build.py --profile=./profiles/minimal.profile
+```
+
+---
+#### `--run-test`
+* `full` | `quiet`
+
+Execute tests after build, optional argument specifies the level of output for the testrunner.
+
+```
+./tools/build.py --run-test=full
+```
+
+---
+#### `--sysroot`
+The location of the development tree root directory (sysroot). Must be compatible with used toolchain.
+
+```
+./tools/build.py --sysroot=/home/iotjs/sysroot-directory
+```
+
+---
+#### `--target-arch`
+* `arm` | `x86` | `i686` | `x86_64` | `x64` | `mips` | `noarch`
+
+Specify target architecture.
+
+```
+./tools/build.py --target-arch=arm
+```
+
+---
+#### `--target-board`
+* `artik10` | `artik05x` | `rpi2` | `rpi3` | `stm32f4dis` | empty
+
+Specify target board.
+
+```
+./tools/build.py --target-os=nuttx --target-arch=arm --target-board=stm32f4dis
+```
+
+---
+#### `--target-os`
+* `linux` | `darwin` | `osx` | `nuttx` | `tizen` | `tizenrt` | `openwrt`
+
+Specify target OS.
+
+```
+./tools/build.py --target-os=nuttx --target-arch=arm
+```
+
+
+### Arguments of JerryScript
+The following arguments are related to the JavaScript engine under the framework. For example they can change the enabled features of the ECMA-262 standard.
+
+---
#### `--jerry-cmake-param`
Specify CMake parameters for JerryScript.
If you have multiple parameters, supply it with multiple use of this option
---
+---
#### `--jerry-compile-flag`
Specify C compiler flags for JerryScript.
./tools/build.py --jerry-compile-flag="-DCONFIG_ECMA_LCACHE_DISABLE"
```
---
-#### `--jerry-link-flag`
-Specify linker flags for JerryScript.
+---
+#### `--jerry-debugger`
+Enable JerryScript debugger. See also ["Use JerryScript Debugger"](../devs/Use-JerryScript-Debugger.md).
-If you have multiple ldflags, supply it with multiple use of this option
+```
+./tools/build.py --jerry-debugger
+```
---
+---
#### `--jerry-heaplimit`
Specify object heap limit for JerryScript engine.
./tools/build.py --jerry-heaplimit=80
```
---
-#### `--jerry-memstat`
-Enable memstat of JerryScript engine.
+---
+#### `--jerry-heap-section`
+Specify the name of the JerryScript heap section.
```
-./tools/build.py --jerry-memstat
+./tools/build.py --jerry-heap-section=".ARM.__at_0x20000"
```
---
+---
#### `--jerry-lto`
With given this option, JerryScript will be built with LTO.
./tools/build.py --jerry-lto
```
---
-#### `--no-init-submodule`
-With given this option, submoduls will not initialized before start build.
+---
+#### `--jerry-memstat`
+Enable memstat of JerryScript engine.
```
-./tools/build.py --no-init-submodule
+./tools/build.py --jerry-memstat
```
---
-#### `--no-check-tidy`
-With given this option, tidy checking will not performed.
+---
+#### `--jerry-profile`
+* `es5.1` | `es2015-subset | absolute path to a custom profile file`
-```
-./tools/build.py --no-check-tidy
-```
-
---
-#### `--no-parallel-build`
-With given this option, compilation process will not run in parallel. In other words, executes `make` without `-j` option.
-
-```
-./tools/build.py --no-parallel-build
-```
-
---
-#### `--nuttx-home`
-To build for nuttx os, nuttx home directory must be given.
+Specify the profile for JerryScript (default: es5.1). In JerryScript all of the features are enabled by default, so an empty profile file turns on all of the available ECMA features. See also the related [README.md](https://github.com/jerryscript-project/jerryscript/blob/master/jerry-core/profiles/README.md).
+E.g.:
+**/home/iotjs/my-jerry-profile.profile**
```
-./tools/build.py --target-os=nuttx --target-arch=arm --target-board=stm32f4dis --nuttx-home="..."
+# Turn off every ES2015 feature EXCEPT the arrow functions
+CONFIG_DISABLE_ES2015_BUILTIN
+CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
+CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS
+CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
```
---
-#### `--run-test`
-With given this option, unit test checking will be performed.
-
```
-./tools/build.py --run-test
+./tools/build.py --jerry-profile=/home/iotjs/my-jerry-profile.profile
```
---
-#### `--config`
-Specify build configuration file path.
+---
+#### `--js-backtrace`
+Enable/disable backtrace information of JavaScript code (default: ON in debug and OFF in release build).
```
-./tools/build.py --config=build.arm.nuttx.stm32f4dis.config
+./tools/build.py --js-backtrace
```
-
-`build.default.config` file is in the source tree for default setting.
-
-If this option is not specified, `build.config` file will be applied. If the file is not exist, it will be copied from `build.default.config`.
-
-Parameters specified by the config file is applied, and then the parameters given by command line overwrite over the settings.
-
-If you need to apply the same set of parameters for each build, making your own config file and trigger build.py with the config file would be more convenient.
\ No newline at end of file
>Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
>Bus 003 Device 005: ID 0403:6010 Future Technology Devices International, Ltd >FT2232C Dual USB-UART/FIFO IC
>```
+
+
+#### 7. Run IoT.js
+
+You should use `minicom` to login to the device:
+
+```bash
+$ sudo minicom -s
+```
+The following changes are necessaries in the `Serial port setup` menu:
+
+```
+Serial Device : /dev/<device-id> # e.g. /dev/ttyUSB0
+Hardware Flow Control : No
+```
+After `Exit`, press an enter and the prompt should be available:
+
+```bash
+TASH>>
+```
+The following commands help to establish Internet connection on the device:
+
+```bash
+TASH>> wifi startsta
+TASH>> wifi join <ssid> <password>
+TASH>> ifconfig wl1 dhcp
+```
+Finally, the `iotjs` built-in command can be executed:
+
+```bash
+TASH>> iotjs
+Usage: iotjs [options] {FILE | FILE.js} [arguments]
+TASH>>
+```
+++ /dev/null
-
-### 1. Tizen on ARTIK10 cross-compile
-
-#### Prerequisites
-
-* ARTIK10 with Tizen (https://wiki.tizen.org/wiki/Tizen_On_ARTIK)
-* Tizen Studio with Native app development CLI tools.
- This is required to get rootstrap for Tizen (set of native libraries).
-
-* arm-linux-gnueabi-gcc cross compiler (can be found in Tizen Studio / Native toolchain)
- Otherwise, you can install it on your PC.
-```bash
-sudo apt-get install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
-```
-
-#### Building
-1. Make sure arm-linux-gnueabi-gcc is in path.
-2. Locate Tizen SDK. Default location is: ~/tizen-studio.
-3. In platforms/tizen-3.0/mobile there should be compatible rootstrap (eg. mobile-3.0-device)
-
-Compile:
-* Compile with rootstrap in case you use tizen 3.0 libraries.
-``` bash
-tools/build.py \
- --target-arch=arm --target-os=tizen --target-board=artik10 \
- --compile-flag="--sysroot=~/tizen-studio/platforms/tizen-3.0/mobile/rootstraps/mobile-3.0-device.core/"
-```
-
-#### Testing
-Transfer iotjs binary and test file to the device:
-``` bash
- $ sdb push ./build/arm-tizen/debug/bin/iotjs /home/owner/iotjs/
- $ sdb push ./test/run_pass/test_console.js /home/owner/iotjs/
-```
-
-Run the test:
-``` bash
-sdb shell
-$ cd /home/owner/iotjs
-$ ./iotjs test_console.js
-```
#### Install
Transfer iotjs binary and test file to the device:
``` bash
-(ubuntu)$ sdb push ~/GBS-ROOT/local/repos/tizen_unified_preview2/armv7l/RPMS/iotjs-1.0.0-0.armv7l.rpm /tmp
+(ubuntu)$ sdb push ~/GBS-ROOT/local/repos/tizen_unified_m1/armv7l/RPMS/iotjs-1.0.0-0.armv7l.rpm /tmp
(ubuntu)$ sdb push ./test/run_pass/test_console.js /home/owner/iotjs/
(ubuntu)$ sdb root on
(ubuntu)$ sdb shell
#### Supported Nuttx version
|Repository|Tag Name|
|----------|:------:|
-| nuttx | nuttx-7.19 |
-| app | nuttx-7.19 |
+| nuttx | nuttx-7.25 |
+| app | nuttx-7.25 |
We only guarantee that the specified version will work well. It is recommended to check out with the specified tag from a git repository.
$ mkdir iotjs-nuttx
$ cd iotjs-nuttx
$ git clone https://github.com/Samsung/iotjs.git
-$ git clone https://bitbucket.org/nuttx/nuttx.git --branch nuttx-7.19
-$ git clone https://bitbucket.org/nuttx/apps.git --branch nuttx-7.19
+$ git clone https://bitbucket.org/nuttx/nuttx.git --branch nuttx-7.25
+$ git clone https://bitbucket.org/nuttx/apps.git --branch nuttx-7.25
$ git clone https://github.com/texane/stlink.git
```
--- /dev/null
+# IoT.js for Windows build guide
+
+> :exclamation: This document describes an experimental feature and considerations.
+Please be aware that every experimental feature may change, be broken,
+or be removed in the future without any notice.
+
+
+The document presents the steps required to compile the IoT.js
+for Windows.
+Tested on Windows 10 and with Visual Studio 2017 Community Edition.
+
+## Build IoT.js for Windows
+
+### 0. Check environment
+
+Check if the following tools are installed:
+ * GIT
+ * Visual Studio 2017 with C++ support
+ * Python 3
+
+Additionally clone the IoT.js repository into a convenient directory.
+In the document the `C:\dev\iotjs` path will be used as an example.
+
+### 1. Run the build script
+
+To create the required Visual Studio solution file(s) the build scripts needs to be
+executed. Please start a Command Prompt and navigate to the source directory where
+the IoT.js is cloned.
+
+In the IoT.js directory issue the following command:
+
+```sh
+C:\dev\iotjs> .\tools\build.py --experimental
+```
+
+Currently for Windows the `--experimental` option is a must. Additionally if
+other options are required it can be specified after this option.
+
+This command will create the solution files in the build directory.
+Specifically in the `build\i686-windows\debug` directory in case of debug build.
+In case of release build the solution files will be in the `build\i686-windows\release\`
+directory.
+
+Please note that currently only the `i686` target is supported.
+
+### 2. Open the IoT.js solution file
+
+In the `build\i686-windows\debug` directory the `IOTJS.sln` file should be opened
+with Visual Studion 2017.
+
+### 3. Build
+
+After the IoT.js solution file is opened the Visual Studio can now start the build.
+Press CTRL+SHIFT+B to build the whole solution.
+
+The resulting iotjs.exe will be placed in the build's `bin\Debug` or `bin\Release`
+directory depending on the configuration chosen in the Visual Studio.
+
+### Extra
+
+On Windows the test runner can also be executed. To do this the following steps are required:
+
+1. Have a built iotjs.exe
+2. Start a command prompt
+3. Navigate to the IoT.js source directory
+4. Execute the test runner. Ex.:
+```sh
+C:\dev\iotjs> tools\testrunner.py build\i686-windows\debug\bin\Debug\iotjs.exe
+```
<br>
-### Community Consensus, Lazy Consensus and Slient Consent
+### Community Consensus, Lazy Consensus and Silent Consent
Community consensus about a Project issue means that the issue has been submitted to and discussed by Contributors, and that ALL discussing member agree about the issue.<p>
Lazy consensus means that Contributors may proceed with work when they have reason to believe that other Contributors in the community will agree with the direction of their work, and do not need to stop or initiate unnecessary discussion about the work. Contributors should publish their work (that is, merge proposals to master branch) in a timely manner to allow others to possibly raise issues about the work. When the Contributor is not sure there will be consensus, they should raise a proposal to the community via appropriate public communication channels(**_currently Github issues is possible way to achieve this_**)<p>
The following shows `{Your_module_name}` module APIs available for each platform.
-| | Linux<br/>(Ubuntu) | Raspbian<br/>(Raspberry Pi) | NuttX<br/>(STM32F4-Discovery) |
-| :---: | :---: | :---: | :---: |
-| {class_name}.{functionName1} | O | O | O |
-| {class_name}.{functionName2} | O | O | O |
-| {class_name}.{functionName3} | O | O | O |
+| | Linux<br/>(Ubuntu) | Tizen<br/>(Raspberry Pi) | Raspbian<br/>(Raspberry Pi) | NuttX<br/>(STM32F4-Discovery) | TizenRT<br/>(Artik053) |
+| :---: | :---: | :---: | :---: | :---: | :---: |
+| {class_name}.{functionName1} | O | O | O | O | O |
+| {class_name}.{functionName2} | O | O | O | O | O |
+| {class_name}.{functionName3} | O | O | O | O | O |
# {Your_module_name}
## Javascript Style Rules
### Naming
-Use lowerCamelCase for varible names and function names.
+Use lowerCamelCase for variable names and function names.
var myFirstVariable;
function myFirstFunction {
```bash
$ sudo apt-get update
-$ sudo apt-get install clang-format-3.8
+$ sudo apt-get install clang-format-3.9
$ cd iotjs
$ npm install
```
* [Design](#design)
* [Javascript Binding](#javascript-binding)
- * jerry_value_t
- * iotjs_jobjectwrap_t
- * Native handler
- * Embedding API
+ * [jerry_value_t](#jerry_value_t)
+ * [Native handler](#native-handler)
+ * [Embedding API](#embedding-api)
* [libuv Binding](#libuv-binding)
- * iotjs_handlewrap_t
- * iotjs_reqwrap_t
+ * [iotjs_handlewrap_t](#iotjs_handlewrap_t)
+ * [iotjs_reqwrap_t](#iotjs_reqwrap_t)
* [IoT.js Core](#iotjscoe)
- * Life cycle of IoT.js
- * Builtin modules
- * Event loop
+ * [Life cycle of IoT.js](#life-cycle-of-iot.js)
+ * [Builtin modules](#builtin-modules)
+ * [Event loop](#event-loop)
# Design
* Evaluating a Javascript script.
* Set and Get corresponding native data to the Javascript object.
-## iotjs_jobjectwrap_t
-
-You can refer Javascript object from C code side using `jerry_value_t` as saw above.
-When a reference for a Javascript object was made using `jerry_value_t`, it will increase the reference count and will decrease the count when it goes out of scope.
-
-```c
-{
- // Create JavaScript object
- // It increases reference count in JerryScript side.
- jerry_value_t jobject = iotjs_jval_create();
-
- // Use `jobject`
- ...
-
- // Before jobject goes out of scope, destroy it.
- // It decreases reference count in JerryScript side so that it can be GC-ed.
- iotjs_jval_destroy(&jobject)
-}
-```
-
-But the situation is different if you want to refer a Javascript object through out program execution until the object is live.
-You may write code like this:
-
-```c
- jerry_value_t* jobject = (jerry_value_t*)malloc(sizeof(jerry_value_t)); // Not allowed
-```
-
-To achieve your wish, we recommend using `iotjs_jobjectwrap_t` for that purpose.
-`iotjs_jobjectwrap_t` is kind of weak pointer to a Javascript Object.
-It refers a Javascript object but never increase reference count so that Javascript engine can collect the object when it turns into garbage.
-The `iotjs_jobjectwrap_t` instance will be released at the time the corresponding Javascript object is being reclaimed.
-
-Do not hold pointer to the wrapper in native code side globally because even if you are holding a wrapper by pointer, Javascript engine probably releases the corresponding Javascript object resulting deallocation of wrapper. Consequentially your pointer will turned into dangling.
-
-The only safe way to get wrapper is to get it from Javascript object. When a wrapper is being created, it links itself with corresponding Javascript object with `iotjs_jval_set_object_native_handle()` method of `jerry_value_t`. And you can get the wrapper from the object with `iotjs_jval_get_object_native_handle()` method of `jerry_value_t` later when you need it.
-
-
## Native handler
Some operations - such as file I/O, networking, device control, multitasking, and etc - can not be performed by pure Javascript.
jmem_heap_t jerry_global_heap __attribute__ ((aligned (JMEM_ALIGNMENT))) JERRY_GLOBAL_HEAP_SECTION;
```
+
+## Modify the default jerry-heap size
+
+By default, JerryScript uses 16 bit long (8 byte aligned) pointers, that is why the maximum addressable area (on the JerryScript heap) is 512 KB. Of course, these compressed pointers can be extended to 32 bit to cover the entire address space of a 32 bit system.
+
+You can modify the default JerryScript heap size by using the `--jerry-heaplimit` argument when building IoT.js. If that value is bigger than `512`, the JerryScript submodule is compiled with 32 bit pointer support.
Depend on the purpose of the test case (whether it's a positive or negative one), place it under `test/run_pass` or `test/run_fail` directory. The required external resources should be placed into `test/resources`.
-All test case files must be named in the following form `test_<module name>[_<functionallity].js` where `<module name>`
+All test case files must be named in the following form `test_<module name>[_<functionality].js` where `<module name>`
should match one of the JS modules name in the IoT.js. If there is a test case which can not tied to a
module (like some js features) then the `iotjs` name can be used as module name. It is important to
correctly specify the module name as the test executor relies on that information.
1. Write a test case and place it into the proper directory.
2. List up the test case in [test/testsets.json](https://github.com/Samsung/iotjs/blob/master/test/testsets.json), and set attributes (timeout, skip, ...) on the test case if it needs.
+#### Test set descriptor
+* [`test/testsets.json`](https://github.com/Samsung/iotjs/blob/master/test/testsets.json)
+
+```
+{
+ "directory": [
+ { "name": "filename",
+ "skip": ["all"],
+ "reason": "reason of skipping",
+ "timeout": seconds,
+ "expected-failure": true,
+ "required-modules": ["my_module"],
+ "required-features": ["es-262-feature"]
+ },
+ ...
+ ],
+ ...
+}
+```
+
+ - _directory_: group of tests
+ - _name_: filename = testname
+ - _skip_: platform where the test must be skipped. ["all", "darwin", "linux", "nuttx", "tizen", "tizenrt"] **(optional)**
+ - _reason_: it belongs to skip property, reason of skipping. **(optional)**
+ - _timeout_: timeout in seconds **(optional)**
+ - _expected-failure_: identifies the "must fail" testcases. Still catches segfaults, IOTJS_ASSERT and JERRY_ASSERT. Default: false [true, false] **(optional)**
+
### How to Test
Existing test options are listed as follows;
```
-start-from
-quiet=yes|no (default is yes)
-output-file
-skip-module
-output-coverage=yes|no (default is no)
-experimental=yes|no (default is no)
+-h, --help show this help message and exit
+--quiet show or hide the output of the tests
+--skip-modules list module list to skip test of specific modules
+--testsets TESTSETS JSON file to extend or override the default testsets
+--timeout TIMEOUT default timeout for the tests in seconds
+--valgrind check tests with Valgrind
+--coverage measure JavaScript coverage
```
-
-To give options, please use two dashes '--' **once** before the option name as described in the following sections.
-
-Options that may need explanations.
-* start-from: a test case file name where the driver starts.
-* quiet: a flag that indicates if the driver suppresses console outputs of test case.
-* output-file: a file name where the driver leaves output.
-* skip-module: a module list to skip test of specific modules.
-* output-coverage: a flag that indicates wether coverage data should be written to disk
-* experimental: a flag that indicates if tests for experimental are needed
-
-#### Options example
-
-```bash
-build/x86_64-linux/debug/bin/iotjs tools/check_test.js -- start-from=test_console.js quiet=no
-```
\ No newline at end of file
you can do so with the `--debugger-port <PORT>` option:
`<iotjs binary> --start-debug-server --debugger-port 8080 test.js`
-Two clients are included, a [python](https://github.com/jerryscript-project/jerryscript/blob/master/jerry-debugger/jerry-client-ws.py)
-and an [HTML](https://github.com/jerryscript-project/jerryscript/blob/master/jerry-debugger/jerry-client-ws.html) variant, they can be found under `deps/jerry/jerry-debugger/`.
+#### Available Clients
-*Note*: When snapshot support is enabled, you won't be able to examine js-modules
+* [JerryScript console debugger client](https://github.com/jerryscript-project/jerryscript/blob/master/jerry-debugger/jerry-client-ws.py)
+* [Iot.js Code](https://github.com/Samsung/iotjscode)
+* [Jerryscript debugger Chrome webtool](https://github.com/jerryscript-project/jerryscript-debugger-ts)
+
+**Note**: When snapshot support is enabled, you won't be able to examine js-modules
that are loaded from snapshots.
Source1001: %{name}.manifest
ExclusiveArch: %arm %ix86 x86_64
-
BuildRequires: python
BuildRequires: cmake
BuildRequires: glibc-static
# Initialize the variables
%{!?build_mode: %define build_mode release}
%{!?external_build_options: %define external_build_options %{nil}}
+
%package service
Summary: Development files for %{name}
Group: Network & Connectivity/Service
cat LICENSE
cp %{SOURCE1001} .
-
%build
V=1 VERBOSE=1 ./tools/build.py \
--clean \
--buildtype=%{build_mode} \
--profile=test/profiles/tizen.profile \
+ --jerry-profile $PWD/test/profiles/tizen-jerry.profile \
+ --js-backtrace ON \
--target-arch=noarch \
--target-os=tizen \
%ifarch %{arm}
--external-lib=appcore-agent \
--external-lib=pthread \
--external-lib=curl \
+ --external-lib=glib-2.0 \
--external-include-dir=/usr/include/dlog/ \
--external-include-dir=/usr/include/appcore-agent/ \
--external-include-dir=/usr/include/appfw/ \
--compile-flag="%(pkg-config --cflags glib-2.0)" \
--compile-flag=-D__TIZEN__ \
--compile-flag=-DENABLE_DEBUG_LOG \
- --jerry-cmake-param=-DENABLE_STATIC_LINK=OFF \
--create-shared-lib \
--no-init-submodule \
--no-parallel-build \
+++ /dev/null
-# Sample bridge module
-
-See also:
-* [Writing-new-module](Writing-New-Module.md)
-* [Native Module vs. JS module](Native-Module-vs-JS-Module.md)
-* [Inside IoT.js](Inside-IoT.js.md)
-* [Developer Tutorial](Developer-Tutorial.md)
-
-
-## Description
-This sample show you how you can create a 'mixed' module using brige module that has some interfaces to support communicattion between JS and Native code. This sample created using tools/iotjs-create-module.py script.
-You can see how you could reduce your effor to create native module using simple methods provided bridge module.
-
-
-## Build
-
-$ ./tools/build.py --external-modules=./samples/bridge_sample --cmake-param=-DENABLE_MODULE_BRIDGE_SAMPLE=ON
-
-## Testing
-
-$ iotjs samples/bridge_sample/test.js
+++ /dev/null
-/* 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');
-
-function bridge_sample(){
- this.bridge = new Bridge(native.MODULE_NAME);
-}
-
-bridge_sample.prototype.getResPath = function(){
- return this.bridge.sendSync('getResPath', '');
-};
-
-bridge_sample.prototype.getSystemInfo = function(callback){
- this.bridge.send('getSystemInfo', '', function(err, msg){
- callback(err, msg);
- });
-};
-
-bridge_sample.prototype.testThread = function(callback){
- this.bridge.send('testThread', '', function(err, msg){
- callback(err, msg);
- });
-};
-
-module.exports = new bridge_sample();
+++ /dev/null
-# 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 "bridge_sample")
-
-# 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)
+++ /dev/null
-{
- "modules": {
- "bridge_sample": {
- "js_file": "js/bridge_sample.js",
- "native_files": ["src/iotjs_bridge_sample.c"],
- "init": "InitBridgeSample",
- "cmakefile": "module.cmake",
- "require": ["bridge"]
- }
- }
-}
+++ /dev/null
-/* 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"
-
-
-char* iotjs_bridge_sample_getSystemInfo(const char* message) {
- return "{'OS':'tizen'}";
-}
-
-void thread1_worker(void* return_handle) {
- uv_sleep(500);
- iotjs_bridge_set_msg(return_handle, "{'return':'from thread..'}");
-}
-
-void iotjs_bridge_sample_func(const char* command, const char* message,
- void* return_handle) {
- char* result = 0;
- if (strncmp(command, "getSystemInfo", strlen("getSystemInfo")) == 0) {
- result = iotjs_bridge_sample_getSystemInfo(message);
- if (result == 0) {
- iotjs_bridge_set_err(return_handle, "Can't get the resource path");
- } else {
- iotjs_bridge_set_msg(return_handle, result);
- }
- } else if (strncmp(command, "testThread", strlen("testThread")) == 0) {
- uv_thread_t thread1;
- uv_thread_create(&thread1, thread1_worker, return_handle);
- } else if (strncmp(command, "getResPath", strlen("getResPath")) == 0) {
- iotjs_bridge_set_msg(return_handle, "res/");
- } else {
- iotjs_bridge_set_err(return_handle, "Can't find command");
- }
-}
-
-/**
- * Init method called by IoT.js
- */
-jerry_value_t InitBridgeSample() {
- char* module_name = "bridge_sample";
- 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_bridge_sample_func);
- return mymodule;
-}
+++ /dev/null
-/* 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 bridgeSample = require('bridge_sample');
-
-
-console.log('TestApp: getResPath(): ' + bridgeSample.getResPath());
-
-
-bridgeSample.testThread(function(err, msg) {
- console.log('TestApp: testThread(): err: ' + err + ' msg: ' + msg);
-});
-
-bridgeSample.getSystemInfo(function(err, msg) {
- console.log('TestApp: getSystemInfo(): err: ' + err + ' msg: ' + msg);
-});
+++ /dev/null
-/* 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:
- *
- * Plays Bethovens Fur Elise using PWM
- *
- * Usage:
- *
- * To run this sample please connect a low-power speaker, like a buzzer
- * (piezoelectric speaker), negative feed (-) to GND and positive feed (+) to
- * pin 7 on Artik053 CON703, and run the code by executing
- *
- * $ iotjs play.js
- *
- */
-
-var pwm = require('pwm'),
- // note indexes definition
- // please remember that D# is same as Bb here
- notes = {
- "C": 0,
- "C#": 1,
- "D": 2,
- "D#": 3,
- "E": 4,
- "F": 5,
- "F#": 6,
- "G": 7,
- "G#": 8,
- "A": 9,
- "Bb": 10,
- "B": 11
- },
- // note frequencies
- frequencies = [
- //C, C#, D, Eb, E, F, F#, G, G#, A, Bb, B in ocatves from 0 to 8
- [16.35, 17.32, 18.35, 19.45, 20.60, 21.83, 23.12, 24.50, 25.96, 27.50,
- 29.14, 30.87],
- [32.70, 34.65, 36.71, 38.89, 41.20, 43.65, 46.25, 49.00, 51.91, 55.00,
- 58.27, 61.74],
- [65.41, 69.30, 73.42, 77.78, 82.41, 87.31, 92.50, 98.00, 103.8, 110.0,
- 116.5, 123.5],
- [130.8, 138.6, 146.8, 155.6, 164.8, 174.6, 185.0, 196.0, 207.7, 220.0,
- 233.1, 246.9],
- [261.6, 277.2, 293.7, 311.1, 329.6, 349.2, 370.0, 392.0, 415.3, 440.0,
- 466.2, 493.9],
- [523.3, 554.4, 587.3, 622.3, 659.3, 698.5, 740.0, 784.0, 830.6, 880.0,
- 932.3, 987.8],
- [1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976],
- [2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951],
- [4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902]
- ],
- // fur elise notes
- song = [
- ["E6", 0.2], ["D#6", 0.2], ["E6", 0.2], ["D#6", 0.2], ["E6", 0.2],
- ["B5", 0.2], ["D6", 0.2], ["C6", 0.2], ["A5", 0.2], ["A3", 0.2],
- ["E4", 0.2], ["A4", 0.2], ["C5", 0.2], ["E5", 0.2], ["A5", 0.2],
- ["E3", 0.2], ["B5", 0.2], ["E4", 0.2], ["G#4", 0.2], ["E5", 0.2],
- ["G#5", 0.2], ["B5", 0.2], ["A3", 0.2], ["C6", 0.2], ["E4", 0.2],
- ["A4", 0.2], ["E5", 0.2], ["E6", 0.2], ["E6", 0.2], ["D#6", 0.2],
- ["D#6", 0.2], ["E6", 0.2], ["E6", 0.2], ["D#6", 0.2], ["D#6", 0.2],
- ["E6", 0.2], ["E6", 0.2], ["B5", 0.2], ["B5", 0.2], ["D6", 0.2],
- ["D6", 0.2], ["C6", 0.2], ["C6", 0.2], ["A3", 0.2], ["A5", 0.2],
- ["A5", 0.2], ["E4", 0.2], ["A4", 0.2], ["C5", 0.2], ["E5", 0.2],
- ["A5", 0.2], ["E3", 0.2], ["B5", 0.2], ["E4", 0.2], ["G#4", 0.2],
- ["E5", 0.2], ["C6", 0.2], ["B5", 0.2], ["A5", 0.2], ["A3", 0.2],
- ["E4", 0.2], ["A4", 0.2], ["B5", 0.2], ["C6", 0.2], ["D6", 0.2],
- ["C4", 0.2], ["E6", 0.2], ["G4", 0.2], ["C5", 0.2], ["G5", 0.2],
- ["F6", 0.2], ["E6", 0.2], ["G3", 0.2], ["D6", 0.2], ["G4", 0.2],
- ["B4", 0.2], ["F5", 0.2], ["E6", 0.2], ["D6", 0.2], ["A3", 0.2],
- ["C6", 0.2], ["E4", 0.2], ["A4", 0.2], ["E5", 0.2], ["D6", 0.2],
- ["C6", 0.2], ["E3", 0.2], ["B5", 0.2], ["E4", 0.4],
- ["E5", 0.2], ["E6", 0.2], ["E5", 0.4], ["E6", 0.2],
- ["E7", 0.2], ["D#6", 0.2], ["E6", 0.2], ["D#6", 0.2], ["E6", 0.2],
- ["D#6", 0.2], ["E6", 0.2], ["D#6", 0.2], ["E6", 0.2], ["D#6", 0.2],
- ["E6", 0.2], ["D#6", 0.2], ["E6", 0.2], ["B5", 0.2], ["D6", 0.2],
- ["C6", 0.2], ["A3", 0.2], ["A5", 0.2], ["E4", 0.2], ["A4", 0.2],
- ["C5", 0.2], ["E5", 0.2], ["A5", 0.2], ["E3", 0.2], ["B5", 0.2],
- ["E4", 0.2], ["G#4", 0.2], ["E5", 0.2], ["G#5", 0.2], ["B5", 0.2],
- ["A3", 0.2], ["C6", 0.2], ["E4", 0.2], ["A4", 0.2], ["E5", 0.2],
- ["E6", 0.2], ["D#6", 0.2], ["E6", 0.2], ["D#6", 0.2], ["E6", 0.2],
- ["B5", 0.2], ["D6", 0.2], ["C6", 0.2], ["A3", 0.2], ["A5", 0.2],
- ["E4", 0.2], ["A4", 0.2], ["C5", 0.2], ["E5", 0.2], ["A5", 0.2],
- ["E3", 0.2], ["B5", 0.2], ["E4", 0.2], ["G#4", 0.2], ["E5", 0.2],
- ["C6", 0.2], ["B5", 0.2], ["A3", 0.2], ["A5", 0.2], ["E4", 0.2],
- ["A4", 0.8]
- ],
- log_enable = true,
- device = null;
-
-// log only when log_enable flag is set to true
-function log(/*...args*/) {
- if (log_enable) {
- console.log.apply(console, [].slice.call(arguments));
- }
-}
-
-// extracts frequency from freq array based on supplied note
-function note2freq(noteStr) {
- var matches = noteStr.match(/([a-zA-Z\#]+)([0-9]+)/i),
- freq = 0;
-
- if (matches && matches.length === 3) {
- return frequencies[parseInt(matches[2], 10)][notes[matches[1]]];
- }
-
- return 0;
-}
-
-// sets pwm period and runs callback after specified length of time
-function setPeriod(period, length, callback) {
- log('period: ' + period + ', length: ' + length + ' ms');
- device.setPeriod(period, function (err) {
- if (err) {
- callback(err);
- } else {
- setTimeout(callback, length);
- }
- });
-}
-
-// plays each note of song recursively and runs callback on end
-function playSong(song, callback, currentNote) {
- var idx = currentNote === undefined ? 0 : currentNote,
- freq = 0;
- if (idx < song.length) {
- freq = note2freq(song[idx][0]);
- // period = 1 second / frequency
- setPeriod(freq !== 0 ? 1 / freq : 0.5, 1000 * song[idx][1],
- playSong.bind(null, song, callback, ++idx));
- } else {
- callback();
- }
-}
-
-device = pwm.open({
- pin: 0,
- dutyCycle: 0.5,
- period: 1 / 10
-}, function (err) {
- if (err) {
- log('could not open pwm device: ' + err);
- } else {
- device.setEnableSync(true);
- log('playing song');
- playSong(song, function () {
- device.close(function (err) {
- if (err) {
- log('error while closing device: ' + err);
- } else {
- log('done');
- }
- });
- });
- }
-});
+++ /dev/null
-/* 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 gpio = require('gpio');
-var pin = require('systemio_pin').pin;
-
-var gpio_led = gpio.open({
- pin: pin.led1,
- direction: gpio.DIRECTION.OUT
-}, function(err) {
- if (!err) {
- gpio_led.writeSync(true);
-
- var interval = setInterval(function() {
- gpio_led.read(function(err, value) {
- if (!err) {
- console.log("read value:%d", value);
- gpio_led.write(!value);
- } else {
- clearInterval(interval);
- }
- });
- }, 1000);
- }
-});
+++ /dev/null
-/* 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 pin = {};
-
-if (process.platform === 'linux') {
- pin.led1 = 20;
-} else if (process.platform === 'nuttx') {
- var stm32_pin = require('stm32f4dis').pin;
- pin.led1 = stm32_pin.PA10;
-} else {
- throw new Error('Unsupported platform');
-}
-
-exports.pin = pin;
+++ /dev/null
-<!--
-/* 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.
- */
-//-->
-<html lang="en">
- <head>
- <title>http gpio panel sample</title>
- </head>
- <body>
- <form id="gpioconf">
- <fieldset>
- <legend>GPIO Pin configuration</legend>
- <label>
- Pin number
- <input type="number" value="0" name="pin">
- </label>
- <label>
- Direction
- <select name="direction">
- <option value="0" selected>IN</option>
- <option value="1">OUT</option>
- </select>
- </label>
- <label>
- Mode
- <select name="mode">
- <option value="0" selected>NONE</option>
- <option value="1">PULLUP</option>
- <option value="2">PULLDOWN</option>
- <option value="3">FLOAT</option>
- <option value="4">PUSHPULL</option>
- <option value="5">OPENDRAIN</option>
- </select>
- </label>
- <label>
- State
- <select name="pinValue">
- <option value="0" selected>LOW</option>
- <option value="1">HIGH</option>
- </select>
- </label>
- <input type="submit" value="Add">
- </fieldset>
- </form>
- <h3>ACTIVE PINS</h3>
- <table id="gpioresults">
- <thead>
- <tr>
- <th>Pin</pin>
- <th>Direction</th>
- <th>Mode</th>
- <th>State</th>
- <th></th>
- </tr>
- </thead>
- <tbody>
- </tbody>
- </table>
- <script type="text/javascript">
- var form = document.getElementById('gpioconf'),
- results = document.getElementById('gpioresults'),
- GPIO_DIRECTION = {
- '0': 'IN',
- '1': 'OUT'
- },
- GPIO_MODE = {
- '0': 'NONE',
- '1': 'PULLUP',
- '2': 'PULLDOWN',
- '3': 'FLOAT',
- '4': 'PUSHPULL',
- '5': 'OPENDRAIN'
- },
- currentPins = {};
-
- // synchronize pins with response from server
- function syncPins(pins) {
- var pin = '',
- updated = {};
- // handle updates and add
- for (pin in pins) {
- if (pins.hasOwnProperty(pin)) {
- currentPins[pin] = pins[pin];
- };
- }
- // handle removals
- for (pin in currentPins) {
- if (currentPins.hasOwnProperty(pin)) {
- if (pins[pin] !== undefined) {
- updated[pin] = currentPins[pin];
- }
- }
- }
- // update data
- currentPins = updated;
- }
-
- // creates <tr> element with pin data in result table
- function createRowForPin(pin, data) {
- var row = document.createElement('tr'),
- checked = !!parseInt(data.value, 0) ? ' checked' : '',
- disabled = parseInt(data.direction, 10) === 0 ? ' disabled' : '',
- attrs = checked + disabled;
-
- row.setAttribute('id', 'pin_' + pin);
- row.innerHTML = '<td>' + pin + '</td>'
- + '<td>' + GPIO_DIRECTION[data.direction] + '</td>'
- + '<td>' + GPIO_MODE[data.mode] + '</td>'
- + '<td><input name="value" type="checkbox"' + attrs + '></td>'
- + '<td><button value="remove">Remove</button></td>';
-
- results.tBodies[0].appendChild(row);
- }
-
- // removes <tr> element for pin
- function removeRowForPin(pin) {
- var pinEl = document.getElementById('pin_' + pin);
- if (pinEl) {
- pinEl.parentNode.removeChild(pinEl);
- }
- }
-
- // updates <tr> for pin with specified data
- function updateRowForPin(row, pin, data) {
- if (parseInt(data.direction, 10) === 0) {
- row.children[3].children[0].checked = !!parseInt(data.value);
- }
- }
-
- // updates table with new data
- function updateResults(data) {
- var pin = '',
- pinEl = null;
- syncPins(data);
- for (pin in currentPins) {
- if (currentPins.hasOwnProperty(pin)) {
- pinEl = document.getElementById('pin_' + pin);
- if (pinEl) {
- updateRowForPin(pinEl, pin, data[pin]);
- } else {
- pinEl = createRowForPin(pin, data[pin]);
- }
- }
- }
- }
-
- // polling for data
- function updateDataPoll(interval) {
- var xhr = new XMLHttpRequest();
- xhr.addEventListener('load', function (e) {
- var updatedData = [];
- if (e.target.status === 200) {
- updateResults(JSON.parse(e.target.responseText));
- }
- if (interval) {
- setTimeout(updateDataPoll.bind(null, interval), interval);
- }
- });
- xhr.open('POST', '/update', true);
- xhr.send(JSON.stringify(currentPins));
- }
-
- // handle clicks on "remove" button
- document.addEventListener('click', function (e) {
- var pin = '',
- id = '',
- prop = '',
- updated = {};
- if (e.target.value && e.target.value === 'remove') {
- id = e.target.parentNode.parentNode.id;
- pin = id.replace(/[^0-9]+/gi, '');
- for (prop in currentPins) {
- if (currentPins.hasOwnProperty(prop) && prop !== pin) {
- updated[pin] = currentPins[pin];
- }
- }
- removeRowForPin(pin);
- currentPins = updated;
- updateDataPoll(0);
- }
- });
-
- // handles changes on state checkboxes
- document.addEventListener('change', function (e) {
- var id = '',
- pin = '';
- if (e.target.name && e.target.name === 'value') {
- id = e.target.parentNode.parentNode.id;
- pin = id.replace(/[^0-9]+/gi, '');
- if (currentPins[pin] && currentPins[pin].direction === '1') {
- currentPins[pin].value = e.target.checked ? '1' : '0';
- updateDataPoll(0);
- }
- }
- });
-
- // handles adding of new pins
- form.addEventListener('submit', function (e) {
- var formElements = e.target.elements;
- if (currentPins[formElements.pin.value] === undefined) {
- currentPins[formElements.pin.value] = {
- mode: formElements.mode.value,
- direction: formElements.direction.value,
- value: formElements.pinValue.value
- }
- e.target.reset();
- updateDataPoll(0);
- } else {
- alert('pin already exists');
- }
-
- e.preventDefault();
- return false;
- });
-
- updateDataPoll(500);
- </script>
- </body>
-</html>
+++ /dev/null
-/* 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);
- }
-});
+++ /dev/null
-/* 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 http = require('http');
-var options = {
- hostname: '127.0.0.1',
- port: 8080,
- path: '/'
-};
-
-http.request(options, function (res) {
- receive(res, function (data) {
- console.log(data);
- });
-}).end();
-
-function receive(incoming, callback) {
- var data = '';
-
- incoming.on('data', function (chunk) {
- data += chunk;
- });
-
- incoming.on('end', function () {
- callback ? callback(data) : '';
- });
-}
+++ /dev/null
-/* 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 http = require('http');
-
-var message = JSON.stringify({
- greeting: 'Hello, IoT.JS!',
- answer: '',
-});
-
-var options = {
- hostname: '127.0.0.1',
- port: 8080,
- path: '/',
- method: 'POST',
- headers: {
- 'Content-Length': message.length
- }
-};
-
-http.request(options, function (res) {
- receive(res, function (data) {
- var obj = JSON.parse(data);
- console.log(obj.answer);
- });
-}).end(message);
-
-function receive(incoming, callback) {
- var data = '';
-
- incoming.on('data', function (chunk) {
- data += chunk;
- });
-
- incoming.on('end', function () {
- callback ? callback(data) : '';
- });
-}
+++ /dev/null
-/* 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 http = require('http');
-var port = 8080;
-
-http.createServer(function (req, res) {
- if (req.method == 'GET') {
- status(res, 'Hello, IoT.JS!');
-
- } else if (req.method == 'POST') {
- receive(req, function (data) {
- var obj = JSON.parse(data);
- obj.answer = 'Hello, There!'
- status(res, obj);
- });
- }
-}).listen(port);
-
-function receive(incoming, callback) {
- var data = '';
-
- incoming.on('data', function (chunk) {
- data += chunk;
- });
-
- incoming.on('end', function () {
- callback ? callback(data) : '';
- });
-}
-
-function status(res, data) {
- var isJson = (typeof data === 'object');
-
- if (isJson) {
- data = JSON.stringify(data);
- }
-
- var headers = {
- 'Access-Control-Allow-Origin': '*',
- 'Access-Control-Allow-Headers':
- 'Origin, X-Requested-With, Content-Type, Accept',
- 'Content-Type': isJson ? 'application/json' : 'text/plain',
- };
-
- res.writeHead(200, headers);
- res.end(data);
-};
+++ /dev/null
-/* 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 i2c = require('i2c');
-
-var CMD_BRIGHTNESS = 0xE0;
-var CMD_OSCILLATOR = 0x21;
-var CMD_DISPLAY_ON = 0x81;
-
-var iotChar = [0x00, 0x00, 0x00, 0x00,
- 0xCE, 0x73, 0x44, 0x22,
- 0x44, 0x22, 0xCE, 0x23,
- 0x00, 0x00, 0x00, 0x00];
-
-var writeLed = function(wire, data) {
- // 0x00 is a initial signal for writing
- var buffer = [0x00].concat(data);
- wire.write(buffer);
-};
-
-var configuration = {};
-configuration.address = 0x70;
-
-if (process.platform === 'linux') {
- configuration.device = '/dev/i2c-1';
-} else if (process.platform === 'nuttx' || process.platform == 'tizenrt') {
- configuration.bus = 1;
-} else {
- throw new Error('Unsupported platform');
-}
-
-i2c.open(configuration, function(err, wire) {
- if (err) {
- throw err;
- }
-
- wire.writeSync([CMD_OSCILLATOR]); // turn on oscillator
- wire.writeSync([CMD_DISPLAY_ON]);
- wire.writeSync([CMD_BRIGHTNESS | 1]); // adjust brightness
- writeLed(wire, iotChar);
-});
+++ /dev/null
-/* 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:
- *
- * Turns light on/off with a fade effect
- *
- * Usage:
- *
- * To run this sample please connect a button to GND and pin 8 on CON708
- * header, the LED light cathode (-) to GND and anode (+) to pin 7 on CON703.
- * Next run:
- *
- * $ iotjs light-fade.js
- *
- * Pushing the button will turn on/off (toggle) the light with a fade effect.
- *
- */
-
-var pwm = require('pwm'),
- gpio = require('gpio'),
- LOW = 0,
- HIGH = 1,
- FADE_TIME = 10000, // 10 seconds
- log_enabled = true,
- direction = 0, // 0 off 1 on
- buttonPin = 50,
- pwmPin = 0,
- step = 0.05,
- value = LOW,
- buttonDevice = null,
- pwmDevice = null;
-
-// log only when log_enabled flag is set to true
-function log(/*...args*/) {
- if (log_enabled) {
- console.log.apply(console, [].slice.call(arguments));
- }
-}
-
-// polling for gpio button changes
-function buttonPoll() {
- buttonDevice.read(function (err, buttonValue) {
- var timeoutOffset = 0;
- if (buttonValue) {
- direction = direction ? 0 : 1; //reverse on button push
- log('switching to: ' + (direction ? 'ON': 'OFF'));
- timeoutOffset = 500; // offset the time for next check to prevent errors
- // of mechanical buttons
- }
- setTimeout(buttonPoll, 100 + timeoutOffset);
- });
-}
-
-function mainLoop() {
- // handle fading
- if (direction === 0 && value > LOW) {
- value -= step;
- } else if (direction === 1 && value < HIGH) {
- value += step;
- }
-
- // clamping
- if (value > HIGH) {
- value = HIGH;
- } else if (value < LOW) {
- value = LOW;
- }
-
- pwmDevice.setDutyCycle(value, function (err) {
- if (err) {
- log('could not set device duty cycle');
- }
- setTimeout(mainLoop, FADE_TIME / (HIGH / step));
- });
-}
-
-log('setting up gpio');
-buttonDevice = gpio.open({
- pin: buttonPin,
- direction: gpio.DIRECTION.IN,
- mode: gpio.MODE.NONE
-}, function (err) {
- if (err) {
- log('error when opening gpio device: ' + err);
- } else {
- log('setting up pwm');
- pwmDevice = pwm.open({
- pin: pwmPin,
- period: 0.0001,
- dutyCycle: value
- }, function (err) {
- if (err) {
- log('error when opening pwm device: ' + err);
- buttonDevice.closeSync();
- } else {
- pwmDevice.setEnable(true, function (err) {
- if (err) {
- log('error when enabling pwm: ' + err);
- buttonDevice.closeSync();
- pwmDevice.close();
- } else {
- log('wating for user input');
- buttonPoll();
- mainLoop();
- }
- });
- }
- });
- }
-});
+++ /dev/null
-/* 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 net = require('net');
-
-var port = 7468;
-
-var msg = '';
-var socket = new net.Socket();
-
-var address = process.argv[2] ? process.argv[2] : "127.0.0.1";
-
-socket.connect(port, address);
-
-socket.on('data', function(data) {
- msg += data;
-});
-
-socket.on('end', function() {
- console.log(msg);
- socket.end();
-});
+++ /dev/null
-/* 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 net = require('net');
-
-var port = 7468;
-var server = net.createServer();
-
-server.listen(port, 5);
-
-server.on('connection', function(socket) {
- socket.end('Hello IoT.js');
-});
+++ /dev/null
-/* 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.h"
-#include "iotjs_tizen_service_app.h"
-
-/* thread */
-#include <pthread.h>
-#include <unistd.h>
-/* printf */
-#include <stdio.h>
-
-
-static void user_cb(int err, const char* data) {
- printf("err: %d, data: %s\n", err, data);
-}
-
-
-void* thread(void* data) {
- sleep(1);
-
- char* str = "1234567A1234567B1234567C";
- IOTJS_TIZEN_CALL_JFUNC("hello", "world", user_cb);
- IOTJS_TIZEN_CALL_JFUNC("hello", str, user_cb);
- IOTJS_TIZEN_CALL_JFUNC("hello", "", user_cb);
- IOTJS_TIZEN_CALL_JFUNC("", "", user_cb);
- IOTJS_TIZEN_CALL_JFUNC("", "", NULL);
- IOTJS_TIZEN_CALL_JFUNC("notReturnString", "", user_cb);
- return 0;
-}
-
-
-int main(int argc, char** argv) {
- pthread_t tid;
- if (pthread_create(&(tid), NULL, &thread, NULL)) {
- return 1;
- }
-
- return iotjs_entry(argc, argv);
-}
+++ /dev/null
-/* 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');
-
-tizen.hello = function(data) {
- return 'tizen.hello is called with data, ' + (data ? data : 'null');
-}
-
-tizen.notReturnString = function(data) {
-}
-
-setInterval(function() {
- console.log('heartbeat');
-}, 10000);
+++ /dev/null
-/* 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 <CR>
- 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);
- }
-});
+++ /dev/null
-/* 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:
- *
- * Runs chat-bots which talk to each other using UDP protocol. The first
- * instance will create a server node and the other will connect to it
- * automatically
- *
- * Usage:
- *
- * This example requires multiple iotjs instances on different machines in the
- * same LAN/WIFI network. Each machine should run:
- *
- * $ iotjs chat.js
- *
- * This will handle everything and the "chat" activity will be printed on
- * the console
- */
-
-var dgram = require('dgram'),
- log_enabled = true,
- socket = null,
- mode = 'client', // client / server
- messages = [ // some sentences to send over udp
- 'Hello! How are you?',
- 'The wether was great last weekend, what did you do?',
- 'Last weekend I was trekking in the mountains, it was great.',
- 'How\'s the family?',
- 'My family is great.',
- 'I have watched a great film yesterday.',
- 'I have to go to the dentist.',
- 'What\'s on your mind?',
- 'It\'s getting late.',
- 'You can do anything you want.',
- 'I love camping in the woods',
- 'Do you like rock music?',
- 'I like pop music.',
- 'I would really like to spend some time with you.',
- 'My dad owns a radio store.',
- 'I had great success with building my business'
- ],
- names = [ // few available nicknames
- 'phil',
- 'tom',
- 'kate',
- 'john',
- 'george'
- ],
- nickname = '',
- remote = {},
- clients = [],
- MSG = {
- INQUIRE_SERVER: 'is_anyone_here',
- INQUIRE_SERVER_ADDR: 'i_am_here_dave',
- JOIN: 'join',
- CHAT: 'chat'
- },
- joined = false,
- PORT = 9292,
- bcastTimer = null,
- converseTimer = null,
- CONVERSE_INTERVAL = (1 + (Math.random() * 3)) * 1000, // between 1 and 3
- BCAST_TTL = 1000, // 1s wait for response
- BCAST_ADDR = '255.255.255.255';
-
-// log only if log_enabled flag is set to true
-function log(/*...args*/) {
- if (log_enabled) {
- console.log.apply(console, [].slice.call(arguments));
- }
-}
-
-// return a random sentence
-function randomMessage() {
- return messages[(Math.random() * messages.length) | 0];
-}
-
-// return a random nickname with random "year" suffix
-function randomNickname() {
- var name = names[(Math.random() * names.length) | 0];
- return name + '_' + (1980 + ((Math.random() * 30) | 0));
-}
-
-// wraps arguments to JSON string format
-function wrapToString(/*...args*/) {
- return JSON.stringify([].slice.call(arguments));
-}
-
-// closes socket and releases timers
-function cleanup() {
- if (socket) {
- socket.close(function (err) {
- if (err) {
- log('ERROR: could not close server: ' + err);
- } else {
- log('INFO: server closed');
- }
- });
- }
-
- if (converseTimer) {
- clearInterval(converseTimer);
- }
-
- if (bcastTimer) {
- clearTimeout(bcastTimer);
- }
-}
-
-// sends a random message to udp server/clients
-function converse() {
- var message = randomMessage(),
- msg = new Buffer(wrapToString(MSG.CHAT, nickname, message));
-
- if (mode === 'server') {
- console.log(nickname + ': ' + message); // log my messages
- forwardMessageToClients(msg);
- } else {
- socket.send(
- msg,
- 0,
- msg.length,
- remote.port,
- remote.address,
- function (err) {
- if (err) {
- log('ERROR: could not send message: ' + err);
- }
- });
- }
-}
-
-// set server mode if no udp inquire was received
-function bcastTimeoutHandle() {
- mode = 'server';
- log('INFO: nobody replied, starting server mode');
-}
-
-// send join message to server and generate nickname
-function join() {
- var message = new Buffer(wrapToString(MSG.JOIN));
-
- nickname = randomNickname();
-
- socket.send(
- message,
- 0,
- message.length,
- remote.port,
- remote.address,
- function (err) {
- if (err) {
- log('ERROR: could not join: ' + err);
- } else {
- log('INFO: joined!');
- joined = true;
- converseTimer = setInterval(converse, CONVERSE_INTERVAL);
- }
- });
-}
-
-// sends supplied message to connected clients
-function forwardMessageToClients(message) {
- var i = 0,
- l = clients.length;
-
- for (; i < l; ++i) {
- socket.send(
- message,
- 0,
- message.length,
- clients[i].port,
- clients[i].address,
- function (err) {
- if (err) {
- log('ERROR: could not send data to client: ' + err);
- }
- });
- }
-}
-
-// handles incomming UDP data
-function handleServerMessage(data, rinfo) {
- var message = JSON.parse(data.toString());
-
- switch (message[0]) {
- case MSG.INQUIRE_SERVER: // when somebody asks for the server addres
- if (mode === 'server') {
- log('INFO: host inquiry: ' + rinfo.address + ':' + rinfo.port);
- message = new Buffer(wrapToString(MSG.INQUIRE_SERVER_ADDR));
- socket.send(
- message,
- 0,
- message.length,
- rinfo.port,
- rinfo.address,
- function (err) {
- if (err) {
- log('ERROR: could not respond to inquiry: ' + err);
- } else {
- log('INFO: responded');
- }
- });
- }
- break;
- case MSG.INQUIRE_SERVER_ADDR: // response with server address
- if (mode === 'client' && !joined) {
- remote.port = rinfo.port;
- remote.address = rinfo.address;
- clearTimeout(bcastTimer);
- join();
- }
- break;
- case MSG.JOIN: // when a host joins server chat
- log('INFO: host joining: ' + rinfo.address + ':' + rinfo.port);
- clients.push(rinfo);
- if (!converseTimer) {
- nickname = randomNickname();
- converseTimer = setInterval(converse, CONVERSE_INTERVAL);
- }
- break;
- case MSG.CHAT: // plain chat messages
- console.log(message[1] + ': ' + message[2]); // console here
- // not log wrap
- if (mode === 'server') {
- forwardMessageToClients(data);
- }
- break;
- default: // everything other, should never run
- log('INFO: i do not understand: ' + data.toString());
- break;
- }
-}
-
-
-// check if anyone else is server
-log('INFO: looking up server');
-socket = dgram.createSocket({type: 'udp4'});
-socket.on('message', handleServerMessage);
-socket.bind(PORT, function (err) {
- var message = new Buffer(wrapToString(MSG.INQUIRE_SERVER));
- if (err) {
- log('ERROR: could not bind to server port: ' + err);
- } else {
- bcastTimer = setTimeout(bcastTimeoutHandle, BCAST_TTL);
-
- // first try to find out if any server is available in the network
- socket.setBroadcast(true);
- socket.send(
- message,
- 0,
- message.length,
- PORT,
- BCAST_ADDR,
- function (err) {
- if (err) {
- log('ERROR: could not send broadcast message: ' + err);
- }
- });
- }
-});
-
-process.on('exit', cleanup);
#include "iotjs_def.h"
#include "iotjs.h"
-#include "iotjs_handlewrap.h"
#include "iotjs_js.h"
#include "iotjs_string_ext.h"
-#include "jerryscript-debugger.h"
-#ifndef __NUTTX__
+#include "jerryscript-ext/debugger.h"
+#if !defined(__NUTTX__) && !defined(__TIZENRT__)
#include "jerryscript-port-default.h"
#endif
#include "jerryscript-port.h"
#include "jerryscript.h"
+#include "iotjs_uv_handle.h"
+
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
// Initialize jerry.
jerry_init(jerry_flags);
+#ifdef JERRY_DEBUGGER
if (iotjs_environment_config(env)->debugger != NULL) {
- jerry_debugger_init(iotjs_environment_config(env)->debugger->port);
+ uint16_t port = iotjs_environment_config(env)->debugger->port;
+ jerryx_debugger_after_connect(jerryx_debugger_tcp_create(port) &&
+ jerryx_debugger_ws_create());
if (!jerry_debugger_is_connected()) {
- DLOG("jerry_debugger_init() failed");
+ DLOG("jerry debugger connection failed");
return false;
}
jerry_debugger_continue();
}
+#endif
// Set magic strings.
iotjs_register_jerry_magic_string();
// Do parse and run to generate initial javascript environment.
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)) {
+ if (jerry_value_is_error(parsed_code)) {
DLOG("jerry_parse() failed");
jerry_release_value(parsed_code);
return false;
}
jerry_value_t ret_val = jerry_run(parsed_code);
- if (jerry_value_has_error_flag(ret_val)) {
+ if (jerry_value_is_error(ret_val)) {
DLOG("jerry_run() failed");
jerry_release_value(parsed_code);
jerry_release_value(ret_val);
}
+#ifdef JERRY_DEBUGGER
+void iotjs_restart(iotjs_environment_t* env, jerry_value_t jmain) {
+ jerry_value_t abort_value = jerry_get_value_from_error(jmain, false);
+ if (jerry_value_is_string(abort_value)) {
+ /* TODO: When there is an api function to check for reset,
+ this needs an update. */
+ static const char restart_str[] = "r353t";
+
+ jerry_size_t str_size = jerry_get_string_size(abort_value);
+
+ if (str_size == sizeof(restart_str) - 1) {
+ jerry_char_t str_buf[5];
+ jerry_string_to_char_buffer(abort_value, str_buf, str_size);
+ if (memcmp(restart_str, (char*)(str_buf), str_size) == 0) {
+ iotjs_environment_config(env)->debugger->context_reset = true;
+ }
+ }
+ }
+ jerry_release_value(abort_value);
+}
+#endif
+
+
void iotjs_run(iotjs_environment_t* env) {
// Evaluating 'iotjs.js' returns a function.
#ifndef ENABLE_SNAPSHOT
iotjs_s, iotjs_l, false);
#else
jerry_value_t jmain =
- jerry_exec_snapshot((const void*)iotjs_js_modules_s, iotjs_js_modules_l,
- module_iotjs_idx, 0);
+ jerry_exec_snapshot((const uint32_t*)iotjs_js_modules_s,
+ iotjs_js_modules_l, module_iotjs_idx,
+ JERRY_SNAPSHOT_EXEC_ALLOW_STATIC);
#endif
- if (jerry_value_has_error_flag(jmain) && !iotjs_environment_is_exiting(env)) {
- jerry_value_t errval = jerry_get_value_without_error_flag(jmain);
+#ifdef JERRY_DEBUGGER
+ if (jerry_value_is_abort(jmain)) {
+ iotjs_restart(env, jmain);
+ } else
+#endif
+ if (jerry_value_is_error(jmain) && !iotjs_environment_is_exiting(env)) {
+ jerry_value_t errval = jerry_get_value_from_error(jmain, false);
iotjs_uncaught_exception(errval);
jerry_release_value(errval);
}
more |= iotjs_process_next_tick();
jerry_value_t ret_val = jerry_run_all_enqueued_jobs();
- if (jerry_value_has_error_flag(ret_val)) {
+ if (jerry_value_is_error(ret_val)) {
DLOG("jerry_run_all_enqueued_jobs() failed");
}
}
-static void iotjs_uv_walk_to_close_callback(uv_handle_t* handle, void* arg) {
- iotjs_handlewrap_t* handle_wrap = iotjs_handlewrap_from_handle(handle);
- IOTJS_ASSERT(handle_wrap != NULL);
-
- 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_walk(loop, (uv_walk_cb)iotjs_uv_handle_close, NULL);
uv_run(loop, UV_RUN_DEFAULT);
int res = uv_loop_close(loop);
// Initialize debug log and environments
iotjs_debuglog_init();
+ srand((unsigned)jerry_port_get_current_time());
iotjs_environment_t* env = iotjs_environment_get();
if (!iotjs_environment_parse_command_line_arguments(env, (uint32_t)argc,
argv)) {
- DLOG("iotjs_environment_parse_command_line_arguments failed");
ret_code = 1;
goto exit;
}
iotjs_terminate(env);
exit:
+#ifdef JERRY_DEBUGGER
if (iotjs_environment_config(env)->debugger &&
iotjs_environment_config(env)->debugger->context_reset) {
iotjs_environment_release();
return iotjs_entry(argc, argv);
}
+#endif
iotjs_environment_release();
iotjs_debuglog_release();
#include "iotjs_def.h"
#include "iotjs_binding.h"
#include "iotjs_js.h"
+#include "modules/iotjs_module_buffer.h"
#include <string.h>
-static iotjs_jargs_t jargs_empty;
-
-
jerry_value_t iotjs_jval_create_string(const iotjs_string_t* v) {
jerry_value_t jval;
jerry_value_t iotjs_jval_create_byte_array(uint32_t len, const char* data) {
- IOTJS_ASSERT(data != NULL);
+ if (data == NULL) {
+ len = 0;
+ }
jerry_value_t jval = jerry_create_array(len);
jerry_value_t iotjs_jval_create_error_without_error_flag(const char* msg) {
jerry_value_t jval =
jerry_create_error(JERRY_ERROR_COMMON, (const jerry_char_t*)(msg));
- jerry_value_clear_error_flag(&jval);
-
- return jval;
+ return jerry_get_value_from_error(jval, true);
}
}
+bool iotjs_jbuffer_as_string(jerry_value_t jval, iotjs_string_t* out_string) {
+ if (out_string == NULL) {
+ return false;
+ }
+
+ if (jerry_value_is_string(jval)) {
+ jerry_size_t size = jerry_get_string_size(jval);
+
+ if (size == 0) {
+ return false;
+ }
+
+ char* buffer = iotjs_buffer_allocate(size + 1);
+ size_t check =
+ jerry_string_to_char_buffer(jval, (jerry_char_t*)buffer, size);
+
+ IOTJS_ASSERT(check == size);
+
+ buffer[size] = '\0';
+ *out_string = iotjs_string_create_with_buffer(buffer, size);
+ return true;
+ }
+
+ iotjs_bufferwrap_t* buffer_wrap = iotjs_jbuffer_get_bufferwrap_ptr(jval);
+
+ if (buffer_wrap == NULL || buffer_wrap->length == 0) {
+ return false;
+ }
+
+ size_t size = buffer_wrap->length;
+
+ char* buffer = iotjs_buffer_allocate(size + 1);
+ memcpy(buffer, buffer_wrap->buffer, size);
+ buffer[size] = '\0';
+ *out_string = iotjs_string_create_with_buffer(buffer, size);
+ return true;
+}
+
+
+void iotjs_jval_as_tmp_buffer(jerry_value_t jval,
+ iotjs_tmp_buffer_t* out_buffer) {
+ out_buffer->jval = jerry_create_undefined();
+ out_buffer->buffer = NULL;
+ out_buffer->length = 0;
+
+ if (jerry_value_is_undefined(jval)) {
+ return;
+ }
+
+ iotjs_bufferwrap_t* buffer_wrap = iotjs_jbuffer_get_bufferwrap_ptr(jval);
+
+ if (buffer_wrap != NULL) {
+ IOTJS_ASSERT(buffer_wrap->jobject == jval);
+
+ jerry_acquire_value(jval);
+ out_buffer->jval = buffer_wrap->jobject;
+ out_buffer->buffer = buffer_wrap->buffer;
+ out_buffer->length = buffer_wrap->length;
+ return;
+ }
+
+ bool was_string = true;
+
+ if (!jerry_value_is_string(jval)) {
+ jval = jerry_value_to_string(jval);
+
+ if (jerry_value_is_error(jval)) {
+ out_buffer->jval = jval;
+ return;
+ }
+
+ was_string = false;
+ }
+
+ jerry_size_t size = jerry_get_string_size(jval);
+
+ if (size == 0) {
+ if (!was_string) {
+ jerry_release_value(jval);
+ }
+ return;
+ }
+
+ char* buffer = iotjs_buffer_allocate(size);
+ size_t check = jerry_string_to_char_buffer(jval, (jerry_char_t*)buffer, size);
+
+ IOTJS_ASSERT(check == size);
+
+ out_buffer->buffer = buffer;
+ out_buffer->length = size;
+
+ if (!was_string) {
+ jerry_release_value(jval);
+ }
+}
+
+
+void iotjs_jval_get_jproperty_as_tmp_buffer(jerry_value_t jobj,
+ const char* name,
+ iotjs_tmp_buffer_t* out_buffer) {
+ jerry_value_t jproperty = iotjs_jval_get_property(jobj, name);
+
+ if (jerry_value_is_error(jproperty)) {
+ out_buffer->jval = jproperty;
+ out_buffer->buffer = NULL;
+ out_buffer->length = 0;
+ return;
+ }
+
+ iotjs_jval_as_tmp_buffer(jproperty, out_buffer);
+
+ jerry_release_value(jproperty);
+}
+
+
+void iotjs_free_tmp_buffer(iotjs_tmp_buffer_t* tmp_buffer) {
+ if (jerry_value_is_undefined(tmp_buffer->jval)) {
+ if (tmp_buffer->buffer != NULL) {
+ iotjs_buffer_release(tmp_buffer->buffer);
+ }
+ return;
+ }
+
+ IOTJS_ASSERT(!jerry_value_is_error(tmp_buffer->jval) ||
+ tmp_buffer->buffer == NULL);
+
+ jerry_release_value(tmp_buffer->jval);
+}
+
+
iotjs_string_t iotjs_jval_as_string(jerry_value_t jval) {
IOTJS_ASSERT(jerry_value_is_string(jval));
- jerry_size_t size = jerry_get_string_size(jval);
+ jerry_size_t size = jerry_get_utf8_string_size(jval);
if (size == 0)
return iotjs_string_create();
char* buffer = iotjs_buffer_allocate(size + 1);
jerry_char_t* jerry_buffer = (jerry_char_t*)(buffer);
- size_t check = jerry_string_to_char_buffer(jval, jerry_buffer, size);
+ size_t check = jerry_string_to_utf8_char_buffer(jval, jerry_buffer, size);
IOTJS_ASSERT(check == size);
buffer[size] = '\0';
bool iotjs_jval_set_prototype(const jerry_value_t jobj, jerry_value_t jproto) {
jerry_value_t ret = jerry_set_prototype(jobj, jproto);
- bool error_found = jerry_value_has_error_flag(ret);
+ bool error_found = jerry_value_is_error(ret);
jerry_release_value(ret);
return !error_found;
jerry_value_t ret_val = jerry_set_property(jobj, prop_name, value);
jerry_release_value(prop_name);
- IOTJS_ASSERT(!jerry_value_has_error_flag(ret_val));
+ IOTJS_ASSERT(!jerry_value_is_error(ret_val));
jerry_release_value(ret_val);
}
jerry_value_t res = jerry_get_property(jobj, prop_name);
jerry_release_value(prop_name);
- if (jerry_value_has_error_flag(res)) {
+ if (jerry_value_is_error(res)) {
jerry_release_value(res);
return jerry_create_undefined();
}
}
-uintptr_t iotjs_jval_get_object_native_handle(jerry_value_t jobj) {
+void* iotjs_jval_get_object_native_handle(jerry_value_t jobj,
+ JNativeInfoType* required_info) {
IOTJS_ASSERT(jerry_value_is_object(jobj));
- uintptr_t ptr = 0x0;
+ void* ptr = NULL;
JNativeInfoType* out_info;
- jerry_get_object_native_pointer(jobj, (void**)&ptr, &out_info);
+ bool has_p = jerry_get_object_native_pointer(jobj, (void**)&ptr, &out_info);
+
+ if (!has_p || (required_info != NULL && out_info != required_info)) {
+ return NULL;
+ }
return ptr;
}
IOTJS_ASSERT(jerry_value_is_object(jarr));
jerry_value_t ret_val = jerry_set_property_by_index(jarr, idx, jval);
- IOTJS_ASSERT(!jerry_value_has_error_flag(ret_val));
+ IOTJS_ASSERT(!jerry_value_is_error(ret_val));
jerry_release_value(ret_val);
}
jerry_value_t res = jerry_get_property_by_index(jarr, idx);
- if (jerry_value_has_error_flag(res)) {
+ if (jerry_value_is_error(res)) {
jerry_release_value(res);
return jerry_create_undefined();
}
}
-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_length_t jargc_ = iotjs_jargs_length(jargs);
-
- jerry_value_t jres = jerry_call_function(jfunc, jthis, jargs->argv, jargc_);
-
- 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((const jerry_char_t*)name, name_len,
(const jerry_char_t*)data, size, opts);
- if (!jerry_value_has_error_flag(jres)) {
+ if (!jerry_value_is_error(jres)) {
jerry_value_t func = jres;
jres = jerry_run(func);
jerry_release_value(func);
return jerry_create_string((const jerry_char_t*)"Abort script");
}
-
-
-iotjs_jargs_t iotjs_jargs_create(uint16_t capacity) {
- if (capacity == 0) {
- return jargs_empty;
- }
-
- iotjs_jargs_t jargs;
-
- jargs.capacity = capacity;
- jargs.argc = 0;
- unsigned buffer_size = sizeof(jerry_value_t) * capacity;
- jargs.argv = (jerry_value_t*)iotjs_buffer_allocate(buffer_size);
-
- return jargs;
-}
-
-
-const iotjs_jargs_t* iotjs_jargs_get_empty() {
- return &jargs_empty;
-}
-
-
-void iotjs_jargs_destroy(iotjs_jargs_t* jargs) {
- IOTJS_ASSERT(jargs && jargs->argc <= jargs->capacity);
-
- if (jargs->capacity > 0) {
- IOTJS_ASSERT(jargs->argv);
- for (unsigned i = 0; i < jargs->argc; ++i) {
- jerry_release_value(jargs->argv[i]);
- }
- IOTJS_RELEASE(jargs->argv);
- } else {
- IOTJS_ASSERT(jargs->argv == NULL);
- }
-}
-
-
-uint16_t iotjs_jargs_length(const iotjs_jargs_t* jargs) {
- IOTJS_ASSERT(jargs);
- return jargs->argc;
-}
-
-
-void iotjs_jargs_append_jval(iotjs_jargs_t* jargs, jerry_value_t 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_jargs_append_jval(jargs, jerry_create_undefined());
-}
-
-
-void iotjs_jargs_append_null(iotjs_jargs_t* jargs) {
- iotjs_jargs_append_jval(jargs, jerry_create_null());
-}
-
-
-void iotjs_jargs_append_bool(iotjs_jargs_t* jargs, bool x) {
- iotjs_jargs_append_jval(jargs, jerry_create_boolean(x));
-}
-
-
-void iotjs_jargs_append_number(iotjs_jargs_t* jargs, double x) {
- jerry_value_t jval = jerry_create_number(x);
- iotjs_jargs_append_jval(jargs, jval);
- jerry_release_value(jval);
-}
-
-
-void iotjs_jargs_append_string(iotjs_jargs_t* jargs, const iotjs_string_t* x) {
- jerry_value_t jval = iotjs_jval_create_string(x);
- iotjs_jargs_append_jval(jargs, jval);
- jerry_release_value(jval);
-}
-
-
-void iotjs_jargs_append_error(iotjs_jargs_t* jargs, const char* msg) {
- jerry_value_t error = iotjs_jval_create_error_without_error_flag(msg);
- iotjs_jargs_append_jval(jargs, error);
- jerry_release_value(error);
-}
-
-
-void iotjs_jargs_append_string_raw(iotjs_jargs_t* jargs, const char* x) {
- jerry_value_t jval = jerry_create_string((const jerry_char_t*)x);
- iotjs_jargs_append_jval(jargs, jval);
- jerry_release_value(jval);
-}
-
-
-void iotjs_jargs_replace(iotjs_jargs_t* jargs, uint16_t index,
- jerry_value_t x) {
- IOTJS_ASSERT(jargs && index < jargs->argc);
- IOTJS_ASSERT(jargs->argv);
-
- jerry_release_value(jargs->argv[index]);
- jargs->argv[index] = jerry_acquire_value(x);
-}
jerry_value_t iotjs_jval_as_object(jerry_value_t);
jerry_value_t iotjs_jval_as_array(jerry_value_t);
jerry_value_t iotjs_jval_as_function(jerry_value_t);
+bool iotjs_jbuffer_as_string(jerry_value_t jval, iotjs_string_t* out_string);
+
+/* Temporary Buffers for JavaScript Values */
+
+typedef struct {
+ jerry_value_t jval;
+ char* buffer;
+ size_t length;
+} iotjs_tmp_buffer_t;
+
+void iotjs_jval_as_tmp_buffer(jerry_value_t jval,
+ iotjs_tmp_buffer_t* out_buffer);
+void iotjs_jval_get_jproperty_as_tmp_buffer(jerry_value_t jobj,
+ const char* name,
+ iotjs_tmp_buffer_t* out_buffer);
+void iotjs_free_tmp_buffer(iotjs_tmp_buffer_t* tmp_buffer);
/* Methods for General JavaScript Object */
void iotjs_jval_set_method(jerry_value_t jobj, const char* name,
jerry_value_t iotjs_jval_get_property(jerry_value_t jobj, const char* name);
-uintptr_t iotjs_jval_get_object_native_handle(jerry_value_t jobj);
+void* iotjs_jval_get_object_native_handle(jerry_value_t jobj,
+ JNativeInfoType* required_info);
void iotjs_jval_set_property_by_index(jerry_value_t jarr, uint32_t idx,
jerry_value_t jval);
jerry_value_t iotjs_jval_get_property_by_index(jerry_value_t jarr,
uint32_t idx);
-
-typedef struct {
- uint16_t capacity;
- uint16_t argc;
- jerry_value_t* argv;
-} iotjs_jargs_t;
-
-
-iotjs_jargs_t iotjs_jargs_create(uint16_t capacity);
-
-const iotjs_jargs_t* iotjs_jargs_get_empty();
-
-void iotjs_jargs_destroy(iotjs_jargs_t* jargs);
-
-uint16_t iotjs_jargs_length(const iotjs_jargs_t* jargs);
-
-void iotjs_jargs_append_jval(iotjs_jargs_t* jargs, jerry_value_t x);
-void iotjs_jargs_append_undefined(iotjs_jargs_t* jargs);
-void iotjs_jargs_append_null(iotjs_jargs_t* jargs);
-void iotjs_jargs_append_bool(iotjs_jargs_t* jargs, bool x);
-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);
-void iotjs_jargs_append_string_raw(iotjs_jargs_t* jargs, const char* x);
-void iotjs_jargs_append_error(iotjs_jargs_t* jargs, const char* msg);
-
-
-void iotjs_jargs_replace(iotjs_jargs_t* jargs, uint16_t index, jerry_value_t x);
-
-// Calls JavaScript function.
-jerry_value_t iotjs_jhelper_call(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,
#define JS_CREATE_ERROR(TYPE, message) \
jerry_create_error(JERRY_ERROR_##TYPE, (const jerry_char_t*)message)
+#define jerry_value_is_any(value) true
+#define iotjs_jval_as_any(value) (value)
+
#define JS_CHECK(predicate) \
if (!(predicate)) { \
return JS_CREATE_ERROR(COMMON, "Internal error"); \
#define DJS_CHECK_ARG_IF_EXIST(index, type) JS_CHECK_ARG_IF_EXIST(index, type)
#endif
-#define __JS_DECLARE_PTR(type, name, value) \
- iotjs_##type##_t* name; \
+#define JS_DECLARE_PTR(JOBJ, TYPE, NAME) \
+ TYPE* NAME; \
do { \
- JNativeInfoType* 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, ""); \
+ NAME = \
+ iotjs_jval_get_object_native_handle(JOBJ, &this_module_native_info); \
+ if (NAME == NULL) { \
+ return JS_CREATE_ERROR(COMMON, "Internal"); \
} \
} while (0)
-#define JS_DECLARE_THIS_PTR(type, name) __JS_DECLARE_PTR(type, name, jthis)
+#define JS_DECLARE_THIS_PTR(type, name) \
+ JS_DECLARE_PTR(jthis, iotjs_##type##_t, name)
#define JS_DECLARE_OBJECT_PTR(index, type, name) \
- __JS_DECLARE_PTR(type, name, jargv[index])
+ JS_DECLARE_PTR(jargv[index], iotjs_##type##_t, name)
-#define __JS_GET_REQUIRED_VALUE(target, property, type, value) \
+#define JS_GET_REQUIRED_ARG_VALUE(index, target, property, type) \
do { \
+ if (jerry_value_is_undefined(jargv[index])) { \
+ 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 { \
+ return JS_CREATE_ERROR(TYPE, "Bad arguments, required " property \
+ " is not a " #type); \
+ } \
+ } while (0)
+
+#define JS_GET_REQUIRED_CONF_VALUE(src, target, property, type) \
+ do { \
+ jerry_value_t value = iotjs_jval_get_property(src, property); \
if (jerry_value_is_undefined(value)) { \
+ jerry_release_value(value); \
return JS_CREATE_ERROR(TYPE, "Missing argument, required " property); \
} else if (jerry_value_is_##type(value)) { \
target = iotjs_jval_as_##type(value); \
+ jerry_release_value(value); \
} else { \
+ jerry_release_value(value); \
return JS_CREATE_ERROR(TYPE, "Bad arguments, required " property \
" is not a " #type); \
} \
} while (0)
-#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);
/**
iotjs_jval_get_property(process, IOTJS_MAGIC_STRING__ONUNCAUGHTEXCEPTION);
IOTJS_ASSERT(jerry_value_is_function(jonuncaughtexception));
- iotjs_jargs_t args = iotjs_jargs_create(1);
- iotjs_jargs_append_jval(&args, jexception);
-
- jerry_value_t jres = iotjs_jhelper_call(jonuncaughtexception, process, &args);
+ jerry_value_t jres =
+ jerry_call_function(jonuncaughtexception, process, &jexception, 1);
- iotjs_jargs_destroy(&args);
jerry_release_value(jonuncaughtexception);
- if (jerry_value_has_error_flag(jres)) {
+ if (jerry_value_is_error(jres)) {
iotjs_environment_t* env = iotjs_environment_get();
if (!iotjs_environment_is_exiting(env)) {
iotjs_jval_get_property(process, IOTJS_MAGIC_STRING_EMITEXIT);
if (jerry_value_is_function(jexit)) {
- iotjs_jargs_t jargs = iotjs_jargs_create(1);
- iotjs_jargs_append_number(&jargs, code);
+ jerry_value_t jcode = jerry_create_number(code);
+ jerry_value_t jres = jerry_call_function(jexit, process, &jcode, 1);
- jerry_value_t jres = iotjs_jhelper_call(jexit, process, &jargs);
-
- if (jerry_value_has_error_flag(jres)) {
+ if (jerry_value_is_error(jres)) {
iotjs_set_process_exitcode(2);
}
- iotjs_jargs_destroy(&jargs);
+ jerry_release_value(jcode);
jerry_release_value(jres);
}
IOTJS_ASSERT(jerry_value_is_function(jon_next_tick));
jerry_value_t jres =
- iotjs_jhelper_call(jon_next_tick, jerry_create_undefined(),
- iotjs_jargs_get_empty());
+ jerry_call_function(jon_next_tick, jerry_create_undefined(), NULL, 0);
bool ret = false;
- if (!jerry_value_has_error_flag(jres)) {
+ if (!jerry_value_is_error(jres)) {
ret = iotjs_jval_as_boolean(jres);
}
// Make a callback for the given `function` with `this_` binding and `args`
// arguments. The next tick callbacks registered via `process.nextTick()`
// will be called after the callback function `function` returns.
-void iotjs_make_callback(jerry_value_t jfunction, jerry_value_t jthis,
- const iotjs_jargs_t* jargs) {
+void iotjs_invoke_callback(jerry_value_t jfunc, jerry_value_t jthis,
+ const jerry_value_t* jargv, size_t jargc) {
jerry_value_t result =
- iotjs_make_callback_with_result(jfunction, jthis, jargs);
+ iotjs_invoke_callback_with_result(jfunc, jthis, jargv, jargc);
jerry_release_value(result);
}
+jerry_value_t iotjs_invoke_callback_with_result(jerry_value_t jfunc,
+ jerry_value_t jthis,
+ const jerry_value_t* jargv,
+ size_t jargc) {
+ IOTJS_ASSERT(jerry_value_is_function(jfunc));
-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)) {
- jerry_value_t errval = jerry_get_value_without_error_flag(jres);
+ jerry_value_t jres = jerry_call_function(jfunc, jthis, jargv, jargc);
+ if (jerry_value_is_error(jres)) {
+ jerry_value_t errval = jerry_get_value_from_error(jres, false);
iotjs_uncaught_exception(errval);
jerry_release_value(errval);
}
iotjs_jval_get_property(process, IOTJS_MAGIC_STRING_EXITCODE);
uint8_t exitcode = 0;
jerry_value_t num_val = jerry_value_to_number(jexitcode);
- if (jerry_value_has_error_flag(num_val)) {
+ if (jerry_value_is_error(num_val)) {
exitcode = 1;
- jerry_value_clear_error_flag(&num_val);
} else {
exitcode = (uint8_t)iotjs_jval_as_number(num_val);
}
+
+ uint8_t native_exitcode = iotjs_environment_get()->exitcode;
+ if (native_exitcode != exitcode && native_exitcode) {
+ exitcode = native_exitcode;
+ }
jerry_release_value(num_val);
jerry_release_value(jexitcode);
return (int)exitcode;
void iotjs_set_process_exitcode(int code) {
const jerry_value_t process = iotjs_module_get("process");
- iotjs_jval_set_property_number(process, IOTJS_MAGIC_STRING_EXITCODE, code);
+ jerry_value_t jstring =
+ jerry_create_string((jerry_char_t*)IOTJS_MAGIC_STRING_EXITCODE);
+ jerry_value_t jcode = jerry_create_number(code);
+ jerry_value_t ret_val = jerry_set_property(process, jstring, jcode);
+ if (jerry_value_is_error(ret_val)) {
+ iotjs_environment_get()->exitcode = 1;
+ }
+
+ jerry_release_value(ret_val);
+ jerry_release_value(jstring);
+ jerry_release_value(jcode);
}
bool iotjs_process_next_tick();
-void iotjs_make_callback(jerry_value_t jfunction, jerry_value_t jthis,
- const iotjs_jargs_t* jargs);
-
-jerry_value_t iotjs_make_callback_with_result(jerry_value_t jfunction,
- jerry_value_t jthis,
- const iotjs_jargs_t* jargs);
+void iotjs_invoke_callback(jerry_value_t jfunc, jerry_value_t jthis,
+ const jerry_value_t* jargv, size_t jargc);
+jerry_value_t iotjs_invoke_callback_with_result(jerry_value_t jfunc,
+ jerry_value_t jthis,
+ const jerry_value_t* jargv,
+ size_t jargc);
int iotjs_process_exitcode();
void iotjs_set_process_exitcode(int code);
--- /dev/null
+/* 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_COMPATIBILITY_H
+#define IOTJS_COMPATIBILITY_H
+
+/* Windows compatiblity defines */
+#ifdef WIN32
+#include <fcntl.h>
+#include <windows.h>
+/* Map windows _O_* to O_* defines as on Linux systems. */
+#define O_APPEND _O_APPEND
+#define O_CREAT _O_CREAT
+#define O_EXCL _O_EXCL
+#define O_RDONLY _O_RDONLY
+#define O_RDWR _O_RDWR
+#define O_TRUNC _O_TRUNC
+#define O_WRONLY _O_WRONLY
+/* On windows there is no O_SYNC directly, disable it for now. */
+#define O_SYNC 0x0
+
+#ifndef PATH_MAX
+#define PATH_MAX MAX_PATH
+#endif
+
+#endif
+
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode) & (S_IFMT)) == S_IFREG)
+#endif
+
+#endif /* IOTJS_COMPATIBILITY_H */
#define TARGET_OS "darwin"
#elif defined(__TIZENRT__)
#define TARGET_OS "tizenrt"
-#else /* !__linux__ && !__NUTTX__ !__APPLE__ && !__TIZENRT__*/
+#elif defined(WIN32)
+#define TARGET_OS "windows"
+#else /* !__linux__ && !__NUTTX__ !__APPLE__ && !__TIZENRT__ && !WIN32 */
#define TARGET_OS "unknown"
#endif /* __linux__ */
-#define IOTJS_VERSION "1.0.0"
+#define IOTJS_VERSION "1.0.0" "181221_630f029"
#if !defined(STRINGIFY)
#define STRINGIFY(x) #x
OPT_HELP,
OPT_MEM_STATS,
OPT_SHOW_OP,
+#ifdef JERRY_DEBUGGER
OPT_DEBUG_SERVER,
OPT_DEBUGGER_WAIT_SOURCE,
OPT_DEBUG_PORT,
+#endif
NUM_OF_OPTIONS
} cli_option_id_t;
return;
iotjs_environment_t* env = iotjs_environment_get();
+#ifdef JERRY_DEBUGGER
IOTJS_RELEASE(env->config.debugger);
+#endif
IOTJS_RELEASE(env->argv);
initialized = false;
}
env->state = kInitializing;
env->config.memstat = false;
env->config.show_opcode = false;
+#ifdef JERRY_DEBUGGER
env->config.debugger = NULL;
+#endif
+ env->exitcode = 0;
}
.longopt = "show-opcodes",
.help = "dump parser byte-code",
},
+#ifdef JERRY_DEBUGGER
{
.id = OPT_DEBUG_SERVER,
.opt = "d",
.more = 1,
.help = "debug server port (default: 5001)",
},
+#endif
};
const cli_option_t* cur_opt;
case OPT_SHOW_OP: {
env->config.show_opcode = true;
} break;
+#ifdef JERRY_DEBUGGER
+ case OPT_DEBUGGER_WAIT_SOURCE:
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;
+ env->config.debugger->wait_source =
+ cur_opt->id == OPT_DEBUGGER_WAIT_SOURCE;
} break;
case OPT_DEBUG_PORT: {
if (env->config.debugger) {
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;
+#endif
default:
break;
}
i += (1 + cur_opt->more);
}
+#ifdef JERRY_DEBUGGER
// If IoT.js is waiting for source from the debugger client,
// Further processing over command line argument is not needed.
if (env->config.debugger && env->config.debugger->wait_source)
return true;
+#endif
// There must be at least one argument after processing the IoT.js args,
if (argc - i < 1) {
#include "uv.h"
+#ifdef JERRY_DEBUGGER
typedef struct {
bool wait_source;
bool context_reset;
uint16_t port;
} DebuggerConfig;
+#endif
typedef struct {
uint32_t memstat : 1;
uint32_t show_opcode : 1;
+#ifdef JERRY_DEBUGGER
DebuggerConfig* debugger;
+#endif
} Config;
typedef enum {
// Run config
Config config;
+
+ // Exitcode
+ uint8_t exitcode;
} iotjs_environment_t;
void iotjs_environment_set_loop(iotjs_environment_t* env, uv_loop_t* loop);
const Config* iotjs_environment_config(const iotjs_environment_t* env);
+#ifdef JERRY_DEBUGGER
const DebuggerConfig* iotjs_environment_dconfig(const iotjs_environment_t* env);
+#endif
void iotjs_environment_set_state(iotjs_environment_t* env, State s);
bool iotjs_environment_is_exiting(iotjs_environment_t* env);
+++ /dev/null
-/* 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_handlewrap.h"
-
-
-void iotjs_handlewrap_initialize(iotjs_handlewrap_t* handlewrap,
- jerry_value_t jobject, uv_handle_t* handle,
- JNativeInfoType* native_info) {
- // Increase ref count of Javascript object to guarantee it is alive until the
- // handle has closed.
- jerry_value_t jobjectref = jerry_acquire_value(jobject);
- handlewrap->jobject = jobjectref;
- jerry_set_object_native_pointer(jobjectref, handlewrap, native_info);
-
- handlewrap->handle = handle;
- handlewrap->on_close_cb = NULL;
-
- handle->data = handlewrap;
-
- iotjs_handlewrap_validate(handlewrap);
-}
-
-
-void iotjs_handlewrap_destroy(iotjs_handlewrap_t* handlewrap) {
- // Handle should have been release before this.
- IOTJS_ASSERT(handlewrap->handle == NULL);
-}
-
-
-iotjs_handlewrap_t* iotjs_handlewrap_from_handle(uv_handle_t* handle) {
- iotjs_handlewrap_t* handlewrap = (iotjs_handlewrap_t*)(handle->data);
- iotjs_handlewrap_validate(handlewrap);
- return handlewrap;
-}
-
-
-iotjs_handlewrap_t* iotjs_handlewrap_from_jobject(jerry_value_t jobject) {
- iotjs_handlewrap_t* handlewrap =
- (iotjs_handlewrap_t*)(iotjs_jval_get_object_native_handle(jobject));
- iotjs_handlewrap_validate(handlewrap);
- return handlewrap;
-}
-
-
-uv_handle_t* iotjs_handlewrap_get_uv_handle(iotjs_handlewrap_t* handlewrap) {
- iotjs_handlewrap_validate(handlewrap);
- return handlewrap->handle;
-}
-
-
-jerry_value_t iotjs_handlewrap_jobject(iotjs_handlewrap_t* handlewrap) {
- iotjs_handlewrap_validate(handlewrap);
- return handlewrap->jobject;
-}
-
-
-static void iotjs_handlewrap_on_close(iotjs_handlewrap_t* handlewrap) {
- // The handle closed.
- // Calls registered close handler function.
- if (handlewrap->on_close_cb) {
- handlewrap->on_close_cb(handlewrap->handle);
- }
-
- // Set handle null.
- handlewrap->handle = NULL;
-
- // Decrease ref count of Javascript object. From now the object can be
- // reclaimed.
- jerry_release_value(handlewrap->jobject);
-}
-
-
-static void iotjs_on_handle_closed(uv_handle_t* handle) {
- iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_handle(handle);
- iotjs_handlewrap_on_close(handlewrap);
-}
-
-
-void iotjs_handlewrap_close(iotjs_handlewrap_t* handlewrap,
- OnCloseHandler on_close_cb) {
- 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");
- }
-}
-
-
-void iotjs_handlewrap_validate(iotjs_handlewrap_t* handlewrap) {
- IOTJS_ASSERT(handlewrap);
- IOTJS_ASSERT((void*)handlewrap == handlewrap->handle->data);
- IOTJS_ASSERT((uintptr_t)handlewrap ==
- iotjs_jval_get_object_native_handle(handlewrap->jobject));
-}
+++ /dev/null
-/* 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.
- */
-
-#ifndef IOTJS_HANDLEWRAP_H
-#define IOTJS_HANDLEWRAP_H
-
-
-#include <uv.h>
-
-#include "iotjs_binding.h"
-
-
-typedef void (*OnCloseHandler)(uv_handle_t*);
-
-
-// UV handle wrapper.
-// This wrapper connects a Javascript object and a libuv handler.
-// This wrapper will increase ref count for the Javascript object and decrease
-// it after corresponding handle has closed. Hence the Javascript object will
-// not turn into garbage until the handle is open.
-
-// Javascript object
-// ->
-// Create a handle wrap, initializing uv handle, increase ref count.
-// ->
-// The javascript object will be alive until handle has closed.
-// ->
-// Handle closed, release handle, decrease ref count.
-// ->
-// The javascript object now can be reclaimed by GC.
-
-typedef struct {
- jerry_value_t jobject;
- uv_handle_t* handle;
- OnCloseHandler on_close_cb;
-} iotjs_handlewrap_t;
-
-
-// jobject: Object that connect with the uv handle
-void iotjs_handlewrap_initialize(iotjs_handlewrap_t* handlewrap,
- jerry_value_t jobject, uv_handle_t* handle,
- JNativeInfoType* native_info);
-
-void iotjs_handlewrap_destroy(iotjs_handlewrap_t* handlewrap);
-
-void iotjs_handlewrap_close(iotjs_handlewrap_t* handlewrap,
- OnCloseHandler on_close_cb);
-
-iotjs_handlewrap_t* iotjs_handlewrap_from_handle(uv_handle_t* handle);
-iotjs_handlewrap_t* iotjs_handlewrap_from_jobject(jerry_value_t jobject);
-
-uv_handle_t* iotjs_handlewrap_get_uv_handle(iotjs_handlewrap_t* handlewrap);
-jerry_value_t iotjs_handlewrap_jobject(iotjs_handlewrap_t* handlewrap);
-
-void iotjs_handlewrap_validate(iotjs_handlewrap_t* handlewrap);
-
-
-#endif /* IOTJS_HANDLEWRAP_H */
#define IOTJS_MAGIC_STRING_ARCH "arch"
#define IOTJS_MAGIC_STRING_ARGV "argv"
#define IOTJS_MAGIC_STRING_BASE64 "base64"
+#ifdef ENABLE_MODULE_CRYPTO
+#define IOTJS_MAGIC_STRING_BASE64ENCODE "base64Encode"
+#endif
#if ENABLE_MODULE_UART
#define IOTJS_MAGIC_STRING_BAUDRATE "baudRate"
#endif
#endif
#define IOTJS_MAGIC_STRING_BYTELENGTH "byteLength"
#define IOTJS_MAGIC_STRING_BYTEPARSED "byteParsed"
+#define IOTJS_MAGIC_STRING_FROM_ARRAYBUFFER "fromArrayBuffer"
#if ENABLE_MODULE_HTTPS || ENABLE_MODULE_TLS
#define IOTJS_MAGIC_STRING_CA "ca"
#define IOTJS_MAGIC_STRING_CERT "cert"
#endif
#define IOTJS_MAGIC_STRING_DEBUGGERGETSOURCE "debuggerGetSource"
#define IOTJS_MAGIC_STRING_DEBUGGERWAITSOURCE "debuggerWaitSource"
+#if ENABLE_MODULE_WEBSOCKET
+#define IOTJS_MAGIC_STRING_DECODEFRAME "decodeFrame"
+#endif
#define IOTJS_MAGIC_STRING_DEVICE "device"
#if ENABLE_MODULE_GPIO
#define IOTJS_MAGIC_STRING_DIRECTION "direction"
#define IOTJS_MAGIC_STRING_HOME_U "HOME"
#define IOTJS_MAGIC_STRING_HOST "host"
#define IOTJS_MAGIC_STRING_HTTPPARSER "HTTPParser"
+#define IOTJS_MAGIC_STRING_HTTP_VERSION_MAJOR "http_major"
+#define IOTJS_MAGIC_STRING_HTTP_VERSION_MINOR "http_minor"
#if ENABLE_MODULE_GPIO
#define IOTJS_MAGIC_STRING_IN "IN"
#endif
#define IOTJS_MAGIC_STRING_LSB "LSB"
#define IOTJS_MAGIC_STRING_MAXSPEED "maxSpeed"
#endif
-#if ENABLE_MODULE_MQTT
+#if ENABLE_MODULE_MQTT || ENABLE_MODULE_WEBSOCKET
#define IOTJS_MAGIC_STRING_MESSAGE "message"
#endif
#define IOTJS_MAGIC_STRING_METHOD "method"
#if ENABLE_MODULE_MQTT
#define IOTJS_MAGIC_STRING_MQTTINIT "MqttInit"
#define IOTJS_MAGIC_STRING_MQTTMESSAGE "MqttMessage"
-#define IOTJS_MAGIC_STRING_MQTTHANDLE "MqttHandle"
+#define IOTJS_MAGIC_STRING_MQTTRECEIVE "MqttReceive"
#endif
#if ENABLE_MODULE_SPI
#define IOTJS_MAGIC_STRING_MSB "MSB"
#if ENABLE_MODULE_SPI || ENABLE_MODULE_GPIO
#define IOTJS_MAGIC_STRING_NONE_U "NONE"
#endif
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_ONACK "onack"
+#endif
#define IOTJS_MAGIC_STRING_ONBODY "OnBody"
#define IOTJS_MAGIC_STRING_ONCLOSE "onclose"
#define IOTJS_MAGIC_STRING_ONCLOSED "onClosed"
-#if ENABLE_MODULE_MQTT
-#define IOTJS_MAGIC_STRING__ONCONNECT "_onconnect"
-#endif
#define IOTJS_MAGIC_STRING_ONCONNECTION "onconnection"
#define IOTJS_MAGIC_STRING_ONDATA "onData"
-#ifdef ENABLE_MODULE_MQTT
-#define IOTJS_MAGIC_STRING__ONDISCONNECT "_ondisconnect"
-#endif
#define IOTJS_MAGIC_STRING_ONEND "onEnd"
#define IOTJS_MAGIC_STRING_ONERROR "onError"
#if ENABLE_MODULE_TLS
#define IOTJS_MAGIC_STRING_ONHEADERSCOMPLETE "OnHeadersComplete"
#define IOTJS_MAGIC_STRING_ONHEADERS "OnHeaders"
#define IOTJS_MAGIC_STRING_ONMESSAGECOMPLETE "OnMessageComplete"
-#if ENABLE_MODULE_MQTT
-#define IOTJS_MAGIC_STRING__ONMESSAGE "_onmessage"
-#endif
#define IOTJS_MAGIC_STRING_ONMESSAGE "onmessage"
#define IOTJS_MAGIC_STRING__ONNEXTTICK "_onNextTick"
+#if ENABLE_MODULE_WEBSOCKET
+#define IOTJS_MAGIC_STRING_ONPING "onping"
+#endif
+#if ENABLE_MODULE_MQTT || ENABLE_MODULE_WEBSOCKET
+#define IOTJS_MAGIC_STRING_ONPINGRESP "onpingresp"
+#endif
#if ENABLE_MODULE_MQTT
-#define IOTJS_MAGIC_STRING__ONPINGRESP "_onpingresp"
-#define IOTJS_MAGIC_STRING__ONPUBACK "_onpuback"
-#define IOTJS_MAGIC_STRING__ONPUBCOMP "_onpubcomp"
-#define IOTJS_MAGIC_STRING__ONPUBREC "_onpubrec"
-#define IOTJS_MAGIC_STRING__ONPUBREL "_onpubrel"
+#define IOTJS_MAGIC_STRING_ONPUBREC "onpubrec"
+#define IOTJS_MAGIC_STRING_ONPUBREL "onpubrel"
#endif
#define IOTJS_MAGIC_STRING_ONREAD "onread"
#define IOTJS_MAGIC_STRING_ONSOCKET "onSocket"
-#if ENABLE_MODULE_MQTT
-#define IOTJS_MAGIC_STRING__ONSUBACK "_onsuback"
-#define IOTJS_MAGIC_STRING__ONUNSUBACK "_onunsuback"
-#endif
#define IOTJS_MAGIC_STRING_ONTIMEOUT "onTimeout"
#define IOTJS_MAGIC_STRING__ONUNCAUGHTEXCEPTION "_onUncaughtException"
#if ENABLE_MODULE_TLS
#define IOTJS_MAGIC_STRING_OUT_U "OUT"
#endif
#define IOTJS_MAGIC_STRING_OWNER "owner"
+#if ENABLE_MODULE_WEBSOCKET
+#define IOTJS_MAGIC_STRING_PARSEHANDSHAKEDATA "parseHandshakeData"
+#endif
#if ENABLE_MODULE_MQTT
-#define IOTJS_MAGIC_STRING_PACKETID "packet_id"
#define IOTJS_MAGIC_STRING_PASSWORD "password"
#endif
#define IOTJS_MAGIC_STRING_PAUSE "pause"
#define IOTJS_MAGIC_STRING_PERIOD "period"
#define IOTJS_MAGIC_STRING_PIN "pin"
-#if ENABLE_MODULE_MQTT
+#if ENABLE_MODULE_MQTT || ENABLE_MODULE_WEBSOCKET
#define IOTJS_MAGIC_STRING_PING "ping"
#endif
#define IOTJS_MAGIC_STRING_PLATFORM "platform"
+#if ENABLE_MODULE_WEBSOCKET
+#define IOTJS_MAGIC_STRING_PONG "pong"
+#endif
#define IOTJS_MAGIC_STRING_PORT "port"
+#if ENABLE_MODULE_WEBSOCKET
+#define IOTJS_MAGIC_STRING_PREPAREHANDSHAKE "prepareHandshake"
+#endif
#define IOTJS_MAGIC_STRING_PRIVATE "_private"
#define IOTJS_MAGIC_STRING_PROTOTYPE "prototype"
#if ENABLE_MODULE_MQTT
#define IOTJS_MAGIC_STRING_RECVSTOP "recvStop"
#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
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_REMAINING "remaining"
+#endif
#define IOTJS_MAGIC_STRING_RENAME "rename"
#define IOTJS_MAGIC_STRING_REQUEST_U "REQUEST"
#define IOTJS_MAGIC_STRING_RESPONSE_U "RESPONSE"
#define IOTJS_MAGIC_STRING_RISING_U "RISING"
#endif
#define IOTJS_MAGIC_STRING_RMDIR "rmdir"
+#if ENABLE_MODULE_CRYPTO
+#define IOTJS_MAGIC_STRING_RSAVERIFY "rsaVerify"
+#endif
#define IOTJS_MAGIC_STRING_SEND "send"
#if ENABLE_MODULE_MQTT
#define IOTJS_MAGIC_STRING_SENDACK "sendAck"
#define IOTJS_MAGIC_STRING_SETADDRESS "setAddress"
#endif
#if ENABLE_MODULE_UDP
-#define IOTJS_MAGIC_STRING_SETBROADCAST "setBroadcast"
+#define IOTJS_MAGIC_STRING_CONFIGURE "configure"
+#endif
+#if ENABLE_MODULE_GPIO
+#define IOTJS_MAGIC_STRING_SETDIRECTIONSYNC "setDirectionSync"
#endif
#if ENABLE_MODULE_PWM
#define IOTJS_MAGIC_STRING_SETDUTYCYCLE "setDutyCycle"
#define IOTJS_MAGIC_STRING_SETFILTER "setFilter"
#endif
#define IOTJS_MAGIC_STRING_SETKEEPALIVE "setKeepAlive"
-#define IOTJS_MAGIC_STRING_SETMULTICASTLOOPBACK "setMulticastLoopback"
-#if ENABLE_MODULE_DGRAM
-#define IOTJS_MAGIC_STRING_SETMULTICASTTTL "setMulticastTTL"
-#endif
#if ENABLE_MODULE_PWM
#define IOTJS_MAGIC_STRING_SETPERIOD "setPeriod"
#define IOTJS_MAGIC_STRING_SETPERIODSYNC "setPeriodSync"
#endif
#define IOTJS_MAGIC_STRING_SETTIMEOUT "setTimeout"
-#if ENABLE_MODULE_DGRAM
-#define IOTJS_MAGIC_STRING_SETTTL "setTTL"
+#ifdef ENABLE_MODULE_CRYPTO
+#define IOTJS_MAGIC_STRING_SHAENCODE "shaEncode"
#endif
#define IOTJS_MAGIC_STRING_SHOULDKEEPALIVE "shouldkeepalive"
#define IOTJS_MAGIC_STRING_SHUTDOWN "shutdown"
#if ENABLE_MODULE_HTTPS
#define IOTJS_MAGIC_STRING__WRITE "_write"
#endif
+#ifdef ENABLE_MODULE_WEBSOCKET
+#define IOTJS_MAGIC_STRING_WSINIT "wsInit"
+#define IOTJS_MAGIC_STRING_WSRECEIVE "wsReceive"
+#define IOTJS_MAGIC_STRING_WSRECEIVEHANDSHAKEDATA "ReceiveHandshakeData"
+#endif
#if ENABLE_MODULE_BRIDGE
#define IOTJS_MAGIC_STRING_MODULE_NAME "MODULE_NAME"
#endif
+++ /dev/null
-/* 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_reqwrap.h"
-
-
-void iotjs_reqwrap_initialize(iotjs_reqwrap_t* reqwrap, jerry_value_t jcallback,
- uv_req_t* request) {
- reqwrap->jcallback = jerry_acquire_value(jcallback);
- reqwrap->request = request;
- reqwrap->request->data = reqwrap;
-}
-
-
-void iotjs_reqwrap_destroy(iotjs_reqwrap_t* reqwrap) {
- jerry_release_value(reqwrap->jcallback);
-}
-
-
-static void iotjs_reqwrap_validate(iotjs_reqwrap_t* reqwrap) {
- IOTJS_ASSERT(reqwrap->request->data == reqwrap);
-}
-
-
-jerry_value_t iotjs_reqwrap_jcallback(iotjs_reqwrap_t* reqwrap) {
- iotjs_reqwrap_validate(reqwrap);
- return reqwrap->jcallback;
-}
-
-
-uv_req_t* iotjs_reqwrap_req(iotjs_reqwrap_t* reqwrap) {
- iotjs_reqwrap_validate(reqwrap);
- return reqwrap->request;
-}
-
-
-iotjs_reqwrap_t* iotjs_reqwrap_from_request(uv_req_t* req) {
- iotjs_reqwrap_t* reqwrap = req->data;
- iotjs_reqwrap_validate(reqwrap);
- return reqwrap;
-}
+++ /dev/null
-/* 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.
- */
-
-#ifndef IOTJS_REQWRAP_H
-#define IOTJS_REQWRAP_H
-
-
-#include <uv.h>
-
-#include "iotjs_binding.h"
-
-
-// UV request wrapper.
-// Wrapping UV request and JavaScript callback.
-// When an instance of request wrapper is created. it will increase ref count
-// for JavaScript callback function to prevent it from reclaimed by GC. The
-// reference count will decrease back when wrapper is being freed.
-typedef struct {
- jerry_value_t jcallback;
- uv_req_t* request;
-} iotjs_reqwrap_t;
-
-
-void iotjs_reqwrap_initialize(iotjs_reqwrap_t* reqwrap, jerry_value_t jcallback,
- uv_req_t* request);
-void iotjs_reqwrap_destroy(iotjs_reqwrap_t* reqwrap);
-
-// To retrieve javascript callback function object.
-jerry_value_t iotjs_reqwrap_jcallback(iotjs_reqwrap_t* reqwrap);
-
-// To retrieve pointer to uv request.
-uv_req_t* iotjs_reqwrap_req(iotjs_reqwrap_t* reqwrap);
-
-
-iotjs_reqwrap_t* iotjs_reqwrap_from_request(uv_req_t* req);
-
-
-#endif /* IOTJS_REQWRAP_H */
str.size = size;
- if (size > 0) {
- IOTJS_ASSERT(data != NULL);
+ if (data && size > 0) {
str.data = iotjs_buffer_allocate(size);
memcpy(str.data, data, size);
} else {
void iotjs_string_append(iotjs_string_t* str, const char* data, size_t size) {
IOTJS_ASSERT(data != NULL);
- if (size == 0) {
+ if (data == NULL || size == 0) {
return;
}
//
// declare strings table
//
-static const jerry_char_ptr_t magic_string_items[] = {
+static const jerry_char_t *const magic_string_items[] = {
#define MAGICSTR_EX_DEF(NAME, STRING) \
- (const jerry_char_ptr_t) jerry_magic_string_ex_##NAME,
+ (const jerry_char_t *)jerry_magic_string_ex_##NAME,
JERRY_MAGIC_STRING_ITEMS
void iotjs_register_jerry_magic_string(void) {
uint32_t num_magic_string_items =
- (uint32_t)(sizeof(magic_string_items) / sizeof(jerry_char_ptr_t));
+ (uint32_t)(sizeof(magic_string_items) / sizeof(jerry_char_t *));
jerry_register_magic_strings(magic_string_items, num_magic_string_items,
magic_string_lengths);
}
(type*)iotjs_buffer_allocate((num * sizeof(type)))
#define IOTJS_RELEASE(ptr) /* Release memory allocated by IOTJS_ALLOC() */ \
- ({ \
+ do { \
iotjs_buffer_release((char*)ptr); \
ptr = NULL; \
- })
+ } while (0)
#endif /* IOTJS_UTIL_H */
--- /dev/null
+/* 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_uv_handle.h"
+
+
+uv_handle_t* iotjs_uv_handle_create(size_t handle_size,
+ const jerry_value_t jobject,
+ JNativeInfoType* native_info,
+ size_t extra_data_size) {
+ IOTJS_ASSERT(jerry_value_is_object(jobject));
+
+ /* Make sure that the jerry_value_t is aligned */
+ size_t aligned_request_size = IOTJS_ALIGNUP(handle_size, 8u);
+
+ char* request_memory = iotjs_buffer_allocate(
+ aligned_request_size + sizeof(iotjs_uv_handle_data) + extra_data_size);
+ uv_handle_t* uv_handle = (uv_handle_t*)request_memory;
+ uv_handle->data = request_memory + aligned_request_size;
+
+ IOTJS_UV_HANDLE_DATA(uv_handle)->jobject = jobject;
+ IOTJS_UV_HANDLE_DATA(uv_handle)->on_close_cb = NULL;
+ jerry_acquire_value(jobject);
+
+ jerry_set_object_native_pointer(jobject, uv_handle, native_info);
+
+ return uv_handle;
+}
+
+
+static void iotjs_uv_handle_close_processor(uv_handle_t* handle) {
+ iotjs_uv_handle_data* handle_data = IOTJS_UV_HANDLE_DATA(handle);
+
+ if (handle_data->on_close_cb != NULL) {
+ handle_data->on_close_cb(handle);
+ }
+
+ // Decrease ref count of Javascript object. From now the object can be
+ // reclaimed.
+ jerry_release_value(handle_data->jobject);
+ IOTJS_RELEASE(handle);
+}
+
+
+void iotjs_uv_handle_close(uv_handle_t* handle, OnCloseHandler close_handler) {
+ if (handle == NULL || uv_is_closing(handle)) {
+ DDLOG("Attempt to close uninitialized or already closed handle");
+ return;
+ }
+
+ iotjs_uv_handle_data* handle_data = IOTJS_UV_HANDLE_DATA(handle);
+ handle_data->on_close_cb = close_handler;
+ uv_close(handle, iotjs_uv_handle_close_processor);
+}
--- /dev/null
+/* 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_UV_HANDLE
+#define IOTJS_UV_HANDLE
+
+#include <uv.h>
+
+#include "iotjs_binding.h"
+
+typedef void (*OnCloseHandler)(uv_handle_t*);
+
+typedef struct {
+ jerry_value_t jobject;
+ OnCloseHandler on_close_cb;
+} iotjs_uv_handle_data;
+
+#define IOTJS_ALIGNUP(value, alignment) \
+ (((value) + ((alignment)-1)) & ~((alignment)-1))
+
+/**
+ * Allocate and initialize an uv_handle_t structure with a jerry callback and
+ * extra data.
+ *
+ * The allocated memory has the following layout:
+ *
+ * |-------------| <- start of uv_handle_t*
+ * | uv_handle_t |
+ * | |
+ * |-------------|
+ * | PADDING | <- alignment padding
+ * |-------------| <- start of the iotjs_uv_handle_data struct
+ * | handle_data |
+ * |-------------| <- start of the extra data if required
+ * | extra |
+ * |-------------|
+ *
+ */
+uv_handle_t* iotjs_uv_handle_create(size_t handle_size,
+ const jerry_value_t jobject,
+ JNativeInfoType* native_info,
+ size_t extra_data_size);
+void iotjs_uv_handle_close(uv_handle_t* handle, OnCloseHandler close_handler);
+
+/**
+ * Returns a pointer to the handle data struct referenced
+ * by the uv_handle_t->data member.
+ */
+#define IOTJS_UV_HANDLE_DATA(UV_HANDLE) \
+ ((iotjs_uv_handle_data*)((UV_HANDLE)->data))
+
+/**
+ * Returns a char* pointer for any extra data.
+ *
+ * IMPORTANT!
+ * Make sure that the extra data is correctly allocated by using the
+ * iotjs_uv_handle_create method call.
+ */
+#define IOTJS_UV_HANDLE_EXTRA_DATA(UV_HANDLE) \
+ ((char*)((char*)((UV_HANDLE)->data) + sizeof(iotjs_uv_handle_data)))
+
+
+#endif /* IOTJS_UV_HANDLE */
--- /dev/null
+/* 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_uv_request.h"
+
+#include "iotjs_def.h"
+
+/**
+ * Aligns @a value to @a alignment. @a must be the power of 2.
+ *
+ * Returns minimum positive value, that divides @a alignment and is more than or
+ * equal to @a value
+ */
+#define IOTJS_ALIGNUP(value, alignment) \
+ (((value) + ((alignment)-1)) & ~((alignment)-1))
+
+
+uv_req_t* iotjs_uv_request_create(size_t request_size,
+ const jerry_value_t jcallback,
+ size_t extra_data_size) {
+ IOTJS_ASSERT(jerry_value_is_function(jcallback));
+
+ /* Make sure that the jerry_value_t is aligned */
+ size_t aligned_request_size = IOTJS_ALIGNUP(request_size, 8u);
+
+ char* request_memory = iotjs_buffer_allocate(
+ aligned_request_size + sizeof(jerry_value_t) + extra_data_size);
+ uv_req_t* uv_request = (uv_req_t*)request_memory;
+ uv_request->data = request_memory + aligned_request_size;
+
+ *IOTJS_UV_REQUEST_JSCALLBACK(uv_request) = jcallback;
+ jerry_acquire_value(jcallback);
+
+ return uv_request;
+}
+
+
+void iotjs_uv_request_destroy(uv_req_t* request) {
+ jerry_release_value(*IOTJS_UV_REQUEST_JSCALLBACK(request));
+ IOTJS_RELEASE(request);
+}
--- /dev/null
+/* 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_UV_REQUEST
+#define IOTJS_UV_REQUEST
+
+#include <uv.h>
+
+#include "iotjs_binding.h"
+
+/**
+ * Allocate and initialize an uv_req_t structure with a jerry callback and extra
+ * data.
+ *
+ * The allocated memory has the following layout:
+ *
+ * |----------| <- start of uv_req_t*
+ * | uv_req_t |
+ * | |
+ * |----------|
+ * | PADDING | <- alignment padding
+ * |----------| <- start of jerry_value_t* which is the callback
+ * | callback |
+ * |----------| <- start of the extra data if required
+ * | extra |
+ * |----------|
+ *
+ */
+uv_req_t* iotjs_uv_request_create(size_t request_size,
+ const jerry_value_t jcallback,
+ size_t extra_data_size);
+void iotjs_uv_request_destroy(uv_req_t* request);
+
+/**
+ * Returns a pointer to the js callback referenced by the uv_req_t->data member.
+ */
+#define IOTJS_UV_REQUEST_JSCALLBACK(UV_REQ) ((jerry_value_t*)(UV_REQ->data))
+
+/**
+ * Returns a char* pointer for any extra data.
+ *
+ * IMPORTANT!
+ * Make sure that the extra data is correctly allocated via the
+ * iotjs_uv_request_create method call.
+ */
+#define IOTJS_UV_REQUEST_EXTRA_DATA(UV_REQ) \
+ ((char*)((char*)(UV_REQ->data) + sizeof(jerry_value_t)))
+
+#endif /* IOTJS_UV_REQUEST */
// length
cmd.writeUInt8(15, 3);
- var advertisementInterval = Math.floor((process.env.BLENO_ADVERTISING_INTERVAL ? parseInt(process.env.BLENO_ADVERTISING_INTERVAL) : 100) * 1.6);
+ var advertisementInterval = Math.floor((process.env.BLENO_ADVERTISING_INTERVAL ? parseInt(process.env.BLENO_ADVERTISING_INTERVAL) : 100) * '1.6');
// data
cmd.writeUInt16LE(advertisementInterval, 4); // min interval
var role = data.readUInt8(2);
var addressType = data.readUInt8(3) === 0x01 ? 'random': 'public';
var address = uuidUtil.reverseByteOrder(data.slice(4, 10).toString('hex'), ':');
- var interval = data.readUInt16LE(10) * 1.25;
+ var interval = (data.readUInt16LE(10) * 5) >> 2;
var latency = data.readUInt16LE(12); // TODO: multiplier?
var supervisionTimeout = data.readUInt16LE(14) * 10;
var masterClockAccuracy = data.readUInt8(16); // TODO: multiplier?
Hci.prototype.processLeConnUpdateComplete = function(status, data) {
var handle = data.readUInt16LE(0);
- var interval = data.readUInt16LE(2) * 1.25;
+ var interval = (data.readUInt16LE(2) * 5) >> 2;
var latency = data.readUInt16LE(4); // TODO: multiplier?
var supervisionTimeout = data.readUInt16LE(6) * 10;
* SOFTWARE.
*/
-[
+module.exports = [
"Success",
"Unknown HCI Command",
"Unknown Connection Identifier",
"Connection Failed to be Established",
"MAC Connection Failed",
"Coarse Clock Adjustment Rejected but Will Try to Adjust Using Clock Dragging"
-]
+];
* limitations under the License.
*/
-var util = require('util');
-
function checkInt(buffer, value, offset, ext, max, min) {
if (value > max || value < min)
// [4] new Buffer(string, encoding)
// [5] new Buffer(array)
function Buffer(subject, encoding) {
- if (!util.isBuffer(this)) {
+ if (!Buffer.isBuffer(this)) {
return new Buffer(subject, encoding);
}
- if (util.isNumber(subject)) {
+ if (typeof subject === 'number') {
this.length = subject > 0 ? subject >>> 0 : 0;
- } else if (util.isString(subject)) {
+ } else if (typeof subject === 'string') {
this.length = Buffer.byteLength(subject, encoding);
- } else if (util.isBuffer(subject) || util.isArray(subject)) {
+ } else if (Buffer.isBuffer(subject) || Array.isArray(subject)) {
this.length = subject.length;
} else {
throw new TypeError('Bad arguments: Buffer(string|number|Buffer|Array)');
// 'native' is the buffer object created via the C API.
native(this, this.length);
- if (util.isString(subject)) {
+ if (typeof subject === 'string') {
if (typeof encoding === 'string') {
encoding = getEncodingType(encoding);
if (encoding != -1) {
} else {
this.write(subject);
}
- } else if (util.isBuffer(subject)) {
+ } else if (Buffer.isBuffer(subject)) {
subject.copy(this);
- } else if (util.isArray(subject)) {
+ } else if (Array.isArray(subject)) {
for (var i = 0; i < this.length; ++i) {
native.writeUInt8(this, subject[i], i);
}
// Buffer.concat(list)
Buffer.concat = function(list) {
- if (!util.isArray(list)) {
+ if (!Array.isArray(list)) {
throw new TypeError('Bad arguments: Buffer.concat([Buffer])');
}
var length = 0;
var i;
for (i = 0; i < list.length; ++i) {
- if (!util.isBuffer(list[i])) {
+ if (!Buffer.isBuffer(list[i])) {
throw new TypeError('Bad arguments: Buffer.concat([Buffer])');
}
length += list[i].length;
// Buffer.isBuffer(object)
-Buffer.isBuffer = util.isBuffer;
+Buffer.isBuffer = function(arg) {
+ return arg instanceof Buffer;
+};
// buffer.equals(otherBuffer)
Buffer.prototype.equals = function(otherBuffer) {
- if (!util.isBuffer(otherBuffer)) {
+ if (!Buffer.isBuffer(otherBuffer)) {
throw new TypeError('Bad arguments: buffer.equals(Buffer)');
}
// buffer.compare(otherBuffer)
Buffer.prototype.compare = function(otherBuffer) {
- if (!util.isBuffer(otherBuffer)) {
+ if (!Buffer.isBuffer(otherBuffer)) {
throw new TypeError('Bad arguments: buffer.compare(Buffer)');
}
// * sourceStart - default to 0
// * sourceEnd - default to buffer.length
Buffer.prototype.copy = function(target, targetStart, sourceStart, sourceEnd) {
- if (!util.isBuffer(target)) {
+ if (!Buffer.isBuffer(target)) {
throw new TypeError('Bad arguments: buff.copy(Buffer)');
}
// * offset - default to 0
// * length - default to buffer.length - offset
Buffer.prototype.write = function(string, offset, length, encoding) {
- if (!util.isString(string)) {
+ if (typeof string !== 'string') {
throw new TypeError('Bad arguments: buff.write(string)');
}
// buff.fill(value)
Buffer.prototype.fill = function(value) {
- if (util.isNumber(value)) {
+ if (typeof value === 'number') {
value = value & 255;
for (var i = 0; i < this.length; i++) {
native.writeUInt8(this, value, i);
};
+// Method: Buffer.from()
+// Buffer.from(Array)
+// Buffer.from(string,encoding)
+// Buffer.from(Buffer)
+// Buffer.from(ArrayBuffer)
+function from(value, encoding, length) {
+
+ var arrayBuffer = native.fromArrayBuffer(value, encoding, length);
+
+ if (arrayBuffer) {
+ return arrayBuffer;
+ }
+ if (Buffer.isBuffer(value) || (typeof value) === 'string'
+ || Array.isArray(value)) {
+ return new Buffer(value, encoding);
+ }
+ throw new TypeError('First argument must be' +
+ 'a string, Buffer, ArrayBuffer, Array, or array-like object');
+}
+
+
+/* Register the Buffer object back to the native C
+ * so the other side can get the prototype in a consistent
+ * and safe manner.
+ */
+native.Buffer = Buffer;
+
module.exports = Buffer;
module.exports.Buffer = Buffer;
+module.exports.from = from;
--- /dev/null
+/* 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 shaTypes = {
+ 'sha1': 4,
+ 'sha256': 6,
+};
+
+var hashes = ['sha1', 'sha256'];
+
+function Verify(signtype) {
+ if (!(this instanceof Verify)) {
+ return new Verify(signtype);
+ }
+
+ signtype = signtype.toLowerCase();
+
+ if (hashes.indexOf(signtype) < 0) {
+ throw new Error('Unknown signing algorithm.' +
+ 'Please use crypto.getSignatures()');
+ }
+
+ Object.defineProperty(this, 'hashtype', {
+ // defaults to writable: false, configurable: false
+ value: signtype,
+ enumerable: true,
+ });
+}
+
+Verify.prototype.update = function(data) {
+ if (this.data) {
+ if (Buffer.isBuffer(data)) {
+ this.data = Buffer.concat([this.data, data]);
+ return;
+ }
+
+ this.data = Buffer.concat([this.data, new Buffer(data)]);
+ return;
+ }
+
+ if (Buffer.isBuffer(data)) {
+ this.data = data;
+ return;
+ }
+
+ this.data = new Buffer(data);
+};
+
+Verify.prototype.verify = function(publicKey, signature) {
+ if (this.data) {
+ var type = shaTypes[this.hashtype];
+ var hash = native.shaEncode(this.data, type);
+ return native.rsaVerify(type, hash, publicKey, signature);
+ }
+
+ throw new Error('verify shouldn\'t be called on an empty Verify');
+};
+
+function Hash(hashtype) {
+ if (!(this instanceof Hash)) {
+ return new Hash(hashtype);
+ }
+
+ if (hashes.indexOf(hashtype) < 0) {
+ throw new Error('Unknown hashing algorithm. Please use crypto.getHashes()');
+ }
+ Object.defineProperty(this, 'hashtype', {
+ value: hashtype,
+ writable: false,
+ enumerable: true,
+ });
+}
+
+Hash.prototype.update = function(data) {
+ if (this.data) {
+ if (Buffer.isBuffer(data)) {
+ this.data = Buffer.concat(this.data, data);
+ return;
+ }
+
+ this.data = Buffer.concat([this.data, new Buffer(data)]);
+ return;
+ }
+ this.data = new Buffer(data);
+};
+
+Hash.prototype.digest = function(encoding) {
+ if (this._finished) {
+ throw new Error('Digest can not be called twice on the same Hash object');
+ }
+
+ var result;
+ var type = shaTypes[this.hashtype];
+ result = native.shaEncode(this.data, type);
+
+ if (encoding == 'base64') {
+ result = native.base64Encode(result);
+ } else if (encoding == 'hex') {
+ result = result.toString('hex');
+ }
+
+ Object.defineProperty(this, '_finished', {
+ value: true,
+ writable: false,
+ enumerable: false,
+ });
+
+ return result;
+};
+
+function getHashes() {
+ return hashes;
+}
+
+function createHash(hashtype) {
+ return new Hash(hashtype);
+}
+
+function createVerify(signtype) {
+ return new Verify(signtype);
+}
+
+exports.createHash = createHash;
+exports.getHashes = getHashes;
+exports.createVerify = createVerify;
};
+// These object represents the different config types that
+// this._handle.configure can do.
+// The order of these must match the order in the udp C module.
+var configTypes = {
+ 'BROADCAST': 0,
+ 'TTL': 1,
+ 'MULTICASTTTL': 2,
+ 'MULTICASTLOOPBACK': 3,
+};
+
Socket.prototype.setBroadcast = function(arg) {
- var err = this._handle.setBroadcast(arg ? 1 : 0);
+ var err = this._handle.configure(configTypes.BROADCAST, arg ? 1 : 0);
if (err) {
throw util.errnoException(err, 'setBroadcast');
}
throw new TypeError('Argument must be a number');
}
- var err = this._handle.setTTL(arg);
+ var err = this._handle.configure(configTypes.TTL, arg);
if (err) {
throw util.errnoException(err, 'setTTL');
}
throw new TypeError('Argument must be a number');
}
- var err = this._handle.setMulticastTTL(arg);
+ var err = this._handle.configure(configTypes.MULTICASTTTL, arg);
if (err) {
throw util.errnoException(err, 'setMulticastTTL');
}
Socket.prototype.setMulticastLoopback = function(arg) {
- var err = this._handle.setMulticastLoopback(arg ? 1 : 0);
+ var err = this._handle.configure(configTypes.MULTICASTLOOPBACK,
+ arg ? 1 : 0);
if (err) {
throw util.errnoException(err, 'setMulticastLoopback');
}
if (family !== 0 && family !== 4 && family !== 6)
throw new TypeError('invalid argument: family must be 4 or 6');
- if (process.platform != 'nuttx' && process.platform != 'tizenrt') {
+ if (process.platform != 'nuttx') {
native.getaddrinfo(hostname, family, hints, callback);
} else {
// native.getaddrinfo is synchronous on these platforms.
};
+try {
+ var stream = require('stream');
+ var Readable = stream.Readable;
+ var Writable = stream.Writable;
+
+
+ function ReadStream(path, options) {
+ if (!(this instanceof ReadStream)) {
+ return new ReadStream(path, options);
+ }
+
+ options = options || {};
+
+ Readable.call(this, {defaultEncoding: options.encoding || null});
+
+ this.bytesRead = 0;
+ this.path = path;
+ this._autoClose = util.isNullOrUndefined(options.autoClose) ||
+ options.autoClose;
+ this._fd = options.fd;
+ this._buff = new Buffer(options.bufferSize || 4096);
+
+ var self = this;
+ if (util.isNullOrUndefined(this._fd)) {
+ fs.open(this.path, options.flags || 'r', options.mode || 438,
+ function(err, _fd) {
+ if (err) {
+ throw err;
+ }
+ self._fd = _fd;
+ self.emit('open', self._fd);
+ self.doRead();
+ });
+ }
+
+ this.once('open', function(/* _fd */) {
+ this.emit('ready');
+ });
+
+ if (this._autoClose) {
+ this.on('end', function() {
+ closeFile(self);
+ });
+ }
+ }
+
+
+ util.inherits(ReadStream, Readable);
+
+
+ ReadStream.prototype.doRead = function() {
+ var self = this;
+ fs.read(this._fd, this._buff, 0, this._buff.length, null,
+ function(err, bytes_read/* , buffer*/) {
+ if (err) {
+ if (self._autoClose) {
+ closeFile(self);
+ }
+ throw err;
+ }
+
+ self.bytesRead += bytes_read;
+ if (bytes_read === 0) {
+ // Reached end of file.
+ // null must be pushed so the 'end' event will be emitted.
+ self.push(null);
+ } else {
+ self.push(bytes_read == self._buff.length ?
+ self._buff : self._buff.slice(0, bytes_read));
+ self.doRead();
+ }
+ });
+ };
+
+
+ fs.createReadStream = function(path, options) {
+ return new ReadStream(path, options);
+ };
+
+
+ function WriteStream(path, options) {
+ if (!(this instanceof WriteStream)) {
+ return new WriteStream(path, options);
+ }
+
+ options = options || {};
+
+ Writable.call(this);
+
+ this._fd = options._fd;
+ this._autoClose = util.isNullOrUndefined(options.autoClose) ||
+ options.autoClose;
+ this.bytesWritten = 0;
+
+ var self = this;
+ if (!this._fd) {
+ fs.open(path, options.flags || 'w', options.mode || 438,
+ function(err, _fd) {
+ if (err) {
+ throw err;
+ }
+ self._fd = _fd;
+ self.emit('open', self._fd);
+ });
+ }
+
+ this.once('open', function(/* _fd */) {
+ self.emit('ready');
+ });
+
+ if (this._autoClose) {
+ this.on('finish', function() {
+ closeFile(self);
+ });
+ }
+
+ this._readyToWrite();
+ }
+
+
+ util.inherits(WriteStream, Writable);
+
+
+ WriteStream.prototype._write = function(chunk, callback, onwrite) {
+ var self = this;
+ fs.write(this._fd, chunk, 0, chunk.length,
+ function(err, bytes_written/* , buffer */) {
+ if (err) {
+ if (self._autoClose) {
+ closeFile(self);
+ }
+ throw err;
+ }
+ this.bytesWritten += bytes_written;
+
+ if (callback) {
+ callback();
+ }
+ onwrite();
+ });
+ };
+
+
+ fs.createWriteStream = function(path, options) {
+ return new WriteStream(path, options);
+ };
+
+
+ function closeFile(stream) {
+ fs.close(stream._fd, function(err) {
+ if (err) {
+ throw err;
+ }
+ stream.emit('close');
+ });
+ }
+} catch(e) {
+}
+
+
function convertFlags(flag) {
var O_APPEND = constants.O_APPEND;
var O_CREAT = constants.O_CREAT;
var net = require('net');
var ClientRequest = require('http_client').ClientRequest;
-var HTTPParser = require('http_parser');
+var IncomingMessage = require('http_incoming').IncomingMessage;
+var HTTPParser = require('http_parser').HTTPParser;
var HTTPServer = require('http_server');
var util = require('util');
return new ClientRequest(options, cb, socket);
};
-function Server(requestListener) {
+function Server(options, requestListener) {
if (!(this instanceof Server)) {
- return new Server(requestListener);
+ return new Server(options, requestListener);
}
net.Server.call(this, {allowHalfOpen: true},
HTTPServer.connectionListener);
- HTTPServer.initServer.call(this, {}, requestListener);
+ HTTPServer.initServer.call(this, options, requestListener);
}
util.inherits(Server, net.Server);
exports.Server = Server;
-exports.createServer = function(requestListener) {
- return new Server(requestListener);
+exports.createServer = function(options, requestListener) {
+ return new Server(options, requestListener);
};
req.end();
return req;
};
+
+exports.IncomingMessage = IncomingMessage;
+exports.ServerResponse = HTTPServer.ServerResponse;
function setupConnection(req) {
var socket = req.socket;
- var parser = common.createHTTPParser();
- parser.reinitialize(HTTPParser.RESPONSE);
+ var parser = common.createHTTPParser(HTTPParser.RESPONSE);
socket.parser = parser;
socket._httpMessage = req;
if (err) {
var host;
if ((host = req.getHeader('host'))) {
- err.message += ': ' + (host ? host : '');
+ err.message += ': ' + host;
}
req.emit('error', err);
}
var IncomingMessage = require('http_incoming').IncomingMessage;
var HTTPParser = require('http_parser').HTTPParser;
-var createHTTPParser = function() {
- // REQUEST is the default type.
- // For RESPONSE, use HTTPParser.reinitialize(HTTPParser.RESPONSE)
- var parser = new HTTPParser(HTTPParser.REQUEST);
+exports.createHTTPParser = function(type) {
+ var parser = new HTTPParser(type);
// cb during http parsing from C side(http_parser)
parser.OnHeaders = parserOnHeaders;
parser.OnHeadersComplete = parserOnHeadersComplete;
parser.OnBody = parserOnBody;
parser.OnMessageComplete = parserOnMessageComplete;
+ parser._IncomingMessage = IncomingMessage;
return parser;
};
-exports.createHTTPParser = createHTTPParser;
-
-
// This is called when parsing of incoming http msg done
function parserOnMessageComplete() {
var stream = this.incoming;
}
- this.incoming = new IncomingMessage(this.socket);
+ this.incoming = new this._IncomingMessage(this.socket);
this.incoming.url = url;
+ this.incoming.httpVersion = info.http_major + '.' + info.http_minor;
// add header fields of headers to incoming.headers
this.incoming.addHeaders(headers);
// for request (server)
this.url = '';
this.method = null;
+ this.httpVersion = '';
// for response (client)
this.statusCode = null;
function OutgoingMessage() {
- stream.Stream.call(this);
+ stream.Writable.call(this);
this.writable = true;
}
-util.inherits(OutgoingMessage, stream.Stream);
+util.inherits(OutgoingMessage, stream.Writable);
exports.OutgoingMessage = OutgoingMessage;
callback = encoding;
}
- if (util.isBuffer(chunk)) {
- chunk = chunk.toString();
- }
-
if (!this._sentHeader) {
- chunk = this._header + '\r\n' + chunk;
+ this._chunks.push(this._header + '\r\n');
this._sentHeader = true;
}
throw new TypeError('Name must be string.');
}
- if (!value) {
+ if (util.isNullOrUndefined(value)) {
throw new Error('value required in setHeader(' + name + ', value)');
}
*/
var util = require('util');
+var IncomingMessage = require('http_incoming').IncomingMessage;
var OutgoingMessage = require('http_outgoing').OutgoingMessage;
var common = require('http_common');
+var HTTPParser = require('http_parser').HTTPParser;
// RFC 7231 (http://tools.ietf.org/html/rfc7231#page-49)
var STATUS_CODES = exports.STATUS_CODES = {
}
util.inherits(ServerResponse, OutgoingMessage);
-
+exports.ServerResponse = ServerResponse;
// default status code : 200
ServerResponse.prototype.statusCode = 200;
function initServer(options, requestListener) {
+ if (util.isFunction(options)) {
+ requestListener = options;
+ }
+
+ if (typeof options !== 'object') {
+ options = {};
+ }
+
if (util.isFunction(requestListener)) {
this.addListener('request', requestListener);
}
+ this._IncomingMessage = options.IncomingMessage || IncomingMessage;
+ this._ServerResponse = options.ServerResponse || ServerResponse;
this.httpAllowHalfOpen = false;
this.on('clientError', function(err, conn) {
// cf) In Node.js, freelist returns a new parser.
// parser initialize
- var parser = common.createHTTPParser();
+ var parser = common.createHTTPParser(HTTPParser.REQUEST);
parser._headers = [];
parser._url = '';
parser.onIncoming = parserOnIncoming;
+ parser._IncomingMessage = server._IncomingMessage;
parser.socket = socket;
parser.incoming = null;
var socket = req.socket;
var server = socket._server;
- var res = new ServerResponse(req);
+ var res = new server._ServerResponse(req);
res.assignSocket(socket);
res.on('prefinish', resOnFinish);
--- /dev/null
+/* 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 crypto = require('crypto');
+
+function parseRequest(request) {
+ var authHeader = false;
+ var authType = false;
+ if (request.headers['authorization']) {
+ authType = 'authorization';
+ authHeader = request.headers['authorization'];
+ } else if (request.headers['Authorization']) {
+ authType = 'Authorization';
+ authHeader = request.headers['Authorization'];
+ }
+
+ if (!authHeader) {
+ throw new Error('Authorization header is not present, invalid request.');
+ }
+
+ var requestHeaders = {
+ 'request-line': request.method + ' ' + request.url + ' HTTP/' +
+ request.httpVersion,
+ '(request-target)': '(request-target): ' + request.method.toLowerCase() +
+ ' ' + request.url,
+ };
+
+ for (var key in request.headers) {
+ if (key !== authType) {
+ var keyData = key.toLowerCase();
+ requestHeaders[keyData] = keyData + ': ' + request.headers[key];
+ }
+ }
+
+ var authObject = {};
+
+ var idx = 0;
+ var types = ['keyId=', 'signature=', 'algorithm=', 'headers='];
+ // TODO: We currently only accept data that's enclosed with double quotes.
+ // The newest RFC doesn't state if the data in the authorization header needs
+ // to be in double quotes, or just simply be after the equals sign.
+ // reference: https://tools.ietf.org/html/draft-cavage-http-signatures-10
+ for (var i = 0; i < types.length; i++) {
+ if ((idx = authHeader.indexOf(types[i])) < 0) {
+ throw new Error('Couldn\'t find header: ', types[i]);
+ }
+
+ idx += types[i].length + 1;
+ var endIdx = authHeader.substring(idx).indexOf('"') + idx;
+ authObject[types[i].slice(0, -1)] = authHeader.substring(idx, endIdx);
+ }
+
+ var parsedRequest = {
+ requestObject: requestHeaders,
+ authObject: authObject,
+ };
+
+ return parsedRequest;
+}
+
+function verifySignature(parsedRequest, pubKey) {
+ // We only support RSA-SHAX signatures right now
+ var algorithm = parsedRequest.authObject.algorithm.toLowerCase();
+ if (algorithm.indexOf('rsa-sha') < 0) {
+ throw new Error('Only rsa-shaX signatures are supported');
+ }
+
+ // We know it begins with rsa-sha, so give only the sha info to crypto
+ var toVerify = crypto.createVerify(algorithm.split('-')[1]);
+ var headersToHash = parsedRequest.authObject.headers.split(' ');
+
+ for (var i = 0; i < headersToHash.length; i++) {
+ toVerify.update(parsedRequest.requestObject[headersToHash[i]]);
+ // 2.1.2.3 If value is not the last value then append an ASCII newline `\n`.
+ // The string MUST NOT include a trailing ASCII newline.
+ if (i + 1 != headersToHash.length) {
+ toVerify.update('\n');
+ }
+ }
+
+ return toVerify.verify(pubKey, parsedRequest.authObject.signature);
+}
+
+exports.verifySignature = verifySignature;
+exports.parseRequest = parseRequest;
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');
-exports.ClientRequest = ClientRequest;
-
exports.request = function(options, cb) {
options.port = options.port || 443;
// Create socket.
return new Server(options, requestListener);
};
-exports.METHODS = HTTPParser.methods;
-
exports.get = function(options, cb) {
var req = exports.request(options, cb);
req.end();
process.exitCode = 0;
process._exiting = false;
process.emitExit = function(code) {
+ code = code || process.exitCode;
if (typeof code !== 'number') {
code = 0;
}
var Builtin = require('builtin');
var fs = Builtin.require('fs');
-var dynamicloader = Builtin.require('dynamicloader');
+var dynamicloader;
+try {
+ dynamicloader = Builtin.require('dynamicloader');
+} catch (e) {
+ // the 'dynamicloader' module is not enabled, nothing to do.
+}
+
+function normalizePathString(path) {
+ // Assume all path separators are '/'
+ var input = path.split('/');
+ var output = [];
+ while (input.length > 0) {
+ if (input[0] === '.' || (input[0] === '' && input.length > 1)) {
+ input.shift();
+ continue;
+ }
+ if (input[0] === '..') {
+ input.shift();
+ if (output.length > 0 && output[output.length - 1] !== '..') {
+ output.pop();
+ } else {
+ throw new Error('Requested path is below root: ' + path);
+ }
+ continue;
+ }
+ output.push(input.shift());
+ }
+ return output;
+}
+
+var path;
+if (process.platform === 'windows') {
+ /* In case of windows:
+ * replace all '\' characters to '/' for ease of use for now.
+ */
+ path = {
+ pathReplacer: new RegExp('\\\\', 'g'),
+ pathSeparator: '\\',
+ normalizeSeparators: function(pathString) {
+ return pathString.replace(path.pathReplacer, '/');
+ },
+ isDeviceRoot: function(pathString) {
+ if (pathString.charCodeAt(1) !== 0x3A /* ':' */) {
+ return false;
+ }
+ var drive = pathString.charCodeAt(0);
+ return (drive >= 0x61 /* a */ && drive <= 0x7A /* z */)
+ || (drive >= 0x41 /* A */ && drive <= 0x5A /* Z */);
+ },
+ normalizePath: function(pathString) {
+ pathString = path.normalizeSeparators(pathString);
+
+ var deviceRoot = '';
+ if (!path.isDeviceRoot(pathString)) {
+ deviceRoot = path.cwd().substr(0, 2) + '/';
+ }
+
+ var pathElements = normalizePathString(pathString);
+ return deviceRoot + pathElements.join('/');
+ },
+ cwd: function() {
+ return path.normalizeSeparators(process.cwd());
+ },
+ };
+} else {
+ path = {
+ isDeviceRoot: function(pathString) {
+ return pathString.charCodeAt(0) === 0x2F; /* '/' */
+ },
+ normalizePath: function(path) {
+ var beginning = '';
+ if (path.indexOf('/') === 0) {
+ beginning = '/';
+ }
+
+ var pathElements = normalizePathString(path);
+ return beginning + pathElements.join('/');
+ },
+ cwd: process.cwd,
+ };
+}
function Module(id, parent) {
this.id = id;
var cwd;
try {
- cwd = process.env.IOTJS_WORKING_DIR_PATH || process.cwd();
+ cwd = process.env.IOTJS_WORKING_DIR_PATH || path.cwd();
} catch (e) { }
if (cwd) {
moduledirs.push(cwd + '/');
var dir = directories[i];
var modulePath = dir + id;
- if (modulePath[0] !== '/') {
- modulePath = process.cwd() + '/' + modulePath;
+ if (!path.isDeviceRoot(modulePath)) {
+ modulePath = path.cwd() + '/' + modulePath;
}
if ((process.platform === 'tizenrt' || process.platform === 'nuttx') &&
(modulePath.indexOf('../') != -1 || modulePath.indexOf('./') != -1)) {
- modulePath = Module.normalizePath(modulePath);
+ modulePath = path.normalizePath(modulePath);
}
var filepath,
var filepath = Module.resolveFilepath(id, directories);
if (filepath) {
- return Module.normalizePath(filepath);
+ return path.normalizePath(filepath);
}
return false;
};
-Module.normalizePath = function(path) {
- var beginning = '';
- if (path.indexOf('/') === 0) {
- beginning = '/';
- }
-
- var input = path.split('/');
- var output = [];
- while (input.length > 0) {
- if (input[0] === '.' || (input[0] === '' && input.length > 1)) {
- input.shift();
- continue;
- }
- if (input[0] === '..') {
- input.shift();
- if (output.length > 0 && output[output.length - 1] !== '..') {
- output.pop();
- } else {
- throw new Error('Requested path is below root: ' + path);
- }
- continue;
- }
- output.push(input.shift());
- }
- return beginning + output.join('/');
-};
-
-
Module.tryPath = function(path) {
try {
var stats = fs.statSync(path);
Module.runMain = function() {
if (Builtin.debuggerWaitSource) {
var sources = Builtin.debuggerGetSource();
+
+ if (sources.length == 0) {
+ var err = new Error('No remote source received!');
+ return process._onUncaughtException(err);
+ }
+
sources.forEach(function(rModule) {
Module.remoteCache[rModule[0]] = rModule[1];
});
* limitations under the License.
*/
-var net = require('net');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
-
-util.inherits(MQTTClient, EventEmitter);
+var net, tls;
var PacketTypeEnum = {
PUBACK: 4,
PUBCOMP: 7,
};
-function MQTTClient(options) {
- if (!(this instanceof MQTTClient)) {
- return new MQTTClient(options);
- }
-
- EventEmitter.call(this);
+// In seconds (should be divisible by 8)
+var MQTTTimeout = 64;
- this._clientOptions = Object.create(options, {
- host: { value: options.host || '127.0.0.1'},
- port: { value: options.port || 8883 },
- qos: { value: options.qos || 0 },
- keepalive: { value: options.keepalive || 60 },
- });
+function MQTTHandle(client, keepalive) {
+ this.client = client;
+ this.isConnected = false;
+ this.nextPacketId = 0;
+ this.keepalive = keepalive;
+ this.keepaliveCounter = 0;
+ this.pingrespCounter = 0;
+ this.storage = { };
+ this.storageCount = 0;
- this._socket = options.socket || new net.Socket();
- this._socket.on('error', onerror);
-
- this._isConnected = false;
- this._reconnecting = false;
- this._package_id = 0;
-
- // Set the native callbacks
- this._onconnect = onconnect;
- this._ondisconnect = ondisconnect;
- this._onmessage = onmessage;
- this._onpingresp = onpingresp;
- this._onpuback = onpuback;
- this._onpubcomp = onpubcomp;
- this._onpubrec = onpubrec;
- this._onpubrel = onpubrel;
- this._onsuback = onsuback;
+ native.MqttInit(this);
}
+MQTTHandle.prototype = {};
-/*
- * Connect to an MQTT broker.
- */
-function MqttConnect(socket, options) {
- var buff = native.connect(options);
- socket.write(buff);
-}
-
-MQTTClient.prototype.connect = function(callback) {
- this._clientOptions.cb = callback;
- var jsref = this;
- if (this._socket instanceof net.Socket) {
- this._socket = net.connect(this._clientOptions);
- this._socket.on('connect', function() {
- MqttConnect(this, jsref._clientOptions);
- });
- }
-
- if (util.isFunction(callback)) {
- this.on('connect', callback);
- }
-
- this._socket.on('data', function(data) {
- ondata(jsref, data);
- });
- this._socket.on('error', function(e) {
- jsref.emit('error', e);
- });
- this._socket.on('end', function() {
- ondisconnect(jsref);
- });
+MQTTHandle.prototype.write = function(buf) {
+ this.socket.write(buf);
+ this.keepaliveCounter = 0;
};
-MQTTClient.prototype.disconnect = function(error) {
- if (error) {
- this.emit('error', error);
- }
-
- this._isConnected = false;
- var buf = native.disconnect();
- this._socket.write(buf);
- this._socket.end();
+MQTTHandle.prototype.sendAck = function(type, packet_id) {
+ this.write(native.sendAck(type, packet_id));
};
-MQTTClient.prototype.reconnect = function() {
- if (this._reconnecting) {
- return;
- }
+MQTTHandle.prototype.onconnection = function() {
+ this.isConnected = true;
+ this.timer = setInterval(storageTimerHit.bind(this), 1000);
- this.disconnect();
- setTimeout(this.connect, this._options.reconnectPeriod);
+ this.client.emit('connect');
};
-MQTTClient.prototype.publish = function(options) {
- if (!Buffer.isBuffer(options.message)) {
- options.message = new Buffer(options.message);
- }
- if (!Buffer.isBuffer(options.topic)) {
- options.topic = new Buffer(options.topic);
- }
-
- if (util.isNumber(options.qos) && options.qos > 0) {
- options.packet_id = this._package_id;
- this._package_id++;
+MQTTHandle.prototype.onEnd = function() {
+ this.isConnected = false;
- var buffer = native.publish(options);
- this._socket.write(buffer);
+ // Abort outgoing messages.
+ clearInterval(this.timer);
+ this.storage = null;
+ this.storageCount = 0;
- var self = this;
+ this.client.emit('end');
+};
- var interval = setInterval(function() {
- self._socket.write(buffer);
- }, 3000);
+MQTTHandle.prototype.onmessage = function(message, topic, qos, packet_id) {
+ var data = {
+ message: message,
+ topic: topic,
+ qos: qos,
+ packet_id: packet_id,
+ };
- this.on('puback', function() {
- clearInterval(interval);
- });
- this.on('pubrec', function() {
- clearInterval(interval);
- });
+ if (qos >= 1) {
+ var type = (qos == 1) ? PacketTypeEnum.PUBACK : PacketTypeEnum.PUBREC;
- return;
+ this.sendAck(type, packet_id);
}
- this._socket.write(native.publish(options));
+ this.client.emit('message', data);
};
-MQTTClient.prototype.subscribe = function(options) {
- if (!Buffer.isBuffer(options.topic)) {
- options.topic = new Buffer(options.topic);
- }
+MQTTHandle.prototype.getPacketId = function() {
+ while (true) {
+ var packet_id = this.nextPacketId;
+ this.nextPacketId = (this.nextPacketId + 1) & 0xffff;
- var buff = native.subscribe(options);
- this._socket.write(buff);
-};
+ if (!(packet_id in this.storage)) {
+ this.storage[packet_id] = { remainingTime: MQTTTimeout };
+ this.storageCount++;
-MQTTClient.prototype.ping = function() {
- var buff = native.ping();
- this._socket.write(buff);
+ return packet_id;
+ }
+ }
};
-MQTTClient.prototype.unsubscribe = function(topic) {
- if (!Buffer.isBuffer(topic)) {
- topic = new Buffer(topic);
+MQTTHandle.prototype.releasePacket = function(packet_id, error) {
+ // callback will be invalid after delete
+ var callback = this.storage[packet_id].callback;
+
+ delete this.storage[packet_id];
+ this.storageCount--;
+
+ // This function should never fail.
+ try {
+ if (typeof callback == 'function') {
+ callback(error);
+ } else if (error) {
+ this.client.emit('error', error);
+ }
+ } catch (e) {
+ // Do nothing.
}
+};
- var buf = native.unsubscribe(topic);
- this._socket.write(buf);
+MQTTHandle.prototype.onpingresp = function() {
+ this.pingrespCounter = 0;
};
-MQTTClient.prototype.sendAcknowledge = function(options) {
- var buff = native.sendAck(options);
- this._socket.write(buff);
+MQTTHandle.prototype.onack = function(packet_id, error) {
+ this.releasePacket(packet_id, error);
};
-function onpubcomp(jsref, data) {
+MQTTHandle.prototype.onpubrec = function(packet_id) {
/*
* Qos level 2
- * Handle PUBCOMP package. If this package is arrived, the sending process
- * is done.
+ * Handle PUBREC package. If this package is arrived, we have to send back
+ * a PUBREL package to the server.
*/
- jsref.emit('pubcomp', data);
-}
+ var buffer = native.sendAck(PacketTypeEnum.PUBREL, packet_id);
+ this.write(buffer);
+
+ // Upodate packet rather than create a new one
+ var packet = this.storage[packet_id];
+ packet.remainingTime = MQTTTimeout;
+ packet.packet = buffer;
+};
-function onpubrel(jsref, data) {
+MQTTHandle.prototype.onpubrel = function(data) {
/*
* Qos level 2
* Handle PUBREL package. If this package is arrived, we have to send back
* a PUBCOMP package to the server.
*/
- var options = {
- type: PacketTypeEnum.PUBCOMP,
- packet_id: data,
- };
+ this.sendAck(PacketTypeEnum.PUBCOMP, data);
+};
- jsref.sendAcknowledge(options);
-}
+function MQTTClient(url, options, callback) {
+ if (!(this instanceof MQTTClient)) {
+ return new MQTTClient(url, options, callback);
+ }
+
+ EventEmitter.call(this);
+
+ var socket;
-function ondata(jsref, data) {
- var ret_val = native.MqttHandle(jsref, data);
- if (ret_val instanceof Error) {
- jsref.disconnect();
- onerror(jsref, ret_val);
+ if (typeof url == 'string') {
+ if (typeof options == 'function') {
+ callback = options;
+ options = {};
+ }
+ } else {
+ if (typeof url == 'function') {
+ callback = url;
+ options = {};
+ } else if (typeof options == 'function') {
+ callback = options;
+ options = url;
+ } else {
+ options = url;
+ }
+
+ if (options.socket) {
+ socket = options.socket;
+ } else {
+ url = options.host || '127.0.0.1';
+ }
}
-}
-function onconnect(jsref) {
- jsref.emit('connect');
-}
+ if (typeof callback == 'function') {
+ this.on('connect', callback);
+ }
-function onpingresp(jsref) {
- jsref.emit('pingresp');
-}
+ if (options.will) {
+ if (typeof options.topic == 'undefined' ||
+ typeof options.message == 'undefined' ||
+ options.qos < 0 || options.qos > 2) {
+ throw new Error('Incorrect mqtt will options');
+ }
+ }
-function onmessage(jsref, message, topic, qos, packet_id) {
- var data = {
- message: message,
- topic: topic,
- qos: qos,
- packet_id: packet_id,
+ var host = '';
+ var create_tls = false;
+
+ if (!socket) {
+ if (url.substring(0, 8) == 'mqtts://') {
+ create_tls = true;
+ host = url.substring(8);
+ } else if (url.substring(0, 7) == 'mqtt://') {
+ host = url.substring(7);
+ } else {
+ host = url;
+ }
+ }
+
+ var keepalive = (options.keepalive || 60) | 0;
+
+ if (keepalive < 30) {
+ keepalive = 30;
+ }
+
+ if (keepalive > 65535) {
+ keepalive = 65535;
+ }
+
+ options = Object.create(options, {
+ clientId: { value: options.clientId || defaultClientId() },
+ host: { value: host },
+ port: { value: options.port || 8883 },
+ qos: { value: options.qos || 0 },
+ keepalive: { value: keepalive },
+ });
+
+ // Since network transmission takes time, the
+ // actual keepalive message is sent a bit earlier
+ this._handle = new MQTTHandle(this, keepalive - 5);
+
+ var connectionMessage = native.connect(options);
+
+ var onconnect = function() {
+ // Currently the connect message is tried only once.
+ // Multiple tries can be implemented later.
+ this.write(connectionMessage);
};
- if (qos == 1) {
- var opts = {
- type: PacketTypeEnum.PUBACK,
- packet_id: packet_id,
- };
-
- jsref.sendAcknowledge(opts);
- } else if (qos == 2) {
- var options = {
- type: PacketTypeEnum.PUBREC,
- packet_id: packet_id,
- };
- jsref.sendAcknowledge(options);
+ if (socket) {
+ onconnect.call(socket);
+ } else {
+ if (create_tls) {
+ if (!tls) {
+ tls = require('tls');
+ }
+
+ socket = tls.connect(options, onconnect);
+ } else {
+ if (!net) {
+ net = require('net');
+ }
+
+ socket = net.connect(options, onconnect);
+ }
}
- jsref.emit('message', data);
-}
+ this._handle.socket = socket;
+ socket._mqttSocket = this;
-function ondisconnect(jsref, message) {
- jsref._isConnected = false;
- jsref.emit('disconnect', message);
+ socket.on('error', onerror);
+ socket.on('data', ondata);
+ socket.on('finish', onfinish);
}
+util.inherits(MQTTClient, EventEmitter);
-function onpuback(jsref, data) {
- /*
- * QoS level 1
- * Handle PUBACK package. If this package isn't arrived (properly),
- * we have to resend the last message.
- *
- * The 'data' contains the packet identifier.
- */
+MQTTClient.prototype.end = function(force) {
+ var handle = this._handle;
- jsref.emit('puback', data);
-}
+ handle.isConnected = false;
-function onpubrec(jsref, data) {
- /*
- * Qos level 2
- * Handle PUBREC package. If this package is arrived, we have to send back
- * a PUBREL package to the server.
- */
- var options = {
- type: PacketTypeEnum.PUBREL,
- packet_id: data,
- };
+ if (force || handle.storageCount == 0) {
+ handle.socket.end(native.disconnect());
- jsref.sendAcknowledge(options);
+ // Abort ongoing messages.
+ clearInterval(this.timer);
+ this.storage = null;
+ this.storageCount = 0;
+ }
+};
- var interval = setInterval(function() {
- jsref.sendAcknowledge(options);
- }, 3000);
+MQTTClient.prototype.checkConnection = function() {
+ if (!this._handle.isConnected) {
+ throw new Error('MQTT client is not connected');
+ }
+};
- jsref.on('pubcomp', function() {
- clearInterval(interval);
- });
+MQTTClient.prototype.publish = function(topic, message, options, callback) {
+ this.checkConnection();
- jsref.emit('pubrec', data);
-}
+ var handle = this._handle;
-function onsuback(jsref, data) {
- /*
- * Successful subscription, the client will get messages from the requested
- * topic. The granted QoS is given in data.
- */
- jsref.emit('suback', data);
-}
+ // header bits: | 16 bit packet id | 4 bit PUBLISH header |
+ var header = 0;
+ var qos = 0;
-function onerror(jsref, error) {
- jsref.emit('error', error);
-}
+ if (options) {
+ if (options.retain) {
+ header = 0x1;
+ }
-/*
- * Returns an unique client ID based on current time.
- */
-function defaultClientId() {
- return 'iotjs_mqtt_client_' + Date.now();
-}
+ qos = options.qos;
+
+ if (qos !== 1 && qos !== 2) {
+ qos = 0;
+ }
-function getClient(connectOptions) {
- if (util.isUndefined(connectOptions.clientId)) {
- connectOptions.clientId = defaultClientId();
+ header |= (qos << 1);
}
- if (!Buffer.isBuffer(connectOptions.clientId)) {
- connectOptions.clientId =
- new Buffer(connectOptions.clientId.toString());
+
+ if (qos > 0) {
+ var packet_id = handle.getPacketId();
+ header |= (packet_id << 4);
+
+ var buffer = native.publish(topic, message, header);
+ handle.write(buffer);
+
+ // Set dup flag.
+ buffer.writeUInt8(buffer.readUInt8(0) | 0x08, 0);
+
+ var packet = handle.storage[packet_id];
+
+ packet.packet = buffer;
+ packet.callback = callback;
+ return;
}
- if (!util.isUndefined(connectOptions.username) &&
- !Buffer.isBuffer(connectOptions.username)) {
- connectOptions.username = new Buffer(connectOptions.username.toString());
+
+ handle.write(native.publish(topic, message, header));
+
+ if (typeof callback == 'function') {
+ process.nextTick(callback);
}
- if (!util.isUndefined(connectOptions.password) &&
- !Buffer.isBuffer(connectOptions.password)) {
- connectOptions.password = new Buffer(connectOptions.password.toString());
+};
+
+MQTTClient.prototype.subscribe = function(topic, options, callback) {
+ this.checkConnection();
+
+ var handle = this._handle;
+
+ var packet_id = handle.getPacketId();
+
+ // header bits: | 2 bit qos | 16 bit packet id |
+ var header = packet_id;
+
+ var qos = 0;
+
+ if (options) {
+ qos = options.qos;
+
+ if (qos !== 1 || qos !== 2) {
+ qos = 0;
+ }
+
+ header |= (qos << 16);
}
- if (connectOptions.will) {
- if (util.isUndefined(connectOptions.topic) ||
- util.isUndefined(connectOptions.message) ||
- connectOptions.qos < 0 || connectOptions.qos > 2) {
- throw new Error('Wrong options given! Please refer to the documentation');
+
+ var buffer = native.subscribe(topic, header);
+
+ handle.write(buffer);
+
+ var packet = handle.storage[packet_id];
+
+ packet.packet = buffer;
+ packet.callback = callback;
+};
+
+MQTTClient.prototype.unsubscribe = function(topic, callback) {
+ this.checkConnection();
+
+ var handle = this._handle;
+
+ var packet_id = handle.getPacketId();
+
+ // header bits: | 16 bit packet id |
+ var header = packet_id;
+
+ var buffer = native.unsubscribe(topic, header);
+
+ handle.write(buffer);
+
+ var packet = handle.storage[packet_id];
+
+ packet.packet = buffer;
+ packet.callback = callback;
+};
+
+function onerror(error) {
+ this._mqttSocket.emit('error', error);
+}
+
+function ondata(data) {
+ native.MqttReceive(this._mqttSocket._handle, data);
+}
+
+function onfinish() {
+ this._mqttSocket._handle.onEnd();
+}
+
+function storageTimerHit() {
+ // this: MQTTHandle
+
+ // eslint-disable-next-line guard-for-in
+ for (var packet_id in this.storage) {
+ var packet = this.storage[packet_id];
+
+ packet.remainingTime--;
+
+ if (packet.remainingTime <= 0) {
+ this.releasePacket(packet_id, new Error('Undelivered message'));
+ continue;
}
- if (!util.isUndefined(connectOptions.topic) &&
- !Buffer.isBuffer(connectOptions.topic)) {
- connectOptions.topic = new Buffer(connectOptions.topic.toString());
+ // Every 8 seconds, the message is retransmitted.
+ if (!(packet.remainingTime & 0x7)) {
+ this.write(packet.packet);
}
- if (!util.isUndefined(connectOptions.message) &&
- !Buffer.isBuffer(connectOptions.message)) {
- connectOptions.message = new Buffer(connectOptions.message.toString());
+ }
+
+ if (this.storageCount == 0 && !this.isConnected) {
+ // Graceful disconnect after all messages transmitted.
+ this.socket.end(native.disconnect());
+
+ clearInterval(this.timer);
+ this.storage = null;
+ return;
+ }
+
+ if (this.pingrespCounter > 0) {
+ this.pingrespCounter--;
+
+ if (this.pingrespCounter <= 0) {
+ this.onEnd();
+ }
+ }
+
+ this.keepaliveCounter++;
+
+ if (this.keepaliveCounter >= this.keepalive) {
+ this.write(native.ping());
+
+ if (this.pingrespCounter == 0) {
+ this.pingrespCounter = (this.keepalive + 5) * 3 >> 1;
}
}
- return new MQTTClient(connectOptions);
}
-exports.getClient = getClient;
+/*
+ * Returns an unique client ID based on current time.
+ */
+function defaultClientId() {
+ return 'iotjs_mqtt_client_' + Date.now();
+}
+
+function connect(url, options, callback) {
+ return new MQTTClient(url, options, callback);
+}
+
+exports.connect = connect;
return _tcp;
}
+// Expected end message on nuttx platform.
+var expectedEnding;
+
+if (process.platform == 'nuttx') {
+ expectedEnding = new Buffer('\\e\\n\\d');
+}
+
function SocketState(options) {
// 'true' during connection handshaking.
return;
}
- var str = buffer.toString();
+ // We know for sure the last 6 characters are going to be the ending.
+ // Lets create a buffer with those 6 characters without toString conversion.
+ var eofLength = 6;
+ var bufferLength = buffer.length;
+
var eofNeeded = false;
- if (str.length >= 6
- && str.substr(str.length - 6, str.length) == '\\e\\n\\d') {
+ if (bufferLength >= eofLength &&
+ expectedEnding.compare(buffer.slice(bufferLength - eofLength,
+ bufferLength)) == 0) {
eofNeeded = true;
- buffer = buffer.slice(0, str.length - 6);
+ buffer = buffer.slice(0, bufferLength - eofLength);
}
- if (str.length == 6 && eofNeeded) {
+ if (bufferLength == eofLength && eofNeeded) {
// Socket.prototype.end with no argument
} else {
stream.Readable.prototype.push.call(socket, buffer);
var Stream = require('stream_internal');
+var Writable = require('stream_writable');
var util = require('util');
};
+Readable.prototype.pipe = function(destination, options) {
+ if (!(destination instanceof Writable || isDuplex(destination))) {
+ throw new TypeError('pipe excepts stream.Writable or' +
+ ' stream.Duplex as argument');
+ }
+
+ options = options || {'end': true};
+
+ var listeners = {
+ readableListener: readableListener.bind(this),
+ dataListener: dataListener.bind(destination),
+ endListener: endListener.bind(destination),
+ };
+
+ this.on('readable', listeners.readableListener);
+ this.on('data', listeners.dataListener);
+
+ if (options.end) {
+ this.on('end', listeners.endListener);
+ }
+
+ this._piped = this._piped || [];
+ this._piped.push(destination);
+
+ this._piped_listeners = this._piped_listeners || [];
+ this._piped_listeners.push(listeners);
+
+ return destination;
+};
+
+
+Readable.prototype.unpipe = function(destination) {
+ if (destination === undefined) {
+ this.removeAllListeners();
+ this._piped = undefined;
+ this._piped_listeners = undefined;
+ return;
+ }
+
+ var idx = this._piped.indexOf(destination);
+ if (idx === -1) {
+ return;
+ }
+
+ this._piped.splice(idx, 1);
+ var listeners = this._piped_listeners.splice(idx, 1)[0];
+
+ this.removeListener('readable', listeners.readableListener);
+ this.removeListener('data', listeners.dataListener);
+ this.removeListener('end', listeners.endListener);
+
+ return destination;
+};
+
+
+function readableListener() {
+ this.resume();
+}
+
+
+function dataListener(data) {
+ this.write(data);
+}
+
+
+function endListener() {
+ this.end();
+}
+
+
function readBuffer(stream, n) {
var state = stream._readableState;
var res;
}
+function isDuplex(stream) {
+ if (!(stream instanceof Readable)) {
+ return false;
+ }
+
+ var wr_keys = Object.keys(Writable.prototype);
+ for (var i = 0; i < wr_keys.length; i++) {
+ var wr_key = wr_keys[i];
+ if (!stream[wr_key]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
module.exports = Readable;
// Because NuttX cannot poll 'EOF',so forcely raise EOF event.
if (process.platform === 'nuttx') {
if (!state.ending) {
+ var eof = '\\e\\n\\d';
if (util.isNullOrUndefined(chunk)) {
- chunk = '\\e\\n\\d';
+ chunk = eof;
+ } else if (Buffer.isBuffer(chunk)) {
+ chunk = Buffer.concat([chunk, new Buffer(eof)]);
} else {
- chunk += '\\e\\n\\d';
+ chunk += eof;
}
}
}
var util = require('util');
-var TIMEOUT_MAX = 2147483647; // 2^31-1
+var TIMEOUT_MAX = '2147483647.0' - 0; // 2^31-1
function Timeout(after) {
};
+var getDataPath = function() {
+ return bridge.sendSync('getDataPath', '');
+};
+
+
module.exports = util.mixin(native, EventEmitter.prototype, {
launchAppControl: launchAppControl,
getResPath: getResPath,
+ getDataPath: getDataPath,
on: on,
});
var net = require('net');
var util = require('util');
-var EventEmitter = require('events').EventEmitter;
+var Duplex = require('stream').Duplex;
function TLSSocket(socket, options) {
if (!(this instanceof TLSSocket)) {
this._socket = socket;
socket._tlsSocket = this;
- EventEmitter.call(this);
+ Duplex.call(this);
this.authorized = false;
this._socket.on('data', this.ondata);
this._socket.on('error', this.onerror);
this._socket.on('close', this.onclose);
- this._socket.on('finish', this.onfinish);
+ if (this._socket instanceof net.Socket) {
+ this._socket.on('finish', this.onfinish);
+ } else {
+ this._socket.on('finish', this.onend);
+ }
this._socket.on('end', this.onend);
// Native handle
native.TlsInit(this, options, secureContext);
this._socketState = socket._socketState;
+
+ var self = this;
+ if (socket._writableState.ready && !options.isServer) {
+ process.nextTick(function() {
+ self._native_connect(options.servername || options.host || 'localhost');
+ self._native_read(null);
+ });
+ }
}
-util.inherits(TLSSocket, EventEmitter);
+util.inherits(TLSSocket, Duplex);
-TLSSocket.prototype._read = native.read;
-TLSSocket.prototype._write = native.write;
-TLSSocket.prototype._connect = native.connect;
+TLSSocket.prototype._native_read = native.read;
+TLSSocket.prototype._native_write = native.write;
+TLSSocket.prototype._native_connect = native.connect;
TLSSocket.prototype.connect = function(options, callback) {
- this._connect(options.servername || options.host || 'localhost');
+ this._native_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._write = function(chunk, callback, onwrite) {
+ chunk = this._native_write(chunk);
+ this._socket.write(chunk, callback);
+ onwrite();
};
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);
+ Duplex.prototype.end.call(this, data, callback);
+ this._socket.end();
};
TLSSocket.prototype.destroy = function() {
};
TLSSocket.prototype.onconnect = function() {
- var self = this._tlsSocket;
- self._read(null);
+ this._tlsSocket._native_read(null);
};
TLSSocket.prototype.encrypted = function() {
TLSSocket.prototype.ondata = function(data) {
var self = this._tlsSocket;
- self._read(data);
+ self._native_read(data);
};
TLSSocket.prototype.onerror = function(error) {
return;
}
+ this._readyToWrite();
+
if (server) {
server.emit('secureConnection', this);
} else {
}
function connect(arg0, arg1, arg2, callback) {
- var options;
- var tlsSocket;
+ var options = {};
if (typeof arg0 == 'object') {
options = Object.create(arg0, {
isServer: { value: false, enumerable: true },
callback = arg1;
}
}
- tlsSocket = new TLSSocket(new net.Socket(), options);
- tlsSocket.connect(options, callback);
+
+ var tlsSocket = new TLSSocket(options.socket || new net.Socket(), options);
+ if (tlsSocket._socket instanceof net.Socket) {
+ tlsSocket.connect(options, callback);
+ } else if (util.isFunction(callback)) {
+ tlsSocket.on('secureConnect', callback);
+ }
return tlsSocket;
}
* limitations under the License.
*/
+var Buffer = require('buffer');
+
function isNull(arg) {
return arg === null;
}
-function isBuffer(arg) {
- return arg instanceof Buffer;
-}
-
-
function inherits(ctor, superCtor) {
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
exports.isObject = isObject;
exports.isFinite = isFinite;
exports.isFunction = isFunction;
-exports.isBuffer = isBuffer;
+exports.isBuffer = Buffer.isBuffer;
exports.isArray = Array.isArray;
exports.exceptionWithHostPort = exceptionWithHostPort;
exports.errnoException = errnoException;
--- /dev/null
+/* 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;
+ var tls = require('tls');
+
+util.inherits(Websocket, EventEmitter);
+util.inherits(WebsocketClient, EventEmitter);
+util.inherits(Server, EventEmitter);
+
+function WebSocketHandle(client) {
+ this.client = client;
+ this.pings = [];
+ this.connected = false;
+
+ native.wsInit(this);
+}
+
+function Websocket(options) {
+ if (!(this instanceof Websocket)) {
+ return new Websocket(options);
+ }
+
+ EventEmitter.call(this);
+ this._firstMessage = true;
+ this._handle = new WebSocketHandle(this);
+ this._secure = false;
+}
+
+function WebsocketClient(socket, handle) {
+ if (!(this instanceof WebsocketClient)) {
+ return new WebsocketClient(socket, handle);
+ }
+
+ if ((Object.keys(tls).length != 0 &&
+ socket instanceof tls.TLSSocket) ||
+ (socket instanceof net.Socket)) {
+ this._socket = socket;
+ this.readyState = 'CONNECTING';
+ } else {
+ this._firstMessage = true;
+ }
+ this._handle = handle;
+
+ EventEmitter.call(this);
+}
+
+function ServerHandle() {
+ this.clients = [];
+
+ native.wsInit(this);
+}
+
+function connectionListener(socket) {
+ var ws = new WebsocketClient(socket, this._serverHandle);
+ this._serverHandle.clients.push(ws);
+ var self = this;
+
+ ws._socket.on('data', function(data) {
+ if (ws.readyState === 'CONNECTING') {
+ parseServerHandshakeData(data, ws, self);
+ } else if (ws.readyState === 'OPEN') {
+ self._serverHandle.ondata(data, ws);
+ }
+ });
+}
+
+function parseServerHandshakeData(data, client, server) {
+ data = data.toString();
+ var res = data.split('\r\n');
+ var method = res[0].split(' ');
+
+ var headers = { 'Connection': '',
+ 'Upgrade': '',
+ 'Host': '',
+ 'Sec-WebSocket-Key': '',
+ 'Sec-WebSocket-Version': -1,
+ };
+
+ for (var i = 1; i < res.length; i++) {
+ var temp = res[i].split(': ');
+ headers[temp[0]] = temp[1];
+ }
+
+ var response = '';
+ if (method[0] === 'GET' &&
+ method[2] === 'HTTP/1.1' &&
+ method[1] === server.path &&
+ headers['Connection'] === 'Upgrade' &&
+ headers['Upgrade'] === 'websocket' &&
+ headers['Sec-WebSocket-Version'] === '13') {
+ response = native.ReceiveHandshakeData(
+ headers['Sec-WebSocket-Key']
+ ).toString();
+ client.readyState = 'OPEN';
+ client._socket.write(response);
+ server.emit('open', client);
+ } else {
+ response = method[2] + ' 400 Bad Request';
+ client._socket.write(response);
+ }
+}
+
+function Server(options, listener) {
+ if (!(this instanceof Server)) {
+ return new Server(options);
+ }
+
+ EventEmitter.call(this);
+ var emit_type = 'connection';
+ this._netserver = null;
+
+ if (options.server) {
+ if (Object.keys(tls).length != 0 && options.server instanceof tls.Server) {
+ this._netserver = options.server;
+ emit_type = 'secureConnection';
+ } else if (options.server instanceof net.Server) {
+ this._netserver = options.server;
+ }
+ } else if (options.port) {
+ if (options.secure == true) {
+ if (Object.keys(tls).length == 0) {
+ throw new Error('TLS module is required to create a secure server.');
+ }
+ this._netserver = tls.createServer(options);
+ this._netserver.on('error', this.onError);
+ this._netserver.listen(options.port);
+ emit_type = 'secureConnection';
+ } else {
+ this._netserver = net.createServer(options);
+ this._netserver.on('error', this.onError);
+ this._netserver.listen(options.port);
+ }
+ } else {
+ throw new Error('One of port or server must be provided as option');
+ }
+ this._netserver.path = options.path || '/';
+
+ this._netserver.on('error', this.onError);
+ this._netserver.on(emit_type, connectionListener);
+ this._netserver._serverHandle = new ServerHandle();
+
+ if (listener) {
+ this._netserver.on('open', listener);
+ }
+
+ this.options = options;
+}
+
+ServerHandle.prototype.ondata = function(data, client) {
+ native.wsReceive(this, data, client);
+};
+
+ServerHandle.prototype.onmessage = function(msg, client) {
+ client.emit('message', msg);
+};
+
+ServerHandle.prototype.pong = function(msg, client) {
+ client.emit('ping', msg);
+ this.sendFrame(native.ping(false, msg, true), client);
+};
+
+ServerHandle.prototype.onError = function(err, client) {
+ client.emit('error', err);
+};
+
+ServerHandle.prototype.sendFrame = function(msg, client) {
+ if (client._socket._socketState.writable) {
+ client._socket.write(msg);
+ } else {
+ if (this.clients.indexOf(client) > -1) {
+ this.onError('Underlying socket', client);
+ }
+ }
+};
+
+ServerHandle.prototype.onclose = function(msg, client) {
+ client.readyState = 'CLOSING';
+ if (msg) {
+ // If there is msg we know the following:
+ // 4 characters status code (1000-4999)
+ // rest is msg payload
+ var msg_str = msg.toString();
+ msg = {
+ code: msg_str.substr(0, 4),
+ reason: msg_str.substr(4, msg_str.length),
+ };
+ } else {
+ msg = {};
+ }
+
+ client.close(msg);
+};
+
+Server.prototype.close = function(reason, code) {
+ var msg = {
+ code: code || 1000,
+ reason: reason || 'Connection successfully closed',
+ };
+
+ var i = 0;
+ while (this._netserver._serverHandle.clients.length != 0) {
+ this._netserver._serverHandle.clients[i].readyState = 'CLOSING';
+ this._netserver._serverHandle.clients[i].close(msg);
+ }
+
+ this._netserver.close();
+ this.emit('close', msg);
+};
+
+Server.prototype.broadcast = function(msg, options) {
+ if (options) {
+ var mask = options.mask || true;
+ var binary = options.binary || false;
+ var compress = options.compress;
+ if (compress) {
+ // Currently not supported, needs zlib
+ this.onError('Compression is not supported');
+ }
+ }
+ var buff = native.send(msg, binary, mask);
+
+ var self = this;
+ this._netserver._serverHandle.clients.forEach(function each(client) {
+ if (client.readyState === 'OPEN') {
+ self._netserver._serverHandle.sendFrame(buff, client);
+ }
+ });
+};
+
+Server.prototype.address = function() {
+ return this._netserver.address();
+};
+
+Server.prototype.onError = function(err) {
+ this.emit('error', err);
+};
+
+WebsocketClient.prototype.send = function(message, opts) {
+ if (opts) {
+ var mask = opts.mask;
+ var binary = opts.binary;
+ var compress = opts.compress;
+ if (compress) {
+ // Currently not supported, needs zlib
+ this._handle.onError('Compression is not supported');
+ }
+ }
+ var buff = native.send(message, binary, mask, compress);
+ if (buff) {
+ this._handle.sendFrame(buff, this);
+ }
+};
+
+WebsocketClient.prototype.close = function(msg) {
+ msg = {
+ reason: msg.reason || 'Connection successfully closed',
+ code: msg.code || 1000,
+ };
+
+ var buff = native.close(msg.reason, msg.code);
+ this._handle.sendFrame(buff, this);
+ this.emit('close', msg);
+ this._socket.end();
+ var id = this._handle.clients.indexOf(this);
+ this._handle.clients.splice(id, 1);
+};
+
+WebsocketClient.prototype.onError = function(err) {
+ this.emit('error', err);
+};
+
+WebSocketHandle.prototype.onmessage = function(msg) {
+ this.client.emit('message', msg);
+};
+
+WebSocketHandle.prototype.ondata = function(data) {
+ native.wsReceive(this, data, this);
+};
+
+WebSocketHandle.prototype.onhandshakedone = function(remaining) {
+ this.client.emit('open');
+ this.client._firstMessage = false;
+ if (remaining) {
+ this.ondata(remaining);
+ }
+};
+
+WebSocketHandle.prototype.onError = function(err) {
+ this.client.emit('error', err);
+};
+
+WebSocketHandle.prototype.onclose = function(msg) {
+ if (msg) {
+ // If there is msg we know the following:
+ // 4 characters status code (1000-4999)
+ // rest is msg payload
+ var msg_str = msg.toString();
+ msg = {
+ code: msg_str.substr(0, 4),
+ reason: msg_str.substr(4, msg_str.length),
+ };
+ } else {
+ msg = {};
+ }
+
+ this.client.emit('close', msg);
+ for (var i = 0; i < this.pings.length; i++) {
+ clearInterval(this.pings[i].timer);
+ }
+ this.client._socket.end();
+};
+
+WebSocketHandle.prototype.sendFrame = function(msg, cb) {
+ if (this.connected) {
+ if (typeof cb == 'function') {
+ this.client._socket.write(msg, cb);
+ } else {
+ this.client._socket.write(msg);
+ }
+ } else {
+ this.onError('Underlying socket connection is closed');
+ }
+};
+
+WebSocketHandle.prototype.pong = function(msg) {
+ this.client._socket.write(native.ping(false, msg, true));
+};
+
+WebSocketHandle.prototype.onpingresp = function(msg) {
+ for (var i = 0; i < this.pings.length; i++) {
+ if (this.pings[i].id == msg) {
+ clearInterval(this.pings[i].timer);
+ this.pings[i].callback(msg);
+ this.pings.splice(i, 1);
+ return;
+ }
+ }
+};
+
+function sendHandshake(jsref, host, path) {
+ return native.prepareHandshake(jsref, host, path);
+}
+
+Websocket.prototype.connect = function(url, port, path, callback) {
+ var host = url.toString() || '127.0.0.1';
+ path = path || '/';
+
+ var emit_type = 'connect';
+
+ if (host.substr(0, 3) == 'wss') {
+ this._secure = true;
+ if (Object.keys(tls).length == 0) {
+ this._handle.onError('TLS module was not found!');
+ }
+ port = port || 443;
+ host = host.substr(6);
+ this._socket = tls.connect(port, host);
+ emit_type = 'secureConnect';
+ } else if (host.substr(0, 2) == 'ws') {
+ port = port || 80;
+ this._socket = new net.Socket();
+ host = host.substr(5);
+ } else {
+ port = port || 80;
+ this._socket = new net.Socket();
+ }
+
+ if (typeof callback == 'function') {
+ this.on('open', callback);
+ }
+
+ var self = this;
+
+ this._socket.on(emit_type, function() {
+ self._handle.connected = true;
+ self._socket.write(sendHandshake(self._handle, host, path));
+ });
+
+ this._socket.on('end', function() {
+ self._handle.connected = false;
+ });
+ if (emit_type == 'connect') {
+ this._socket.connect(port, host);
+ }
+
+ this._socket.on('data', function(data) {
+ if (self._firstMessage) {
+ var remaining_data = native.parseHandshakeData(data, self._handle);
+ self._handle.onhandshakedone(remaining_data);
+ } else {
+ self._handle.ondata(data);
+ }
+ });
+};
+
+Websocket.prototype.close = function(message, code, cb) {
+ this._handle.sendFrame(native.close(message, code), cb);
+};
+
+Websocket.prototype.ping = function(message, mask, cb) {
+ var self = this;
+ var obj = {
+ id: message,
+ callback: cb,
+ timer: setTimeout(function() {
+ self.close('Ping timeout limit exceeded', 1002);
+ }, 30000),
+ };
+ this._handle.pings.push(obj);
+ this._handle.sendFrame(native.ping(true, message, mask));
+};
+
+Websocket.prototype.send = function(message, opts, cb) {
+ if (opts) {
+ var mask = opts.mask;
+ var binary = opts.binary;
+ var compress = opts.compress;
+ if (compress) {
+ // Currently not supported, needs zlib
+ this._handle.onError('Compression is not supported');
+ }
+ }
+ var buff = native.send(message, binary, mask, compress);
+ if (buff) {
+ this._handle.sendFrame(buff, cb);
+ }
+};
+
+exports.Websocket = Websocket;
+exports.Server = Server;
},
"ble": {
"js_file": "js/ble.js",
- "require": ["blehcisocket", "ble_characteristic", "ble_descriptor",
+ "require": ["ble_hci_socket", "ble_characteristic", "ble_descriptor",
"ble_hci_socket_acl_stream", "ble_hci_socket_bindings",
"ble_hci_socket_crypto", "ble_hci_socket_gap",
"ble_hci_socket_gatt", "ble_hci_socket_hci",
"ble_hci_socket_hci": {
"js_file": "js/ble_hci_socket_hci.js",
"require": ["console", "events", "util", "ble_uuid_util",
- "blehcisocket"]
+ "ble_hci_socket"]
},
"ble_hci_socket_hci_status": {
"js_file": "js/ble_hci_socket_hci_status.js"
},
"ble_hci_socket_mgmt": {
"js_file": "js/ble_hci_socket_mgmt.js",
- "require": ["console", "events", "util", "blehcisocket"]
+ "require": ["console", "events", "util", "ble_hci_socket"]
},
"ble_hci_socket_smp": {
"js_file": "js/ble_hci_socket_smp.js",
"ble_uuid_util": {
"js_file": "js/ble_uuid_util.js"
},
- "blehcisocket": {
+ "ble_hci_socket": {
"platforms": {
"linux": {
"native_files": ["modules/linux/iotjs_module_blehcisocket-linux.c"]
"native_files": ["modules/iotjs_module_constants.c"],
"init": "InitConstants"
},
+ "crypto": {
+ "native_files": ["modules/iotjs_module_crypto.c"],
+ "init": "InitCrypto",
+ "js_file": "js/crypto.js"
+ },
"dgram": {
"js_file": "js/dgram.js",
"require": ["events", "udp", "util"]
"linux": {
"native_files": ["modules/linux/iotjs_module_gpio-linux.c"]
},
+ "mocklinux": {
+ "native_files": ["modules/mock/iotjs_module_gpio-mock.c"]
+ },
"nuttx": {
"native_files": ["modules/nuttx/iotjs_module_gpio-nuttx.c"]
},
"js_file": "js/http_server.js",
"require": ["http_common", "http_outgoing", "net", "util"]
},
+ "http_signature": {
+ "js_file": "js/http_signature.js",
+ "require": ["tls", "crypto"]
+ },
"http_parser": {
"native_files": ["modules/iotjs_module_http_parser.c"],
"init": "InitHttpParser"
"linux": {
"native_files": ["modules/linux/iotjs_module_i2c-linux.c"]
},
+ "mocklinux": {
+ "native_files": ["modules/mock/iotjs_module_i2c-mock.c"]
+ },
"nuttx": {
"native_files": ["modules/nuttx/iotjs_module_i2c-nuttx.c"]
},
"util": {
"js_file": "js/util.js"
},
+ "websocket": {
+ "native_files": ["modules/iotjs_module_websocket.h",
+ "modules/iotjs_module_websocket.c"],
+ "init": "InitWebsocket",
+ "js_file": "js/websocket.js",
+ "require": ["crypto", "events", "net", "util"]
+ },
"bridge": {
"native_files": ["modules/iotjs_module_bridge.c"],
"init": "InitBridge",
#include "iotjs_def.h"
#include "iotjs_module_adc.h"
+#include "iotjs_uv_request.h"
IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(adc);
}
static void adc_worker(uv_work_t* work_req) {
- 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;
+ iotjs_periph_data_t* worker_data =
+ (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req);
+ iotjs_adc_t* adc = (iotjs_adc_t*)worker_data->data;
- switch (req_wrap->op) {
+ switch (worker_data->op) {
case kAdcOpOpen:
- req_wrap->result = iotjs_adc_open(adc);
+ worker_data->result = iotjs_adc_open(adc);
break;
case kAdcOpRead:
- req_wrap->result = iotjs_adc_read(adc);
+ worker_data->result = iotjs_adc_read(adc);
break;
case kAdcOpClose:
- req_wrap->result = iotjs_adc_close(adc);
+ worker_data->result = iotjs_adc_close(adc);
break;
default:
IOTJS_ASSERT(!"Invalid Adc Operation");
// Create ADC object
const jerry_value_t jadc = JS_GET_THIS();
iotjs_adc_t* adc = adc_create(jadc);
- IOTJS_ASSERT(adc ==
- (iotjs_adc_t*)(iotjs_jval_get_object_native_handle(jadc)));
+ IOTJS_ASSERT(adc == (iotjs_adc_t*)(iotjs_jval_get_object_native_handle(
+ jadc, &this_module_native_info)));
jerry_value_t jconfig;
JS_GET_REQUIRED_ARG_VALUE(0, jconfig, IOTJS_MAGIC_STRING_CONFIG, object);
jerry_value_t config_res = iotjs_adc_set_platform_config(adc, jconfig);
- if (jerry_value_has_error_flag(config_res)) {
+ if (jerry_value_is_error(config_res)) {
return config_res;
}
IOTJS_ASSERT(jerry_value_is_undefined(config_res));
#include "iotjs_def.h"
#include "iotjs_module_periph_common.h"
-#include "iotjs_reqwrap.h"
// Forward declaration of platform data. These are only used by platform code.
// Generic ADC module never dereferences platform data pointer.
// Create object
jerry_value_t jblehcisocket = JS_GET_THIS();
iotjs_blehcisocket_t* blehcisocket = iotjs_blehcisocket_create(jblehcisocket);
- IOTJS_ASSERT(blehcisocket ==
- (iotjs_blehcisocket_t*)(iotjs_jval_get_object_native_handle(
- jblehcisocket)));
+ IOTJS_ASSERT(
+ blehcisocket ==
+ (iotjs_blehcisocket_t*)(iotjs_jval_get_object_native_handle(jblehcisocket,
+ NULL)));
return jerry_create_undefined();
}
#define IOTJS_MODULE_BLE_HCI_SOCKET_H
#include "iotjs_def.h"
-#include "iotjs_reqwrap.h"
typedef struct {
jerry_value_t jobject;
*/
#include "iotjs_def.h"
#include "iotjs_module_bridge.h"
-#include "iotjs_reqwrap.h"
#include <stdio.h>
typedef enum {
}
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) {
+ iotjs_bridge_object_t* bridgeobj =
+ (iotjs_bridge_object_t*)iotjs_jval_get_object_native_handle(obj_val,
+ NULL);
+
+ if (bridgeobj == NULL) {
bridgeobj = IOTJS_ALLOC(iotjs_bridge_object_t);
bridgeobj->jobject = obj_val;
bridgeobj->calls = NULL;
}
static void iotjs_bridge_js_call(iotjs_bridge_call_t* bridgecall) {
- iotjs_jargs_t jargs = iotjs_jargs_create(2);
+ jerry_value_t jargs[2] = { 0 };
if (bridgecall->status == CALL_STATUS_ERROR) { // internal error
- iotjs_jargs_append_error(&jargs, iotjs_string_data(&bridgecall->ret_msg));
- iotjs_jargs_append_null(&jargs);
+ jargs[0] = iotjs_jval_create_error_without_error_flag(
+ iotjs_string_data(&bridgecall->ret_msg));
+ jargs[1] = jerry_create_null();
} else {
- iotjs_jargs_append_null(&jargs);
- iotjs_jargs_append_string_raw(&jargs,
- iotjs_string_data(&bridgecall->ret_msg));
+ jargs[0] = jerry_create_null();
+ jargs[1] = jerry_create_string_from_utf8(
+ (const jerry_char_t*)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_invoke_callback(jcallback, jerry_create_undefined(), jargs, 2);
}
- iotjs_jargs_destroy(&jargs);
+ jerry_release_value(jargs[0]);
+ jerry_release_value(jargs[1]);
}
static void aysnc_callback(uv_async_t* async) {
iotjs_bufferwrap_t* iotjs_bufferwrap_create(const jerry_value_t jobject,
size_t length) {
- iotjs_bufferwrap_t* bufferwrap = IOTJS_ALLOC(iotjs_bufferwrap_t);
+ iotjs_bufferwrap_t* bufferwrap = (iotjs_bufferwrap_t*)iotjs_buffer_allocate(
+ sizeof(iotjs_bufferwrap_t) + length);
bufferwrap->jobject = jobject;
jerry_set_object_native_pointer(jobject, bufferwrap,
&this_module_native_info);
- if (length > 0) {
- bufferwrap->length = length;
- bufferwrap->buffer = iotjs_buffer_allocate(length);
- IOTJS_ASSERT(bufferwrap->buffer != NULL);
- } else {
- bufferwrap->length = 0;
- bufferwrap->buffer = NULL;
- }
+ bufferwrap->length = length;
IOTJS_ASSERT(
bufferwrap ==
- (iotjs_bufferwrap_t*)(iotjs_jval_get_object_native_handle(jobject)));
+ (iotjs_bufferwrap_t*)(iotjs_jval_get_object_native_handle(jobject,
+ NULL)));
return bufferwrap;
}
static void iotjs_bufferwrap_destroy(iotjs_bufferwrap_t* bufferwrap) {
- IOTJS_RELEASE(bufferwrap->buffer);
IOTJS_RELEASE(bufferwrap);
}
iotjs_bufferwrap_t* iotjs_bufferwrap_from_jbuffer(const jerry_value_t jbuffer) {
IOTJS_ASSERT(jerry_value_is_object(jbuffer));
- iotjs_bufferwrap_t* buffer =
- (iotjs_bufferwrap_t*)iotjs_jval_get_object_native_handle(jbuffer);
+ iotjs_bufferwrap_t* buffer = (iotjs_bufferwrap_t*)
+ iotjs_jval_get_object_native_handle(jbuffer, &this_module_native_info);
IOTJS_ASSERT(buffer != NULL);
return buffer;
}
size_t iotjs_bufferwrap_length(iotjs_bufferwrap_t* bufferwrap) {
- IOTJS_ASSERT(bufferwrap != NULL);
+ if (bufferwrap == NULL) {
+ IOTJS_ASSERT(0);
+ return 0;
+ }
#ifndef NDEBUG
jerry_value_t jlength =
iotjs_jval_get_property(bufferwrap->jobject, IOTJS_MAGIC_STRING_LENGTH);
}
+iotjs_bufferwrap_t* iotjs_jbuffer_get_bufferwrap_ptr(
+ const jerry_value_t jbuffer) {
+ if (!jerry_value_is_object(jbuffer)) {
+ return NULL;
+ }
+
+ iotjs_bufferwrap_t* buffer = (iotjs_bufferwrap_t*)
+ iotjs_jval_get_object_native_handle(jbuffer, &this_module_native_info);
+ if (buffer != NULL) {
+ return buffer;
+ }
+
+ return NULL;
+}
+
+
static size_t bound_range(size_t index, size_t low, size_t upper) {
if (index == SIZE_MAX) {
return low;
}
-static size_t base64_decode(char* buf, size_t len, const char* src,
+static size_t base64_decode(char* dst, size_t len, const char* src,
const size_t srcLen) {
if (srcLen == 0) {
- return 0 + 1;
+ return 1;
+ }
+
+ char* decoded_base64 = NULL;
+ size_t decoded_len = iotjs_base64_decode(&decoded_base64, src, srcLen);
+ size_t ret_val = 0;
+ if (decoded_len) {
+ char* buf = dst;
+ char* bufEnd = len > decoded_len ? dst + decoded_len : dst + len;
+
+ char* pos = decoded_base64;
+ while (buf < bufEnd) {
+ *buf++ = *pos++;
+ }
+ ret_val = (size_t)(buf - dst) + 1;
}
- if ((srcLen & 0x3) != 0) {
+ IOTJS_RELEASE(decoded_base64);
+ return ret_val;
+}
+
+
+size_t iotjs_base64_decode(char** out_buff, const char* src,
+ const size_t srcLen) {
+ if ((srcLen & 0x3) != 0 || srcLen == 0) {
return 0;
}
- const char* bufStart = buf;
- const char* bufEnd = buf + len;
+ size_t len = (3 * (srcLen / 4));
+
const char* srcEnd = src + srcLen;
if (srcEnd[-1] == '=') {
srcEnd--;
+ len--;
if (srcEnd[-1] == '=') {
srcEnd--;
+ len--;
}
}
+ if (*out_buff == NULL) {
+ *out_buff = IOTJS_CALLOC(len, char);
+ }
+
+ char* buf = *out_buff;
+
+ const char* bufStart = buf;
+ const char* bufEnd = buf + len;
+
int32_t current_bits = 0;
int32_t shift = 8;
shift = 8;
}
- if (buf < bufEnd) {
- *buf++ = (char)byte;
+ if (buf <= bufEnd) {
+ *buf++ = byte;
}
}
- return (size_t)((buf - bufStart) + 1);
+ return (size_t)((buf - bufStart));
}
}
jerry_value_t iotjs_bufferwrap_create_buffer(size_t len) {
- jerry_value_t jglobal = jerry_get_global_object();
+ jerry_value_t jres_buffer = jerry_create_object();
+
+ iotjs_bufferwrap_create(jres_buffer, len);
+
+ iotjs_jval_set_property_number(jres_buffer, IOTJS_MAGIC_STRING_LENGTH, len);
+ // Support for 'instanceof' operator
+ jerry_value_t native_buffer = iotjs_module_get("buffer");
jerry_value_t jbuffer =
- iotjs_jval_get_property(jglobal, IOTJS_MAGIC_STRING_BUFFER);
- jerry_release_value(jglobal);
- IOTJS_ASSERT(jerry_value_is_function(jbuffer));
+ iotjs_jval_get_property(native_buffer, IOTJS_MAGIC_STRING_BUFFER);
- jerry_value_t arg = jerry_create_number(len);
+ if (!jerry_value_is_error(jbuffer) && jerry_value_is_object(jbuffer)) {
+ jerry_value_t jbuffer_proto =
+ iotjs_jval_get_property(jbuffer, IOTJS_MAGIC_STRING_PROTOTYPE);
- 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));
+ if (!jerry_value_is_error(jbuffer_proto) &&
+ jerry_value_is_object(jbuffer_proto)) {
+ jerry_set_prototype(jres_buffer, jbuffer_proto);
+ }
- jerry_release_value(arg);
+ jerry_release_value(jbuffer_proto);
+ }
jerry_release_value(jbuffer);
- return jres;
+ return jres_buffer;
}
DJS_CHECK_ARGS(2, object, number);
JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap);
-
size_t buffer_length = iotjs_bufferwrap_length(buffer_wrap);
+
+ if (buffer_length == 0) {
+ return jerry_create_number(0);
+ }
+
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;
- uint8_t result = 0;
-
- if (buffer != NULL) {
- result = (uint8_t)buffer[offset];
- }
-
- return jerry_create_number(result);
+ return jerry_create_number((uint8_t)buffer[offset]);
}
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) {
+ unsigned char* buffer = NULL;
+ size_t buffer_length = iotjs_base64_encode(&buffer, data, length);
+ jerry_value_t ret_value = jerry_create_string_sz(buffer, buffer_length);
+ IOTJS_RELEASE(buffer);
+
+ return ret_value;
}
-static jerry_value_t to_base64_string(const uint8_t* data, size_t length) {
- if (length == 0) {
- return jerry_create_string_sz(NULL, 0);
- }
+static const unsigned char base64_enc_map[65] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- 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;
+size_t iotjs_base64_encode(unsigned char** out_buff, const unsigned char* data,
+ size_t buff_len) {
+ size_t i, n;
+ int C1, C2, C3;
+ unsigned char* p;
- uint32_t current_bits = 0;
- int32_t shift = 2;
+ if (buff_len == 0) {
+ return 0;
+ }
- while (data < end) {
- current_bits = (current_bits << 8) | *data++;
+ n = buff_len / 3 + (buff_len % 3 != 0);
- *buffer++ = to_base64_char(current_bits >> shift);
- current_bits &= (uint32_t)((1 << shift) - 1);
+ if (n > ((size_t)-2) / 4) {
+ return 0;
+ }
+
+ if (*out_buff == NULL) {
+ *out_buff = IOTJS_CALLOC(n * 4 + 1, unsigned char);
+ }
- shift += 2;
+ n = (buff_len / 3) * 3;
- if (shift == 8) {
- *buffer++ = to_base64_char(current_bits);
- current_bits = 0;
- shift = 2;
- }
+ for (i = 0, p = *out_buff; i < n; i += 3) {
+ C1 = *data++;
+ C2 = *data++;
+ C3 = *data++;
+
+ *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+ *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+ *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
+ *p++ = base64_enc_map[C3 & 0x3F];
}
- char* buffer_end = (char*)str + buffer_length;
- if (buffer < buffer_end) {
- buffer[0] = to_base64_char(current_bits << (8 - shift));
- buffer[1] = '=';
+ if (i < buff_len) {
+ C1 = *data++;
+ C2 = ((i + 1) < buff_len) ? *data++ : 0;
- if (buffer + 2 < buffer_end)
- buffer[2] = '=';
+ *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+ *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+
+ if ((i + 1) < buff_len) {
+ *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
+ } else {
+ *p++ = '=';
+ }
+
+ *p++ = '=';
}
- jerry_value_t ret_value = jerry_create_string_sz(str, buffer_length);
- IOTJS_RELEASE(str);
+ size_t ret_len = (size_t)(p - *out_buff);
+ *p = 0;
- return ret_value;
+ return ret_len;
}
}
+JS_FUNCTION(FromArrayBuffer) {
+ if (jargc < 1 || !jerry_value_is_arraybuffer(jargv[0])) {
+ return jerry_create_undefined();
+ }
+ jerry_length_t offset = 0;
+ jerry_length_t length = jerry_get_arraybuffer_byte_length(jargv[0]);
+
+ if (jargc >= 2) {
+ jerry_value_t offset_num = jerry_value_to_number(jargv[1]);
+
+ if (jerry_value_is_error(offset_num)) {
+ return offset_num;
+ }
+
+ double offset_value = jerry_get_number_value(offset_num);
+ if (isnan(offset_value)) {
+ offset_value = 0;
+ }
+ jerry_release_value(offset_num);
+
+ if (offset_value < 0 || offset_value > length) {
+ return JS_CREATE_ERROR(RANGE, "'offset' is out of bounds");
+ }
+ offset = (jerry_length_t)offset_value;
+ }
+
+ length -= offset;
+
+ if (jargc >= 3) {
+ if (jerry_value_is_error(jargv[2])) {
+ return length;
+ }
+
+ if (jerry_value_is_number(jargv[2])) {
+ double length_value = (double)length;
+ length_value = jerry_get_number_value(jargv[2]);
+
+ if (isnan(length_value) || length_value < 0) {
+ length = 0;
+ } else if (length_value < length) {
+ length = (jerry_length_t)length_value;
+ } else if (length_value > length) {
+ return JS_CREATE_ERROR(RANGE, "'length' is out of bounds");
+ }
+ }
+ }
+
+ if (length < 1) {
+ return iotjs_bufferwrap_create_buffer(0);
+ }
+
+ jerry_value_t jres_bufferwrap = iotjs_bufferwrap_create_buffer(length);
+ iotjs_bufferwrap_t* jsres_buffer =
+ iotjs_jbuffer_get_bufferwrap_ptr(jres_bufferwrap);
+ jerry_arraybuffer_read(jargv[0], offset, (uint8_t*)jsres_buffer->buffer,
+ length);
+ return jres_bufferwrap;
+}
+
+
jerry_value_t InitBuffer() {
jerry_value_t buffer = jerry_create_external_function(Buffer);
iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_BYTELENGTH, ByteLength);
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);
+ iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_FROM_ARRAYBUFFER,
+ FromArrayBuffer);
return buffer;
}
typedef struct {
jerry_value_t jobject;
- char* buffer;
size_t length;
+ char buffer[];
} iotjs_bufferwrap_t;
-
+size_t iotjs_base64_decode(char** out_buff, const char* src,
+ const size_t srcLen);
+size_t iotjs_base64_encode(unsigned char** out_buff, const uint8_t* data,
+ size_t length);
iotjs_bufferwrap_t* iotjs_bufferwrap_create(const jerry_value_t jbuiltin,
size_t length);
size_t iotjs_bufferwrap_copy(iotjs_bufferwrap_t* bufferwrap, const char* src,
size_t len);
+iotjs_bufferwrap_t* iotjs_jbuffer_get_bufferwrap_ptr(const jerry_value_t);
-// Create buffer object.
+// Fail-safe creation of Buffer object.
jerry_value_t iotjs_bufferwrap_create_buffer(size_t len);
*/
#include "iotjs_def.h"
+#include "iotjs_compatibility.h"
#include "iotjs_module.h"
-
#define SET_CONSTANT(object, constant) \
do { \
iotjs_jval_set_property_number(object, #constant, constant); \
--- /dev/null
+/* 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.
+ */
+
+/*
+ * FIPS-180-1 compliant SHA-1 implementation
+ *
+ * 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)
+ */
+
+/*
+ * The SHA-1 standard was published by NIST in 1993.
+ *
+ * http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ */
+
+#include "iotjs_def.h"
+#include "iotjs_module_crypto.h"
+#include "iotjs_module_buffer.h"
+
+/* These enum values are the same as the ones in crypto.js as well as the
+ corresponding ones in sha.h in mbedTLS.*/
+typedef enum {
+ IOTJS_CRYPTO_SHA1 = 4,
+ IOTJS_CRYPTO_SHA256 = 6,
+} iotjs_crypto_sha_t;
+
+#if !ENABLE_MODULE_TLS
+const char no_tls_err_str[] = "TLS module must be enabled to use this feature";
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n, b, i) \
+ { \
+ (n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | \
+ ((uint32_t)(b)[(i) + 2] << 8) | ((uint32_t)(b)[(i) + 3]); \
+ }
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n, b, i) \
+ { \
+ (b)[(i)] = (unsigned char)((n) >> 24); \
+ (b)[(i) + 1] = (unsigned char)((n) >> 16); \
+ (b)[(i) + 2] = (unsigned char)((n) >> 8); \
+ (b)[(i) + 3] = (unsigned char)((n)); \
+ }
+#endif
+
+static int iotjs_sha1_process(uint32_t state[5], const unsigned char data[64]) {
+ uint32_t temp, W[16], A, B, C, D, E;
+
+ GET_UINT32_BE(W[0], data, 0);
+ GET_UINT32_BE(W[1], data, 4);
+ GET_UINT32_BE(W[2], data, 8);
+ GET_UINT32_BE(W[3], data, 12);
+ GET_UINT32_BE(W[4], data, 16);
+ GET_UINT32_BE(W[5], data, 20);
+ GET_UINT32_BE(W[6], data, 24);
+ GET_UINT32_BE(W[7], data, 28);
+ GET_UINT32_BE(W[8], data, 32);
+ GET_UINT32_BE(W[9], data, 36);
+ GET_UINT32_BE(W[10], data, 40);
+ GET_UINT32_BE(W[11], data, 44);
+ GET_UINT32_BE(W[12], data, 48);
+ GET_UINT32_BE(W[13], data, 52);
+ GET_UINT32_BE(W[14], data, 56);
+ GET_UINT32_BE(W[15], data, 60);
+
+#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t) \
+ (temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ \
+ W[t & 0x0F], \
+ (W[t & 0x0F] = S(temp, 1)))
+
+#define P(a, b, c, d, e, x) \
+ { \
+ e += S(a, 5) + F(b, c, d) + K + x; \
+ b = S(b, 30); \
+ }
+
+ A = state[0];
+ B = state[1];
+ C = state[2];
+ D = state[3];
+ E = state[4];
+
+#define F(x, y, z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+ P(A, B, C, D, E, W[0]);
+ P(E, A, B, C, D, W[1]);
+ P(D, E, A, B, C, W[2]);
+ P(C, D, E, A, B, W[3]);
+ P(B, C, D, E, A, W[4]);
+ P(A, B, C, D, E, W[5]);
+ P(E, A, B, C, D, W[6]);
+ P(D, E, A, B, C, W[7]);
+ P(C, D, E, A, B, W[8]);
+ P(B, C, D, E, A, W[9]);
+ P(A, B, C, D, E, W[10]);
+ P(E, A, B, C, D, W[11]);
+ P(D, E, A, B, C, W[12]);
+ P(C, D, E, A, B, W[13]);
+ P(B, C, D, E, A, W[14]);
+ P(A, B, C, D, E, W[15]);
+ P(E, A, B, C, D, R(16));
+ P(D, E, A, B, C, R(17));
+ P(C, D, E, A, B, R(18));
+ P(B, C, D, E, A, R(19));
+
+#undef K
+#undef F
+
+#define F(x, y, z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+ P(A, B, C, D, E, R(20));
+ P(E, A, B, C, D, R(21));
+ P(D, E, A, B, C, R(22));
+ P(C, D, E, A, B, R(23));
+ P(B, C, D, E, A, R(24));
+ P(A, B, C, D, E, R(25));
+ P(E, A, B, C, D, R(26));
+ P(D, E, A, B, C, R(27));
+ P(C, D, E, A, B, R(28));
+ P(B, C, D, E, A, R(29));
+ P(A, B, C, D, E, R(30));
+ P(E, A, B, C, D, R(31));
+ P(D, E, A, B, C, R(32));
+ P(C, D, E, A, B, R(33));
+ P(B, C, D, E, A, R(34));
+ P(A, B, C, D, E, R(35));
+ P(E, A, B, C, D, R(36));
+ P(D, E, A, B, C, R(37));
+ P(C, D, E, A, B, R(38));
+ P(B, C, D, E, A, R(39));
+
+#undef K
+#undef F
+
+#define F(x, y, z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+ P(A, B, C, D, E, R(40));
+ P(E, A, B, C, D, R(41));
+ P(D, E, A, B, C, R(42));
+ P(C, D, E, A, B, R(43));
+ P(B, C, D, E, A, R(44));
+ P(A, B, C, D, E, R(45));
+ P(E, A, B, C, D, R(46));
+ P(D, E, A, B, C, R(47));
+ P(C, D, E, A, B, R(48));
+ P(B, C, D, E, A, R(49));
+ P(A, B, C, D, E, R(50));
+ P(E, A, B, C, D, R(51));
+ P(D, E, A, B, C, R(52));
+ P(C, D, E, A, B, R(53));
+ P(B, C, D, E, A, R(54));
+ P(A, B, C, D, E, R(55));
+ P(E, A, B, C, D, R(56));
+ P(D, E, A, B, C, R(57));
+ P(C, D, E, A, B, R(58));
+ P(B, C, D, E, A, R(59));
+
+#undef K
+#undef F
+
+#define F(x, y, z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+ P(A, B, C, D, E, R(60));
+ P(E, A, B, C, D, R(61));
+ P(D, E, A, B, C, R(62));
+ P(C, D, E, A, B, R(63));
+ P(B, C, D, E, A, R(64));
+ P(A, B, C, D, E, R(65));
+ P(E, A, B, C, D, R(66));
+ P(D, E, A, B, C, R(67));
+ P(C, D, E, A, B, R(68));
+ P(B, C, D, E, A, R(69));
+ P(A, B, C, D, E, R(70));
+ P(E, A, B, C, D, R(71));
+ P(D, E, A, B, C, R(72));
+ P(C, D, E, A, B, R(73));
+ P(B, C, D, E, A, R(74));
+ P(A, B, C, D, E, R(75));
+ P(E, A, B, C, D, R(76));
+ P(D, E, A, B, C, R(77));
+ P(C, D, E, A, B, R(78));
+ P(B, C, D, E, A, R(79));
+
+#undef K
+#undef F
+
+ state[0] += A;
+ state[1] += B;
+ state[2] += C;
+ state[3] += D;
+ state[4] += E;
+
+ return (0);
+}
+
+
+static const unsigned char sha1_padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0 };
+
+
+static int iotjs_sha1_update(uint32_t total[2], uint32_t state[5],
+ unsigned char buffer[64],
+ const unsigned char *in_buff, size_t buff_len) {
+ int ret;
+ size_t fill;
+ uint32_t left;
+
+ if (buff_len == 0) {
+ return 0;
+ }
+
+ left = total[0] & 0x3F;
+ fill = 64 - left;
+
+ total[0] += (uint32_t)buff_len;
+ total[0] &= 0xFFFFFFFF;
+
+ if (total[0] < (uint32_t)buff_len) {
+ total[1]++;
+ }
+
+ if (left && buff_len >= fill) {
+ memcpy((void *)(buffer + left), in_buff, fill);
+
+ if ((ret = iotjs_sha1_process(state, buffer)) != 0) {
+ return ret;
+ }
+
+ in_buff += fill;
+ buff_len -= fill;
+ left = 0;
+ }
+
+ while (buff_len >= 64) {
+ if ((ret = iotjs_sha1_process(state, buffer)) != 0) {
+ return ret;
+ }
+ }
+
+ if (buff_len > 0) {
+ memcpy((void *)(buffer + left), in_buff, buff_len);
+ }
+
+ return 0;
+}
+
+
+static int iotjs_sha1_finish(uint32_t total[2], uint32_t state[5],
+ unsigned char buffer[64],
+ unsigned char *out_buff) {
+ int ret;
+ uint32_t last, padn;
+ uint32_t high, low;
+ unsigned char msglen[8];
+
+ high = (total[0] >> 29) | (total[1] << 3);
+ low = (total[0] << 3);
+
+ PUT_UINT32_BE(high, msglen, 0);
+ PUT_UINT32_BE(low, msglen, 4);
+
+ last = total[0] & 0x3F;
+ padn = (last < 56) ? (56 - last) : (120 - last);
+
+ if ((ret = iotjs_sha1_update(total, state, buffer, sha1_padding, padn)) !=
+ 0) {
+ return ret;
+ }
+
+ if ((ret = iotjs_sha1_update(total, state, buffer, msglen, 8)) != 0) {
+ return ret;
+ }
+
+ PUT_UINT32_BE(state[0], out_buff, 0);
+ PUT_UINT32_BE(state[1], out_buff, 4);
+ PUT_UINT32_BE(state[2], out_buff, 8);
+ PUT_UINT32_BE(state[3], out_buff, 12);
+ PUT_UINT32_BE(state[4], out_buff, 16);
+
+ return 0;
+}
+#else /* ENABLE_MODULE_TLS */
+
+#include "mbedtls/pk.h"
+#include "mbedtls/sha1.h"
+#include "mbedtls/sha256.h"
+
+#endif /* !ENABLE_MODULE_TLS */
+
+size_t iotjs_sha1_encode(unsigned char **out_buff, const unsigned char *in_buff,
+ size_t buff_len) {
+ size_t sha1_size = 20; // 160 bytes
+ *out_buff = IOTJS_CALLOC(sha1_size, unsigned char);
+#if !ENABLE_MODULE_TLS
+ uint32_t total[2] = { 0 };
+ uint32_t state[5] = { 0 };
+ unsigned char buffer[64] = { 0 };
+
+ total[0] = 0;
+ total[1] = 0;
+
+ state[0] = 0x67452301;
+ state[1] = 0xEFCDAB89;
+ state[2] = 0x98BADCFE;
+ state[3] = 0x10325476;
+ state[4] = 0xC3D2E1F0;
+
+ iotjs_sha1_update(total, state, buffer, in_buff, buff_len);
+ iotjs_sha1_finish(total, state, buffer, *out_buff);
+#else /* ENABLE_MODULE_TLS */
+ mbedtls_sha1_context sha_ctx;
+ mbedtls_sha1_init(&sha_ctx);
+#if defined(__TIZENRT__)
+ mbedtls_sha1_starts(&sha_ctx);
+ mbedtls_sha1_update(&sha_ctx, in_buff, buff_len);
+ mbedtls_sha1_finish(&sha_ctx, *out_buff);
+#else /* !__TIZENRT__ */
+ mbedtls_sha1_starts_ret(&sha_ctx);
+ mbedtls_sha1_update_ret(&sha_ctx, in_buff, buff_len);
+ mbedtls_sha1_finish_ret(&sha_ctx, *out_buff);
+#endif /* __TIZENRT__ */
+ mbedtls_sha1_free(&sha_ctx);
+#endif /* ENABLE_MODULE_TLS */
+
+ return sha1_size;
+}
+
+
+#if ENABLE_MODULE_TLS
+size_t iotjs_sha256_encode(unsigned char **out_buff,
+ const unsigned char *in_buff, size_t buff_len) {
+ size_t sha256_size = 32;
+ *out_buff = IOTJS_CALLOC(sha256_size, unsigned char);
+
+ mbedtls_sha256_context sha_ctx;
+ mbedtls_sha256_init(&sha_ctx);
+#if defined(__TIZENRT__)
+ mbedtls_sha256_starts(&sha_ctx, 0);
+ mbedtls_sha256_update(&sha_ctx, in_buff, buff_len);
+ mbedtls_sha256_finish(&sha_ctx, *out_buff);
+#else /* !__TIZENRT__ */
+ mbedtls_sha256_starts_ret(&sha_ctx, 0);
+ mbedtls_sha256_update_ret(&sha_ctx, in_buff, buff_len);
+ mbedtls_sha256_finish_ret(&sha_ctx, *out_buff);
+#endif /* __TIZENRT__ */
+ mbedtls_sha256_free(&sha_ctx);
+
+ return sha256_size;
+}
+#endif /* ENABLE_MODULE_TLS */
+
+
+JS_FUNCTION(ShaEncode) {
+ DJS_CHECK_THIS();
+ DJS_CHECK_ARGS(2, any, number);
+
+ uint8_t type = JS_GET_ARG(1, number);
+
+ jerry_value_t jstring = JS_GET_ARG(0, any);
+ iotjs_string_t user_str = iotjs_string_create();
+
+ if (!iotjs_jbuffer_as_string(jstring, &user_str)) {
+ return jerry_create_undefined();
+ }
+
+ const unsigned char *user_str_data =
+ (const unsigned char *)iotjs_string_data(&user_str);
+ size_t user_str_sz = iotjs_string_size(&user_str);
+
+ size_t sha_sz = 0;
+
+ unsigned char *sha_ret = NULL;
+
+ switch (type) {
+ case IOTJS_CRYPTO_SHA1: {
+ sha_sz = iotjs_sha1_encode(&sha_ret, user_str_data, user_str_sz);
+ break;
+ }
+ case IOTJS_CRYPTO_SHA256: {
+#if !ENABLE_MODULE_TLS
+ iotjs_string_destroy(&user_str);
+ return JS_CREATE_ERROR(COMMON, no_tls_err_str);
+#else /* ENABLE_MODULE_TLS */
+ sha_sz = iotjs_sha256_encode(&sha_ret, user_str_data, user_str_sz);
+ break;
+#endif /* !ENABLE_MODULE_TLS */
+ }
+ default: {
+ iotjs_string_destroy(&user_str);
+ return JS_CREATE_ERROR(COMMON, "Unknown SHA hashing algorithm");
+ }
+ }
+
+ iotjs_string_destroy(&user_str);
+
+ jerry_value_t ret_val;
+ ret_val = iotjs_bufferwrap_create_buffer(sha_sz);
+ iotjs_bufferwrap_t *ret_wrap = iotjs_bufferwrap_from_jbuffer(ret_val);
+ memcpy(ret_wrap->buffer, sha_ret, sha_sz);
+ ret_wrap->length = sha_sz;
+
+ IOTJS_RELEASE(sha_ret);
+ return ret_val;
+}
+
+
+JS_FUNCTION(RsaVerify) {
+#if !ENABLE_MODULE_TLS
+ return JS_CREATE_ERROR(COMMON, no_tls_err_str);
+#else /* ENABLE_MODULE_TLS */
+ DJS_CHECK_THIS();
+ DJS_CHECK_ARGS(2, any, any);
+
+ uint8_t type = JS_GET_ARG(0, number);
+ jerry_value_t jdata = JS_GET_ARG(1, any);
+ jerry_value_t jkey = JS_GET_ARG(2, any);
+ jerry_value_t jsignature = JS_GET_ARG(3, any);
+
+ iotjs_string_t key = iotjs_string_create();
+ iotjs_string_t data = iotjs_string_create();
+ iotjs_string_t signature = iotjs_string_create();
+
+ if ((!iotjs_jbuffer_as_string(jkey, &key)) ||
+ (!iotjs_jbuffer_as_string(jdata, &data)) ||
+ (!iotjs_jbuffer_as_string(jsignature, &signature))) {
+ iotjs_string_destroy(&key);
+ iotjs_string_destroy(&data);
+ iotjs_string_destroy(&signature);
+
+ return jerry_create_boolean(false);
+ }
+
+ mbedtls_pk_context pk;
+
+ char *raw_signature = NULL;
+ size_t raw_signature_sz =
+ iotjs_base64_decode(&raw_signature, iotjs_string_data(&signature),
+ iotjs_string_size(&signature));
+ mbedtls_pk_init(&pk);
+ int ret_val =
+ mbedtls_pk_parse_public_key(&pk, (const unsigned char *)iotjs_string_data(
+ &key),
+ iotjs_string_size(&key) + 1);
+
+
+ jerry_value_t js_ret_val = jerry_create_boolean(true);
+ if ((ret_val =
+ mbedtls_pk_verify(&pk, type,
+ (const unsigned char *)iotjs_string_data(&data), 0,
+ (const unsigned char *)raw_signature,
+ raw_signature_sz))) {
+ js_ret_val = jerry_create_boolean(false);
+ }
+
+ iotjs_string_destroy(&key);
+ iotjs_string_destroy(&data);
+ iotjs_string_destroy(&signature);
+ mbedtls_pk_free(&pk);
+ IOTJS_RELEASE(raw_signature);
+
+ return js_ret_val;
+#endif /* !ENABLE_MODULE_TLS */
+}
+
+
+JS_FUNCTION(Base64Encode) {
+ DJS_CHECK_THIS();
+
+ jerry_value_t jstring = JS_GET_ARG(0, any);
+ iotjs_string_t user_str = iotjs_string_create();
+
+ if (!iotjs_jbuffer_as_string(jstring, &user_str)) {
+ return jerry_create_undefined();
+ }
+
+ unsigned char *out_buff = NULL;
+ size_t out_size =
+ iotjs_base64_encode(&out_buff,
+ (const unsigned char *)iotjs_string_data(&user_str),
+ iotjs_string_size(&user_str));
+
+ iotjs_string_destroy(&user_str);
+ jerry_value_t ret_val = jerry_create_string_sz(out_buff, out_size);
+
+ IOTJS_RELEASE(out_buff);
+ return ret_val;
+}
+
+
+jerry_value_t InitCrypto() {
+ jerry_value_t jcrypto = jerry_create_object();
+
+ iotjs_jval_set_method(jcrypto, IOTJS_MAGIC_STRING_SHAENCODE, ShaEncode);
+ iotjs_jval_set_method(jcrypto, IOTJS_MAGIC_STRING_BASE64ENCODE, Base64Encode);
+ iotjs_jval_set_method(jcrypto, IOTJS_MAGIC_STRING_RSAVERIFY, RsaVerify);
+
+ return jcrypto;
+}
--- /dev/null
+/* 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_CRYPTO_H
+#define IOTJS_MODULE_CRYPTO_H
+
+size_t iotjs_sha1_encode(unsigned char **out_buff, const unsigned char *in_buff,
+ size_t buff_len);
+size_t iotjs_sha256_encode(unsigned char **out_buff,
+ const unsigned char *in_buff, size_t buff_len);
+#endif /* IOTJS_MODULE_CRYPTO_H */
#include "iotjs_def.h"
-#include "iotjs_module_dns.h"
+#include "iotjs_uv_request.h"
-#include "iotjs_reqwrap.h"
-#include "uv.h"
-
-
-iotjs_getaddrinfo_reqwrap_t* iotjs_getaddrinfo_reqwrap_create(
- const jerry_value_t jcallback) {
- iotjs_getaddrinfo_reqwrap_t* getaddrinfo_reqwrap =
- IOTJS_ALLOC(iotjs_getaddrinfo_reqwrap_t);
- iotjs_reqwrap_initialize(&getaddrinfo_reqwrap->reqwrap, jcallback,
- (uv_req_t*)&getaddrinfo_reqwrap->req);
- return getaddrinfo_reqwrap;
-}
-
-
-static void iotjs_getaddrinfo_reqwrap_destroy(
- iotjs_getaddrinfo_reqwrap_t* getaddrinfo_reqwrap) {
- iotjs_reqwrap_destroy(&getaddrinfo_reqwrap->reqwrap);
- IOTJS_RELEASE(getaddrinfo_reqwrap);
-}
-
-
-void iotjs_getaddrinfo_reqwrap_dispatched(
- iotjs_getaddrinfo_reqwrap_t* getaddrinfo_reqwrap) {
- iotjs_getaddrinfo_reqwrap_destroy(getaddrinfo_reqwrap);
-}
-
-
-jerry_value_t iotjs_getaddrinfo_reqwrap_jcallback(
- iotjs_getaddrinfo_reqwrap_t* getaddrinfo_reqwrap) {
- return iotjs_reqwrap_jcallback(&getaddrinfo_reqwrap->reqwrap);
-}
-
-
-#if !defined(__NUTTX__) && !defined(__TIZENRT__)
+#if !defined(__NUTTX__)
char* getaddrinfo_error_str(int status) {
switch (status) {
case UV__EAI_ADDRFAMILY:
return "EAI_ADDRFAMILY, address family for hostname not supported";
- break;
case UV__EAI_AGAIN:
return "EAI_AGAIN, temporary failure in name resolution";
- break;
case UV__EAI_BADFLAGS:
return "EAI_BADFLAGS, bad flags";
- break;
case UV__EAI_FAIL:
return "EAI_FAIL, Non-recoverable failure in name resolution";
- break;
case UV__EAI_FAMILY:
return "EAI_FAMILY, family not supported";
- break;
case UV__EAI_CANCELED:
return "EAI_CANCELED, request canceled";
- break;
case UV__EAI_MEMORY:
return "EAI_MEMORY, memory allocation failure";
- break;
case UV__EAI_NODATA:
return "EAI_NODATA, no address association with hostname";
- break;
case UV__EAI_NONAME:
return "EAI_NONAME, name or service not known";
- break;
case UV__EAI_OVERFLOW:
return "EAI_OVERFLOW, argument buffer overflow";
- break;
case UV__EAI_SERVICE:
return "EAI_SERVICE, service not supported";
- break;
case UV__EAI_SOCKTYPE:
return "EAI_SOCKTYPE, socktype not supported";
- break;
case UV__EAI_PROTOCOL:
return "EAI_PROTOCOL, unknown error";
- break;
default:
return "unknown error";
- break;
}
}
static void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status,
struct addrinfo* res) {
- iotjs_getaddrinfo_reqwrap_t* req_wrap =
- (iotjs_getaddrinfo_reqwrap_t*)(req->data);
-
- iotjs_jargs_t args = iotjs_jargs_create(3);
+ size_t argc = 0;
+ jerry_value_t args[3] = { 0 };
- if (status == 0) {
+ if (status == 0 && res != NULL) {
char ip[INET6_ADDRSTRLEN];
int family;
const char* addr;
+ struct addrinfo* info;
+
+ /* search for the first AF_INET entry */
+ for (info = res; info != NULL; info = info->ai_next) {
+ if (info->ai_family == AF_INET) {
+ break;
+ }
+ }
+
+ if (info == NULL) {
+ /* Did not find an AF_INET addr, using the first one */
+ info = res;
+ }
+
+ IOTJS_ASSERT(info != NULL);
- // Only first address is used
- if (res->ai_family == AF_INET) {
- struct sockaddr_in* sockaddr = (struct sockaddr_in*)(res->ai_addr);
+ if (info->ai_family == AF_INET) {
+ struct sockaddr_in* sockaddr = (struct sockaddr_in*)(info->ai_addr);
addr = (char*)(&(sockaddr->sin_addr));
family = 4;
} else {
- struct sockaddr_in6* sockaddr = (struct sockaddr_in6*)(res->ai_addr);
+ struct sockaddr_in6* sockaddr = (struct sockaddr_in6*)(info->ai_addr);
addr = (char*)(&(sockaddr->sin6_addr));
family = 6;
}
- int err = uv_inet_ntop(res->ai_family, addr, ip, INET6_ADDRSTRLEN);
+ int err = uv_inet_ntop(info->ai_family, addr, ip, INET6_ADDRSTRLEN);
if (err) {
ip[0] = 0;
- iotjs_jargs_append_error(&args,
- "EAFNOSUPPORT, DNS could not resolve hostname");
+ args[argc++] = iotjs_jval_create_error_without_error_flag(
+ "EAFNOSUPPORT, DNS could not resolve hostname");
} else {
- iotjs_jargs_append_null(&args);
+ args[argc++] = jerry_create_null();
}
- iotjs_jargs_append_string_raw(&args, ip);
- iotjs_jargs_append_number(&args, family);
+ args[argc++] = jerry_create_string_from_utf8((const jerry_char_t*)ip);
+ args[argc++] = jerry_create_number(family);
} else {
- iotjs_jargs_append_error(&args, getaddrinfo_error_str(status));
+ args[argc++] = iotjs_jval_create_error_without_error_flag(
+ getaddrinfo_error_str(status));
}
uv_freeaddrinfo(res);
// Make the callback into JavaScript
- jerry_value_t jcallback = iotjs_getaddrinfo_reqwrap_jcallback(req_wrap);
- iotjs_make_callback(jcallback, jerry_create_undefined(), &args);
+ jerry_value_t jcallback = *IOTJS_UV_REQUEST_JSCALLBACK(req);
+ iotjs_invoke_callback(jcallback, jerry_create_undefined(), args, argc);
- iotjs_jargs_destroy(&args);
+ for (size_t i = 0; i < argc; i++) {
+ jerry_release_value(args[i]);
+ }
- iotjs_getaddrinfo_reqwrap_dispatched(req_wrap);
+ iotjs_uv_request_destroy((uv_req_t*)req);
}
#endif
-JS_FUNCTION(GetAddrInfo) {
+JS_FUNCTION(GetAddressInfo) {
DJS_CHECK_THIS();
DJS_CHECK_ARGS(4, string, number, number, function);
return JS_CREATE_ERROR(TYPE, "bad address family");
}
-#if defined(__NUTTX__) || defined(__TIZENRT__)
- iotjs_jargs_t args = iotjs_jargs_create(3);
+#if defined(__NUTTX__)
char ip[INET6_ADDRSTRLEN] = "";
const char* hostname_data = iotjs_string_data(&hostname);
}
}
+ size_t argc = 0;
+ jerry_value_t args[3] = { 0 };
+
if (error) {
- iotjs_jargs_append_error(&args, "EAFNOSUPPORT, could not resolve hostname");
+ args[argc++] = iotjs_jval_create_error_without_error_flag(
+ "EAFNOSUPPORT, could not resolve hostname");
} else {
- iotjs_jargs_append_null(&args);
+ args[argc++] = jerry_create_null();
}
- iotjs_jargs_append_string_raw(&args, ip);
- iotjs_jargs_append_number(&args, option);
+ args[argc++] = jerry_create_string_from_utf8((const jerry_char_t*)ip);
+ args[argc++] = jerry_create_number(option);
- iotjs_make_callback(jcallback, jerry_create_undefined(), &args);
- iotjs_jargs_destroy(&args);
+ iotjs_invoke_callback(jcallback, jerry_create_undefined(), args, argc);
+ for (size_t i = 0; i < argc; i++) {
+ jerry_release_value(args[i]);
+ }
IOTJS_UNUSED(flags);
#else
- iotjs_getaddrinfo_reqwrap_t* req_wrap =
- iotjs_getaddrinfo_reqwrap_create(jcallback);
+ uv_req_t* req_addr =
+ iotjs_uv_request_create(sizeof(uv_getaddrinfo_t), jcallback, 0);
static const struct addrinfo empty_hints;
struct addrinfo hints = empty_hints;
hints.ai_flags = flags;
error = uv_getaddrinfo(iotjs_environment_loop(iotjs_environment_get()),
- &req_wrap->req, AfterGetAddrInfo,
+ (uv_getaddrinfo_t*)req_addr, AfterGetAddrInfo,
iotjs_string_data(&hostname), NULL, &hints);
if (error) {
- iotjs_getaddrinfo_reqwrap_dispatched(req_wrap);
+ iotjs_uv_request_destroy(req_addr);
}
#endif
jerry_value_t InitDns() {
jerry_value_t dns = jerry_create_object();
- iotjs_jval_set_method(dns, IOTJS_MAGIC_STRING_GETADDRINFO, GetAddrInfo);
+ iotjs_jval_set_method(dns, IOTJS_MAGIC_STRING_GETADDRINFO, GetAddressInfo);
SET_CONSTANT(dns, AI_ADDRCONFIG);
SET_CONSTANT(dns, AI_V4MAPPED);
+++ /dev/null
-/* 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.
- */
-
-
-#ifndef IOTJS_MODULE_DNS_H
-#define IOTJS_MODULE_DNS_H
-
-
-#include "iotjs_def.h"
-#include "iotjs_reqwrap.h"
-
-
-typedef struct {
- iotjs_reqwrap_t reqwrap;
- uv_getaddrinfo_t req;
-} iotjs_getaddrinfo_reqwrap_t;
-
-iotjs_getaddrinfo_reqwrap_t* iotjs_getaddrinfo_reqwrap_create(
- const jerry_value_t jcallback);
-
-void iotjs_getaddrinfo_reqwrap_dispatched(
- iotjs_getaddrinfo_reqwrap_t* getaddrinfo_reqwrap);
-
-jerry_value_t iotjs_getaddrinfo_reqwrap_jcallback(
- iotjs_getaddrinfo_reqwrap_t* getaddrinfo_reqwrap);
-
-
-#endif /* IOTJS_MODULE_DNS_H */
#include "iotjs_def.h"
#include "iotjs_module_buffer.h"
-#include "iotjs_reqwrap.h"
-
-
-typedef struct {
- iotjs_reqwrap_t reqwrap;
- uv_fs_t req;
-} iotjs_fs_reqwrap_t;
-
-
-iotjs_fs_reqwrap_t* iotjs_fs_reqwrap_create(const jerry_value_t jcallback) {
- iotjs_fs_reqwrap_t* fs_reqwrap = IOTJS_ALLOC(iotjs_fs_reqwrap_t);
- iotjs_reqwrap_initialize(&fs_reqwrap->reqwrap, jcallback,
- (uv_req_t*)&fs_reqwrap->req);
- return fs_reqwrap;
-}
-
-
-static void iotjs_fs_reqwrap_destroy(iotjs_fs_reqwrap_t* fs_reqwrap) {
- uv_fs_req_cleanup(&fs_reqwrap->req);
- iotjs_reqwrap_destroy(&fs_reqwrap->reqwrap);
- IOTJS_RELEASE(fs_reqwrap);
-}
+#include "iotjs_uv_request.h"
jerry_value_t MakeStatObject(uv_stat_t* statbuf);
static void AfterAsync(uv_fs_t* req) {
- iotjs_fs_reqwrap_t* req_wrap = (iotjs_fs_reqwrap_t*)(req->data);
- IOTJS_ASSERT(req_wrap != NULL);
- IOTJS_ASSERT(&req_wrap->req == req);
-
- const jerry_value_t cb = iotjs_reqwrap_jcallback(&req_wrap->reqwrap);
+ const jerry_value_t cb = *IOTJS_UV_REQUEST_JSCALLBACK(req);
IOTJS_ASSERT(jerry_value_is_function(cb));
- iotjs_jargs_t jarg = iotjs_jargs_create(2);
+ jerry_value_t jargs[2] = { 0 };
+ size_t jargc = 0;
if (req->result < 0) {
jerry_value_t jerror = iotjs_create_uv_exception(req->result, "open");
- iotjs_jargs_append_jval(&jarg, jerror);
- jerry_release_value(jerror);
+ jargs[jargc++] = jerror;
} else {
- iotjs_jargs_append_null(&jarg);
+ jargs[jargc++] = jerry_create_null();
switch (req->fs_type) {
case UV_FS_CLOSE: {
break;
case UV_FS_OPEN:
case UV_FS_READ:
case UV_FS_WRITE: {
- iotjs_jargs_append_number(&jarg, (double)req->result);
+ jargs[jargc++] = jerry_create_number((double)req->result);
break;
}
case UV_FS_SCANDIR: {
int r;
uv_dirent_t ent;
uint32_t idx = 0;
- jerry_value_t ret = jerry_create_array(0);
+ jargs[jargc++] = 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);
+ iotjs_jval_set_property_by_index(jargs[1], idx, name);
jerry_release_value(name);
idx++;
}
- iotjs_jargs_append_jval(&jarg, ret);
- jerry_release_value(ret);
break;
}
case UV_FS_FSTAT:
case UV_FS_STAT: {
uv_stat_t s = (req->statbuf);
- jerry_value_t ret = MakeStatObject(&s);
- iotjs_jargs_append_jval(&jarg, ret);
- jerry_release_value(ret);
- break;
- }
- default: {
- iotjs_jargs_append_null(&jarg);
+ jargs[jargc++] = MakeStatObject(&s);
break;
}
+ default: { break; }
}
}
- iotjs_make_callback(cb, jerry_create_undefined(), &jarg);
+ iotjs_invoke_callback(cb, jerry_create_undefined(), jargs, jargc);
- iotjs_jargs_destroy(&jarg);
- iotjs_fs_reqwrap_destroy(req_wrap);
+ jerry_release_value(jargs[0]);
+ jerry_release_value(jargs[1]);
+ uv_fs_req_cleanup(req);
+ iotjs_uv_request_destroy((uv_req_t*)req);
}
static jerry_value_t AfterSync(uv_fs_t* req, int err,
const char* syscall_name) {
if (err < 0) {
- jerry_value_t jerror = iotjs_create_uv_exception(err, syscall_name);
- jerry_value_set_error_flag(&jerror);
+ jerry_value_t jvalue = iotjs_create_uv_exception(err, syscall_name);
+ jerry_value_t jerror = jerry_create_error_from_value(jvalue, true);
return jerror;
}
#define FS_ASYNC(env, syscall, pcallback, ...) \
- iotjs_fs_reqwrap_t* req_wrap = iotjs_fs_reqwrap_create(pcallback); \
- uv_fs_t* fs_req = &req_wrap->req; \
+ uv_fs_t* fs_req = \
+ (uv_fs_t*)iotjs_uv_request_create(sizeof(uv_fs_t), pcallback, 0); \
int err = uv_fs_##syscall(iotjs_environment_loop(env), fs_req, __VA_ARGS__, \
AfterAsync); \
if (err < 0) { \
}
-JS_FUNCTION(Read) {
+typedef enum { IOTJS_FS_READ, IOTJS_FS_WRITE } iotjs_fs_op_t;
+
+jerry_value_t fs_do_read_or_write(const jerry_value_t jfunc,
+ const jerry_value_t jthis,
+ const jerry_value_t jargv[],
+ const jerry_length_t jargc,
+ const iotjs_fs_op_t fs_op) {
DJS_CHECK_THIS();
DJS_CHECK_ARGS(5, number, object, number, number, number);
DJS_CHECK_ARG_IF_EXIST(5, function);
uv_buf_t uvbuf = uv_buf_init(data + offset, length);
jerry_value_t ret_value;
- if (!jerry_value_is_null(jcallback)) {
- FS_ASYNC(env, read, jcallback, fd, &uvbuf, 1, position);
+ if (fs_op == IOTJS_FS_READ) {
+ if (!jerry_value_is_null(jcallback)) {
+ FS_ASYNC(env, read, jcallback, fd, &uvbuf, 1, position);
+ } else {
+ FS_SYNC(env, read, fd, &uvbuf, 1, position);
+ }
} else {
- FS_SYNC(env, read, fd, &uvbuf, 1, position);
+ if (!jerry_value_is_null(jcallback)) {
+ FS_ASYNC(env, write, jcallback, fd, &uvbuf, 1, position);
+ } else {
+ FS_SYNC(env, write, fd, &uvbuf, 1, position);
+ }
}
return ret_value;
}
-JS_FUNCTION(Write) {
- DJS_CHECK_THIS();
- DJS_CHECK_ARGS(5, number, object, number, number, number);
- DJS_CHECK_ARG_IF_EXIST(5, function);
-
- const iotjs_environment_t* env = iotjs_environment_get();
-
- int fd = JS_GET_ARG(0, number);
- const jerry_value_t jbuffer = JS_GET_ARG(1, object);
- size_t offset = JS_GET_ARG(2, number);
- size_t length = JS_GET_ARG(3, number);
- int position = JS_GET_ARG(4, number);
- const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(5, function);
-
- 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 && data_length > 0);
-
- if (!IsWithinBounds(offset, length, data_length)) {
- return JS_CREATE_ERROR(RANGE, "length out of bound");
- }
+JS_FUNCTION(Read) {
+ return fs_do_read_or_write(jfunc, jthis, jargv, jargc, IOTJS_FS_READ);
+}
- uv_buf_t uvbuf = uv_buf_init(data + offset, length);
- jerry_value_t ret_value;
- if (!jerry_value_is_null(jcallback)) {
- FS_ASYNC(env, write, jcallback, fd, &uvbuf, 1, position);
- } else {
- FS_SYNC(env, write, fd, &uvbuf, 1, position);
- }
- return ret_value;
+JS_FUNCTION(Write) {
+ return fs_do_read_or_write(jfunc, jthis, jargv, jargc, IOTJS_FS_WRITE);
}
#include "iotjs_def.h"
#include "iotjs_module_gpio.h"
+#include "iotjs_uv_request.h"
IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(gpio);
}
static void gpio_worker(uv_work_t* work_req) {
- 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;
+ iotjs_periph_data_t* worker_data =
+ (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req);
+ iotjs_gpio_t* gpio = (iotjs_gpio_t*)worker_data->data;
- switch (req_wrap->op) {
+ switch (worker_data->op) {
case kGpioOpOpen:
- req_wrap->result = iotjs_gpio_open(gpio);
+ worker_data->result = iotjs_gpio_open(gpio);
break;
case kGpioOpWrite:
- req_wrap->result = iotjs_gpio_write(gpio);
+ worker_data->result = iotjs_gpio_write(gpio);
break;
case kGpioOpRead:
- req_wrap->result = iotjs_gpio_read(gpio);
+ worker_data->result = iotjs_gpio_read(gpio);
break;
case kGpioOpClose:
- req_wrap->result = iotjs_gpio_close(gpio);
+ worker_data->result = iotjs_gpio_close(gpio);
break;
default:
IOTJS_ASSERT(!"Invalid Operation");
jerry_value_t jconfigurable) {
jerry_value_t jpin =
iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_PIN);
- gpio->pin = iotjs_jval_as_number(jpin);
+
+ double pin = -1.0;
+ if (!jerry_value_is_number(jpin) || (pin = iotjs_jval_as_number(jpin)) < 0) {
+ jerry_release_value(jpin);
+ return JS_CREATE_ERROR(TYPE, "Bad arguments gpio.pin should be a number");
+ }
+ gpio->pin = (uint32_t)pin;
jerry_release_value(jpin);
// Direction
gpio->direction = __kGpioDirectionMax;
}
if (gpio->direction >= __kGpioDirectionMax) {
+ jerry_release_value(jdirection);
return JS_CREATE_ERROR(
TYPE, "Bad arguments - gpio.direction should be DIRECTION.IN or OUT");
}
gpio->edge = __kGpioEdgeMax;
}
if (gpio->edge >= __kGpioEdgeMax) {
+ jerry_release_value(jedge);
return JS_CREATE_ERROR(TYPE,
"Bad arguments - gpio.edge should be EDGE.NONE, "
"RISING, FALLING or BOTH");
jerry_value_t config_res =
gpio_set_configuration(gpio, JS_GET_ARG(0, object));
- if (jerry_value_has_error_flag(config_res)) {
+ if (jerry_value_is_error(config_res)) {
return config_res;
}
IOTJS_ASSERT(jerry_value_is_undefined(config_res));
return jerry_create_undefined();
}
-JS_FUNCTION(Write) {
+typedef enum { IOTJS_GPIO_WRITE, IOTJS_GPIO_WRITESYNC } iotjs_gpio_op_t;
+
+jerry_value_t gpio_do_write_or_writesync(const jerry_value_t jfunc,
+ const jerry_value_t jthis,
+ const jerry_value_t jargv[],
+ const jerry_length_t jargc,
+ const iotjs_gpio_op_t gpio_op) {
JS_DECLARE_THIS_PTR(gpio, gpio);
bool value;
} else if (jerry_value_is_boolean(jargv[0])) {
value = jerry_get_boolean_value(jargv[0]);
} else {
- return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kGpioOpWrite));
- }
+ const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function);
+ if (gpio_op == IOTJS_GPIO_WRITE && !jerry_value_is_null(jcallback)) {
+ const char* error_msg = iotjs_periph_error_str(kGpioOpWrite);
+ jerry_value_t error_str = jerry_create_string((jerry_char_t*)error_msg);
+ iotjs_invoke_callback(jcallback, jthis, &error_str, 1);
+ jerry_release_value(error_str);
+ return jerry_create_undefined();
+ }
- DJS_CHECK_ARG_IF_EXIST(1, function);
+ return JS_CREATE_ERROR(TYPE, "GPIO WriteSync Error - Wrong argument type");
+ }
gpio->value = value;
-
- 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);
-
- bool value;
- if (jerry_value_is_number(jargv[0])) {
- value = (bool)jerry_get_number_value(jargv[0]);
- } else if (jerry_value_is_boolean(jargv[0])) {
- value = jerry_get_boolean_value(jargv[0]);
+ if (gpio_op == IOTJS_GPIO_WRITE) {
+ DJS_CHECK_ARG_IF_EXIST(1, function);
+ iotjs_periph_call_async(gpio, JS_GET_ARG_IF_EXIST(1, function),
+ kGpioOpWrite, gpio_worker);
} else {
- return JS_CREATE_ERROR(COMMON,
- "GPIO WriteSync Error - Wrong argument type");
+ if (!iotjs_gpio_write(gpio)) {
+ return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kGpioOpWrite));
+ }
}
- gpio->value = value;
+ return jerry_create_undefined();
+}
- if (!iotjs_gpio_write(gpio)) {
- return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kGpioOpWrite));
- }
+JS_FUNCTION(Write) {
+ return gpio_do_write_or_writesync(jfunc, jthis, jargv, jargc,
+ IOTJS_GPIO_WRITE);
+}
- return jerry_create_undefined();
+JS_FUNCTION(WriteSync) {
+ return gpio_do_write_or_writesync(jfunc, jthis, jargv, jargc,
+ IOTJS_GPIO_WRITESYNC);
}
JS_FUNCTION(Read) {
return jerry_create_boolean(gpio->value);
}
+JS_FUNCTION(SetDirectionSync) {
+ DJS_CHECK_ARGS(1, number);
+ JS_DECLARE_THIS_PTR(gpio, gpio);
+
+ int direction;
+ JS_GET_REQUIRED_ARG_VALUE(0, direction, IOTJS_MAGIC_STRING_DIRECTION, number);
+ if (direction >= __kGpioDirectionMax) {
+ return JS_CREATE_ERROR(
+ TYPE, "Bad arguments - gpio.direction should be DIRECTION.IN or OUT");
+ }
+ gpio->direction = direction;
+
+ if (!iotjs_gpio_set_direction(gpio)) {
+ return JS_CREATE_ERROR(
+ COMMON, "GPIO SetDirectionSync Error - Cannot set direction");
+ }
+
+ return jerry_create_undefined();
+}
+
jerry_value_t InitGpio() {
jerry_value_t jgpioConstructor = jerry_create_external_function(GpioCons);
iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_WRITESYNC, WriteSync);
iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_READ, Read);
iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_READSYNC, ReadSync);
+ iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_SETDIRECTIONSYNC,
+ SetDirectionSync);
iotjs_jval_set_property_jval(jgpioConstructor, IOTJS_MAGIC_STRING_PROTOTYPE,
jprototype);
#include "iotjs_def.h"
#include "iotjs_module_periph_common.h"
-#include "iotjs_reqwrap.h"
typedef enum {
bool iotjs_gpio_write(iotjs_gpio_t* gpio);
bool iotjs_gpio_read(iotjs_gpio_t* gpio);
bool iotjs_gpio_close(iotjs_gpio_t* gpio);
+bool iotjs_gpio_set_direction(iotjs_gpio_t* gpio);
// Platform-related functions; they are implemented
// by platform code (i.e.: linux, nuttx, tizen).
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);
+ size_t argc = 1;
+ jerry_value_t argv[2] = { jheader, 0 };
+
if (http_parserwrap->parser.type == HTTP_REQUEST &&
!iotjs_string_is_empty(&http_parserwrap->url)) {
- iotjs_jargs_append_string(&argv, &http_parserwrap->url);
+ argv[argc++] = iotjs_jval_create_string(&http_parserwrap->url);
}
- iotjs_make_callback(func, jobj, &argv);
+ iotjs_invoke_callback(func, jobj, argv, argc);
iotjs_string_destroy(&http_parserwrap->url);
- iotjs_jargs_destroy(&argv);
+ for (size_t i = 0; i < argc; i++) {
+ jerry_release_value(argv[i]);
+ }
jerry_release_value(func);
http_parserwrap->flushed = true;
}
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) {
http_should_keep_alive(
&http_parserwrap->parser));
+ // http version number
+ iotjs_jval_set_property_number(info, IOTJS_MAGIC_STRING_HTTP_VERSION_MAJOR,
+ parser->http_major);
+ iotjs_jval_set_property_number(info, IOTJS_MAGIC_STRING_HTTP_VERSION_MINOR,
+ parser->http_minor);
- iotjs_jargs_append_jval(&argv, info);
-
- jerry_value_t res = iotjs_make_callback_with_result(func, jobj, &argv);
+ jerry_value_t res = iotjs_invoke_callback_with_result(func, jobj, &info, 1);
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.
+ } else if (jerry_value_is_error(res)) {
ret = 0;
}
- iotjs_jargs_destroy(&argv);
jerry_release_value(func);
jerry_release_value(res);
jerry_release_value(info);
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);
-
+ jerry_value_t argv[3] = { http_parserwrap->cur_jbuf,
+ jerry_create_number(at - http_parserwrap->cur_buf),
+ jerry_create_number(length) };
- iotjs_make_callback(func, jobj, &argv);
+ iotjs_invoke_callback(func, jobj, argv, 3);
- iotjs_jargs_destroy(&argv);
+ jerry_release_value(argv[1]);
+ jerry_release_value(argv[2]);
jerry_release_value(func);
return 0;
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());
+ iotjs_invoke_callback(func, jobj, NULL, 0);
jerry_release_value(func);
}
-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_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");
+ return JS_CREATE_ERROR(TYPE, "Invalid type of HTTP.");
}
iotjs_http_parserwrap_create(jparser, httpparser_type);
return jerry_create_undefined();
}
+static void http_parser_register_methods_object(jerry_value_t target) {
+ jerry_value_t methods = jerry_create_array(26);
+
+ jerry_value_t method_name;
+ uint32_t idx = 0;
+#define V(num, name, string) \
+ do { \
+ method_name = jerry_create_string((const jerry_char_t*)#string); \
+ jerry_set_property_by_index(methods, idx++, method_name); \
+ jerry_release_value(method_name); \
+ } while (0);
+
+ HTTP_METHOD_MAP(V)
+#undef V
+
+ iotjs_jval_set_property_jval(target, IOTJS_MAGIC_STRING_METHODS, methods);
+ jerry_release_value(methods);
+}
jerry_value_t InitHttpParser() {
jerry_value_t http_parser = jerry_create_object();
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);
+ http_parser_register_methods_object(jParserCons);
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);
prototype);
jerry_release_value(jParserCons);
- jerry_release_value(methods);
jerry_release_value(prototype);
return http_parser;
#include "iotjs_def.h"
#include "iotjs_module_i2c.h"
+#include "iotjs_uv_request.h"
IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(i2c);
}
static void i2c_worker(uv_work_t* work_req) {
- 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;
+ iotjs_periph_data_t* worker_data =
+ (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req);
+ iotjs_i2c_t* i2c = (iotjs_i2c_t*)worker_data->data;
- switch (req_wrap->op) {
+ switch (worker_data->op) {
case kI2cOpOpen:
- req_wrap->result = iotjs_i2c_open(i2c);
+ worker_data->result = iotjs_i2c_open(i2c);
break;
case kI2cOpWrite:
- req_wrap->result = iotjs_i2c_write(i2c);
+ worker_data->result = iotjs_i2c_write(i2c);
break;
case kI2cOpRead:
- req_wrap->result = iotjs_i2c_read(i2c);
+ worker_data->result = iotjs_i2c_read(i2c);
break;
case kI2cOpClose:
- req_wrap->result = iotjs_i2c_close(i2c);
+ worker_data->result = iotjs_i2c_close(i2c);
break;
default:
IOTJS_ASSERT(!"Invalid Operation");
JS_GET_REQUIRED_ARG_VALUE(0, jconfig, IOTJS_MAGIC_STRING_CONFIG, object);
jerry_value_t res = iotjs_i2c_set_platform_config(i2c, jconfig);
- if (jerry_value_has_error_flag(res)) {
+ if (jerry_value_is_error(res)) {
return res;
}
i2c->buf_data = iotjs_buffer_allocate_from_number_array(i2c->buf_len, jarray);
if (async) {
+ DJS_CHECK_ARG_IF_EXIST(1, function);
iotjs_periph_call_async(i2c, JS_GET_ARG_IF_EXIST(1, function), kI2cOpWrite,
i2c_worker);
} else {
return jerry_create_undefined();
}
-JS_FUNCTION(Write) {
+typedef enum { IOTJS_I2C_WRITE, IOTJS_I2C_WRITESYNC } iotjs_i2c_op_t;
+
+jerry_value_t i2c_do_write_or_writesync(const jerry_value_t jfunc,
+ const jerry_value_t jthis,
+ const jerry_value_t jargv[],
+ const jerry_length_t jargc,
+ const iotjs_i2c_op_t i2c_op) {
JS_DECLARE_THIS_PTR(i2c, i2c);
DJS_CHECK_ARGS(1, array);
- DJS_CHECK_ARG_IF_EXIST(1, function);
+ return i2c_write(i2c, jargv, jargc, i2c_op == IOTJS_I2C_WRITE);
+}
- return i2c_write(i2c, jargv, jargc, true);
+JS_FUNCTION(Write) {
+ return i2c_do_write_or_writesync(jfunc, jthis, jargv, jargc, IOTJS_I2C_WRITE);
}
JS_FUNCTION(WriteSync) {
- JS_DECLARE_THIS_PTR(i2c, i2c);
- DJS_CHECK_ARGS(1, array);
-
- return i2c_write(i2c, jargv, jargc, false);
+ return i2c_do_write_or_writesync(jfunc, jthis, jargv, jargc,
+ IOTJS_I2C_WRITESYNC);
}
JS_FUNCTION(Read) {
#include "iotjs_def.h"
#include "iotjs_module_periph_common.h"
-#include "iotjs_reqwrap.h"
// Forward declaration of platform data. These are only used by platform code.
// Generic I2C module never dereferences platform data pointer.
#include "iotjs_module_mqtt.h"
-#include "iotjs_handlewrap.h"
-#include "iotjs_reqwrap.h"
+static void iotjs_mqttclient_destroy(iotjs_mqttclient_t *mqttclient) {
+ IOTJS_RELEASE(mqttclient->buffer);
+ IOTJS_RELEASE(mqttclient);
+}
+static const jerry_object_native_info_t mqttclient_native_info = {
+ .free_cb = (jerry_object_native_free_callback_t)iotjs_mqttclient_destroy
+};
-static jerry_value_t mqtt_client_connack_error(const unsigned char error_code) {
- switch (error_code) {
- case UNACCEPTABLE_PROTOCOL:
- return JS_CREATE_ERROR(COMMON,
- "MQTT: Connection refused: unacceptable protocol");
- case BAD_IDENTIFIER:
- return JS_CREATE_ERROR(COMMON,
- "MQTT: Connection refused: bad client identifier");
- case SERVER_UNAVIABLE:
- return JS_CREATE_ERROR(COMMON,
- "MQTT: Connection refused: server unaviable");
- case BAD_CREDENTIALS:
- return JS_CREATE_ERROR(
- COMMON, "MQTT: Connection refused: bad username or password");
- case UNAUTHORISED:
- return JS_CREATE_ERROR(COMMON, "MQTT: Connection refused: unauthorised");
- default:
- return JS_CREATE_ERROR(COMMON, "MQTT: Unknown error");
- }
+
+iotjs_mqttclient_t *iotjs_mqttclient_create(const jerry_value_t jobject) {
+ iotjs_mqttclient_t *mqttclient = IOTJS_ALLOC(iotjs_mqttclient_t);
+
+ jerry_set_object_native_pointer(jobject, mqttclient, &mqttclient_native_info);
+ return mqttclient;
}
}
-static uint32_t iotjs_decode_remaining_length(char *buffer, size_t *offset) {
- unsigned char c;
- uint32_t remaining_length = 0;
- uint32_t length = 0;
- uint32_t shift = 0;
+static uint32_t iotjs_decode_remaining_length(char *buffer,
+ uint32_t *out_length) {
+ // There must be at least 2 bytes to decode
+ uint32_t c = (uint32_t)(*buffer);
+ uint32_t decoded_length = (c & 0x7F);
+ uint32_t length = 1;
+ uint32_t shift = 7;
+
+ buffer++;
do {
if (++length > IOTJS_MODULE_MQTT_MAX_REMAINING_LENGTH_BYTES) {
- return UINT32_MAX;
+ return 0;
}
- c = (unsigned char)buffer[*offset];
- remaining_length += (uint32_t)(c & 0x7F) << shift;
+ c = (uint32_t)(*buffer);
+ decoded_length += (c & 0x7F) << shift;
+
shift += 7;
+ buffer++;
+ } while ((c & 0x80) != 0);
- (*offset)++;
- } while ((c & 128) != 0);
+ if (c == 0) {
+ // The length must be encoded with the least amount of bytes.
+ // This rule is not fulfilled if the last byte is zero.
+ return 0;
+ }
- return remaining_length;
+ *out_length = length;
+ return decoded_length;
}
static uint8_t *iotjs_mqtt_string_serialize(uint8_t *dst_buffer,
- iotjs_bufferwrap_t *src_buffer) {
+ iotjs_tmp_buffer_t *src_buffer) {
uint16_t len = src_buffer->length;
dst_buffer[0] = (uint8_t)(len >> 8);
dst_buffer[1] = (uint8_t)(len & 0x00FF);
return (dst_buffer + 2 + src_buffer->length);
}
-void iotjs_create_ack_callback(char *buffer, char *name, jerry_value_t jsref) {
- uint8_t packet_identifier_MSB = (uint8_t)buffer[2];
- uint8_t packet_identifier_LSB = (uint8_t)buffer[3];
-
+void iotjs_mqtt_ack(char *buffer, char *name, jerry_value_t jsref,
+ char *error) {
uint16_t package_id =
- iotjs_mqtt_calculate_length(packet_identifier_MSB, packet_identifier_LSB);
+ iotjs_mqtt_calculate_length((uint8_t)buffer[0], (uint8_t)buffer[1]);
// The callback takes the packet identifier as parameter.
- iotjs_jargs_t args = iotjs_jargs_create(2);
- iotjs_jargs_append_jval(&args, jsref);
- iotjs_jargs_append_number(&args, package_id);
+ jerry_value_t args[2] = { jerry_create_number(package_id),
+ jerry_create_undefined() };
+
+ if (error) {
+ args[1] = iotjs_jval_create_error_without_error_flag(error);
+ }
jerry_value_t fn = iotjs_jval_get_property(jsref, name);
- iotjs_make_callback(fn, jsref, &args);
+ iotjs_invoke_callback(fn, jsref, args, 2);
jerry_release_value(fn);
- iotjs_jargs_destroy(&args);
+ jerry_release_value(args[0]);
+ jerry_release_value(args[1]);
+}
+
+
+JS_FUNCTION(MqttInit) {
+ DJS_CHECK_THIS();
+
+ const jerry_value_t jmqtt = JS_GET_ARG(0, object);
+
+ iotjs_mqttclient_t *mqttclient = iotjs_mqttclient_create(jmqtt);
+ mqttclient->buffer = NULL;
+ mqttclient->buffer_length = 0;
+
+ return jerry_create_undefined();
}
jerry_value_t joptions = JS_GET_ARG(0, object);
- jerry_value_t jclient_id =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_CLIENTID);
- jerry_value_t jusername =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_USERNAME);
- jerry_value_t jpassword =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_PASSWORD);
+ iotjs_tmp_buffer_t client_id;
+ iotjs_jval_get_jproperty_as_tmp_buffer(joptions, IOTJS_MAGIC_STRING_CLIENTID,
+ &client_id);
+ iotjs_tmp_buffer_t username;
+ iotjs_jval_get_jproperty_as_tmp_buffer(joptions, IOTJS_MAGIC_STRING_USERNAME,
+ &username);
+ iotjs_tmp_buffer_t password;
+ iotjs_jval_get_jproperty_as_tmp_buffer(joptions, IOTJS_MAGIC_STRING_PASSWORD,
+ &password);
+ iotjs_tmp_buffer_t message;
+ iotjs_jval_get_jproperty_as_tmp_buffer(joptions, IOTJS_MAGIC_STRING_MESSAGE,
+ &message);
+ iotjs_tmp_buffer_t topic;
+ iotjs_jval_get_jproperty_as_tmp_buffer(joptions, IOTJS_MAGIC_STRING_TOPIC,
+ &topic);
+
+ if (client_id.buffer == NULL || client_id.length >= UINT16_MAX ||
+ username.length >= UINT16_MAX || password.length >= UINT16_MAX ||
+ message.length >= UINT16_MAX || topic.length >= UINT16_MAX) {
+ iotjs_free_tmp_buffer(&client_id);
+ iotjs_free_tmp_buffer(&username);
+ iotjs_free_tmp_buffer(&password);
+ iotjs_free_tmp_buffer(&message);
+ iotjs_free_tmp_buffer(&topic);
+ return JS_CREATE_ERROR(COMMON, "mqtt id too long (max: 65535)");
+ }
+
jerry_value_t jkeepalive =
iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_KEEPALIVE);
jerry_value_t jwill =
iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_WILL);
jerry_value_t jqos =
iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_QOS);
- jerry_value_t jmessage =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_MESSAGE);
- jerry_value_t jtopic =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_TOPIC);
jerry_value_t jretain =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_TOPIC);
+ iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_RETAIN);
uint8_t connect_flags = 0;
- uint8_t keep_alive_msb = 0;
- uint8_t keep_alive_lsb = 10;
connect_flags |= MQTT_FLAG_CLEANSESSION;
- iotjs_bufferwrap_t *username = NULL;
- iotjs_bufferwrap_t *password = NULL;
- iotjs_bufferwrap_t *message = NULL;
- iotjs_bufferwrap_t *topic = NULL;
uint8_t header_byte = 0;
header_byte |= (CONNECT << 4);
-
if (!jerry_value_is_undefined(jwill) && jerry_get_boolean_value(jwill)) {
connect_flags |= MQTT_FLAG_WILL;
- if (!jerry_value_is_undefined(jqos)) {
- uint8_t qos = 0;
- qos = jerry_get_number_value(qos);
- if (qos) {
- connect_flags |= (qos == 1) ? MQTT_FLAG_WILLQOS_1 : MQTT_FLAG_WILLQOS_2;
+ if (jerry_value_is_number(jqos)) {
+ double qos = jerry_get_number_value(jqos);
+
+ if (qos == 1.0) {
+ connect_flags |= MQTT_FLAG_WILLQOS_1;
+ } else if (qos == 2.0) {
+ connect_flags |= MQTT_FLAG_WILLQOS_2;
}
}
jerry_get_boolean_value(jretain)) {
connect_flags |= MQTT_FLAG_WILLRETAIN;
}
- message = iotjs_bufferwrap_from_jbuffer(jmessage);
- topic = iotjs_bufferwrap_from_jbuffer(jtopic);
}
- if (!jerry_value_is_undefined(jusername)) {
+ if (username.buffer != NULL) {
connect_flags |= MQTT_FLAG_USERNAME;
- username = iotjs_bufferwrap_from_jbuffer(jusername);
}
- if (!jerry_value_is_undefined(jpassword)) {
+ if (password.buffer != NULL) {
connect_flags |= MQTT_FLAG_PASSWORD;
- password = iotjs_bufferwrap_from_jbuffer(jpassword);
- }
- if (!jerry_value_is_undefined(jkeepalive)) {
- uint16_t len = jerry_get_number_value(jkeepalive);
- keep_alive_msb = (uint8_t)(len >> 8);
- keep_alive_lsb = (uint8_t)(len & 0x00FF);
}
+ uint16_t keepalive = 0;
+
+ if (jerry_value_is_number(jkeepalive)) {
+ keepalive = (uint16_t)jerry_get_number_value(jkeepalive);
+ }
- iotjs_bufferwrap_t *client_id = iotjs_bufferwrap_from_jbuffer(jclient_id);
+ if (keepalive < 30) {
+ keepalive = 30;
+ }
unsigned char variable_header_protocol[7];
variable_header_protocol[0] = 0;
variable_header_protocol[6] = 4;
size_t variable_header_len = sizeof(variable_header_protocol) +
- sizeof(connect_flags) + sizeof(keep_alive_lsb) +
- sizeof(keep_alive_msb);
+ sizeof(connect_flags) + IOTJS_MQTT_LSB_MSB_SIZE;
+
+ size_t payload_len = IOTJS_MQTT_LSB_MSB_SIZE + client_id.length;
- size_t payload_len = client_id->length + IOTJS_MQTT_LSB_MSB_SIZE;
if (connect_flags & MQTT_FLAG_USERNAME) {
- payload_len += IOTJS_MQTT_LSB_MSB_SIZE + username->length;
+ payload_len += IOTJS_MQTT_LSB_MSB_SIZE + username.length;
}
if (connect_flags & MQTT_FLAG_PASSWORD) {
- payload_len += IOTJS_MQTT_LSB_MSB_SIZE + password->length;
+ payload_len += IOTJS_MQTT_LSB_MSB_SIZE + password.length;
}
if (connect_flags & MQTT_FLAG_WILL) {
- payload_len += IOTJS_MQTT_LSB_MSB_SIZE + topic->length;
- payload_len += IOTJS_MQTT_LSB_MSB_SIZE + message->length;
+ payload_len += IOTJS_MQTT_LSB_MSB_SIZE + topic.length;
+ payload_len += IOTJS_MQTT_LSB_MSB_SIZE + message.length;
}
+
uint32_t remaining_length = payload_len + variable_header_len;
size_t full_len = sizeof(header_byte) +
get_remaining_length_size(remaining_length) +
memcpy(buff_ptr, variable_header_protocol, sizeof(variable_header_protocol));
buff_ptr += sizeof(variable_header_protocol);
*buff_ptr++ = connect_flags;
- *buff_ptr++ = keep_alive_msb;
- *buff_ptr++ = keep_alive_lsb;
+ *buff_ptr++ = (uint8_t)(keepalive >> 8);
+ *buff_ptr++ = (uint8_t)(keepalive & 0x00FF);
- buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, client_id);
+ buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, &client_id);
if (connect_flags & MQTT_FLAG_WILL) {
- buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, topic);
- buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, message);
+ buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, &topic);
+ buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, &message);
}
if (connect_flags & MQTT_FLAG_USERNAME) {
- buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, username);
+ buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, &username);
}
if (connect_flags & MQTT_FLAG_PASSWORD) {
- buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, password);
+ buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, &password);
}
- jerry_release_value(jretain);
- jerry_release_value(jtopic);
- jerry_release_value(jmessage);
- jerry_release_value(jqos);
- jerry_release_value(jwill);
+ iotjs_free_tmp_buffer(&client_id);
+ iotjs_free_tmp_buffer(&username);
+ iotjs_free_tmp_buffer(&password);
+ iotjs_free_tmp_buffer(&message);
+ iotjs_free_tmp_buffer(&topic);
+
jerry_release_value(jkeepalive);
- jerry_release_value(jclient_id);
- jerry_release_value(jusername);
- jerry_release_value(jpassword);
+ jerry_release_value(jwill);
+ jerry_release_value(jqos);
+ jerry_release_value(jretain);
return jbuff;
}
JS_FUNCTION(MqttPublish) {
DJS_CHECK_THIS();
- DJS_CHECK_ARGS(1, object);
+ DJS_CHECK_ARGS(3, any, any, number);
- jerry_value_t joptions = JS_GET_ARG(0, object);
+ iotjs_tmp_buffer_t topic;
+ iotjs_jval_as_tmp_buffer(JS_GET_ARG(0, any), &topic);
- jerry_value_t jmessage =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_MESSAGE);
- jerry_value_t jtopic =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_TOPIC);
- jerry_value_t jretain =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_RETAIN);
- jerry_value_t jqos =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_QOS);
- jerry_value_t jpacket_id =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_PACKETID);
+ if (jerry_value_is_error(topic.jval)) {
+ return topic.jval;
+ }
- uint8_t qos = 0;
- if (jerry_value_is_number(jqos)) {
- qos = jerry_get_number_value(jqos);
+ if (topic.buffer == NULL || topic.length >= UINT16_MAX) {
+ iotjs_free_tmp_buffer(&topic);
+
+ return JS_CREATE_ERROR(COMMON, "Topic for PUBLISH is empty or too long.");
+ }
+
+ iotjs_tmp_buffer_t message;
+ iotjs_jval_as_tmp_buffer(JS_GET_ARG(1, any), &message);
+
+ if (jerry_value_is_error(message.jval)) {
+ iotjs_free_tmp_buffer(&topic);
+ return message.jval;
}
- bool dup = false;
+ // header bits: | 16 bit packet id | 4 bit PUBLISH header |
+ uint32_t header = (uint32_t)JS_GET_ARG(2, number);
+ uint32_t packet_identifier = (header >> 4);
uint8_t header_byte = 0;
- header_byte |= (PUBLISH << 4);
- header_byte |= (dup << 3);
- header_byte |= (qos << 1);
- header_byte |= (jerry_get_boolean_value(jretain));
+ header_byte |= (PUBLISH << 4) | (header & 0xf);
- iotjs_bufferwrap_t *message_payload = iotjs_bufferwrap_from_jbuffer(jmessage);
- iotjs_bufferwrap_t *topic_payload = iotjs_bufferwrap_from_jbuffer(jtopic);
+ const uint8_t qos_mask = (0x3 << 1);
- uint8_t packet_identifier_lsb = 0;
- uint8_t packet_identifier_msb = 0;
+ size_t payload_len = message.length + IOTJS_MQTT_LSB_MSB_SIZE;
+ size_t variable_header_len = topic.length + IOTJS_MQTT_LSB_MSB_SIZE;
- if (qos > 0 && jerry_value_is_number(jpacket_id)) {
- uint16_t packet_identifier = jerry_get_number_value(jpacket_id);
- packet_identifier_msb = (uint8_t)(packet_identifier >> 8);
- packet_identifier_lsb = (uint8_t)(packet_identifier & 0x00FF);
+ if (header_byte & qos_mask) {
+ variable_header_len += IOTJS_MQTT_LSB_MSB_SIZE;
}
- size_t payload_len = message_payload->length + IOTJS_MQTT_LSB_MSB_SIZE;
- size_t variable_header_len = topic_payload->length + IOTJS_MQTT_LSB_MSB_SIZE +
- sizeof(packet_identifier_msb) +
- sizeof(packet_identifier_lsb);
uint32_t remaining_length = payload_len + variable_header_len;
size_t full_len = sizeof(header_byte) +
get_remaining_length_size(remaining_length) +
*buff_ptr++ = header_byte;
buff_ptr = iotjs_encode_remaining_length(buff_ptr, remaining_length);
- buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, topic_payload);
- *buff_ptr++ = packet_identifier_msb;
- *buff_ptr++ = packet_identifier_lsb;
+ buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, &topic);
+
+ if (header_byte & qos_mask) {
+ // Packet id format is MSB / LSB.
+ *buff_ptr++ = (uint8_t)(packet_identifier >> 8);
+ *buff_ptr++ = (uint8_t)(packet_identifier & 0x00FF);
+ }
// Don't need to put length before the payload, so we can't use the
// iotjs_mqtt_string_serialize. The broker and the other clients calculate
// the payload length from remaining length and the topic length.
- memcpy(buff_ptr, message_payload->buffer, message_payload->length);
-
- jerry_release_value(jmessage);
- jerry_release_value(jtopic);
- jerry_release_value(jretain);
+ memcpy(buff_ptr, message.buffer, message.length);
+ iotjs_free_tmp_buffer(&message);
+ iotjs_free_tmp_buffer(&topic);
return jbuff;
}
-JS_FUNCTION(MqttHandle) {
- DJS_CHECK_THIS();
- DJS_CHECK_ARGS(2, object, object);
-
- jerry_value_t jsref = JS_GET_ARG(0, object);
- jerry_value_t jparam = JS_GET_ARG(1, object);
-
- iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jparam);
- char *buffer = buffer_wrap->buffer;
-
- char first_byte = buffer[0];
+static int iotjs_mqtt_handle(jerry_value_t jsref, char first_byte, char *buffer,
+ uint32_t packet_size) {
char packet_type = (first_byte >> 4) & 0x0F;
- size_t offset = 1;
- uint32_t remaining_length = iotjs_decode_remaining_length(buffer, &offset);
-
switch (packet_type) {
case CONNACK: {
- if (remaining_length != 2) {
- return JS_CREATE_ERROR(COMMON, "MQTT: CONNACK packet is corrupted");
+ if (packet_size != 2) {
+ return MQTT_ERR_CORRUPTED_PACKET;
}
- uint8_t return_code = (uint8_t)buffer[++offset];
+ uint8_t return_code = (uint8_t)buffer[1];
if (return_code != 0) {
- return mqtt_client_connack_error(return_code);
+ return return_code;
}
jerry_value_t fn =
- iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING__ONCONNECT);
- iotjs_jargs_t jargs = iotjs_jargs_create(1);
- iotjs_jargs_append_jval(&jargs, jsref);
- iotjs_make_callback(fn, jsref, &jargs);
+ iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING_ONCONNECTION);
+ iotjs_invoke_callback(fn, jsref, NULL, 0);
- iotjs_jargs_destroy(&jargs);
jerry_release_value(fn);
break;
}
header.bits.qos = (first_byte & 0x06) >> 1;
header.bits.retain = first_byte & 0x01;
- uint8_t topic_length_MSB = (uint8_t)buffer[offset];
- offset += sizeof(topic_length_MSB);
-
- uint8_t topic_length_LSB = (uint8_t)buffer[offset];
- offset += sizeof(topic_length_LSB);
+ uint8_t topic_length_MSB = (uint8_t)buffer[0];
+ uint8_t topic_length_LSB = (uint8_t)buffer[1];
+ buffer += 2;
uint16_t topic_length =
iotjs_mqtt_calculate_length(topic_length_MSB, topic_length_LSB);
- jerry_value_t jtopic = iotjs_bufferwrap_create_buffer(topic_length);
- iotjs_bufferwrap_t *topic_wrap = iotjs_bufferwrap_from_jbuffer(jtopic);
+ if (!jerry_is_valid_utf8_string((const uint8_t *)buffer, topic_length)) {
+ return MQTT_ERR_CORRUPTED_PACKET;
+ }
- memcpy(topic_wrap->buffer, buffer + offset, topic_length);
- offset += topic_length;
+ const jerry_char_t *topic = (const jerry_char_t *)buffer;
+ jerry_value_t jtopic = jerry_create_string_sz(topic, topic_length);
+ buffer += topic_length;
// The Packet Identifier field is only present in PUBLISH packets
// where the QoS level is 1 or 2.
uint16_t packet_identifier = 0;
if (header.bits.qos > 0) {
- uint8_t packet_identifier_MSB = 0;
- uint8_t packet_identifier_LSB = 0;
-
-
- memcpy(&packet_identifier_MSB, buffer + offset, sizeof(uint8_t));
- offset += sizeof(packet_identifier_MSB);
-
- memcpy(&packet_identifier_LSB, buffer + offset, sizeof(uint8_t));
- offset += sizeof(packet_identifier_LSB);
+ uint8_t packet_identifier_MSB = (uint8_t)buffer[0];
+ uint8_t packet_identifier_LSB = (uint8_t)buffer[1];
+ buffer += 2;
packet_identifier = iotjs_mqtt_calculate_length(packet_identifier_MSB,
packet_identifier_LSB);
}
size_t payload_length =
- (size_t)remaining_length - topic_length - sizeof(topic_length);
+ (size_t)packet_size - topic_length - sizeof(topic_length);
if (header.bits.qos > 0) {
payload_length -= sizeof(packet_identifier);
jerry_value_t jmessage = iotjs_bufferwrap_create_buffer(payload_length);
iotjs_bufferwrap_t *msg_wrap = iotjs_bufferwrap_from_jbuffer(jmessage);
- IOTJS_ASSERT(jerry_is_valid_utf8_string((const uint8_t *)msg_wrap->buffer,
- msg_wrap->length));
-
- IOTJS_ASSERT(
- jerry_is_valid_utf8_string((const uint8_t *)topic_wrap->buffer,
- topic_wrap->length));
-
- memcpy(msg_wrap->buffer, buffer + offset, payload_length);
- offset += payload_length;
+ memcpy(msg_wrap->buffer, buffer, payload_length);
- iotjs_jargs_t args = iotjs_jargs_create(5);
- iotjs_jargs_append_jval(&args, jsref);
- iotjs_jargs_append_string_raw(&args, msg_wrap->buffer);
- iotjs_jargs_append_string_raw(&args, topic_wrap->buffer);
- iotjs_jargs_append_number(&args, header.bits.qos);
- iotjs_jargs_append_number(&args, packet_identifier);
+ jerry_value_t args[4] = { jmessage, jtopic,
+ jerry_create_number(header.bits.qos),
+ jerry_create_number(packet_identifier) };
jerry_value_t fn =
- iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING__ONMESSAGE);
- iotjs_make_callback(fn, jsref, &args);
+ iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING_ONMESSAGE);
+ iotjs_invoke_callback(fn, jsref, args, 4);
jerry_release_value(fn);
- iotjs_jargs_destroy(&args);
- jerry_release_value(jmessage);
- jerry_release_value(jtopic);
+ for (uint8_t i = 0; i < 4; i++) {
+ jerry_release_value(args[i]);
+ }
break;
}
case PUBACK: {
- if (remaining_length != 2) {
- return JS_CREATE_ERROR(COMMON, "MQTT: PUBACK packet is corrupted");
+ if (packet_size != 2 || (first_byte & 0x0F) != 0x0) {
+ return MQTT_ERR_CORRUPTED_PACKET;
}
- iotjs_create_ack_callback(buffer, IOTJS_MAGIC_STRING__ONPUBACK, jsref);
+ iotjs_mqtt_ack(buffer, IOTJS_MAGIC_STRING_ONACK, jsref, NULL);
break;
}
case PUBREC: {
- if (remaining_length != 2) {
- return JS_CREATE_ERROR(COMMON, "MQTT: RUBREC packet is corrupted");
+ if (packet_size != 2 || (first_byte & 0x0F) != 0x0) {
+ return MQTT_ERR_CORRUPTED_PACKET;
}
- iotjs_create_ack_callback(buffer, IOTJS_MAGIC_STRING__ONPUBREC, jsref);
+ iotjs_mqtt_ack(buffer, IOTJS_MAGIC_STRING_ONPUBREC, jsref, NULL);
break;
}
case PUBREL: {
- if (remaining_length != 2) {
- return JS_CREATE_ERROR(COMMON, "MQTT: PUBREL packet is corrupted");
- }
-
- char control_packet_reserved = first_byte & 0x0F;
- if (control_packet_reserved != 2) {
- return JS_CREATE_ERROR(COMMON, "MQTT: PUBREL packet is corrupted");
+ if (packet_size != 2 || (first_byte & 0x0F) != 0x2) {
+ return MQTT_ERR_CORRUPTED_PACKET;
}
- iotjs_create_ack_callback(buffer, IOTJS_MAGIC_STRING__ONPUBREL, jsref);
+ iotjs_mqtt_ack(buffer, IOTJS_MAGIC_STRING_ONPUBREL, jsref, NULL);
break;
}
case PUBCOMP: {
- if (remaining_length != 2) {
- return JS_CREATE_ERROR(COMMON, "MQTT: PUBCOMP packet is corrupted");
+ if (packet_size != 2 || (first_byte & 0x0F) != 0x0) {
+ return MQTT_ERR_CORRUPTED_PACKET;
}
- iotjs_create_ack_callback(buffer, IOTJS_MAGIC_STRING__ONPUBCOMP, jsref);
+ iotjs_mqtt_ack(buffer, IOTJS_MAGIC_STRING_ONACK, jsref, NULL);
break;
}
case SUBACK: {
// We assume that only one topic was in the SUBSCRIBE packet.
- if (remaining_length != 3) {
- return JS_CREATE_ERROR(COMMON, "MQTT: SUBACK packet is corrupted");
+ if (packet_size != 3 || (first_byte & 0x0F) != 0x0) {
+ return MQTT_ERR_CORRUPTED_PACKET;
}
- uint8_t return_code = (uint8_t)buffer[4];
- if (return_code == 128) {
- return JS_CREATE_ERROR(COMMON, "MQTT: Subscription was unsuccessful");
- }
+ char *error = NULL;
- // The callback takes the granted QoS as parameter.
- iotjs_jargs_t args = iotjs_jargs_create(2);
- iotjs_jargs_append_jval(&args, jsref);
- iotjs_jargs_append_number(&args, return_code);
+ if ((uint8_t)buffer[2] == 0x80) {
+ error = "Subscribe failed";
+ }
- jerry_value_t sub_fn =
- iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING__ONSUBACK);
- iotjs_make_callback(sub_fn, jsref, &args);
- jerry_release_value(sub_fn);
- iotjs_jargs_destroy(&args);
+ iotjs_mqtt_ack(buffer, IOTJS_MAGIC_STRING_ONACK, jsref, error);
break;
}
case UNSUBACK: {
- if (remaining_length != 2) {
- return JS_CREATE_ERROR(COMMON, "MQTT: UNSUBACK packet is corrupted");
+ if (packet_size != 2 || (first_byte & 0x0F) != 0x0) {
+ return MQTT_ERR_CORRUPTED_PACKET;
}
- iotjs_create_ack_callback(buffer, IOTJS_MAGIC_STRING__ONUNSUBACK, jsref);
+ iotjs_mqtt_ack(buffer, IOTJS_MAGIC_STRING_ONACK, jsref, NULL);
break;
}
case PINGRESP: {
- if (remaining_length != 0) {
- return JS_CREATE_ERROR(COMMON, "MQTT: PingRESP packet is corrupted");
+ if (packet_size != 0 || (first_byte & 0x0F) != 0x0) {
+ return MQTT_ERR_CORRUPTED_PACKET;
}
+
jerry_value_t fn =
- iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING__ONPINGRESP);
- iotjs_jargs_t jargs = iotjs_jargs_create(1);
- iotjs_jargs_append_jval(&jargs, jsref);
- iotjs_make_callback(fn, jsref, &jargs);
+ iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING_ONPINGRESP);
+ iotjs_invoke_callback(fn, jsref, NULL, 0);
jerry_release_value(fn);
- iotjs_jargs_destroy(&jargs);
break;
}
case DISCONNECT: {
- iotjs_jargs_t jargs = iotjs_jargs_create(2);
- iotjs_jargs_append_jval(&jargs, jsref);
- jerry_value_t str_arg = jerry_create_string(
- (jerry_char_t *)"The broker disconnected the client");
- iotjs_jargs_append_jval(&jargs, str_arg);
+ if (packet_size != 0 || (first_byte & 0x0F) != 0x0) {
+ return MQTT_ERR_CORRUPTED_PACKET;
+ }
+
jerry_value_t fn =
- iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING__ONDISCONNECT);
- iotjs_make_callback(fn, jsref, &jargs);
- jerry_release_value(str_arg);
+ iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING_ONEND);
+ iotjs_invoke_callback(fn, jsref, NULL, 0);
jerry_release_value(fn);
- iotjs_jargs_destroy(&jargs);
break;
}
case SUBSCRIBE:
case UNSUBSCRIBE:
case PINGREQ:
- return JS_CREATE_ERROR(
- COMMON, "MQTT: Unallowed packet has arrived to the client");
+ return MQTT_ERR_UNALLOWED_PACKET;
}
- return jerry_create_undefined();
+ return 0;
}
-JS_FUNCTION(MqttSubscribe) {
+static void iotjs_mqtt_concat_buffers(iotjs_mqttclient_t *mqttclient,
+ iotjs_bufferwrap_t *buff_recv) {
+ char *tmp_buf = mqttclient->buffer;
+ mqttclient->buffer =
+ IOTJS_CALLOC(mqttclient->buffer_length + buff_recv->length, char);
+ memcpy(mqttclient->buffer, tmp_buf, mqttclient->buffer_length);
+ memcpy(mqttclient->buffer + mqttclient->buffer_length, buff_recv->buffer,
+ buff_recv->length);
+ mqttclient->buffer_length += buff_recv->length;
+ IOTJS_RELEASE(tmp_buf);
+}
+
+
+static jerry_value_t iotjs_mqtt_handle_error(
+ iotjs_mqtt_packet_error_t error_code) {
+ switch (error_code) {
+ case MQTT_ERR_UNACCEPTABLE_PROTOCOL:
+ return JS_CREATE_ERROR(COMMON,
+ "MQTT: Connection refused: unacceptable protocol");
+ case MQTT_ERR_BAD_IDENTIFIER:
+ return JS_CREATE_ERROR(COMMON,
+ "MQTT: Connection refused: bad client identifier");
+ case MQTT_ERR_SERVER_UNAVIABLE:
+ return JS_CREATE_ERROR(COMMON,
+ "MQTT: Connection refused: server unavailable");
+ case MQTT_ERR_BAD_CREDENTIALS:
+ return JS_CREATE_ERROR(
+ COMMON, "MQTT: Connection refused: bad username or password");
+ case MQTT_ERR_UNAUTHORISED:
+ return JS_CREATE_ERROR(COMMON, "MQTT: Connection refused: unauthorised");
+ case MQTT_ERR_CORRUPTED_PACKET:
+ return JS_CREATE_ERROR(COMMON, "MQTT: Corrupted packet");
+ case MQTT_ERR_UNALLOWED_PACKET:
+ return JS_CREATE_ERROR(COMMON, "MQTT: Broker sent an unallowed packet");
+ case MQTT_ERR_SUBSCRIPTION_FAILED:
+ return JS_CREATE_ERROR(COMMON, "MQTT: Subscription failed");
+ default:
+ return JS_CREATE_ERROR(COMMON, "MQTT: Unknown error");
+ }
+}
+
+
+JS_FUNCTION(MqttReceive) {
DJS_CHECK_THIS();
- DJS_CHECK_ARGS(1, object);
+ DJS_CHECK_ARGS(2, object, object);
- jerry_value_t joptions = JS_GET_ARG(0, object);
+ jerry_value_t jnat = JS_GET_ARG(0, object);
- jerry_value_t jtopic =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_TOPIC);
- jerry_value_t jqos =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_QOS);
+ iotjs_mqttclient_t *mqttclient = (iotjs_mqttclient_t *)
+ iotjs_jval_get_object_native_handle(jnat, &mqttclient_native_info);
+ if (mqttclient == NULL) {
+ return JS_CREATE_ERROR(COMMON, "MQTT native pointer not available");
+ }
- uint8_t qos = 0;
- if (jerry_value_is_number(jqos)) {
- qos = (uint8_t)jerry_get_number_value(jqos);
+ jerry_value_t jbuffer = JS_GET_ARG(1, object);
+ iotjs_bufferwrap_t *buff_recv = iotjs_bufferwrap_from_jbuffer(jbuffer);
+ if (buff_recv->length == 0) {
+ return jerry_create_undefined();
}
- bool dup = false;
- bool retain = false;
+ char *current_buffer = buff_recv->buffer;
+ char *current_buffer_end = current_buffer + buff_recv->length;
- uint8_t header_byte = 0;
- header_byte |= (SUBSCRIBE << 4);
- header_byte |= (dup << 3);
- header_byte |= (1 << 1); // always 1
- header_byte |= retain;
+ // Concat the buffers if we previously needed to
+ if (mqttclient->buffer_length > 0) {
+ iotjs_mqtt_concat_buffers(mqttclient, buff_recv);
+ current_buffer = mqttclient->buffer;
+ current_buffer_end = current_buffer + mqttclient->buffer_length;
+ }
- iotjs_bufferwrap_t *topic_payload = iotjs_bufferwrap_from_jbuffer(jtopic);
+ // Keep on going, if data remains just continue looping
+ while (true) {
+ if (current_buffer >= current_buffer_end) {
+ if (mqttclient->buffer_length > 0) {
+ IOTJS_RELEASE(mqttclient->buffer);
+ mqttclient->buffer_length = 0;
+ }
+ return jerry_create_undefined();
+ }
- uint8_t packet_identifier_lsb = 0;
- uint8_t packet_identifier_msb = 0;
+ if (current_buffer + 2 > current_buffer_end) {
+ break;
+ }
- size_t payload_len =
- sizeof(qos) + topic_payload->length + IOTJS_MQTT_LSB_MSB_SIZE;
- size_t variable_header_len =
- sizeof(packet_identifier_msb) + sizeof(packet_identifier_lsb);
- uint32_t remaining_length = payload_len + variable_header_len;
- size_t full_len = sizeof(header_byte) +
- get_remaining_length_size(remaining_length) +
- variable_header_len + payload_len;
+ uint32_t packet_size;
+ uint32_t packet_size_length;
- jerry_value_t jbuff = iotjs_bufferwrap_create_buffer(full_len);
- iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuff);
+ if ((uint8_t)current_buffer[1] <= 0x7f) {
+ packet_size = (uint32_t)current_buffer[1];
+ packet_size_length = 1;
- uint8_t *buff_ptr = (uint8_t *)buffer_wrap->buffer;
+ if (current_buffer + 2 + packet_size > current_buffer_end) {
+ break;
+ }
+ } else {
+ // At least 128 bytes arrived
+ if (current_buffer + 5 >= current_buffer_end) {
+ break;
+ }
- *buff_ptr++ = header_byte;
+ packet_size = iotjs_decode_remaining_length(current_buffer + 1,
+ &packet_size_length);
- buff_ptr = iotjs_encode_remaining_length(buff_ptr, remaining_length);
+ if (packet_size == 0) {
+ return iotjs_mqtt_handle_error(MQTT_ERR_CORRUPTED_PACKET);
+ }
- *buff_ptr++ = packet_identifier_msb;
- *buff_ptr++ = packet_identifier_lsb;
+ if (current_buffer + 1 + packet_size_length + packet_size >
+ current_buffer_end) {
+ break;
+ }
+ }
- buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, topic_payload);
+ char first_byte = current_buffer[0];
+ current_buffer += 1 + packet_size_length;
- buff_ptr[0] = qos;
+ int ret_val =
+ iotjs_mqtt_handle(jnat, first_byte, current_buffer, packet_size);
- jerry_release_value(jtopic);
- jerry_release_value(jqos);
+ if (ret_val != 0) {
+ return iotjs_mqtt_handle_error(ret_val);
+ }
- return jbuff;
-}
+ current_buffer += packet_size;
+ }
+ if (current_buffer == mqttclient->buffer) {
+ return jerry_create_undefined();
+ }
-JS_FUNCTION(MqttPing) {
- DJS_CHECK_THIS();
+ uint32_t remaining_size = (uint32_t)(current_buffer_end - current_buffer);
+ char *buffer = IOTJS_CALLOC(remaining_size, char);
+ memcpy(buffer, current_buffer, remaining_size);
- uint8_t header_byte = 0;
- header_byte |= (PINGREQ << 4);
+ if (mqttclient->buffer != NULL) {
+ IOTJS_RELEASE(mqttclient->buffer);
+ }
- uint8_t remaining_length = 0;
- size_t full_len = sizeof(header_byte) + sizeof(remaining_length);
+ mqttclient->buffer = buffer;
+ mqttclient->buffer_length = remaining_size;
- jerry_value_t jbuff = iotjs_bufferwrap_create_buffer(full_len);
- iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuff);
+ return jerry_create_undefined();
+}
- uint8_t *buff_ptr = (uint8_t *)buffer_wrap->buffer;
+static jerry_value_t iotjs_mqtt_subscribe_handler(
+ const jerry_value_t jthis, const jerry_value_t jargv[],
+ const jerry_value_t jargc,
+ const iotjs_mqtt_control_packet_type packet_type) {
+ DJS_CHECK_THIS();
+ DJS_CHECK_ARGS(2, any, number);
- buff_ptr[0] = header_byte;
- buff_ptr[1] = remaining_length;
+ JS_CHECK(packet_type == SUBSCRIBE || packet_type == UNSUBSCRIBE);
- return jbuff;
-}
+ iotjs_tmp_buffer_t topic;
+ iotjs_jval_as_tmp_buffer(JS_GET_ARG(0, any), &topic);
+ if (jerry_value_is_error(topic.jval)) {
+ return topic.jval;
+ }
-JS_FUNCTION(MqttUnsubscribe) {
- DJS_CHECK_THIS();
- DJS_CHECK_ARGS(1, object);
+ if (topic.buffer == NULL || topic.length >= UINT16_MAX) {
+ iotjs_free_tmp_buffer(&topic);
+
+ return JS_CREATE_ERROR(COMMON, "Topic for SUBSCRIBE is empty or too long.");
+ }
- jerry_value_t jtopic = JS_GET_ARG(0, object);
+ // header bits: |2 bit qos | 16 bit packet id |
+ // qos is only available in case of subscribe
+ uint32_t header = (uint32_t)JS_GET_ARG(1, number);
+ uint32_t packet_identifier = (header & 0xFFFF);
- iotjs_bufferwrap_t *topic_payload = iotjs_bufferwrap_from_jbuffer(jtopic);
+ // Low 4 bits must be 0,0,1,0
+ uint8_t header_byte = (packet_type << 4) | (1 << 1);
- uint8_t header_byte = 0;
- header_byte |= (UNSUBSCRIBE << 4);
- // Reserved
- header_byte |= (1 << 1);
+ size_t payload_len = topic.length + IOTJS_MQTT_LSB_MSB_SIZE;
- uint8_t packet_identifier_msb = 0;
- uint8_t packet_identifier_lsb = 0;
+ if (packet_type == SUBSCRIBE) {
+ // Add place for the SUBSCRIBE QoS data.
+ payload_len += sizeof(uint8_t);
+ }
- size_t payload_len = topic_payload->length + IOTJS_MQTT_LSB_MSB_SIZE;
- size_t variable_header_len =
- sizeof(packet_identifier_msb) + sizeof(packet_identifier_lsb);
+ size_t variable_header_len = IOTJS_MQTT_LSB_MSB_SIZE;
uint32_t remaining_length = payload_len + variable_header_len;
size_t full_len = sizeof(header_byte) +
get_remaining_length_size(remaining_length) +
- variable_header_len + payload_len;
+ remaining_length;
jerry_value_t jbuff = iotjs_bufferwrap_create_buffer(full_len);
iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuff);
buff_ptr = iotjs_encode_remaining_length(buff_ptr, remaining_length);
- *buff_ptr++ = packet_identifier_msb;
- *buff_ptr++ = packet_identifier_lsb;
+ // Packet id format is MSB / LSB.
+ *buff_ptr++ = (uint8_t)(packet_identifier >> 8);
+ *buff_ptr++ = (uint8_t)(packet_identifier & 0x00FF);
+
+ buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, &topic);
- buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, topic_payload);
+ if (packet_type == SUBSCRIBE) {
+ uint8_t qos = ((header >> 16) & 0x3);
+ buff_ptr[0] = qos;
+ }
+
+ iotjs_free_tmp_buffer(&topic);
+ return jbuff;
+}
+
+
+JS_FUNCTION(MqttUnsubscribe) {
+ return iotjs_mqtt_subscribe_handler(jthis, jargv, jargc, UNSUBSCRIBE);
+}
+
+
+JS_FUNCTION(MqttSubscribe) {
+ return iotjs_mqtt_subscribe_handler(jthis, jargv, jargc, SUBSCRIBE);
+}
+
+
+JS_FUNCTION(MqttPing) {
+ DJS_CHECK_THIS();
+
+ uint8_t header_byte = 0;
+ header_byte |= (PINGREQ << 4);
+
+ uint8_t remaining_length = 0;
+ size_t full_len = sizeof(header_byte) + sizeof(remaining_length);
+
+ jerry_value_t jbuff = iotjs_bufferwrap_create_buffer(full_len);
+ iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuff);
+
+ uint8_t *buff_ptr = (uint8_t *)buffer_wrap->buffer;
+
+ buff_ptr[0] = header_byte;
+ buff_ptr[1] = remaining_length;
return jbuff;
}
JS_FUNCTION(MqttSendAck) {
DJS_CHECK_THIS();
- DJS_CHECK_ARGS(1, object);
+ DJS_CHECK_ARGS(2, number, number);
- jerry_value_t joptions = JS_GET_ARG(0, object);
- jerry_value_t jack_type =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_ACKTYPE);
- jerry_value_t jpacket_id =
- iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_PACKETID);
+ uint8_t ack_type = (uint8_t)JS_GET_ARG(0, number);
+ uint16_t packet_id = (uint16_t)JS_GET_ARG(1, number);
- uint16_t packet_id = 0;
- if (!jerry_value_is_undefined(jpacket_id)) {
- packet_id = (uint16_t)jerry_get_number_value(jpacket_id);
- }
-
- uint8_t ack_type = 0;
- if (!jerry_value_is_undefined(jack_type)) {
- ack_type = (uint8_t)jerry_get_number_value(jack_type);
- }
+ uint8_t header_byte = (ack_type << 4);
- uint8_t header_byte = 0;
- uint8_t remaining_length = 2;
-
- switch (ack_type) {
- case PUBACK: {
- header_byte |= (PUBACK << 4);
- break;
- }
- case PUBREC: {
- header_byte |= (PUBREC << 4);
- break;
- }
- case PUBREL: {
- header_byte |= (PUBREL << 4);
- header_byte |= 2;
- break;
- }
- case PUBCOMP: {
- header_byte |= (PUBCOMP << 4);
- break;
- }
+ if (ack_type == PUBREL) {
+ header_byte |= 0x2;
}
uint8_t packet_identifier_msb = (uint8_t)(packet_id >> 8);
uint8_t packet_identifier_lsb = (uint8_t)(packet_id & 0x00FF);
- size_t full_len =
- sizeof(header_byte) + sizeof(remaining_length) + sizeof(packet_id);
+ size_t full_len = sizeof(uint8_t) * 2 + sizeof(packet_id);
jerry_value_t jbuff = iotjs_bufferwrap_create_buffer(full_len);
iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuff);
uint8_t *buff_ptr = (uint8_t *)buffer_wrap->buffer;
buff_ptr[0] = header_byte;
- buff_ptr[1] = remaining_length;
+ buff_ptr[1] = 2; /* length */
buff_ptr[2] = packet_identifier_msb;
buff_ptr[3] = packet_identifier_lsb;
- jerry_release_value(jpacket_id);
- jerry_release_value(jack_type);
-
return jbuff;
}
jerry_value_t jMQTT = jerry_create_object();
iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_CONNECT, MqttConnect);
iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_DISCONNECT, MqttDisconnect);
- iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_MQTTHANDLE, MqttHandle);
iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_PING, MqttPing);
iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_PUBLISH, MqttPublish);
+ iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_MQTTINIT, MqttInit);
+ iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_MQTTRECEIVE, MqttReceive);
iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_SENDACK, MqttSendAck);
iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_SUBSCRIBE, MqttSubscribe);
iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_UNSUBSCRIBE, MqttUnsubscribe);
* The types of the control packet.
* These values determine the aim of the message.
*/
-enum {
+typedef enum {
CONNECT = 0x1,
CONNACK = 0x2,
PUBLISH = 0x3,
DISCONNECT = 0xE
} iotjs_mqtt_control_packet_type;
+// Packet error types
+typedef enum {
+ MQTT_ERR_UNACCEPTABLE_PROTOCOL = 1,
+ MQTT_ERR_BAD_IDENTIFIER = 2,
+ MQTT_ERR_SERVER_UNAVIABLE = 3,
+ MQTT_ERR_BAD_CREDENTIALS = 4,
+ MQTT_ERR_UNAUTHORISED = 5,
+ MQTT_ERR_CORRUPTED_PACKET = 6,
+ MQTT_ERR_UNALLOWED_PACKET = 7,
+ MQTT_ERR_SUBSCRIPTION_FAILED = 8,
+} iotjs_mqtt_packet_error_t;
+
/*
* The values of the Quality of Service.
*/
QoS2 = 2 // Exactly once delivery.
} iotjs_mqtt_quality_of_service;
-enum {
- UNACCEPTABLE_PROTOCOL = 1,
- BAD_IDENTIFIER = 2,
- SERVER_UNAVIABLE = 3,
- BAD_CREDENTIALS = 4,
- UNAUTHORISED = 5
-} iotjs_mqtt_connection_error;
-
/*
* First byte of the message's fixed header.
* Contains:
MQTT_FLAG_USERNAME = 1 << 7
} iotjs_mqtt_connect_flag_t;
+typedef struct {
+ char *buffer;
+ uint32_t buffer_length;
+} iotjs_mqttclient_t;
+
#endif /* IOTJS_MODULE_MQTT_H */
#include "iotjs_module_pwm.h"
#include "iotjs_module_spi.h"
#include "iotjs_module_uart.h"
+#include "iotjs_uv_request.h"
const char* iotjs_periph_error_str(uint8_t op) {
switch (op) {
}
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_periph_data_t* worker_data =
+ (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req);
- iotjs_jargs_t jargs = iotjs_jargs_create(2);
+ size_t jargc = 0;
+ jerry_value_t jargs[2] = { 0 };
if (status) {
- iotjs_jargs_append_error(&jargs, "System error");
+ jargs[jargc++] = iotjs_jval_create_error_without_error_flag("System error");
} else {
- if (!reqwrap->result) {
- iotjs_jargs_append_error(&jargs, iotjs_periph_error_str(reqwrap->op));
+ if (!worker_data->result) {
+ jargs[jargc++] = iotjs_jval_create_error_without_error_flag(
+ iotjs_periph_error_str(worker_data->op));
} else {
- switch (reqwrap->op) {
+ jargs[jargc++] = jerry_create_null();
+ switch (worker_data->op) {
case kAdcOpClose:
case kAdcOpOpen:
case kGpioOpClose:
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);
+ iotjs_adc_t* adc = (iotjs_adc_t*)worker_data->data;
+ jargs[jargc++] = jerry_create_number(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);
+ iotjs_gpio_t* gpio = (iotjs_gpio_t*)worker_data->data;
+ jargs[jargc++] = jerry_create_boolean(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_i2c_t* i2c = (iotjs_i2c_t*)worker_data->data;
+ jargs[jargc++] =
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);
-
+ iotjs_spi_t* spi = (iotjs_spi_t*)worker_data->data;
// Append read data
- jerry_value_t result =
+ jargs[jargc++] =
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;
}
}
#if ENABLE_MODULE_SPI
- if (reqwrap->op == kSpiOpTransferArray) {
- iotjs_spi_t* spi = (iotjs_spi_t*)reqwrap->data;
+ if (worker_data->op == kSpiOpTransferArray) {
+ iotjs_spi_t* spi = (iotjs_spi_t*)worker_data->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;
+ if (worker_data->op == kUartOpWrite) {
+ iotjs_uart_t* uart = (iotjs_uart_t*)worker_data->data;
iotjs_string_destroy(&uart->buf_data);
}
#endif /* ENABLE_MODULE_UART */
}
- jerry_value_t jcallback = iotjs_reqwrap_jcallback(&reqwrap->reqwrap);
+ jerry_value_t jcallback = *IOTJS_UV_REQUEST_JSCALLBACK(work_req);
if (jerry_value_is_function(jcallback)) {
- iotjs_make_callback(jcallback, jerry_create_undefined(), &jargs);
+ iotjs_invoke_callback(jcallback, jerry_create_undefined(), jargs, jargc);
}
- iotjs_jargs_destroy(&jargs);
- iotjs_reqwrap_destroy(&reqwrap->reqwrap);
- IOTJS_RELEASE(reqwrap);
-}
+ for (size_t i = 0; i < jargc; i++) {
+ jerry_release_value(jargs[i]);
+ }
-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;
+ iotjs_uv_request_destroy((uv_req_t*)work_req);
}
+
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);
+
+ uv_req_t* work_req = iotjs_uv_request_create(sizeof(uv_work_t), jcallback,
+ sizeof(iotjs_periph_data_t));
+ iotjs_periph_data_t* worker_data =
+ (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req);
+ worker_data->op = op;
+ worker_data->data = data;
+
+ uv_queue_work(loop, (uv_work_t*)work_req, worker, after_worker);
}
#define IOTJS_MODULE_PERIPH_COMMON_H
#include "iotjs_def.h"
-#include "iotjs_reqwrap.h"
typedef enum {
kAdcOpOpen,
} 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;
+} iotjs_periph_data_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,
*/
#include "iotjs_def.h"
+#include "iotjs_compatibility.h"
#include "iotjs_js.h"
#include "jerryscript-debugger.h"
iotjs_string_t source = JS_GET_ARG(1, string);
const char* filename = iotjs_string_data(&file);
- const iotjs_environment_t* env = iotjs_environment_get();
+#ifdef JERRY_DEBUGGER
+ const iotjs_environment_t* env = iotjs_environment_get();
if (iotjs_environment_config(env)->debugger != NULL) {
jerry_debugger_stop();
}
+#endif
jerry_value_t jres =
WrapEval(filename, strlen(filename), iotjs_string_data(&source),
}
+#ifdef JERRY_DEBUGGER
// Callback function for DebuggerGetSource
static jerry_value_t wait_for_source_callback(
const jerry_char_t* resource_name_p, size_t resource_name_size,
return ret_val;
}
+#endif
JS_FUNCTION(CompileModule) {
}
jerry_value_t native_module_jval = iotjs_module_get(name);
- if (jerry_value_has_error_flag(native_module_jval)) {
+
+ if (jerry_value_is_error(native_module_jval)) {
+ iotjs_string_destroy(&id);
return native_module_jval;
}
- jerry_value_t jexports = iotjs_jval_get_property(jmodule, "exports");
jerry_value_t jres = jerry_create_undefined();
if (js_modules[i].name != NULL) {
#ifdef ENABLE_SNAPSHOT
- jres = jerry_exec_snapshot((const void*)iotjs_js_modules_s,
- iotjs_js_modules_l, js_modules[i].idx, 0);
+ jres = jerry_exec_snapshot((const uint32_t*)iotjs_js_modules_s,
+ iotjs_js_modules_l, js_modules[i].idx,
+ JERRY_SNAPSHOT_EXEC_ALLOW_STATIC);
#else
jres = WrapEval(name, iotjs_string_size(&id),
(const char*)js_modules[i].code, js_modules[i].length);
#endif
-
- if (!jerry_value_has_error_flag(jres)) {
+ if (!jerry_value_is_error(jres)) {
+ jerry_value_t jexports = iotjs_jval_get_property(jmodule, "exports");
jerry_value_t args[] = { jexports, jrequire, jmodule,
native_module_jval };
jres = jerry_call_function(jfunc, jerry_create_undefined(), args,
sizeof(args) / sizeof(jerry_value_t));
jerry_release_value(jfunc);
+ jerry_release_value(jexports);
}
} else if (!jerry_value_is_undefined(native_module_jval)) {
iotjs_jval_set_property_jval(jmodule, "exports", native_module_jval);
} else {
- jres = iotjs_jval_create_error_without_error_flag("Unknown native module");
+ jres = JS_CREATE_ERROR(COMMON, "Unknown native module");
}
- jerry_release_value(jexports);
iotjs_string_destroy(&id);
+
return jres;
}
iotjspath = getenv(IOTJS_MAGIC_STRING_IOTJS_PATH_U);
if (iotjspath == NULL) {
-#if defined(__NUTTX__) || defined(__TIZENRT__)
+#if defined(__NUTTX__)
iotjspath = "/mnt/sdcard";
+#elif defined(__TIZENRT__)
+ iotjspath = "/rom";
#else
iotjspath = "";
#endif
CompileModule);
iotjs_jval_set_method(private, IOTJS_MAGIC_STRING_READSOURCE, ReadSource);
+#ifdef JERRY_DEBUGGER
// debugger
iotjs_jval_set_method(private, IOTJS_MAGIC_STRING_DEBUGGERGETSOURCE,
DebuggerGetSource);
wait_source_val);
jerry_release_value(wait_source_val);
+#endif
+
jerry_release_value(private);
}
// Set iotjs
SetProcessIotjs(process);
bool wait_source = false;
+#ifdef JERRY_DEBUGGER
if (iotjs_environment_config(iotjs_environment_get())->debugger != NULL) {
wait_source = iotjs_environment_config(iotjs_environment_get())
->debugger->wait_source;
}
+#endif
if (!wait_source) {
SetProcessArgv(process);
#include "iotjs_def.h"
#include "iotjs_module_pwm.h"
+#include "iotjs_uv_request.h"
IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(pwm);
}
static void pwm_worker(uv_work_t* work_req) {
- 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;
+ iotjs_periph_data_t* worker_data =
+ (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req);
+ iotjs_pwm_t* pwm = (iotjs_pwm_t*)worker_data->data;
- switch (req_wrap->op) {
+ switch (worker_data->op) {
case kPwmOpClose:
- req_wrap->result = iotjs_pwm_close(pwm);
+ worker_data->result = iotjs_pwm_close(pwm);
break;
case kPwmOpOpen:
- req_wrap->result = iotjs_pwm_open(pwm);
+ worker_data->result = iotjs_pwm_open(pwm);
break;
case kPwmOpSetDutyCycle:
- req_wrap->result = iotjs_pwm_set_dutycycle(pwm);
+ worker_data->result = iotjs_pwm_set_dutycycle(pwm);
break;
case kPwmOpSetEnable:
- req_wrap->result = iotjs_pwm_set_enable(pwm);
+ worker_data->result = iotjs_pwm_set_enable(pwm);
break;
case kPwmOpSetFrequency: /* update the period */
case kPwmOpSetPeriod:
- req_wrap->result = iotjs_pwm_set_period(pwm);
+ worker_data->result = iotjs_pwm_set_period(pwm);
break;
default:
IOTJS_ASSERT(!"Invalid Operation");
JS_GET_REQUIRED_ARG_VALUE(0, jconfig, IOTJS_MAGIC_STRING_CONFIG, object);
jerry_value_t res = iotjs_pwm_set_platform_config(pwm, jconfig);
- if (jerry_value_has_error_flag(res)) {
+ if (jerry_value_is_error(res)) {
return res;
}
IOTJS_ASSERT(jerry_value_is_undefined(res));
res = pwm_set_configuration(pwm, jconfig);
- if (jerry_value_has_error_flag(res)) {
+ if (jerry_value_is_error(res)) {
return res;
}
IOTJS_ASSERT(jerry_value_is_undefined(res));
#include "iotjs_def.h"
#include "iotjs_module_periph_common.h"
-#include "iotjs_reqwrap.h"
#if defined(__TIZENRT__)
#include <iotbus_pwm.h>
#include "iotjs_def.h"
#include "iotjs_module_spi.h"
#include "iotjs_module_buffer.h"
+#include "iotjs_uv_request.h"
IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(spi);
* SPI worker function
*/
static void spi_worker(uv_work_t* work_req) {
- 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;
+ iotjs_periph_data_t* worker_data =
+ (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req);
+ iotjs_spi_t* spi = (iotjs_spi_t*)worker_data->data;
- switch (req_wrap->op) {
+ switch (worker_data->op) {
case kSpiOpClose: {
- req_wrap->result = iotjs_spi_close(spi);
+ worker_data->result = iotjs_spi_close(spi);
break;
}
case kSpiOpOpen: {
- req_wrap->result = iotjs_spi_open(spi);
+ worker_data->result = iotjs_spi_open(spi);
break;
}
case kSpiOpTransferArray:
case kSpiOpTransferBuffer: {
- req_wrap->result = iotjs_spi_transfer(spi);
+ worker_data->result = iotjs_spi_transfer(spi);
break;
}
default:
JS_GET_REQUIRED_ARG_VALUE(0, jconfig, IOTJS_MAGIC_STRING_CONFIG, object);
jerry_value_t res = iotjs_spi_set_platform_config(spi, jconfig);
- if (jerry_value_has_error_flag(res)) {
+ if (jerry_value_is_error(res)) {
return res;
}
IOTJS_ASSERT(jerry_value_is_undefined(res));
res = spi_set_configuration(spi, jconfig);
- if (jerry_value_has_error_flag(res)) {
+ if (jerry_value_is_error(res)) {
return res;
}
IOTJS_ASSERT(jerry_value_is_undefined(res));
#include "iotjs_def.h"
#include "iotjs_module_buffer.h"
#include "iotjs_module_periph_common.h"
-#include "iotjs_reqwrap.h"
typedef enum {
#include "iotjs_def.h"
#include "iotjs_module_tcp.h"
-#include "iotjs_handlewrap.h"
#include "iotjs_module_buffer.h"
-#include "iotjs_reqwrap.h"
+#include "iotjs_uv_handle.h"
+#include "iotjs_uv_request.h"
+static const jerry_object_native_info_t this_module_native_info = { NULL };
-IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(tcpwrap);
-
-iotjs_tcpwrap_t* iotjs_tcpwrap_create(jerry_value_t jtcp) {
- iotjs_tcpwrap_t* tcpwrap = IOTJS_ALLOC(iotjs_tcpwrap_t);
-
- iotjs_handlewrap_initialize(&tcpwrap->handlewrap, jtcp,
- (uv_handle_t*)(&tcpwrap->handle),
- &this_module_native_info);
+void iotjs_tcp_object_init(jerry_value_t jtcp) {
+ // uv_tcp_t* can be handled as uv_handle_t* or even as uv_stream_t*
+ uv_handle_t* handle = iotjs_uv_handle_create(sizeof(uv_tcp_t), jtcp,
+ &this_module_native_info, 0);
const iotjs_environment_t* env = iotjs_environment_get();
- uv_tcp_init(iotjs_environment_loop(env), &tcpwrap->handle);
-
- return tcpwrap;
-}
-
-
-static void iotjs_tcpwrap_destroy(iotjs_tcpwrap_t* tcpwrap) {
- iotjs_handlewrap_destroy(&tcpwrap->handlewrap);
- IOTJS_RELEASE(tcpwrap);
-}
-
-
-iotjs_tcpwrap_t* iotjs_tcpwrap_from_handle(uv_tcp_t* tcp_handle) {
- uv_handle_t* handle = (uv_handle_t*)(tcp_handle);
- iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_handle(handle);
- iotjs_tcpwrap_t* tcpwrap = (iotjs_tcpwrap_t*)handlewrap;
- IOTJS_ASSERT(iotjs_tcpwrap_tcp_handle(tcpwrap) == tcp_handle);
- return tcpwrap;
-}
-
-
-iotjs_tcpwrap_t* iotjs_tcpwrap_from_jobject(jerry_value_t jtcp) {
- iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_jobject(jtcp);
- return (iotjs_tcpwrap_t*)handlewrap;
-}
-
-
-uv_tcp_t* iotjs_tcpwrap_tcp_handle(iotjs_tcpwrap_t* tcpwrap) {
- uv_handle_t* handle = iotjs_handlewrap_get_uv_handle(&tcpwrap->handlewrap);
- return (uv_tcp_t*)handle;
-}
-
-
-static void iotjs_connect_reqwrap_destroy(
- iotjs_connect_reqwrap_t* connect_reqwrap);
-
-
-iotjs_connect_reqwrap_t* iotjs_connect_reqwrap_create(jerry_value_t jcallback) {
- iotjs_connect_reqwrap_t* connect_reqwrap =
- IOTJS_ALLOC(iotjs_connect_reqwrap_t);
- iotjs_reqwrap_initialize(&connect_reqwrap->reqwrap, jcallback,
- (uv_req_t*)&connect_reqwrap->req);
- return connect_reqwrap;
+ uv_tcp_init(iotjs_environment_loop(env), (uv_tcp_t*)handle);
}
-static void iotjs_connect_reqwrap_destroy(
- iotjs_connect_reqwrap_t* connect_reqwrap) {
- iotjs_reqwrap_destroy(&connect_reqwrap->reqwrap);
- IOTJS_RELEASE(connect_reqwrap);
-}
-
-
-static void iotjs_write_reqwrap_destroy(iotjs_write_reqwrap_t* write_reqwrap);
-
-
-iotjs_write_reqwrap_t* iotjs_write_reqwrap_create(jerry_value_t jcallback) {
- iotjs_write_reqwrap_t* write_reqwrap = IOTJS_ALLOC(iotjs_write_reqwrap_t);
- iotjs_reqwrap_initialize(&write_reqwrap->reqwrap, jcallback,
- (uv_req_t*)&write_reqwrap->req);
- return write_reqwrap;
-}
-
-
-static void iotjs_write_reqwrap_destroy(iotjs_write_reqwrap_t* write_reqwrap) {
- iotjs_reqwrap_destroy(&write_reqwrap->reqwrap);
- IOTJS_RELEASE(write_reqwrap);
-}
-
-static void iotjs_shutdown_reqwrap_destroy(
- iotjs_shutdown_reqwrap_t* shutdown_reqwrap);
+static void iotjs_tcp_report_req_result(uv_req_t* req, int status) {
+ IOTJS_ASSERT(req != NULL);
+ // Take callback function object.
+ jerry_value_t jcallback = *IOTJS_UV_REQUEST_JSCALLBACK(req);
+ // Only parameter is status code.
+ jerry_value_t jstatus = jerry_create_number(status);
-iotjs_shutdown_reqwrap_t* iotjs_shutdown_reqwrap_create(
- jerry_value_t jcallback) {
- iotjs_shutdown_reqwrap_t* shutdown_reqwrap =
- IOTJS_ALLOC(iotjs_shutdown_reqwrap_t);
- iotjs_reqwrap_initialize(&shutdown_reqwrap->reqwrap, jcallback,
- (uv_req_t*)&shutdown_reqwrap->req);
- return shutdown_reqwrap;
-}
+ // Make callback.
+ iotjs_invoke_callback(jcallback, jerry_create_undefined(), &jstatus, 1);
+ // Destroy args
+ jerry_release_value(jstatus);
-static void iotjs_shutdown_reqwrap_destroy(
- iotjs_shutdown_reqwrap_t* shutdown_reqwrap) {
- iotjs_reqwrap_destroy(&shutdown_reqwrap->reqwrap);
- IOTJS_RELEASE(shutdown_reqwrap);
+ // Release request.
+ iotjs_uv_request_destroy(req);
}
DJS_CHECK_THIS();
jerry_value_t jtcp = JS_GET_THIS();
- iotjs_tcpwrap_create(jtcp);
+ iotjs_tcp_object_init(jtcp);
return jerry_create_undefined();
}
// Socket close result handler.
void AfterClose(uv_handle_t* handle) {
- iotjs_handlewrap_t* wrap = iotjs_handlewrap_from_handle(handle);
-
- // tcp object.
- jerry_value_t jtcp = iotjs_handlewrap_jobject(wrap);
+ jerry_value_t jtcp = IOTJS_UV_HANDLE_DATA(handle)->jobject;
// callback function.
jerry_value_t jcallback =
iotjs_jval_get_property(jtcp, IOTJS_MAGIC_STRING_ONCLOSE);
if (jerry_value_is_function(jcallback)) {
- iotjs_make_callback(jcallback, jerry_create_undefined(),
- iotjs_jargs_get_empty());
+ iotjs_invoke_callback(jcallback, jerry_create_undefined(), NULL, 0);
}
jerry_release_value(jcallback);
}
// Close socket
JS_FUNCTION(Close) {
- JS_DECLARE_THIS_PTR(handlewrap, wrap);
+ JS_DECLARE_PTR(jthis, uv_handle_t, uv_handle);
- // close uv handle, `AfterClose` will be called after socket closed.
- iotjs_handlewrap_close(wrap, AfterClose);
+ iotjs_uv_handle_close(uv_handle, AfterClose);
return jerry_create_undefined();
}
// [0] address
// [1] port
JS_FUNCTION(Bind) {
- JS_DECLARE_THIS_PTR(tcpwrap, tcp_wrap);
+ JS_DECLARE_PTR(jthis, uv_tcp_t, tcp_handle);
DJS_CHECK_ARGS(2, string, number);
int err = uv_ip4_addr(iotjs_string_data(&address), port, &addr);
if (err == 0) {
- err = uv_tcp_bind(iotjs_tcpwrap_tcp_handle(tcp_wrap),
- (const sockaddr*)(&addr), 0);
+ err = uv_tcp_bind(tcp_handle, (const sockaddr*)(&addr), 0);
}
iotjs_string_destroy(&address);
// Connection request result handler.
static void AfterConnect(uv_connect_t* req, int status) {
- iotjs_connect_reqwrap_t* req_wrap = (iotjs_connect_reqwrap_t*)(req->data);
- IOTJS_ASSERT(req_wrap != NULL);
-
- // Take callback function object.
- // function afterConnect(status)
- jerry_value_t jcallback = iotjs_reqwrap_jcallback(&req_wrap->reqwrap);
- IOTJS_ASSERT(jerry_value_is_function(jcallback));
-
- // Only parameter is status code.
- iotjs_jargs_t args = iotjs_jargs_create(1);
- iotjs_jargs_append_number(&args, status);
-
- // Make callback.
- iotjs_make_callback(jcallback, jerry_create_undefined(), &args);
-
- // Destroy args
- iotjs_jargs_destroy(&args);
-
- // Release request wrapper.
- iotjs_connect_reqwrap_destroy(req_wrap);
+ iotjs_tcp_report_req_result((uv_req_t*)req, status);
}
-
// Create a connection using the socket.
// [0] address
// [1] port
// [2] callback
JS_FUNCTION(Connect) {
- JS_DECLARE_THIS_PTR(tcpwrap, tcp_wrap);
+ JS_DECLARE_PTR(jthis, uv_tcp_t, tcp_handle);
DJS_CHECK_ARGS(3, string, number, function);
int err = uv_ip4_addr(iotjs_string_data(&address), port, &addr);
if (err == 0) {
- // Create connection request wrapper.
- iotjs_connect_reqwrap_t* req_wrap = iotjs_connect_reqwrap_create(jcallback);
+ // Create connection request and configure request data.
+ uv_req_t* req_connect =
+ iotjs_uv_request_create(sizeof(uv_connect_t), jcallback, 0);
// Create connection request.
- err = uv_tcp_connect(&req_wrap->req, iotjs_tcpwrap_tcp_handle(tcp_wrap),
+ err = uv_tcp_connect((uv_connect_t*)req_connect, tcp_handle,
(const sockaddr*)(&addr), AfterConnect);
if (err) {
- iotjs_connect_reqwrap_destroy(req_wrap);
+ iotjs_uv_request_destroy(req_connect);
}
}
// * uv_stream_t* handle - server handle
// * int status - status code
static void OnConnection(uv_stream_t* handle, int status) {
- // Server tcp wrapper.
- iotjs_tcpwrap_t* tcp_wrap = iotjs_tcpwrap_from_handle((uv_tcp_t*)handle);
-
- // Tcp object
- jerry_value_t jtcp = iotjs_handlewrap_jobject(&tcp_wrap->handlewrap);
+ jerry_value_t jtcp = IOTJS_UV_HANDLE_DATA(handle)->jobject;
// `onconnection` callback.
jerry_value_t jonconnection =
// The callback takes two parameter
// [0] status
// [1] client tcp object
- iotjs_jargs_t args = iotjs_jargs_create(2);
- iotjs_jargs_append_number(&args, status);
+ size_t argc = 1;
+ jerry_value_t args[2] = { jerry_create_number(status), 0 };
if (status == 0) {
// Create client socket handle wrapper.
IOTJS_ASSERT(jerry_value_is_function(jcreate_tcp));
jerry_value_t jclient_tcp =
- iotjs_jhelper_call(jcreate_tcp, jerry_create_undefined(),
- iotjs_jargs_get_empty());
- IOTJS_ASSERT(!jerry_value_has_error_flag(jclient_tcp));
+ jerry_call_function(jcreate_tcp, jerry_create_undefined(), NULL, 0);
+ IOTJS_ASSERT(!jerry_value_is_error(jclient_tcp));
IOTJS_ASSERT(jerry_value_is_object(jclient_tcp));
- iotjs_tcpwrap_t* tcp_wrap_client =
- (iotjs_tcpwrap_t*)(iotjs_jval_get_object_native_handle(jclient_tcp));
+ uv_handle_t* client_handle = (uv_handle_t*)
+ iotjs_jval_get_object_native_handle(jclient_tcp,
+ &this_module_native_info);
- uv_stream_t* client_handle =
- (uv_stream_t*)(iotjs_tcpwrap_tcp_handle(tcp_wrap_client));
-
- int err = uv_accept(handle, client_handle);
+ int err = uv_accept(handle, (uv_stream_t*)client_handle);
if (err) {
- iotjs_jargs_destroy(&args);
+ jerry_release_value(args[0]);
return;
}
- iotjs_jargs_append_jval(&args, jclient_tcp);
+ args[argc++] = jclient_tcp;
jerry_release_value(jcreate_tcp);
- jerry_release_value(jclient_tcp);
}
- iotjs_make_callback(jonconnection, jtcp, &args);
+ iotjs_invoke_callback(jonconnection, jtcp, args, argc);
jerry_release_value(jonconnection);
- iotjs_jargs_destroy(&args);
+ for (size_t i = 0; i < argc; i++) {
+ jerry_release_value(args[i]);
+ }
}
JS_FUNCTION(Listen) {
- JS_DECLARE_THIS_PTR(tcpwrap, tcp_wrap);
+ JS_DECLARE_PTR(jthis, uv_tcp_t, tcp_handle);
DJS_CHECK_ARGS(1, number);
int backlog = JS_GET_ARG(0, number);
-
- int err = uv_listen((uv_stream_t*)(iotjs_tcpwrap_tcp_handle(tcp_wrap)),
- backlog, OnConnection);
+ int err = uv_listen((uv_stream_t*)tcp_handle, backlog, OnConnection);
return jerry_create_number(err);
}
void AfterWrite(uv_write_t* req, int status) {
- iotjs_write_reqwrap_t* req_wrap = (iotjs_write_reqwrap_t*)(req->data);
- iotjs_tcpwrap_t* tcp_wrap = (iotjs_tcpwrap_t*)(req->handle->data);
- IOTJS_ASSERT(req_wrap != NULL);
- IOTJS_ASSERT(tcp_wrap != NULL);
-
- // Take callback function object.
- jerry_value_t jcallback = iotjs_reqwrap_jcallback(&req_wrap->reqwrap);
-
- // Only parameter is status code.
- iotjs_jargs_t args = iotjs_jargs_create(1);
- iotjs_jargs_append_number(&args, status);
-
- // Make callback.
- iotjs_make_callback(jcallback, jerry_create_undefined(), &args);
-
- // Destroy args
- iotjs_jargs_destroy(&args);
-
- // Release request wrapper.
- iotjs_write_reqwrap_destroy(req_wrap);
+ iotjs_tcp_report_req_result((uv_req_t*)req, status);
}
JS_FUNCTION(Write) {
- JS_DECLARE_THIS_PTR(tcpwrap, tcp_wrap);
+ JS_DECLARE_PTR(jthis, uv_stream_t, tcp_handle);
DJS_CHECK_ARGS(2, object, function);
const jerry_value_t jbuffer = JS_GET_ARG(0, object);
buf.len = len;
jerry_value_t arg1 = JS_GET_ARG(1, object);
- iotjs_write_reqwrap_t* req_wrap = iotjs_write_reqwrap_create(arg1);
+ uv_req_t* req_write = iotjs_uv_request_create(sizeof(uv_write_t), arg1, 0);
- int err = uv_write(&req_wrap->req,
- (uv_stream_t*)(iotjs_tcpwrap_tcp_handle(tcp_wrap)), &buf,
- 1, AfterWrite);
+ int err = uv_write((uv_write_t*)req_write, tcp_handle, &buf, 1, AfterWrite);
if (err) {
- iotjs_write_reqwrap_destroy(req_wrap);
+ iotjs_uv_request_destroy((uv_req_t*)req_write);
}
return jerry_create_number(err);
void OnRead(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
- iotjs_tcpwrap_t* tcp_wrap = iotjs_tcpwrap_from_handle((uv_tcp_t*)handle);
-
- // tcp handle
- jerry_value_t jtcp = iotjs_handlewrap_jobject(&tcp_wrap->handlewrap);
+ jerry_value_t jtcp = IOTJS_UV_HANDLE_DATA(handle)->jobject;
// socket object
jerry_value_t jsocket =
iotjs_jval_get_property(jtcp, IOTJS_MAGIC_STRING_ONREAD);
IOTJS_ASSERT(jerry_value_is_function(jonread));
- iotjs_jargs_t jargs = iotjs_jargs_create(4);
- iotjs_jargs_append_jval(&jargs, jsocket);
- iotjs_jargs_append_number(&jargs, nread);
- iotjs_jargs_append_bool(&jargs, false);
+ size_t argc = 3;
+ jerry_value_t jargs[4] = { jsocket, jerry_create_number(nread),
+ jerry_create_boolean(false), 0 };
if (nread <= 0) {
iotjs_buffer_release(buf->base);
if (nread < 0) {
if (nread == UV__EOF) {
- iotjs_jargs_replace(&jargs, 2, jerry_create_boolean(true));
+ jargs[2] = jerry_create_boolean(true);
}
- iotjs_make_callback(jonread, jerry_create_undefined(), &jargs);
+ iotjs_invoke_callback(jonread, jerry_create_undefined(), jargs, argc);
}
} else {
jerry_value_t jbuffer = iotjs_bufferwrap_create_buffer((size_t)nread);
iotjs_bufferwrap_copy(buffer_wrap, buf->base, (size_t)nread);
- iotjs_jargs_append_jval(&jargs, jbuffer);
- iotjs_make_callback(jonread, jerry_create_undefined(), &jargs);
+ jargs[argc++] = jbuffer;
+ iotjs_invoke_callback(jonread, jerry_create_undefined(), jargs, argc);
- jerry_release_value(jbuffer);
iotjs_buffer_release(buf->base);
}
- iotjs_jargs_destroy(&jargs);
+ for (uint8_t i = 0; i < argc; i++) {
+ jerry_release_value(jargs[i]);
+ }
jerry_release_value(jonread);
- jerry_release_value(jsocket);
}
JS_FUNCTION(ReadStart) {
- JS_DECLARE_THIS_PTR(tcpwrap, tcp_wrap);
+ JS_DECLARE_PTR(jthis, uv_stream_t, tcp_handle);
- int err = uv_read_start((uv_stream_t*)(iotjs_tcpwrap_tcp_handle(tcp_wrap)),
- OnAlloc, OnRead);
+ int err = uv_read_start(tcp_handle, OnAlloc, OnRead);
return jerry_create_number(err);
}
static void AfterShutdown(uv_shutdown_t* req, int status) {
- iotjs_shutdown_reqwrap_t* req_wrap = (iotjs_shutdown_reqwrap_t*)(req->data);
- iotjs_tcpwrap_t* tcp_wrap = (iotjs_tcpwrap_t*)(req->handle->data);
- IOTJS_ASSERT(req_wrap != NULL);
- IOTJS_ASSERT(tcp_wrap != NULL);
-
- // function onShutdown(status)
- jerry_value_t jonshutdown = iotjs_reqwrap_jcallback(&req_wrap->reqwrap);
- IOTJS_ASSERT(jerry_value_is_function(jonshutdown));
-
- iotjs_jargs_t args = iotjs_jargs_create(1);
- iotjs_jargs_append_number(&args, status);
-
- iotjs_make_callback(jonshutdown, jerry_create_undefined(), &args);
-
- iotjs_jargs_destroy(&args);
-
- iotjs_shutdown_reqwrap_destroy(req_wrap);
+ iotjs_tcp_report_req_result((uv_req_t*)req, status);
}
JS_FUNCTION(Shutdown) {
- JS_DECLARE_THIS_PTR(tcpwrap, tcp_wrap);
+ JS_DECLARE_PTR(jthis, uv_stream_t, tcp_handle);
DJS_CHECK_ARGS(1, function);
jerry_value_t arg0 = JS_GET_ARG(0, object);
- iotjs_shutdown_reqwrap_t* req_wrap = iotjs_shutdown_reqwrap_create(arg0);
+ uv_shutdown_t* req_shutdown =
+ (uv_shutdown_t*)iotjs_uv_request_create(sizeof(uv_shutdown_t), arg0, 0);
- int err = uv_shutdown(&req_wrap->req,
- (uv_stream_t*)(iotjs_tcpwrap_tcp_handle(tcp_wrap)),
- AfterShutdown);
+ int err = uv_shutdown(req_shutdown, tcp_handle, AfterShutdown);
if (err) {
- iotjs_shutdown_reqwrap_destroy(req_wrap);
+ iotjs_uv_request_destroy((uv_req_t*)req_shutdown);
}
return jerry_create_number(err);
// [0] enable
// [1] delay
JS_FUNCTION(SetKeepAlive) {
- JS_DECLARE_THIS_PTR(tcpwrap, tcp_wrap);
+ JS_DECLARE_PTR(jthis, uv_tcp_t, tcp_handle);
DJS_CHECK_ARGS(2, number, number);
int enable = JS_GET_ARG(0, number);
unsigned delay = JS_GET_ARG(1, number);
- int err = uv_tcp_keepalive(iotjs_tcpwrap_tcp_handle(tcp_wrap), enable, delay);
+ int err = uv_tcp_keepalive(tcp_handle, enable, delay);
return jerry_create_number(err);
}
JS_FUNCTION(GetSockeName) {
- DJS_CHECK_ARGS(1, object);
+ JS_DECLARE_PTR(jthis, uv_tcp_t, tcp_handle);
- iotjs_tcpwrap_t* wrap = iotjs_tcpwrap_from_jobject(JS_GET_THIS());
- IOTJS_ASSERT(wrap != NULL);
+ DJS_CHECK_ARGS(1, object);
sockaddr_storage storage;
int addrlen = sizeof(storage);
sockaddr* const addr = (sockaddr*)(&storage);
- int err = uv_tcp_getsockname(iotjs_tcpwrap_tcp_handle(wrap), addr, &addrlen);
+ int err = uv_tcp_getsockname(tcp_handle, addr, &addrlen);
if (err == 0)
AddressToJS(JS_GET_ARG(0, object), addr);
return jerry_create_number(err);
#include "iotjs_binding.h"
-#include "iotjs_handlewrap.h"
-#include "iotjs_reqwrap.h"
typedef struct sockaddr sockaddr;
typedef struct sockaddr_storage sockaddr_storage;
-typedef struct {
- iotjs_handlewrap_t handlewrap;
- uv_tcp_t handle;
-} iotjs_tcpwrap_t;
-
-
-iotjs_tcpwrap_t* iotjs_tcpwrap_create(jerry_value_t jtcp);
-
-iotjs_tcpwrap_t* iotjs_tcpwrap_from_handle(uv_tcp_t* handle);
-iotjs_tcpwrap_t* iotjs_tcpwrap_from_jobject(jerry_value_t jtcp);
-
-uv_tcp_t* iotjs_tcpwrap_tcp_handle(iotjs_tcpwrap_t* tcpwrap);
-
-
-typedef struct {
- iotjs_reqwrap_t reqwrap;
- uv_connect_t req;
-} iotjs_connect_reqwrap_t;
-
-iotjs_connect_reqwrap_t* iotjs_connect_reqwrap_create(jerry_value_t jcallback);
-
-
-typedef struct {
- iotjs_reqwrap_t reqwrap;
- uv_write_t req;
-} iotjs_write_reqwrap_t;
-
-iotjs_write_reqwrap_t* iotjs_write_reqwrap_create(jerry_value_t jcallback);
-
-
-typedef struct {
- iotjs_reqwrap_t reqwrap;
- uv_shutdown_t req;
-} iotjs_shutdown_reqwrap_t;
-
-iotjs_shutdown_reqwrap_t* iotjs_shutdown_reqwrap_create(
- jerry_value_t jcallback);
-
-
void AddressToJS(jerry_value_t obj, const sockaddr* addr);
*/
#include "iotjs_def.h"
-#include "iotjs_module_timer.h"
+#include "iotjs_uv_handle.h"
-static void iotjs_timerwrap_destroy(iotjs_timerwrap_t* timerwrap);
-static void iotjs_timerwrap_on_timeout(iotjs_timerwrap_t* timerwrap);
-IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(timerwrap);
+static const jerry_object_native_info_t this_module_native_info = { NULL };
-iotjs_timerwrap_t* iotjs_timerwrap_create(const jerry_value_t jtimer) {
- iotjs_timerwrap_t* timerwrap = IOTJS_ALLOC(iotjs_timerwrap_t);
- uv_timer_t* uv_timer = IOTJS_ALLOC(uv_timer_t);
+void iotjs_timer_object_init(jerry_value_t jtimer) {
+ uv_handle_t* handle = iotjs_uv_handle_create(sizeof(uv_timer_t), jtimer,
+ &this_module_native_info, 0);
- iotjs_handlewrap_initialize(&timerwrap->handlewrap, jtimer,
- (uv_handle_t*)(uv_timer),
- &this_module_native_info);
-
- // Initialize timer handler.
const iotjs_environment_t* env = iotjs_environment_get();
- uv_timer_init(iotjs_environment_loop(env), uv_timer);
-
- return timerwrap;
+ uv_timer_init(iotjs_environment_loop(env), (uv_timer_t*)handle);
}
-static void iotjs_timerwrap_destroy(iotjs_timerwrap_t* timerwrap) {
- iotjs_handlewrap_destroy(&timerwrap->handlewrap);
-
- IOTJS_RELEASE(timerwrap);
-}
-
-static void TimoutHandlerDestroy(uv_handle_t* handle) {
- IOTJS_RELEASE(handle);
-}
-
-// This function is called from uv when timeout expires.
static void TimeoutHandler(uv_timer_t* handle) {
- // Find timer wrap from handle.
- iotjs_timerwrap_t* timer_wrap = iotjs_timerwrap_from_handle(handle);
-
- // Call the timeout handler.
- iotjs_timerwrap_on_timeout(timer_wrap);
-}
-
-
-int iotjs_timerwrap_start(iotjs_timerwrap_t* timerwrap, uint64_t timeout,
- uint64_t repeat) {
- // Start uv timer.
- uv_timer_t* uv_timer =
- (uv_timer_t*)iotjs_handlewrap_get_uv_handle(&timerwrap->handlewrap);
- return uv_timer_start(uv_timer, TimeoutHandler, timeout, repeat);
-}
-
-
-int iotjs_timerwrap_stop(iotjs_timerwrap_t* timerwrap) {
- if (!uv_is_closing(iotjs_handlewrap_get_uv_handle(&timerwrap->handlewrap))) {
- iotjs_handlewrap_close(&timerwrap->handlewrap, TimoutHandlerDestroy);
- }
-
- return 0;
-}
-
+ IOTJS_ASSERT(handle != NULL);
-static void iotjs_timerwrap_on_timeout(iotjs_timerwrap_t* timerwrap) {
- // Call javascript timeout handler function.
- jerry_value_t jobject = iotjs_timerwrap_jobject(timerwrap);
+ jerry_value_t jobject = IOTJS_UV_HANDLE_DATA(handle)->jobject;
jerry_value_t jcallback =
iotjs_jval_get_property(jobject, IOTJS_MAGIC_STRING_HANDLETIMEOUT);
- iotjs_make_callback(jcallback, jobject, iotjs_jargs_get_empty());
+ iotjs_invoke_callback(jcallback, jobject, NULL, 0);
jerry_release_value(jcallback);
}
-uv_timer_t* iotjs_timerwrap_handle(iotjs_timerwrap_t* timerwrap) {
- return (uv_timer_t*)iotjs_handlewrap_get_uv_handle(&timerwrap->handlewrap);
-}
-
-
-jerry_value_t iotjs_timerwrap_jobject(iotjs_timerwrap_t* timerwrap) {
- jerry_value_t jobject = iotjs_handlewrap_jobject(&timerwrap->handlewrap);
- IOTJS_ASSERT(jerry_value_is_object(jobject));
- return jobject;
-}
-
-
-iotjs_timerwrap_t* iotjs_timerwrap_from_handle(uv_timer_t* timer_handle) {
- uv_handle_t* handle = (uv_handle_t*)(timer_handle);
- iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_handle(handle);
- iotjs_timerwrap_t* timerwrap = (iotjs_timerwrap_t*)handlewrap;
- IOTJS_ASSERT(iotjs_timerwrap_handle(timerwrap) == timer_handle);
- return timerwrap;
-}
-
-
-iotjs_timerwrap_t* iotjs_timerwrap_from_jobject(const jerry_value_t jtimer) {
- iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_jobject(jtimer);
- return (iotjs_timerwrap_t*)handlewrap;
-}
-
-
JS_FUNCTION(Start) {
// Check parameters.
- JS_DECLARE_THIS_PTR(timerwrap, timer_wrap);
+ JS_DECLARE_PTR(jthis, uv_timer_t, timer_handle);
DJS_CHECK_ARGS(2, number, number);
// parameters.
uint64_t repeat = JS_GET_ARG(1, number);
// Start timer.
- int res = iotjs_timerwrap_start(timer_wrap, timeout, repeat);
+ int res = uv_timer_start(timer_handle, TimeoutHandler, timeout, repeat);
return jerry_create_number(res);
}
JS_FUNCTION(Stop) {
- JS_DECLARE_THIS_PTR(timerwrap, timer_wrap);
+ JS_DECLARE_PTR(jthis, uv_handle_t, timer_handle);
// Stop timer.
- int res = iotjs_timerwrap_stop(timer_wrap);
- return jerry_create_number(res);
+ if (!uv_is_closing(timer_handle)) {
+ iotjs_uv_handle_close(timer_handle, NULL);
+ }
+
+ return jerry_create_number(0);
}
const jerry_value_t jtimer = JS_GET_THIS();
- iotjs_timerwrap_t* timer_wrap = iotjs_timerwrap_create(jtimer);
-
- jerry_value_t jobject = iotjs_timerwrap_jobject(timer_wrap);
- IOTJS_ASSERT(jerry_value_is_object(jobject));
- IOTJS_ASSERT(iotjs_jval_get_object_native_handle(jtimer) != 0);
-
+ iotjs_timer_object_init(jtimer);
return jerry_create_undefined();
}
+++ /dev/null
-/* 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.
- */
-
-#ifndef IOTJS_MODULE_TIMER_H
-#define IOTJS_MODULE_TIMER_H
-
-
-#include "iotjs_binding.h"
-#include "iotjs_handlewrap.h"
-
-
-typedef struct { iotjs_handlewrap_t handlewrap; } iotjs_timerwrap_t;
-
-
-iotjs_timerwrap_t* iotjs_timerwrap_create(const jerry_value_t jtimer);
-
-iotjs_timerwrap_t* iotjs_timerwrap_from_jobject(const jerry_value_t jtimer);
-iotjs_timerwrap_t* iotjs_timerwrap_from_handle(uv_timer_t* timer_handle);
-
-uv_timer_t* iotjs_timerwrap_handle(iotjs_timerwrap_t* timerwrap);
-jerry_value_t iotjs_timerwrap_jobject(iotjs_timerwrap_t* timerwrap);
-
-// Start timer.
-int iotjs_timerwrap_start(iotjs_timerwrap_t* timerwrap, uint64_t timeout,
- uint64_t repeat);
-// Stop & close timer.
-int iotjs_timerwrap_stop(iotjs_timerwrap_t* timerwrap);
-
-
-#endif /* IOTJS_MODULE_TIMER_H */
// 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);
+ iotjs_string_t cert_string;
+ iotjs_string_t key_string;
+
+ if (iotjs_jbuffer_as_string(jcert, &cert_string)) {
+ const char *cert_chars = iotjs_string_data(&cert_string);
ret = mbedtls_x509_crt_parse(&tls_context->own_cert,
(const unsigned char *)cert_chars,
- (size_t)iotjs_string_size(&cert) + 1);
+ (size_t)iotjs_string_size(&cert_string) + 1);
- iotjs_string_destroy(&cert);
+ iotjs_string_destroy(&cert_string);
- if (ret == 0) {
- iotjs_string_t key = iotjs_jval_as_string(jkey);
- const char *key_chars = iotjs_string_data(&key);
+ if (ret == 0 && iotjs_jbuffer_as_string(jkey, &key_string)) {
+ const char *key_chars = iotjs_string_data(&key_string);
ret = mbedtls_pk_parse_key(&tls_context->pkey,
(const unsigned char *)key_chars,
- (size_t)iotjs_string_size(&key) + 1, NULL, 0);
+ (size_t)iotjs_string_size(&key_string) + 1,
+ NULL, 0);
- iotjs_string_destroy(&key);
+ iotjs_string_destroy(&key_string);
if (ret == 0) {
+ // Both own_cert and pkey must be valid for setting this flag.
tls_context->context_flags |= SSL_CONTEXT_HAS_KEY;
}
+ } else {
+ ret = -1;
}
+ } else if (!jerry_value_is_undefined(jcert) ||
+ !jerry_value_is_undefined(jkey)) {
+ ret = -1;
}
jerry_release_value(jcert);
// User provided trusted certificates
jerry_value_t jcert_auth =
iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_CA);
+ iotjs_string_t cert_auth_string;
- 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);
+ if (iotjs_jbuffer_as_string(jcert_auth, &cert_auth_string)) {
+ const char *cert_auth_chars = iotjs_string_data(&cert_auth_string);
ret = mbedtls_x509_crt_parse(&tls_context->cert_auth,
(const unsigned char *)cert_auth_chars,
- (size_t)iotjs_string_size(&cert_auth) + 1);
+ (size_t)iotjs_string_size(&cert_auth_string) +
+ 1);
- iotjs_string_destroy(&cert_auth);
+ iotjs_string_destroy(&cert_auth_string);
+ } else if (!jerry_value_is_undefined(jcert_auth)) {
+ ret = -1;
} else {
// Parse the default certificate authority
ret = mbedtls_x509_crt_parse(&tls_context->cert_auth,
// 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) {
+ iotjs_tls_context_t *tls_context = (iotjs_tls_context_t *)
+ iotjs_jval_get_object_native_handle(jtls_context,
+ &tls_context_native_info);
+ if (tls_context == NULL) {
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 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);
+ iotjs_invoke_callback(fn, jthis, &jbuffer, 1);
jerry_release_value(fn);
jerry_release_value(jbuffer);
- iotjs_jargs_destroy(&jargv);
}
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_value_t jargv[2] = { jerror, jmessage };
+ iotjs_invoke_callback(fn, jthis, jargv, 2);
jerry_release_value(fn);
- iotjs_jargs_destroy(&jargv);
+ jerry_release_value(jargv[0]);
+ jerry_release_value(jargv[1]);
}
if (ret_val > 0) {
data += ret_val;
- length -= ret_val;
+ length -= (size_t)ret_val;
} else if (ret_val != MBEDTLS_ERR_SSL_WANT_WRITE) {
tls_data->state = TLS_CLOSED;
return jerry_create_null();
}
// 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 jargv[2] = { jerry_create_boolean(error),
+ jerry_create_boolean(authorized) };
jerry_value_t fn =
iotjs_jval_get_property(jthis, IOTJS_MAGIC_STRING_ONHANDSHAKEDONE);
- iotjs_make_callback(fn, jthis, &jargv);
+ iotjs_invoke_callback(fn, jthis, jargv, 2);
jerry_release_value(fn);
- iotjs_jargs_destroy(&jargv);
+ jerry_release_value(jargv[0]);
+ jerry_release_value(jargv[1]);
}
copy_size = length;
}
- iotjs_bio_write(receive_bio, data, length);
+ iotjs_bio_write(receive_bio, data, copy_size);
data += copy_size;
length -= copy_size;
IOTJS_ASSERT(tls_data->state == TLS_HANDSHAKE_IN_PROGRESS ||
tls_data->state == TLS_CLOSED);
+ if (length > 0 && tls_data->state == TLS_HANDSHAKE_IN_PROGRESS) {
+ continue;
+ }
+
bool result = (tls_data->state != TLS_CLOSED);
return jerry_create_boolean(result);
}
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);
+ iotjs_invoke_callback(fn, jthis, &jbuffer, 1);
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);
+ break;
}
if (ret_val == MBEDTLS_ERR_SSL_WANT_WRITE) {
#include <unistd.h>
#include "iotjs_def.h"
+#include "iotjs_module_buffer.h"
#include "iotjs_module_uart.h"
+#include "iotjs_uv_handle.h"
+#include "iotjs_uv_request.h"
-IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(uart);
+static void iotjs_uart_object_destroy(uv_handle_t* handle);
-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);
+static const jerry_object_native_info_t this_module_native_info = {
+ .free_cb = (jerry_object_native_free_callback_t)iotjs_uart_object_destroy,
+};
- iotjs_handlewrap_initialize(&uart->handlewrap, juart,
- (uv_handle_t*)(&uart->poll_handle),
- &this_module_native_info);
- uart->device_fd = -1;
- return uart;
-}
+void iotjs_uart_object_destroy(uv_handle_t* handle) {
+ iotjs_uart_t* uart = (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(handle);
-static void iotjs_uart_destroy(iotjs_uart_t* uart) {
- iotjs_handlewrap_destroy(&uart->handlewrap);
iotjs_uart_destroy_platform_data(uart->platform_data);
- IOTJS_RELEASE(uart);
}
+
static void uart_worker(uv_work_t* work_req) {
- 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;
+ iotjs_periph_data_t* worker_data =
+ (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req);
+ uv_handle_t* uart_poll_handle = (uv_handle_t*)worker_data->data;
- switch (req_wrap->op) {
+ switch (worker_data->op) {
case kUartOpOpen:
- req_wrap->result = iotjs_uart_open(uart);
+ worker_data->result = iotjs_uart_open(uart_poll_handle);
break;
case kUartOpWrite:
- req_wrap->result = iotjs_uart_write(uart);
+ worker_data->result = iotjs_uart_write(uart_poll_handle);
break;
case kUartOpClose:
- iotjs_handlewrap_close(&uart->handlewrap, iotjs_uart_handlewrap_close_cb);
- req_wrap->result = true;
+ iotjs_uv_handle_close(uart_poll_handle, iotjs_uart_handle_close_cb);
+ worker_data->result = true;
break;
default:
IOTJS_ASSERT(!"Invalid Operation");
int i = read(uart->device_fd, buf, UART_WRITE_BUFFER_SIZE - 1);
if (i > 0) {
buf[i] = '\0';
- DDDLOG("%s - read data: %s", __func__, buf);
+ DDDLOG("%s - read length: %d", __func__, i);
+ jerry_value_t juart = IOTJS_UV_HANDLE_DATA(req)->jobject;
jerry_value_t jemit =
- iotjs_jval_get_property(iotjs_handlewrap_jobject(&uart->handlewrap),
- IOTJS_MAGIC_STRING_EMIT);
+ iotjs_jval_get_property(juart, IOTJS_MAGIC_STRING_EMIT);
IOTJS_ASSERT(jerry_value_is_function(jemit));
- iotjs_jargs_t jargs = iotjs_jargs_create(2);
jerry_value_t str =
jerry_create_string((const jerry_char_t*)IOTJS_MAGIC_STRING_DATA);
- jerry_value_t data = jerry_create_string((const jerry_char_t*)buf);
- iotjs_jargs_append_jval(&jargs, str);
- iotjs_jargs_append_jval(&jargs, data);
+
+ jerry_value_t jbuf = iotjs_bufferwrap_create_buffer((size_t)i);
+ iotjs_bufferwrap_t* buf_wrap = iotjs_bufferwrap_from_jbuffer(jbuf);
+ iotjs_bufferwrap_copy(buf_wrap, buf, (size_t)i);
+
+ jerry_value_t jargs[] = { str, jbuf };
jerry_value_t jres =
- iotjs_jhelper_call(jemit, iotjs_handlewrap_jobject(&uart->handlewrap),
- &jargs);
- IOTJS_ASSERT(!jerry_value_has_error_flag(jres));
+ jerry_call_function(jemit, IOTJS_UV_HANDLE_DATA(req)->jobject, jargs,
+ 2);
+ IOTJS_ASSERT(!jerry_value_is_error(jres));
jerry_release_value(jres);
jerry_release_value(str);
- jerry_release_value(data);
- iotjs_jargs_destroy(&jargs);
+ jerry_release_value(jbuf);
jerry_release_value(jemit);
}
}
-void iotjs_uart_register_read_cb(iotjs_uart_t* uart) {
- uv_poll_t* poll_handle = &uart->poll_handle;
+void iotjs_uart_register_read_cb(uv_poll_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get());
- uv_poll_init(loop, poll_handle, uart->device_fd);
- poll_handle->data = uart;
- uv_poll_start(poll_handle, UV_READABLE, iotjs_uart_read_cb);
+ uv_poll_init(loop, uart_poll_handle, uart->device_fd);
+ uv_poll_start(uart_poll_handle, UV_READABLE, iotjs_uart_read_cb);
}
static jerry_value_t uart_set_configuration(iotjs_uart_t* uart,
DJS_CHECK_ARG_IF_EXIST(1, function);
// Create UART object
- jerry_value_t juart = JS_GET_THIS();
- iotjs_uart_t* uart = uart_create(juart);
+ const jerry_value_t juart = JS_GET_THIS();
+ uv_handle_t* uart_poll_handle =
+ iotjs_uv_handle_create(sizeof(uv_poll_t), juart, &this_module_native_info,
+ sizeof(iotjs_uart_t));
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
+ // TODO: merge platform data allocation into the handle allocation.
+ iotjs_uart_create_platform_data(uart);
+ uart->device_fd = -1;
jerry_value_t jconfig = JS_GET_ARG(0, object);
// set configuration
jerry_value_t res = iotjs_uart_set_platform_config(uart, jconfig);
- if (jerry_value_has_error_flag(res)) {
+ if (jerry_value_is_error(res)) {
return res;
}
res = uart_set_configuration(uart, jconfig);
- if (jerry_value_has_error_flag(res)) {
+ if (jerry_value_is_error(res)) {
return res;
}
// If the callback doesn't exist, it is completed synchronously.
// Otherwise, it will be executed asynchronously.
if (!jerry_value_is_null(jcallback)) {
- iotjs_periph_call_async(uart, jcallback, kUartOpOpen, uart_worker);
- } else if (!iotjs_uart_open(uart)) {
+ iotjs_periph_call_async(uart_poll_handle, jcallback, kUartOpOpen,
+ uart_worker);
+ } else if (!iotjs_uart_open(uart_poll_handle)) {
return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kUartOpOpen));
}
}
JS_FUNCTION(Write) {
- JS_DECLARE_THIS_PTR(uart, uart);
+ JS_DECLARE_PTR(jthis, uv_poll_t, uart_poll_handle);
DJS_CHECK_ARGS(1, string);
DJS_CHECK_ARG_IF_EXIST(1, function);
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
uart->buf_data = JS_GET_ARG(0, string);
uart->buf_len = iotjs_string_size(&uart->buf_data);
- iotjs_periph_call_async(uart, JS_GET_ARG_IF_EXIST(1, function), kUartOpWrite,
- uart_worker);
+ iotjs_periph_call_async(uart_poll_handle, JS_GET_ARG_IF_EXIST(1, function),
+ kUartOpWrite, uart_worker);
return jerry_create_undefined();
}
JS_FUNCTION(WriteSync) {
- JS_DECLARE_THIS_PTR(uart, uart);
+ JS_DECLARE_PTR(jthis, uv_handle_t, uart_poll_handle);
DJS_CHECK_ARGS(1, string);
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
uart->buf_data = JS_GET_ARG(0, string);
uart->buf_len = iotjs_string_size(&uart->buf_data);
- bool result = iotjs_uart_write(uart);
+ bool result = iotjs_uart_write(uart_poll_handle);
iotjs_string_destroy(&uart->buf_data);
if (!result) {
}
JS_FUNCTION(Close) {
- JS_DECLARE_THIS_PTR(uart, uart);
+ JS_DECLARE_PTR(jthis, uv_poll_t, uart_poll_handle);
DJS_CHECK_ARG_IF_EXIST(0, function);
- iotjs_periph_call_async(uart, JS_GET_ARG_IF_EXIST(0, function), kUartOpClose,
- uart_worker);
+ iotjs_periph_call_async(uart_poll_handle, JS_GET_ARG_IF_EXIST(0, function),
+ kUartOpClose, uart_worker);
return jerry_create_undefined();
}
JS_FUNCTION(CloseSync) {
- JS_DECLARE_THIS_PTR(uart, uart);
+ JS_DECLARE_PTR(jthis, uv_handle_t, uart_poll_handle);
- iotjs_handlewrap_close(&uart->handlewrap, iotjs_uart_handlewrap_close_cb);
+ iotjs_uv_handle_close(uart_poll_handle, iotjs_uart_handle_close_cb);
return jerry_create_undefined();
}
#define IOTJS_MODULE_UART_H
#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 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 buf_data;
unsigned buf_len;
- uv_poll_t poll_handle;
-} iotjs_uart_t;
-jerry_value_t iotjs_uart_set_platform_config(iotjs_uart_t* uart,
- const jerry_value_t jconfig);
+ iotjs_uart_platform_data_t* platform_data;
+} iotjs_uart_t;
-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_handle_close_cb(uv_handle_t* handle);
+void iotjs_uart_register_read_cb(uv_poll_t* uart_poll_handle);
void iotjs_uart_create_platform_data(iotjs_uart_t* uart);
+jerry_value_t iotjs_uart_set_platform_config(iotjs_uart_t* uart,
+ const jerry_value_t jconfig);
void iotjs_uart_destroy_platform_data(iotjs_uart_platform_data_t* pdata);
+bool iotjs_uart_open(uv_handle_t* uart_poll_handle);
+bool iotjs_uart_write(uv_handle_t* uart_poll_handle);
+
#endif /* IOTJS_MODULE_UART_H */
#include "iotjs_def.h"
-#include "iotjs_module_udp.h"
-
-#include "iotjs_handlewrap.h"
#include "iotjs_module_buffer.h"
#include "iotjs_module_tcp.h"
-#include "iotjs_reqwrap.h"
-
+#include "iotjs_uv_handle.h"
+#include "iotjs_uv_request.h"
-IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(udpwrap);
+static const jerry_object_native_info_t this_module_native_info = { NULL };
-iotjs_udpwrap_t* iotjs_udpwrap_create(jerry_value_t judp) {
- iotjs_udpwrap_t* udpwrap = IOTJS_ALLOC(iotjs_udpwrap_t);
- iotjs_handlewrap_initialize(&udpwrap->handlewrap, judp,
- (uv_handle_t*)(&udpwrap->handle),
- &this_module_native_info);
+void iotjs_udp_object_init(jerry_value_t judp) {
+ uv_handle_t* handle = iotjs_uv_handle_create(sizeof(uv_udp_t), judp,
+ &this_module_native_info, 0);
const iotjs_environment_t* env = iotjs_environment_get();
- uv_udp_init(iotjs_environment_loop(env), &udpwrap->handle);
-
- return udpwrap;
-}
-
-
-static void iotjs_udpwrap_destroy(iotjs_udpwrap_t* udpwrap) {
- iotjs_handlewrap_destroy(&udpwrap->handlewrap);
- IOTJS_RELEASE(udpwrap);
-}
-
-
-iotjs_udpwrap_t* iotjs_udpwrap_from_handle(uv_udp_t* udp_handle) {
- uv_handle_t* handle = (uv_handle_t*)(udp_handle);
- iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_handle(handle);
- iotjs_udpwrap_t* udpwrap = (iotjs_udpwrap_t*)handlewrap;
- IOTJS_ASSERT(iotjs_udpwrap_udp_handle(udpwrap) == udp_handle);
- return udpwrap;
-}
-
-
-iotjs_udpwrap_t* iotjs_udpwrap_from_jobject(jerry_value_t judp) {
- iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_jobject(judp);
- return (iotjs_udpwrap_t*)handlewrap;
-}
-
-
-uv_udp_t* iotjs_udpwrap_udp_handle(iotjs_udpwrap_t* udpwrap) {
- uv_handle_t* handle = iotjs_handlewrap_get_uv_handle(&udpwrap->handlewrap);
- return (uv_udp_t*)handle;
-}
-
-
-iotjs_send_reqwrap_t* iotjs_send_reqwrap_create(jerry_value_t jcallback,
- const size_t msg_size) {
- iotjs_send_reqwrap_t* send_reqwrap = IOTJS_ALLOC(iotjs_send_reqwrap_t);
-
- iotjs_reqwrap_initialize(&send_reqwrap->reqwrap, jcallback,
- (uv_req_t*)&send_reqwrap->req);
- send_reqwrap->msg_size = msg_size;
-
- return send_reqwrap;
-}
-
-
-static void iotjs_send_reqwrap_destroy(iotjs_send_reqwrap_t* send_reqwrap) {
- iotjs_reqwrap_destroy(&send_reqwrap->reqwrap);
- IOTJS_RELEASE(send_reqwrap);
+ uv_udp_init(iotjs_environment_loop(env), (uv_udp_t*)handle);
}
DJS_CHECK_THIS();
jerry_value_t judp = JS_GET_THIS();
- iotjs_udpwrap_create(judp);
+ iotjs_udp_object_init(judp);
return jerry_create_undefined();
}
JS_FUNCTION(Bind) {
- JS_DECLARE_THIS_PTR(udpwrap, udp_wrap);
+ JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle);
DJS_CHECK_ARGS(2, string, number);
iotjs_string_t address = JS_GET_ARG(0, string);
uv_ip4_addr(iotjs_string_data(&address), port, (sockaddr_in*)(&addr));
if (err == 0) {
- err = uv_udp_bind(iotjs_udpwrap_udp_handle(udp_wrap),
- (const sockaddr*)(&addr), flags);
+ err = uv_udp_bind(udp_handle, (const sockaddr*)(&addr), flags);
}
jerry_release_value(reuse_addr);
return;
}
- iotjs_udpwrap_t* udp_wrap = iotjs_udpwrap_from_handle(handle);
-
// udp handle
- jerry_value_t judp = iotjs_handlewrap_jobject(&udp_wrap->handlewrap);
+ jerry_value_t judp = IOTJS_UV_HANDLE_DATA(handle)->jobject;
IOTJS_ASSERT(jerry_value_is_object(judp));
// onmessage callback
iotjs_jval_get_property(judp, IOTJS_MAGIC_STRING_ONMESSAGE);
IOTJS_ASSERT(jerry_value_is_function(jonmessage));
- iotjs_jargs_t jargs = iotjs_jargs_create(4);
- iotjs_jargs_append_number(&jargs, nread);
- iotjs_jargs_append_jval(&jargs, judp);
+ jerry_value_t jargs[4] = { jerry_create_number(nread),
+ jerry_acquire_value(judp), jerry_create_null(),
+ jerry_create_object() };
if (nread < 0) {
iotjs_buffer_release(buf->base);
- iotjs_make_callback(jonmessage, jerry_create_undefined(), &jargs);
+ iotjs_invoke_callback(jonmessage, jerry_create_undefined(), jargs, 2);
jerry_release_value(jonmessage);
- iotjs_jargs_destroy(&jargs);
+
+ for (int i = 0; i < 4; i++) {
+ jerry_release_value(jargs[i]);
+ }
return;
}
- jerry_value_t jbuffer = iotjs_bufferwrap_create_buffer((size_t)nread);
- iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer);
-
+ jargs[2] = iotjs_bufferwrap_create_buffer((size_t)nread);
+ iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jargs[2]);
iotjs_bufferwrap_copy(buffer_wrap, buf->base, (size_t)nread);
+ AddressToJS(jargs[3], addr);
- iotjs_jargs_append_jval(&jargs, jbuffer);
-
- jerry_value_t rinfo = jerry_create_object();
- AddressToJS(rinfo, addr);
- iotjs_jargs_append_jval(&jargs, rinfo);
+ iotjs_invoke_callback(jonmessage, jerry_create_undefined(), jargs, 4);
- iotjs_make_callback(jonmessage, jerry_create_undefined(), &jargs);
-
- jerry_release_value(rinfo);
- jerry_release_value(jbuffer);
jerry_release_value(jonmessage);
iotjs_buffer_release(buf->base);
- iotjs_jargs_destroy(&jargs);
+
+ for (int i = 0; i < 4; i++) {
+ jerry_release_value(jargs[i]);
+ }
}
JS_FUNCTION(RecvStart) {
- JS_DECLARE_THIS_PTR(udpwrap, udp_wrap);
+ JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle);
- int err =
- uv_udp_recv_start(iotjs_udpwrap_udp_handle(udp_wrap), OnAlloc, OnRecv);
+ int err = uv_udp_recv_start(udp_handle, OnAlloc, OnRecv);
// UV_EALREADY means that the socket is already bound but that's okay
if (err == UV_EALREADY)
JS_FUNCTION(RecvStop) {
- JS_DECLARE_THIS_PTR(udpwrap, udp_wrap);
+ JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle);
- int r = uv_udp_recv_stop(iotjs_udpwrap_udp_handle(udp_wrap));
+ int r = uv_udp_recv_stop(udp_handle);
return jerry_create_number(r);
}
static void OnSend(uv_udp_send_t* req, int status) {
- iotjs_send_reqwrap_t* req_wrap = (iotjs_send_reqwrap_t*)(req->data);
- IOTJS_ASSERT(req_wrap != NULL);
+ IOTJS_ASSERT(req != NULL);
// Take callback function object.
- jerry_value_t jcallback = iotjs_reqwrap_jcallback(&req_wrap->reqwrap);
+ jerry_value_t jcallback = *IOTJS_UV_REQUEST_JSCALLBACK(req);
if (jerry_value_is_function(jcallback)) {
- // Take callback function object.
+ size_t msg_size = *((size_t*)IOTJS_UV_REQUEST_EXTRA_DATA(req));
+ jerry_value_t jargs[2] = { jerry_create_number(status),
+ jerry_create_number(msg_size) };
- iotjs_jargs_t jargs = iotjs_jargs_create(2);
- iotjs_jargs_append_number(&jargs, status);
- iotjs_jargs_append_number(&jargs, req_wrap->msg_size);
-
- iotjs_make_callback(jcallback, jerry_create_undefined(), &jargs);
- iotjs_jargs_destroy(&jargs);
+ iotjs_invoke_callback(jcallback, jerry_create_undefined(), jargs, 2);
+ jerry_release_value(jargs[0]);
+ jerry_release_value(jargs[1]);
}
- iotjs_send_reqwrap_destroy(req_wrap);
+ iotjs_uv_request_destroy((uv_req_t*)req);
}
// [2] ip
// [3] callback function
JS_FUNCTION(Send) {
- JS_DECLARE_THIS_PTR(udpwrap, udp_wrap);
+ JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle);
DJS_CHECK_ARGS(3, object, number, string);
IOTJS_ASSERT(jerry_value_is_function(jargv[3]) ||
jerry_value_is_undefined(jargv[3]));
iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer);
size_t len = iotjs_bufferwrap_length(buffer_wrap);
- iotjs_send_reqwrap_t* req_wrap = iotjs_send_reqwrap_create(jcallback, len);
+ uv_req_t* req_send =
+ iotjs_uv_request_create(sizeof(uv_udp_send_t), jcallback, sizeof(len));
+ *((size_t*)IOTJS_UV_REQUEST_EXTRA_DATA(req_send)) = len;
uv_buf_t buf;
buf.base = buffer_wrap->buffer;
uv_ip4_addr(iotjs_string_data(&address), port, (sockaddr_in*)(&addr));
if (err == 0) {
- err = uv_udp_send(&req_wrap->req, iotjs_udpwrap_udp_handle(udp_wrap), &buf,
- 1, (const sockaddr*)(&addr), OnSend);
+ err = uv_udp_send((uv_udp_send_t*)req_send, udp_handle, &buf, 1,
+ (const sockaddr*)(&addr), OnSend);
}
if (err) {
- iotjs_send_reqwrap_destroy(req_wrap);
+ iotjs_uv_request_destroy(req_send);
}
iotjs_string_destroy(&address);
// Close socket
JS_FUNCTION(Close) {
- JS_DECLARE_THIS_PTR(handlewrap, wrap);
+ JS_DECLARE_PTR(jthis, uv_handle_t, uv_handle);
- iotjs_handlewrap_close(wrap, NULL);
+ iotjs_uv_handle_close(uv_handle, NULL);
return jerry_create_undefined();
}
JS_FUNCTION(GetSockeName) {
+ JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle);
DJS_CHECK_ARGS(1, object);
- iotjs_udpwrap_t* wrap = iotjs_udpwrap_from_jobject(JS_GET_THIS());
- IOTJS_ASSERT(wrap != NULL);
sockaddr_storage storage;
int addrlen = sizeof(storage);
sockaddr* const addr = (sockaddr*)(&storage);
- int err = uv_udp_getsockname(iotjs_udpwrap_udp_handle(wrap), addr, &addrlen);
+ int err = uv_udp_getsockname(udp_handle, addr, &addrlen);
if (err == 0)
AddressToJS(JS_GET_ARG(0, object), addr);
return jerry_create_number(err);
}
-#define IOTJS_UV_SET_SOCKOPT(fn) \
- JS_DECLARE_THIS_PTR(udpwrap, udp_wrap); \
- DJS_CHECK_ARGS(1, number); \
- \
- int flag = JS_GET_ARG(0, number); \
- int err = fn(iotjs_udpwrap_udp_handle(udp_wrap), flag); \
- \
- return jerry_create_number(err);
-
-
-JS_FUNCTION(SetBroadcast) {
-#if !defined(__NUTTX__)
- IOTJS_UV_SET_SOCKOPT(uv_udp_set_broadcast);
-#else
- IOTJS_ASSERT(!"Not implemented");
-
- return jerry_create_null();
-#endif
-}
-
-
-JS_FUNCTION(SetTTL) {
-#if !defined(__NUTTX__)
- IOTJS_UV_SET_SOCKOPT(uv_udp_set_ttl);
-#else
- IOTJS_ASSERT(!"Not implemented");
-
- return jerry_create_null();
-#endif
-}
-
-
-JS_FUNCTION(SetMulticastTTL) {
-#if !defined(__NUTTX__)
- IOTJS_UV_SET_SOCKOPT(uv_udp_set_multicast_ttl);
-#else
- IOTJS_ASSERT(!"Not implemented");
+// The order of these config types must match the order
+// in the dgram js module.
+enum config_type { BROADCAST, TTL, MULTICASTTTL, MULTICASTLOOPBACK };
- return jerry_create_null();
-#endif
-}
+JS_FUNCTION(Configure) {
+ JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle);
+ DJS_CHECK_ARGS(2, number, number);
+ jerry_value_t ret_value = jerry_create_null();
-JS_FUNCTION(SetMulticastLoopback) {
#if !defined(__NUTTX__)
- IOTJS_UV_SET_SOCKOPT(uv_udp_set_multicast_loop);
+ enum config_type type = JS_GET_ARG(0, number);
+ int flag = JS_GET_ARG(1, number);
+ int (*fn)(uv_udp_t*, int) = NULL;
+
+ switch (type) {
+ case BROADCAST: {
+ fn = &uv_udp_set_broadcast;
+ break;
+ }
+ case TTL: {
+ fn = &uv_udp_set_ttl;
+ break;
+ }
+ case MULTICASTTTL: {
+ fn = &uv_udp_set_multicast_ttl;
+ break;
+ }
+ case MULTICASTLOOPBACK: {
+ fn = &uv_udp_set_multicast_loop;
+ break;
+ }
+ default: {
+ IOTJS_ASSERT(!"Unknown config type");
+ return jerry_create_null();
+ }
+ }
+ ret_value = jerry_create_number(fn(udp_handle, flag));
#else
IOTJS_ASSERT(!"Not implemented");
-
- return jerry_create_null();
#endif
+ return ret_value;
}
-#undef IOTJS_UV_SET_SOCKOPT
-
static jerry_value_t SetMembership(const jerry_value_t jthis,
const jerry_value_t* jargv,
const jerry_length_t jargc,
uv_membership membership) {
#if !defined(__NUTTX__)
- JS_DECLARE_THIS_PTR(udpwrap, udp_wrap);
+ JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle);
DJS_CHECK_ARGS(1, string);
iotjs_string_t address = JS_GET_ARG(0, string);
iface_cstr = iotjs_string_data(&iface);
}
- int err = uv_udp_set_membership(iotjs_udpwrap_udp_handle(udp_wrap),
- iotjs_string_data(&address), iface_cstr,
- membership);
+ int err = uv_udp_set_membership(udp_handle, iotjs_string_data(&address),
+ iface_cstr, membership);
if (!isUndefinedOrNull)
iotjs_string_destroy(&iface);
iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CLOSE, Close);
iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_GETSOCKNAME,
GetSockeName);
- iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_SETBROADCAST,
- SetBroadcast);
- iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_SETTTL, SetTTL);
- iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_SETMULTICASTTTL,
- SetMulticastTTL);
- iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_SETMULTICASTLOOPBACK,
- SetMulticastLoopback);
+ iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CONFIGURE, Configure);
iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_ADDMEMBERSHIP,
AddMembership);
iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_DROPMEMBERSHIP,
+++ /dev/null
-/* 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.
- */
-
-
-#ifndef IOTJS_MODULE_UDP_H
-#define IOTJS_MODULE_UDP_H
-
-
-#include "iotjs_def.h"
-#include "iotjs_handlewrap.h"
-#include "iotjs_reqwrap.h"
-
-
-typedef struct {
- iotjs_handlewrap_t handlewrap;
- uv_udp_t handle;
-} iotjs_udpwrap_t;
-
-
-iotjs_udpwrap_t* iotjs_udpwrap_create(jerry_value_t judp);
-
-iotjs_udpwrap_t* iotjs_udpwrap_from_handle(uv_udp_t* handle);
-iotjs_udpwrap_t* iotjs_udpwrap_from_jobject(jerry_value_t judp);
-
-uv_udp_t* iotjs_udpwrap_udp_handle(iotjs_udpwrap_t* udpwrap);
-
-
-typedef struct {
- iotjs_reqwrap_t reqwrap;
- uv_udp_send_t req;
- size_t msg_size;
-} iotjs_send_reqwrap_t;
-
-iotjs_send_reqwrap_t* iotjs_send_reqwrap_create(jerry_value_t jcallback,
- const size_t msg_size);
-
-
-#endif /* IOTJS_MODULE_UDP_H */
--- /dev/null
+/* 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 <stdlib.h>
+#include <time.h>
+
+#include "iotjs_def.h"
+#include "iotjs_module_buffer.h"
+#include "iotjs_module_crypto.h"
+#include "iotjs_module_websocket.h"
+
+
+static void iotjs_wsclient_destroy(iotjs_wsclient_t *wsclient) {
+ IOTJS_RELEASE(wsclient->tcp_buff.buffer);
+ IOTJS_RELEASE(wsclient->ws_buff.data);
+ IOTJS_RELEASE(wsclient->generated_key);
+ IOTJS_RELEASE(wsclient);
+}
+
+static const jerry_object_native_info_t wsclient_native_info = {
+ .free_cb = (jerry_object_native_free_callback_t)iotjs_wsclient_destroy
+};
+
+iotjs_wsclient_t *iotjs_wsclient_create(const jerry_value_t jobject) {
+ iotjs_wsclient_t *wsclient = IOTJS_ALLOC(iotjs_wsclient_t);
+
+ jerry_set_object_native_pointer(jobject, wsclient, &wsclient_native_info);
+ return wsclient;
+}
+
+static const char WS_GUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+
+/**
+ * The protocol is as follows:
+ * method + USER_ENDPOINT + protocol
+ * host + USER_HOST + line_end
+ * upgrade
+ * connection
+ * sec_websocket_key + line_end
+ * sec_websocket_ver
+ */
+static const char method[] = "GET ";
+static const char protocol[] = " HTTP/1.1\r\n";
+static const char host[] = "Host: ";
+static const char line_end[] = "\r\n";
+static const char upgrade[] = "Upgrade: websocket\r\n";
+static const char connection[] = "Connection: Upgrade\r\n";
+static const char sec_websocket_key[] = "Sec-WebSocket-Key: ";
+static const char sec_websocket_ver[] = "Sec-WebSocket-Version: 13\r\n\r\n";
+static const char handshake_response[] =
+ "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: "
+ "Upgrade\r\nSec-WebSocket-Accept: ";
+static size_t header_fixed_size =
+ sizeof(method) + sizeof(protocol) + sizeof(host) + sizeof(upgrade) +
+ sizeof(connection) + sizeof(sec_websocket_key) + sizeof(sec_websocket_ver) -
+ 9; // 9 is for every \0
+
+
+void iotjs_websocket_create_callback(jerry_value_t jsref, jerry_value_t jmsg,
+ char *name, jerry_value_t client) {
+ jerry_value_t args[2];
+ args[0] = jmsg;
+ args[1] = client;
+ jerry_value_t fn = iotjs_jval_get_property(jsref, name);
+ iotjs_invoke_callback(fn, jsref, args, 2);
+
+ jerry_release_value(fn);
+}
+
+
+static unsigned char *ws_generate_key(jerry_value_t jsref, size_t *key_len) {
+ unsigned char *key = IOTJS_CALLOC(16, unsigned char);
+ for (int i = 0; i < 16; i++) {
+ key[i] = rand() % 256;
+ }
+
+ unsigned char *ret_val = NULL;
+
+ if (!(*key_len = iotjs_base64_encode(&ret_val, key, 16))) {
+ jerry_value_t ret_str =
+ jerry_create_string((jerry_char_t *)"mbedtls base64 encode failed");
+ iotjs_websocket_create_callback(jsref, ret_str, IOTJS_MAGIC_STRING_ONERROR,
+ ret_str);
+ jerry_release_value(ret_str);
+ }
+ IOTJS_RELEASE(key);
+
+ return ret_val;
+}
+
+
+static char *iotjs_ws_write_header(char *dst, const char *src) {
+ memcpy(dst, src, strlen(src));
+ return dst + strlen(src);
+}
+
+
+static char *iotjs_ws_write_data(char *buff, void *data, size_t size) {
+ memcpy(buff, data, size);
+ return buff + size;
+}
+
+
+static unsigned char *iotjs_make_handshake_key(char *client_key,
+ size_t *key_len) {
+ unsigned char *out_buff = NULL;
+
+ size_t ws_guid_size = strlen(WS_GUID);
+ size_t client_key_size = strnlen((char *)client_key, 24);
+ size_t concatenated_size = ws_guid_size + client_key_size;
+
+ unsigned char concatenated[concatenated_size + 1];
+ memcpy(concatenated, client_key, client_key_size);
+ memcpy(concatenated + client_key_size, WS_GUID, ws_guid_size);
+ concatenated[concatenated_size] = '\0';
+ size_t out_buff_size =
+ iotjs_sha1_encode(&out_buff, concatenated, concatenated_size);
+ unsigned char *key_out = NULL;
+ if (!(*key_len = iotjs_base64_encode(&key_out, out_buff, out_buff_size))) {
+ key_out = NULL;
+ }
+
+ IOTJS_RELEASE(out_buff);
+ return key_out;
+}
+
+static bool iotjs_check_handshake_key(char *server_key, jerry_value_t jsref) {
+ bool ret_val = true;
+ void *native_p;
+ JNativeInfoType *out_native_info;
+ bool has_p =
+ jerry_get_object_native_pointer(jsref, &native_p, &out_native_info);
+ if (!has_p || out_native_info != &wsclient_native_info) {
+ ret_val = false;
+ }
+
+ iotjs_wsclient_t *wsclient = (iotjs_wsclient_t *)native_p;
+ size_t key_len = 0;
+ unsigned char *key;
+ if (!(key = iotjs_make_handshake_key((char *)wsclient->generated_key,
+ &key_len))) {
+ ret_val = false;
+ }
+
+ if (strncmp(server_key, (const char *)key, key_len)) {
+ ret_val = false;
+ }
+
+ IOTJS_RELEASE(wsclient->generated_key);
+ IOTJS_RELEASE(key);
+
+ return ret_val;
+}
+
+
+static jerry_value_t iotjs_websocket_encode_frame(uint8_t opcode, bool mask,
+ bool compress, char *payload,
+ size_t payload_len) {
+ uint8_t header[2] = { 0 };
+
+ uint64_t buffer_size = payload_len + sizeof(header);
+
+ header[0] |= WS_FIN_BIT;
+ header[0] |= opcode;
+
+ if (compress) {
+ header[0] |= 0x40;
+ }
+
+ if (mask) {
+ header[1] |= WS_MASK_BIT;
+ buffer_size += 4; // mask key size is 32 bits
+ }
+
+ uint8_t extended_len_size = 0;
+ if (payload_len <= WS_ONE_BYTE_LENGTH) {
+ header[1] |= payload_len;
+ } else if (payload_len <= UINT16_MAX) {
+ header[1] |= WS_TWO_BYTES_LENGTH;
+ extended_len_size = 2;
+ } else {
+ header[1] |= WS_THREE_BYTES_LENGTH;
+ extended_len_size = 8;
+ }
+
+ buffer_size += extended_len_size;
+
+ jerry_value_t jframe = iotjs_bufferwrap_create_buffer(buffer_size);
+ iotjs_bufferwrap_t *frame_wrap = iotjs_bufferwrap_from_jbuffer(jframe);
+ char *buff_ptr = frame_wrap->buffer;
+
+ *buff_ptr++ = (char)header[0];
+ *buff_ptr++ = (char)header[1];
+
+ if (extended_len_size) {
+ if (extended_len_size == 2) {
+ uint16_t len = payload_len;
+ *buff_ptr++ = *((char *)&len + 1);
+ *buff_ptr++ = *((char *)&len);
+ } else {
+ uint64_t len = payload_len;
+ for (int8_t i = sizeof(uint64_t) - 1; i >= 0; i--) {
+ *buff_ptr++ = *((char *)&len + i);
+ }
+ }
+ }
+
+ if (payload != NULL) {
+ if (mask) {
+ uint8_t key[4];
+ for (uint8_t i = 0; i < sizeof(key); i++) {
+ key[i] = rand() % 256;
+ }
+
+ buff_ptr = iotjs_ws_write_data(buff_ptr, key, sizeof(key));
+
+ for (size_t i = 0; i < payload_len; i++) {
+ payload[i] ^= key[i % 4];
+ }
+ }
+
+ buff_ptr = iotjs_ws_write_data(buff_ptr, payload, payload_len);
+ }
+
+ return jframe;
+}
+
+
+static void iotjs_websocket_create_buffer_and_cb(char **buff_ptr,
+ uint32_t payload_len,
+ char *cb_type,
+ jerry_value_t jsref,
+ jerry_value_t client) {
+ if (payload_len > 0) {
+ jerry_value_t ret_buff = iotjs_bufferwrap_create_buffer(payload_len);
+ iotjs_bufferwrap_t *buff_wrap = iotjs_bufferwrap_from_jbuffer(ret_buff);
+ iotjs_ws_write_data(buff_wrap->buffer, *buff_ptr, payload_len);
+ *buff_ptr += payload_len;
+ iotjs_websocket_create_callback(jsref, ret_buff, cb_type, client);
+ jerry_release_value(ret_buff);
+
+ return;
+ }
+ iotjs_websocket_create_callback(jsref, jerry_create_undefined(), cb_type,
+ client);
+}
+
+
+static jerry_value_t iotjs_websocket_check_error(uint8_t code) {
+ switch (code) {
+ case WS_ERR_INVALID_UTF8: {
+ return JS_CREATE_ERROR(COMMON, "Invalid UTF8 string in UTF8 message");
+ }
+
+ case WS_ERR_INVALID_TERMINATE_CODE: {
+ return JS_CREATE_ERROR(COMMON, "Invalid terminate code received");
+ }
+
+ case WS_ERR_UNKNOWN_OPCODE: {
+ return JS_CREATE_ERROR(COMMON, "Uknown opcode received");
+ }
+
+ case WS_ERR_NATIVE_POINTER_ERR: {
+ return JS_CREATE_ERROR(COMMON, "WebSocket native pointer unavailable");
+ }
+
+ case WS_ERR_FRAME_SIZE_LIMIT: {
+ return JS_CREATE_ERROR(COMMON, "Frame size received exceeds limit");
+ }
+
+ default: { return jerry_create_undefined(); };
+ }
+}
+
+
+JS_FUNCTION(PrepareHandshakeRequest) {
+ DJS_CHECK_THIS();
+
+ jerry_value_t jsref = JS_GET_ARG(0, object);
+ jerry_value_t jhost = JS_GET_ARG(1, any);
+ jerry_value_t jendpoint = JS_GET_ARG(2, any);
+
+ iotjs_string_t l_host;
+ iotjs_string_t l_endpoint;
+ if (!(iotjs_jbuffer_as_string(jendpoint, &l_endpoint)) ||
+ !(iotjs_jbuffer_as_string(jhost, &l_host))) {
+ return JS_CREATE_ERROR(COMMON, "Invalid host and/or path arguments!");
+ };
+
+ iotjs_wsclient_t *wsclient = (iotjs_wsclient_t *)
+ iotjs_jval_get_object_native_handle(jsref, &wsclient_native_info);
+ if (wsclient == NULL) {
+ return iotjs_websocket_check_error(WS_ERR_NATIVE_POINTER_ERR);
+ }
+
+ size_t generated_key_len = 0;
+ wsclient->generated_key = ws_generate_key(jsref, &generated_key_len);
+
+ jerry_value_t jfinal = iotjs_bufferwrap_create_buffer(
+ header_fixed_size + iotjs_string_size(&l_endpoint) +
+ iotjs_string_size(&l_host) + (sizeof(line_end) * 2) + generated_key_len);
+
+ iotjs_bufferwrap_t *final_wrap = iotjs_bufferwrap_from_jbuffer(jfinal);
+
+ char *buff_ptr = final_wrap->buffer;
+ buff_ptr = iotjs_ws_write_header(buff_ptr, method);
+ memcpy(buff_ptr, iotjs_string_data(&l_endpoint),
+ iotjs_string_size(&l_endpoint));
+ buff_ptr += iotjs_string_size(&l_endpoint);
+ buff_ptr = iotjs_ws_write_header(buff_ptr, protocol);
+ buff_ptr = iotjs_ws_write_header(buff_ptr, host);
+ memcpy(buff_ptr, iotjs_string_data(&l_host), iotjs_string_size(&l_host));
+ buff_ptr += iotjs_string_size(&l_host);
+ buff_ptr = iotjs_ws_write_header(buff_ptr, line_end);
+ buff_ptr = iotjs_ws_write_header(buff_ptr, upgrade);
+ buff_ptr = iotjs_ws_write_header(buff_ptr, connection);
+ buff_ptr = iotjs_ws_write_header(buff_ptr, sec_websocket_key);
+ memcpy(buff_ptr, wsclient->generated_key, generated_key_len);
+ buff_ptr += generated_key_len;
+ buff_ptr = iotjs_ws_write_header(buff_ptr, line_end);
+ buff_ptr = iotjs_ws_write_header(buff_ptr, sec_websocket_ver);
+
+ iotjs_string_destroy(&l_endpoint);
+ iotjs_string_destroy(&l_host);
+
+ return jfinal;
+}
+
+
+/**
+ * HTTP/1.1 101 Switching Protocols
+ * Upgrade: websocket
+ * Connection: Upgrade
+ * Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
+ */
+JS_FUNCTION(ReceiveHandshakeData) {
+ DJS_CHECK_THIS();
+ DJS_CHECK_ARGS(1, string);
+
+ iotjs_string_t client_key = JS_GET_ARG(0, string);
+
+ size_t key_len = 0;
+ unsigned char *key;
+ if (!(key = iotjs_make_handshake_key((char *)iotjs_string_data(&client_key),
+ &key_len))) {
+ return JS_CREATE_ERROR(COMMON, "mbedtls base64 encode failed");
+ }
+
+ jerry_value_t jfinal = iotjs_bufferwrap_create_buffer(
+ sizeof(handshake_response) - 1 + key_len + sizeof(line_end) * 2);
+
+ iotjs_bufferwrap_t *final_wrap = iotjs_bufferwrap_from_jbuffer(jfinal);
+ char *buff_ptr = final_wrap->buffer;
+ buff_ptr = iotjs_ws_write_header(buff_ptr, handshake_response);
+ memcpy(buff_ptr, key, key_len);
+ buff_ptr += key_len;
+ buff_ptr = iotjs_ws_write_header(buff_ptr, line_end);
+ buff_ptr = iotjs_ws_write_header(buff_ptr, line_end);
+
+ iotjs_string_destroy(&client_key);
+ IOTJS_RELEASE(key);
+ return jfinal;
+}
+
+JS_FUNCTION(ParseHandshakeData) {
+ DJS_CHECK_THIS();
+ DJS_CHECK_ARGS(2, object, object);
+
+ jerry_value_t jbuffer = JS_GET_ARG(0, object);
+ iotjs_bufferwrap_t *buff_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer);
+ if (buff_wrap->length < 12 || strncmp(buff_wrap->buffer + 9, "101", 3)) {
+ return JS_CREATE_ERROR(COMMON, "WebSocket connection failed");
+ }
+ jerry_value_t jsref = JS_GET_ARG(1, object);
+
+ char ws_accept[] = "Sec-WebSocket-Accept: ";
+ char *frame_end = strstr(buff_wrap->buffer, "\r\n\r\n");
+ char *key_pos = strstr(buff_wrap->buffer, ws_accept) + strlen(ws_accept);
+ char key[28] = { 0 };
+ memcpy(key, key_pos, 28);
+
+ frame_end += 4; // \r\n\r\n
+
+ if (!iotjs_check_handshake_key(key, jsref)) {
+ return JS_CREATE_ERROR(COMMON, "WebSocket handshake key comparison failed");
+ }
+
+ size_t header_size = (size_t)(frame_end - buff_wrap->buffer);
+ if (buff_wrap->length > header_size) {
+ size_t remaining_length = buff_wrap->length - header_size;
+ jerry_value_t jdata = iotjs_bufferwrap_create_buffer(remaining_length);
+ iotjs_bufferwrap_t *data_wrap = iotjs_bufferwrap_from_jbuffer(jdata);
+
+ memcpy(data_wrap->buffer, buff_wrap->buffer + header_size,
+ remaining_length);
+ data_wrap->length = remaining_length;
+
+ return jdata;
+ }
+
+ return jerry_create_undefined();
+}
+
+
+static void iotjs_websocket_concat_tcp_buffers(iotjs_wsclient_t *wsclient,
+ iotjs_bufferwrap_t *buff_recv) {
+ char *tmp_buf = wsclient->tcp_buff.buffer;
+ wsclient->tcp_buff.buffer =
+ IOTJS_CALLOC(wsclient->tcp_buff.length + buff_recv->length, char);
+ memcpy(wsclient->tcp_buff.buffer, tmp_buf, wsclient->tcp_buff.length);
+ memcpy(wsclient->tcp_buff.buffer + wsclient->tcp_buff.length,
+ buff_recv->buffer, buff_recv->length);
+ wsclient->tcp_buff.length += buff_recv->length;
+ IOTJS_RELEASE(tmp_buf);
+}
+
+
+static uint8_t iotjs_websocket_decode_frame(iotjs_wsclient_t *wsclient,
+ char *first_byte, char *buff_ptr,
+ uint32_t payload_len,
+ jerry_value_t jsref, bool mask,
+ jerry_value_t client) {
+ uint8_t fin_bit = (first_byte[0] >> 7) & 0x01;
+ uint8_t opcode = first_byte[0] & 0x0F;
+
+ uint32_t *mask_key = NULL;
+ if (mask) {
+ mask_key = (uint32_t *)buff_ptr;
+ buff_ptr += sizeof(uint32_t);
+
+ for (uint64_t i = 0; i < payload_len; i++) {
+ buff_ptr[i] ^= ((unsigned char *)(mask_key))[i % 4];
+ }
+ }
+
+ switch (opcode) {
+ case WS_OP_CONTINUE: {
+ if (wsclient->ws_buff.length == 0) {
+ wsclient->ws_buff.masked = mask;
+ wsclient->ws_buff.first_byte = first_byte[0];
+ wsclient->ws_buff.data = IOTJS_CALLOC(payload_len, char);
+ memcpy(wsclient->ws_buff.data, buff_ptr, payload_len);
+ wsclient->ws_buff.length = payload_len;
+ break;
+ }
+
+ char *tmp_ptr = wsclient->ws_buff.data;
+ uint32_t tmp_len = wsclient->ws_buff.length;
+ wsclient->ws_buff.data =
+ IOTJS_CALLOC(wsclient->ws_buff.length + payload_len, char);
+ memcpy(wsclient->ws_buff.data, tmp_ptr, tmp_len);
+ memcpy(wsclient->ws_buff.data + tmp_len, buff_ptr, payload_len);
+ wsclient->ws_buff.length += payload_len;
+ IOTJS_RELEASE(tmp_ptr);
+
+
+ if (fin_bit) {
+ uint8_t ret_val =
+ iotjs_websocket_decode_frame(wsclient,
+ &wsclient->ws_buff.first_byte,
+ wsclient->ws_buff.data,
+ wsclient->ws_buff.length, jsref,
+ wsclient->ws_buff.masked, client);
+
+ IOTJS_RELEASE(wsclient->ws_buff.data);
+ wsclient->ws_buff.length = 0;
+ wsclient->ws_buff.first_byte = 0;
+
+ return ret_val;
+ }
+ break;
+ }
+
+ case WS_OP_UTF8:
+ case WS_OP_BINARY: {
+ if (opcode == WS_OP_UTF8 &&
+ !jerry_is_valid_utf8_string((unsigned char *)buff_ptr, payload_len)) {
+ return WS_ERR_INVALID_UTF8;
+ }
+ iotjs_websocket_create_buffer_and_cb(&buff_ptr, payload_len,
+ IOTJS_MAGIC_STRING_ONMESSAGE, jsref,
+ client);
+ break;
+ }
+
+ case WS_OP_TERMINATE: {
+ if (payload_len > 0) {
+ uint16_t ret_code = (uint16_t)((unsigned char)buff_ptr[0] << 8 |
+ (unsigned char)buff_ptr[1]);
+ if (ret_code > 4999 || ret_code < 1000) {
+ return WS_ERR_INVALID_TERMINATE_CODE;
+ }
+
+ buff_ptr += 2;
+ payload_len -= 2;
+ uint8_t ret_code_str_size = 4;
+ char ret_code_str[ret_code_str_size + 1];
+ sprintf(ret_code_str, "%d", ret_code);
+ ret_code_str[ret_code_str_size] = '\0';
+
+ jerry_value_t ret_buff =
+ iotjs_bufferwrap_create_buffer(payload_len + ret_code_str_size);
+ iotjs_bufferwrap_t *ret_wrap = iotjs_bufferwrap_from_jbuffer(ret_buff);
+ char *local_ptr = ret_wrap->buffer;
+ local_ptr =
+ iotjs_ws_write_data(local_ptr, ret_code_str, ret_code_str_size);
+ local_ptr = iotjs_ws_write_data(local_ptr, buff_ptr, payload_len);
+ buff_ptr += payload_len;
+ iotjs_websocket_create_callback(jsref, ret_buff,
+ IOTJS_MAGIC_STRING_ONCLOSE, client);
+ jerry_release_value(ret_buff);
+ break;
+ }
+ iotjs_websocket_create_callback(jsref, jerry_create_undefined(),
+ IOTJS_MAGIC_STRING_ONCLOSE, client);
+ break;
+ }
+
+ case WS_OP_PING: {
+ iotjs_websocket_create_buffer_and_cb(&buff_ptr, payload_len,
+ IOTJS_MAGIC_STRING_PONG, jsref,
+ client);
+ break;
+ }
+
+ case WS_OP_PONG: {
+ iotjs_websocket_create_buffer_and_cb(&buff_ptr, payload_len,
+ IOTJS_MAGIC_STRING_ONPINGRESP, jsref,
+ client);
+ break;
+ }
+
+ default:
+ return WS_ERR_UNKNOWN_OPCODE;
+ break;
+ }
+
+ return 0;
+}
+
+
+JS_FUNCTION(WsReceive) {
+ DJS_CHECK_THIS();
+ DJS_CHECK_ARGS(3, object, object, object);
+
+ jerry_value_t jsref = JS_GET_ARG(0, object);
+
+ iotjs_wsclient_t *wsclient = (iotjs_wsclient_t *)
+ iotjs_jval_get_object_native_handle(jsref, &wsclient_native_info);
+ if (wsclient == NULL) {
+ return iotjs_websocket_check_error(WS_ERR_NATIVE_POINTER_ERR);
+ }
+
+ jerry_value_t jbuffer = JS_GET_ARG(1, object);
+ iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer);
+
+ jerry_value_t client = JS_GET_ARG(2, object);
+
+ if (buffer_wrap->length == 0) {
+ return jerry_create_undefined();
+ }
+
+ char *current_buffer = buffer_wrap->buffer;
+ char *current_buffer_end = current_buffer + buffer_wrap->length;
+
+ if (wsclient->tcp_buff.length > 0) {
+ iotjs_websocket_concat_tcp_buffers(wsclient, buffer_wrap);
+ current_buffer = wsclient->tcp_buff.buffer;
+ current_buffer_end = current_buffer + wsclient->tcp_buff.length;
+ }
+
+
+ while (true) {
+ if (current_buffer >= current_buffer_end) {
+ if (wsclient->tcp_buff.length > 0) {
+ IOTJS_RELEASE(wsclient->tcp_buff.buffer);
+ wsclient->tcp_buff.length = 0;
+ }
+ return jerry_create_undefined();
+ }
+
+ if (current_buffer + 2 > current_buffer_end) {
+ break;
+ }
+
+ char *first_byte = current_buffer;
+ uint8_t payload_byte = (current_buffer[1]) & WS_THREE_BYTES_LENGTH;
+ uint8_t mask = (first_byte[1] >> 7) & 0x01;
+
+ current_buffer += 2;
+
+ uint32_t payload_len;
+ if (!(payload_byte ^ WS_TWO_BYTES_LENGTH)) {
+ if (current_buffer + sizeof(uint16_t) > current_buffer_end) {
+ break;
+ }
+ payload_len = (uint16_t)(current_buffer[0] << 8 | current_buffer[1]);
+ current_buffer += sizeof(uint16_t);
+ } else if (!(payload_byte ^ WS_THREE_BYTES_LENGTH)) {
+ if (current_buffer + sizeof(uint64_t) > current_buffer_end) {
+ break;
+ }
+ if ((*(uint64_t *)current_buffer & UINT32_MAX) > UINT32_MAX) {
+ return WS_ERR_FRAME_SIZE_LIMIT;
+ }
+ for (uint8_t i = 0; i < sizeof(uint64_t); i++) {
+ memcpy((uint8_t *)&payload_len + i,
+ current_buffer + sizeof(uint64_t) - 1 - i, sizeof(uint8_t));
+ }
+ current_buffer += sizeof(uint64_t);
+ } else {
+ payload_len = payload_byte;
+ }
+
+ if (mask && ((current_buffer + 4 > current_buffer_end) ||
+ (current_buffer + 4 + payload_len > current_buffer_end))) {
+ break;
+ } else if (!mask && (current_buffer + payload_len > current_buffer_end)) {
+ break;
+ }
+
+ uint8_t ret_val =
+ iotjs_websocket_decode_frame(wsclient, first_byte, current_buffer,
+ payload_len, jsref, mask, client);
+ if (ret_val) {
+ return iotjs_websocket_check_error(ret_val);
+ }
+
+ current_buffer += mask ? 4 : 0;
+ current_buffer += payload_len;
+ }
+
+ if (current_buffer == wsclient->tcp_buff.buffer) {
+ return jerry_create_undefined();
+ }
+
+ uint32_t remaining_size = (uint32_t)(current_buffer_end - current_buffer);
+ char *buffer = IOTJS_CALLOC(remaining_size, char);
+ memcpy(buffer, current_buffer, remaining_size);
+
+ if (wsclient->tcp_buff.buffer != NULL) {
+ IOTJS_RELEASE(wsclient->tcp_buff.buffer);
+ }
+
+ wsclient->tcp_buff.buffer = buffer;
+ wsclient->tcp_buff.length = remaining_size;
+
+ return jerry_create_undefined();
+}
+
+
+JS_FUNCTION(WsInit) {
+ DJS_CHECK_THIS();
+
+ const jerry_value_t jws = JS_GET_ARG(0, object);
+
+ iotjs_wsclient_t *wsclient = iotjs_wsclient_create(jws);
+ wsclient->tcp_buff.buffer = NULL;
+ wsclient->tcp_buff.length = 0;
+
+ wsclient->ws_buff.data = NULL;
+ wsclient->ws_buff.length = 0;
+
+ wsclient->generated_key = NULL;
+
+ return jerry_create_undefined();
+}
+
+
+JS_FUNCTION(WsClose) {
+ DJS_CHECK_THIS();
+
+ bool masked = false;
+ uint8_t opcode = WS_OP_TERMINATE;
+ iotjs_string_t payload = iotjs_string_create();
+
+
+ jerry_value_t jmsg = JS_GET_ARG(0, any);
+ jerry_value_t jcode = JS_GET_ARG(1, any);
+
+ iotjs_string_t msg = iotjs_string_create();
+ // Client side close frame must be ALWAYS masked
+ masked = iotjs_jbuffer_as_string(jmsg, &msg) || jerry_value_is_number(jcode);
+
+ if (jerry_value_is_number(jcode)) {
+ uint16_t code = jerry_get_number_value(jcode);
+ iotjs_string_append(&payload, (const char *)&code + 1, 1);
+ iotjs_string_append(&payload, (const char *)&code, 1);
+ }
+
+ if (!iotjs_string_is_empty(&msg)) {
+ // We have no status code, but do have msg, append the status code
+ if (iotjs_string_is_empty(&payload)) {
+ uint16_t code = 1000;
+ iotjs_string_append(&payload, (const char *)&code + 1, 1);
+ iotjs_string_append(&payload, (const char *)&code, 1);
+ }
+ iotjs_string_append(&payload, iotjs_string_data(&msg),
+ iotjs_string_size(&msg));
+ iotjs_string_destroy(&msg);
+ }
+
+ jerry_value_t ret_val =
+ iotjs_websocket_encode_frame(opcode, masked, false,
+ (char *)iotjs_string_data(&payload),
+ iotjs_string_size(&payload));
+
+ if (payload.data != NULL) {
+ iotjs_string_destroy(&payload);
+ }
+
+ return ret_val;
+}
+
+
+JS_FUNCTION(WsSendData) {
+ DJS_CHECK_THIS();
+
+ jerry_value_t jmsg = JS_GET_ARG(0, any);
+ iotjs_string_t msg = iotjs_string_create();
+
+ if (!iotjs_jbuffer_as_string(jmsg, &msg)) {
+ return jerry_create_undefined();
+ }
+
+ bool binary = jerry_get_boolean_value(jargv[1]);
+ bool mask = jerry_get_boolean_value(jargv[2]);
+ bool compress = jerry_get_boolean_value(jargv[3]);
+
+ uint8_t opcode = binary ? WS_OP_BINARY : WS_OP_UTF8;
+
+ jerry_value_t ret_val =
+ iotjs_websocket_encode_frame(opcode, mask, compress,
+ (char *)iotjs_string_data(&msg),
+ iotjs_string_size(&msg));
+
+ iotjs_string_destroy(&msg);
+ return ret_val;
+}
+
+
+JS_FUNCTION(WsPingOrPong) {
+ DJS_CHECK_THIS();
+
+ uint8_t opcode =
+ jerry_get_boolean_value(JS_GET_ARG(0, any)) ? WS_OP_PING : WS_OP_PONG;
+ jerry_value_t jmsg = JS_GET_ARG(1, any);
+
+ iotjs_string_t msg = iotjs_string_create();
+
+ jerry_value_t ret_val;
+
+ if (iotjs_jbuffer_as_string(jmsg, &msg)) {
+ ret_val =
+ iotjs_websocket_encode_frame(opcode, jerry_get_boolean_value(
+ JS_GET_ARG(2, any)),
+ false, (char *)iotjs_string_data(&msg),
+ iotjs_string_size(&msg));
+ iotjs_string_destroy(&msg);
+ } else {
+ ret_val = iotjs_websocket_encode_frame(opcode, false, false, NULL, 0);
+ }
+
+ return ret_val;
+}
+
+
+jerry_value_t InitWebsocket() {
+ IOTJS_UNUSED(WS_GUID);
+ jerry_value_t jws = jerry_create_object();
+ iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_CLOSE, WsClose);
+ iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_PARSEHANDSHAKEDATA,
+ ParseHandshakeData);
+ iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_PING, WsPingOrPong);
+ iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_PREPAREHANDSHAKE,
+ PrepareHandshakeRequest);
+ iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_SEND, WsSendData);
+ iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_WSINIT, WsInit);
+ iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_WSRECEIVE, WsReceive);
+ iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_WSRECEIVEHANDSHAKEDATA,
+ ReceiveHandshakeData);
+
+ return jws;
+}
--- /dev/null
+/* 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_WEBSOCKET_H
+#define IOTJS_MODULE_WEBSOCKET_H
+
+enum {
+ WS_OP_CONTINUE = 0x00,
+ WS_OP_UTF8 = 0x01,
+ WS_OP_BINARY = 0x02,
+ WS_OP_TERMINATE = 0x08,
+ WS_OP_PING = 0x09,
+ WS_OP_PONG = 0x0a,
+} iotjs_websocket_opcodes;
+
+enum {
+ WS_FIN_BIT = 0x80,
+ WS_MASK_BIT = WS_FIN_BIT,
+} iotjs_websocket_header_bits;
+
+enum {
+ WS_ERR_INVALID_UTF8 = 1,
+ WS_ERR_INVALID_TERMINATE_CODE = 2,
+ WS_ERR_UNKNOWN_OPCODE = 3,
+ WS_ERR_NATIVE_POINTER_ERR = 4,
+ WS_ERR_FRAME_SIZE_LIMIT = 5,
+} iotjs_websocket_err_codes;
+
+enum {
+ WS_ONE_BYTE_LENGTH = 125,
+ WS_TWO_BYTES_LENGTH,
+ WS_THREE_BYTES_LENGTH,
+} iotjs_websocket_frame_len_types;
+
+
+typedef struct {
+ struct {
+ uint32_t length;
+ char *buffer;
+ } tcp_buff;
+
+ struct {
+ uint32_t length;
+ char *data;
+ char first_byte;
+ bool masked;
+ } ws_buff;
+ unsigned char *generated_key;
+} iotjs_wsclient_t;
+
+#endif /* IOTJS_MODULE_WEBSOCKET_H */
jerry_value_t jemit = iotjs_jval_get_property(jhcisocket, "emit");
IOTJS_ASSERT(jerry_value_is_function(jemit));
- iotjs_jargs_t jargs = iotjs_jargs_create(2);
jerry_value_t str = jerry_create_string((const jerry_char_t*)"data");
IOTJS_ASSERT(length >= 0);
jerry_value_t jbuf = iotjs_bufferwrap_create_buffer((size_t)length);
iotjs_bufferwrap_t* buf_wrap = iotjs_bufferwrap_from_jbuffer(jbuf);
iotjs_bufferwrap_copy(buf_wrap, data, (size_t)length);
- iotjs_jargs_append_jval(&jargs, str);
- iotjs_jargs_append_jval(&jargs, jbuf);
- jerry_value_t jres = iotjs_jhelper_call(jemit, jhcisocket, &jargs);
- IOTJS_ASSERT(!jerry_value_has_error_flag(jres));
+ jerry_value_t jargs[2] = { str, jbuf };
+ jerry_value_t jres = jerry_call_function(jemit, jhcisocket, jargs, 2);
+ IOTJS_ASSERT(!jerry_value_is_error(jres));
jerry_release_value(jres);
jerry_release_value(str);
jerry_release_value(jbuf);
- iotjs_jargs_destroy(&jargs);
jerry_release_value(jemit);
}
}
jerry_value_t jemit = iotjs_jval_get_property(jhcisocket, "emit");
IOTJS_ASSERT(jerry_value_is_function(jemit));
- iotjs_jargs_t jargs = iotjs_jargs_create(2);
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));
- jerry_value_t jres = iotjs_jhelper_call(jemit, jhcisocket, &jargs);
- IOTJS_ASSERT(!jerry_value_has_error_flag(jres));
+ jerry_value_t jerror =
+ iotjs_jval_create_error_without_error_flag(strerror(errno));
+ jerry_value_t jargs[2] = { str, jerror };
+ jerry_value_t jres = jerry_call_function(jemit, jhcisocket, jargs, 2);
+ IOTJS_ASSERT(!jerry_value_is_error(jres));
jerry_release_value(jres);
jerry_release_value(str);
- iotjs_jargs_destroy(&jargs);
+ jerry_release_value(jerror);
jerry_release_value(jemit);
}
jerry_value_t jonChange = iotjs_jval_get_property(jgpio, "onChange");
IOTJS_ASSERT(jerry_value_is_function(jonChange));
- jerry_value_t jres =
- iotjs_jhelper_call(jonChange, jgpio, iotjs_jargs_get_empty());
- IOTJS_ASSERT(!jerry_value_has_error_flag(jres));
+ jerry_value_t jres = jerry_call_function(jonChange, jgpio, NULL, 0);
+ IOTJS_ASSERT(!jerry_value_is_error(jres));
jerry_release_value(jres);
jerry_release_value(jonChange);
return true;
}
+
+
+bool iotjs_gpio_set_direction(iotjs_gpio_t* gpio) {
+ if (!gpio_set_direction(gpio->pin, gpio->direction)) {
+ DLOG("%s, Cannot set direction.", __func__);
+ return false;
+ }
+ return true;
+}
jerry_value_t jchip =
iotjs_jval_get_property(jconfig, IOTJS_MAGIC_STRING_CHIP);
- if (jerry_value_has_error_flag(jchip)) {
+ if (jerry_value_is_error(jchip)) {
return jchip;
}
#include <termios.h>
#include <unistd.h>
+#include "iotjs_uv_handle.h"
#include "modules/iotjs_module_uart.h"
struct iotjs_uart_platform_data_s {
return jerry_create_undefined();
}
-bool iotjs_uart_open(iotjs_uart_t* uart) {
+bool iotjs_uart_open(uv_handle_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
int fd = open(iotjs_string_data(&uart->platform_data->device_path),
O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0) {
tcsetattr(fd, TCSANOW, &options);
uart->device_fd = fd;
- iotjs_uart_register_read_cb(uart);
+ iotjs_uart_register_read_cb((uv_poll_t*)uart_poll_handle);
return true;
}
-bool iotjs_uart_write(iotjs_uart_t* uart) {
+bool iotjs_uart_write(uv_handle_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
+
int bytesWritten = 0;
unsigned offset = 0;
int fd = uart->device_fd;
return true;
}
-void iotjs_uart_handlewrap_close_cb(uv_handle_t* handle) {
- iotjs_uart_t* uart = (iotjs_uart_t*)handle->data;
+void iotjs_uart_handle_close_cb(uv_handle_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
if (close(uart->device_fd) < 0) {
DLOG(iotjs_periph_error_str(kUartOpClose));
--- /dev/null
+/* 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 <stdlib.h>
+
+#include "modules/iotjs_module_gpio.h"
+
+struct iotjs_gpio_platform_data_s {
+ bool is_open;
+ bool level;
+};
+
+
+void iotjs_gpio_create_platform_data(iotjs_gpio_t* gpio) {
+ gpio->platform_data = IOTJS_ALLOC(iotjs_gpio_platform_data_t);
+}
+
+
+void iotjs_gpio_destroy_platform_data(
+ iotjs_gpio_platform_data_t* platform_data) {
+ IOTJS_RELEASE(platform_data);
+}
+
+
+bool iotjs_gpio_open(iotjs_gpio_t* gpio) {
+ DDDLOG("%s - pin: %d, direction: %d, mode: %d", __func__, gpio->pin,
+ gpio->direction, gpio->mode);
+ if (gpio->platform_data->is_open) {
+ return false; // pin is open already
+ }
+
+ gpio->platform_data->is_open = true;
+ return true;
+}
+
+
+bool iotjs_gpio_write(iotjs_gpio_t* gpio) {
+ gpio->platform_data->level = gpio->value;
+ return true;
+}
+
+
+bool iotjs_gpio_read(iotjs_gpio_t* gpio) {
+ gpio->value = gpio->platform_data->level;
+ return true;
+}
+
+
+bool iotjs_gpio_close(iotjs_gpio_t* gpio) {
+ if (!gpio->platform_data->is_open) {
+ return false; // pin is not open
+ }
+
+ gpio->platform_data->is_open = false;
+ return true;
+}
+
+
+bool iotjs_gpio_set_direction(iotjs_gpio_t* gpio) {
+ return true;
+}
--- /dev/null
+/* 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 "modules/iotjs_module_i2c.h"
+
+struct iotjs_i2c_platform_data_s {
+ int bus;
+};
+
+
+void iotjs_i2c_create_platform_data(iotjs_i2c_t* i2c) {
+ i2c->platform_data = IOTJS_ALLOC(iotjs_i2c_platform_data_t);
+}
+
+
+void iotjs_i2c_destroy_platform_data(iotjs_i2c_platform_data_t* platform_data) {
+ IOTJS_ASSERT(platform_data);
+ IOTJS_RELEASE(platform_data);
+}
+
+jerry_value_t iotjs_i2c_set_platform_config(iotjs_i2c_t* i2c,
+ const jerry_value_t jconfig) {
+ return jerry_create_undefined();
+}
+
+bool iotjs_i2c_open(iotjs_i2c_t* i2c) {
+ return true;
+}
+
+bool iotjs_i2c_close(iotjs_i2c_t* i2c) {
+ return true;
+}
+
+bool iotjs_i2c_write(iotjs_i2c_t* i2c) {
+ IOTJS_RELEASE(i2c->buf_data);
+ return true;
+}
+
+bool iotjs_i2c_read(iotjs_i2c_t* i2c) {
+ i2c->buf_data = iotjs_buffer_allocate(i2c->buf_len);
+ return true;
+}
bool iotjs_gpio_read(iotjs_gpio_t* gpio) {
DDDLOG("%s - pin: %d", __func__, gpio->pin);
- return stm32_gpioread(gpio->pin);
+
+ gpio->value = stm32_gpioread(gpio->pin);
+ return true;
}
}
-bool iotjs_gpio_open(iotjs_gpio_t* gpio) {
- DDDLOG("%s - pin: %d, dir: %d, mode: %d", __func__, gpio->pin,
- gpio->direction, gpio->mode);
-
+static bool gpio_set_config(iotjs_gpio_t* gpio) {
uint32_t cfgset = 0;
// Set pin direction and mode
return true;
}
+
+
+bool iotjs_gpio_open(iotjs_gpio_t* gpio) {
+ DDDLOG("%s - pin: %d, dir: %d, mode: %d", __func__, gpio->pin,
+ gpio->direction, gpio->mode);
+ return gpio_set_config(gpio);
+}
+
+
+bool iotjs_gpio_set_direction(iotjs_gpio_t* gpio) {
+ return gpio_set_config(gpio);
+}
#include "modules/iotjs_module_uart.h"
+#include "iotjs_uv_handle.h"
+
struct iotjs_uart_platform_data_s {
iotjs_string_t device_path;
};
return jerry_create_undefined();
}
-bool iotjs_uart_open(iotjs_uart_t* uart) {
+bool iotjs_uart_open(uv_handle_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
int fd = open(iotjs_string_data(&uart->platform_data->device_path),
O_RDWR | O_NOCTTY | O_NDELAY);
}
uart->device_fd = fd;
- iotjs_uart_register_read_cb(uart);
+ iotjs_uart_register_read_cb((uv_poll_t*)uart);
return true;
}
-bool iotjs_uart_write(iotjs_uart_t* uart) {
+bool iotjs_uart_write(uv_handle_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
int bytesWritten = 0;
unsigned offset = 0;
int fd = uart->device_fd;
return true;
}
-void iotjs_uart_handlewrap_close_cb(uv_handle_t* handle) {
- iotjs_uart_t* uart = (iotjs_uart_t*)handle->data;
+void iotjs_uart_handle_close_cb(uv_handle_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
if (close(uart->device_fd) < 0) {
DLOG(iotjs_periph_error_str(kUartOpClose));
if (gpio->direction == kGpioDirectionIn) {
_direction = PERIPHERAL_GPIO_DIRECTION_IN;
} else {
- _direction = PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_HIGH;
+ _direction = PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW;
}
retVal = peripheral_gpio_set_direction(_gpio, _direction);
return true;
}
+
+
+bool iotjs_gpio_set_direction(iotjs_gpio_t* gpio) {
+ peripheral_gpio_direction_e direction;
+ if (gpio->direction == kGpioDirectionIn) {
+ direction = PERIPHERAL_GPIO_DIRECTION_IN;
+ } else {
+ direction = PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW;
+ }
+
+ int ret = peripheral_gpio_set_direction(gpio->platform_data->peripheral_gpio,
+ direction);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ DLOG("%s, Cannot set direction(%d).", __func__, ret);
+ return false;
+ }
+
+ return true;
+}
return;
}
+ 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);
+
+ if (jerry_value_is_function(fn) == false) {
+ DDDLOG("tizen module is not loaded");
+ goto exit;
+ }
+
// parse app control
char* json = NULL;
bundle* b = NULL;
}
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);
+ jerry_value_t jargv[2] = { jerry_create_string(
+ (const jerry_char_t*)event_name),
+ jerry_create_string((const jerry_char_t*)json) };
- iotjs_make_callback(fn, tizen, &jargv);
+ iotjs_invoke_callback(fn, tizen, jargv, 2);
+ jerry_release_value(jargv[0]);
+ jerry_release_value(jargv[1]);
free(json);
bundle_free(b);
+exit:
jerry_release_value(fn);
- iotjs_jargs_destroy(&jargv);
}
if (app_res_path != NULL) {
free(app_res_path);
}
-
+ } else if (strncmp(command, "getDataPath", strlen("getDataPath")) == 0) {
+ char* app_data_path = app_get_data_path();
+ iotjs_bridge_set_msg(handle, app_data_path);
+ if (app_data_path != NULL) {
+ free(app_data_path);
+ }
} else if (strncmp(command, "launchAppControl", strlen("launchAppControl")) ==
0) {
iotjs_error_t err = tizen_send_launch_request(message, handle);
return result;
}
- iotjs_jargs_t jargv = iotjs_jargs_create(1);
- iotjs_jargs_append_string_raw(&jargv, message);
- jerry_value_t jres = iotjs_make_callback_with_result(jfunc, jmodule, &jargv);
+ jerry_value_t jval = jerry_create_string((const jerry_char_t*)message);
+ jerry_value_t jres =
+ iotjs_invoke_callback_with_result(jfunc, jmodule, &jval, 1);
if (jerry_value_is_string(jres)) {
IOTJS_ASSERT(output_str != NULL);
jerry_release_value(jfunc);
jerry_release_value(jres);
- iotjs_jargs_destroy(&jargv);
+ jerry_release_value(jval);
return result;
}
#include <peripheral_io.h>
+#include "iotjs_uv_handle.h"
#include "modules/iotjs_module_uart.h"
struct _peripheral_uart_s {
return jerry_create_undefined();
}
-bool iotjs_uart_open(iotjs_uart_t* uart) {
+bool iotjs_uart_open(uv_handle_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
iotjs_uart_platform_data_t* platform_data = uart->platform_data;
IOTJS_ASSERT(platform_data);
}
uart->device_fd = platform_data->uart_h->fd;
- iotjs_uart_register_read_cb(uart);
+ iotjs_uart_register_read_cb((uv_poll_t*)uart_poll_handle);
return true;
}
-bool iotjs_uart_write(iotjs_uart_t* uart) {
+bool iotjs_uart_write(uv_handle_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
iotjs_uart_platform_data_t* platform_data = uart->platform_data;
IOTJS_ASSERT(platform_data);
if (!platform_data->uart_h) {
return true;
}
-void iotjs_uart_handlewrap_close_cb(uv_handle_t* handle) {
- iotjs_uart_t* uart = (iotjs_uart_t*)handle->data;
+void iotjs_uart_handle_close_cb(uv_handle_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
if (peripheral_uart_close(uart->platform_data->uart_h) !=
PERIPHERAL_ERROR_NONE) {
bool iotjs_gpio_read(iotjs_gpio_t* gpio) {
- if (iotbus_gpio_read(gpio->platform_data->gpio_context) < 0) {
+ int ret = iotbus_gpio_read(gpio->platform_data->gpio_context);
+ if (ret < 0) {
+ DLOG("%s, Cannot read value(%d).", __func__, ret);
return false;
}
+
+ gpio->value = (bool)ret;
return true;
}
}
return true;
}
+
+
+bool iotjs_gpio_set_direction(iotjs_gpio_t* gpio) {
+ iotbus_gpio_direction_e direction;
+ if (gpio->direction == kGpioDirectionIn) {
+ direction = IOTBUS_GPIO_DIRECTION_IN;
+ } else {
+ direction = IOTBUS_GPIO_DIRECTION_OUT;
+ }
+
+ int ret =
+ iotbus_gpio_set_direction(gpio->platform_data->gpio_context, direction);
+ if (ret != 0) {
+ DLOG("%s, Cannot set direction(%d).", __func__, ret);
+ return false;
+ }
+
+ return true;
+}
#include "modules/iotjs_module_uart.h"
+#include "iotjs_uv_handle.h"
+
struct iotjs_uart_platform_data_s {
iotjs_string_t device_path;
};
return jerry_create_undefined();
}
-bool iotjs_uart_open(iotjs_uart_t* uart) {
+bool iotjs_uart_open(uv_handle_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
int fd = open(iotjs_string_data(&uart->platform_data->device_path),
O_RDWR | O_NOCTTY | O_NDELAY);
}
uart->device_fd = fd;
- iotjs_uart_register_read_cb(uart);
+ iotjs_uart_register_read_cb((uv_poll_t*)uart_poll_handle);
return true;
}
-bool iotjs_uart_write(iotjs_uart_t* uart) {
+bool iotjs_uart_write(uv_handle_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
int bytesWritten = 0;
unsigned offset = 0;
int fd = uart->device_fd;
return true;
}
-void iotjs_uart_handlewrap_close_cb(uv_handle_t* handle) {
- iotjs_uart_t* uart = (iotjs_uart_t*)handle->data;
+void iotjs_uart_handle_close_cb(uv_handle_t* uart_poll_handle) {
+ iotjs_uart_t* uart =
+ (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle);
if (close(uart->device_fd) < 0) {
DLOG(iotjs_periph_error_str(kUartOpClose));
int count_limit = created_files_length * 10;
char buffer[DEVICE_IO_PIN_BUFFER_SIZE];
char path[DEVICE_IO_PATH_BUFFER_SIZE] = { 0 };
- char check_format[DEVICE_IO_PATH_BUFFER_SIZE] = { 0 };
while (!iotjs_systemio_check_path(exported_path) && count < count_limit) {
usleep(100 * 1000); // sleep 100 miliseconds.
count++;
}
- strcat(check_format, exported_path);
- strcat(check_format, "%s");
-
for (int i = 0; i < created_files_length; i++) {
- snprintf(path, DEVICE_IO_PATH_BUFFER_SIZE - 1, check_format,
+ snprintf(path, DEVICE_IO_PATH_BUFFER_SIZE - 1, "%s%s", exported_path,
created_files[i]);
DDDLOG("%s - created file: %s", __func__, path);
more |= iotjs_process_next_tick();
jerry_value_t ret_val = jerry_run_all_enqueued_jobs();
- if (jerry_value_has_error_flag(ret_val)) {
+ if (jerry_value_is_error(ret_val)) {
DLOG("jerry_run_all_enqueued_jobs() failed");
}
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;
}
#include <tinyara/arch.h>
#include <tinyara/config.h>
-#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifdef JERRY_DEBUGGER
+#include <time.h>
+#endif /* JERRY_DEBUGGER */
#include "jerryscript-port.h"
#include "jerryscript.h"
} /* jerry_port_log */
/**
- * Dummy function to get the time zone.
- *
- * @return true
+ * Dummy function to get local time zone adjustment, in milliseconds,
+ * for the given timestamp.
*/
-bool jerry_port_get_time_zone(jerry_time_zone_t *tz_p) {
- /* We live in UTC. */
- tz_p->offset = 0;
- tz_p->daylight_saving_time = 0;
-
- return true;
-} /* jerry_port_get_time_zone */
+double jerry_port_get_local_time_zone_adjustment(double unix_ms, bool is_utc) {
+ (void)unix_ms;
+ (void)is_utc;
+ return 0.0;
+} /* jerry_port_get_local_time_zone_adjustment */
/**
- * Dummy function to get the current time.
+ * Get system time
*
- * @return 0
+ * @return milliseconds since Unix epoch
*/
double jerry_port_get_current_time(void) {
- return 0;
+ struct timespec ts;
+
+ /* Get the current time */
+ int ret = clock_gettime(CLOCK_REALTIME, &ts);
+ if (ret < 0) {
+ return 0.0;
+ }
+
+ return ((double)ts.tv_sec) * 1000.0 + ((double)ts.tv_nsec) / 1000000.0;
} /* jerry_port_get_current_time */
/**
// printf("%c", c);
} /* jerryx_port_handler_print_char */
-
-/**
- * Compiler built-in setjmp function.
- *
- * @return 0 when called the first time
- * 1 when returns from a longjmp call
- */
-
-int setjmp(jmp_buf buf) {
- return __builtin_setjmp(buf);
-} /* setjmp */
-
-/**
- * Compiler built-in longjmp function.
- *
- * Note:
- * ignores value argument
- */
-
-void longjmp(jmp_buf buf, int value) {
- /* Must be called with 1. */
- __builtin_longjmp(buf, 1);
-} /* longjmp */
+#ifdef JERRY_DEBUGGER
+void jerry_port_sleep(uint32_t sleep_time) {
+ nanosleep(
+ &(const struct timespec){
+ (time_t)sleep_time / 1000,
+ ((long int)sleep_time % 1000) * 1000000L /* Seconds, nanoseconds */
+ },
+ NULL);
+} /* jerry_port_sleep */
+#endif /* JERRY_DEBUGGER */
int iotjs_entry(int argc, char **argv);
int tuv_cleanup(void);
# only requires the iotjs and jerry header file(s).
#
cmake_minimum_required(VERSION 2.8)
-set(NAME test-dynamicmodule)
+set(NAME dynamicmodule)
# Currently only Linux and Tizen targets are supported
if(("${TARGET_OS}" STREQUAL "LINUX") OR ("${TARGET_OS}" STREQUAL "TIZEN"))
message(FATAL_ERROR "No 'IOTJS_INCLUDE_DIR' or 'JERRY_INCLUDE_DIR'")
endif()
+ string(TOLOWER ${TARGET_OS} TARGET_OS_NAME)
+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
+ set(OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build/${TARGET_OS_NAME}")
add_library(${NAME} SHARED
src/module_entry.c)
target_include_directories(${NAME}
PRIVATE ${IOTJS_INCLUDE_DIR} ${JERRY_INCLUDE_DIR})
set_target_properties(${NAME} PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY}
PREFIX ""
SUFFIX ".iotjs")
endif()
exports.isSunOS = process.platform === 'sunos';
exports.isFreeBSD = process.platform === 'freebsd';
exports.isLinux = process.platform === 'linux';
+exports.isNuttX = process.platform === 'nuttx';
exports.isTizen = process.platform === 'tizen';
exports.isOSX = process.platform === 'darwin';
var server2 = net.createServer(common.fail);
server2.on('error', common.mustCall(function(e) {
- // EADDRINUSE have different value on OSX.
+ // EADDRINUSE has different values on OSX and NuttX.
if (common.isOSX) {
assert.strictEqual(e, -48);
+ } else if (common.isNuttX) {
+ assert.strictEqual(e, -112);
} else {
assert.strictEqual(e, -98);
}
ENABLE_MODULE_IOTJS_CORE_MODULES
ENABLE_MODULE_ADC
ENABLE_MODULE_BLE
+ENABLE_MODULE_CRYPTO
ENABLE_MODULE_DGRAM
ENABLE_MODULE_GPIO
+ENABLE_MODULE_HTTP_SIGNATURE
ENABLE_MODULE_HTTPS
ENABLE_MODULE_I2C
+ENABLE_MODULE_MQTT
ENABLE_MODULE_PWM
ENABLE_MODULE_SPI
ENABLE_MODULE_UART
+ENABLE_MODULE_WEBSOCKET
--- /dev/null
+ENABLE_MODULE_IOTJS_BASIC_MODULES
+ENABLE_MODULE_IOTJS_CORE_MODULES
+ENABLE_MODULE_GPIO
+ENABLE_MODULE_I2C
ENABLE_MODULE_IOTJS_BASIC_MODULES
ENABLE_MODULE_IOTJS_CORE_MODULES
ENABLE_MODULE_ADC
+ENABLE_MODULE_CRYPTO
ENABLE_MODULE_DGRAM
ENABLE_MODULE_GPIO
ENABLE_MODULE_I2C
ENABLE_MODULE_IOTJS_BASIC_MODULES
ENABLE_MODULE_IOTJS_CORE_MODULES
ENABLE_MODULE_BLE
+ENABLE_MODULE_CRYPTO
ENABLE_MODULE_DGRAM
ENABLE_MODULE_GPIO
+ENABLE_MODULE_HTTP_SIGNATURE
ENABLE_MODULE_HTTPS
+ENABLE_MODULE_MQTT
ENABLE_MODULE_I2C
ENABLE_MODULE_PWM
ENABLE_MODULE_SPI
ENABLE_MODULE_UART
+ENABLE_MODULE_WEBSOCKET
--- /dev/null
+CONFIG_DISABLE_ES2015_BUILTIN
+CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
+CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
ENABLE_MODULE_IOTJS_BASIC_MODULES
ENABLE_MODULE_IOTJS_CORE_MODULES
ENABLE_MODULE_BRIDGE
+ENABLE_MODULE_CRYPTO
ENABLE_MODULE_DGRAM
ENABLE_MODULE_GPIO
+ENABLE_MODULE_HTTP_SIGNATURE
ENABLE_MODULE_HTTPS
+ENABLE_MODULE_MQTT
ENABLE_MODULE_I2C
ENABLE_MODULE_PWM
ENABLE_MODULE_SPI
ENABLE_MODULE_TIZEN
ENABLE_MODULE_UART
+ENABLE_MODULE_WEBSOCKET
ENABLE_MODULE_IOTJS_BASIC_MODULES
ENABLE_MODULE_IOTJS_CORE_MODULES
ENABLE_MODULE_ADC
+ENABLE_MODULE_CRYPTO
ENABLE_MODULE_DGRAM
ENABLE_MODULE_GPIO
+ENABLE_MODULE_HTTP_SIGNATURE
+ENABLE_MODULE_HTTPS
+ENABLE_MODULE_MQTT
ENABLE_MODULE_I2C
ENABLE_MODULE_PWM
ENABLE_MODULE_SPI
ENABLE_MODULE_UART
+ENABLE_MODULE_WEBSOCKET
--- /dev/null
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsHbJBfgc4tPdH0bkuVoL
+AAhN6rxk7RaD73thMVP1KtlyomXdydWT9CEBR/MBepyQaokHHYt430tqbOYeeYss
++SJUp2mU0C+XCcuD27T5lcwbUOFhN8pkerUKvuqM8u+ndYwgEbn8XHXSM+x62qWd
+wM6CO/kJx5CtzQaJ+2jPfdPnUYB3BpZvRL4ymzvGa3lUpwmtns3jfyZjJMz7Bd3A
+kH9gJTREhTLM3A4LNocgvIFLJNadlTbB5OgMMHxH3EEmXn1Wq+LeC57E4f2PuhmX
+vSRLbT85NpGC1U1AmuG2IVitwFkw1Hx23lZG8Zld/ZeV3kLBwJ2o002U3rs+H1aP
+8QIDAQAB
+-----END PUBLIC KEY-----
--- /dev/null
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv5B5QBJx+XGoK8xbY2Q9L5pJyv0Ddlzx
+pwWSz6q049b/+7YzVsFLt7S+O7soW7upfwTxFkCcpWWTKIoRac6vCYY14lTmWK/M1cntho8BiFoL
+cvDAx7dXgH2OfIsr6VgJMFl4DZebcN2fvhsZBo2lTyhJt8lSw8esTDHFZ8App6ilvVXJ4p6uKWJp
+1bzJQxvwHuNa4itN6GKyMR5kqklDwTa359JXXZf5LO7kFwO7ULCrtliaCUEUvG4xTgZfctD4gKMb
+WScMzx2U4ksSFhlmGyxcED2FH+fUn98Qo5KFflu01RaHScodXUZo6VMV5oY466Yq7y7z2R4KdpL4
+vC4v4wIDAQAB
+-----END PUBLIC KEY-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIJAMeGQlu8r9jlMA0GCSqGSIb3DQEBCwUAMHQxCzAJBgNV
+BAYTAkhVMRMwEQYDVQQIDApTb21lLVN0YXRlMQ8wDQYDVQQHDAZTemVnZWQxDjAM
+BgNVBAoMBU15IENBMREwDwYDVQQDDAhteWNhLm9yZzEcMBoGCSqGSIb3DQEJARYN
+bXljYUBteWNhLm9yZzAeFw0xODA2MjgxMDQzMThaFw0yODA2MjUxMDQzMThaMHQx
+CzAJBgNVBAYTAkhVMRMwEQYDVQQIDApTb21lLVN0YXRlMQ8wDQYDVQQHDAZTemVn
+ZWQxDjAMBgNVBAoMBU15IENBMREwDwYDVQQDDAhteWNhLm9yZzEcMBoGCSqGSIb3
+DQEJARYNbXljYUBteWNhLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALCPKzrZoSVHjswF0W/5pn0ElmAjO3GmYH1rHbTdSfQ9fXWiXWHREcGXeGXJ
+Vs/OIr6hxrghuPehYxERW2RhZESosOZgtifLC5hpg5guHzls0p8ix1gZ/olNBhzV
+/1qO5J7MSxx87DldDvoVTNyUzp/FEL5U45N4B8ECrY5+41BN1SPgAs5xc+LJLiag
+JjrsUxrpzngqsfpf15zcFsXcknB3VZKLQStkbmZB2RNWJm2dulSwr1tdXeZhBs1M
+seKh7MZ86ay/8/LJPedBUNUnIm/ZlinFYC5dxRpfA4RFL7Q91PZbAIRMphpXfE2x
+SSeOnkB2InXXwaPi+PlQnDzzSIMCAwEAAaNQME4wHQYDVR0OBBYEFNm9NQ9P2i35
+oCIFHQmft53GXlCNMB8GA1UdIwQYMBaAFNm9NQ9P2i35oCIFHQmft53GXlCNMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAIurYWyw/AkMlNeW7PIu7zsh
+6mknQ0RCI8h05CgJ6SlSlVQSB6Tu9BiLT0DNc0PTIQxHoqgVofATndLLn7a6G0Lc
+iy8mcYDbfAEcXiXFlo58gyWCa+/azJ/hslOVKvCs66BieHOiDhaBVzqWwUYaVMYA
+EocmusQmx44qrSsMfNPqq4b15b9sn0WximHtc76Czibnj35Nkhr/x2Cd07vnoU/2
+5fpiu8PfrSAjOw6oaAINwP6pXskl1+wtJ9NpqvEJVl4aEUWpSJoGtIJGOtM0zbNF
+/IPITiGuLri8FzYqfvYBxRR2Wuq94Vcmwh8r2mysuPC1dHtjg5l1hm8vqiBW3p4=
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAsI8rOtmhJUeOzAXRb/mmfQSWYCM7caZgfWsdtN1J9D19daJd
+YdERwZd4ZclWz84ivqHGuCG496FjERFbZGFkRKiw5mC2J8sLmGmDmC4fOWzSnyLH
+WBn+iU0GHNX/Wo7knsxLHHzsOV0O+hVM3JTOn8UQvlTjk3gHwQKtjn7jUE3VI+AC
+znFz4skuJqAmOuxTGunOeCqx+l/XnNwWxdyScHdVkotBK2RuZkHZE1YmbZ26VLCv
+W11d5mEGzUyx4qHsxnzprL/z8sk950FQ1Scib9mWKcVgLl3FGl8DhEUvtD3U9lsA
+hEymGld8TbFJJ46eQHYiddfBo+L4+VCcPPNIgwIDAQABAoIBAGeShOyP8B07XgRH
+QXYrgEQEZeZdpKhlzmKkbJfF3HU/gRJ5vcf86iqjnYgwVRGwPeeQZU9s0OHLNZ80
+jGVVUImKX8O1ZgXv8YxmEUE7hSudr+yUbVY8YXnPyk8uJg7MlkalV0aN7dE0yu1f
+g2g+jvtgkhLlH19J4VqTJJbbzqMzG+2m9htQqG2vM2spkYtSw3DbsmJS4zklkr/n
+g6VvIzLDzGq6KdIqE0LWvSiPm4pYTXQFk4j+J7UjY+ZmTXZIKedmk3a4vTpppiYu
+HAy1I8a5tZtgPYEOnRaZ2sPGuLcOgcBWa9iPx8JelRDcVB/51KcICsYZU/EOzoDc
+QHtqswECgYEA1ifEjpF4fTdAnXdrmj5ln3wIBjLd/YNAaOJW6ZWCFJ5Rcper7QYK
+2hUG9TvkJ/oq3m4v8X0gdxnOASpHZ5k04JMS58M85ptc4st0wvOvX36qdU9juRz4
+ClnCZDDndc1E7JMkqHl1uJHvDYWLFUYogkk042HIvkTwddNbp1tJL4ECgYEA0w7Q
+Dq6YIc+AHUisE0uVtli8kHZu/pQHv2XFZ3zRkwsYOLB5xwJU5uoXRZJcc6yF2EF+
+/kulJDLTwKi2b9UO491Fl071VqlGW086+gPmSDao0RzTGbfhqc3dAtn6fGHp1Vgf
+xpsxYTWpoiiexljHfa3NkDIYmgZtElRRR4iUugMCgYEAtol9E5xRHEHdNJsWv4lR
+64e3+zieWTjnzL6oID+MefCcMdWv+L8+vrZPkPY0uhKVObSn7umdo4b+PaYA6QAA
+vy79XUjf/xwMJ1AOPSGiqP35YzaBJMbZcVEizW2VzKZjila9V1D4E5NoNJlQfJip
+bKvjhbDSf8OZRoUaSWMY1YECgYApQqAR/rfnBDW7g9WAACrIdxiF9WFFi5LoK/En
+hhNCd8zIaFemPCJ08haSl0ZTpsqTuFonRIqIRRd4doMT4ccDbOKJ7fmwc285soeJ
+EPIX8/eUydnLEVOgaopmYE7DujCIcK3lmblRk7gR53cCt6BoRW4GXoTIt7DjAHDT
+VzQcGQKBgQDIsplosD3lXeRKA2agTozOROlUbJjYFlPLfztiXVPk3+QvGN1s4NIZ
+IzoJX/sufinHYzajRFK+IyAyusmnwHkwZz7WUmgJk0L6K+/T93nQhhwjSue6NMZK
+egpitIY58FY1J6Y67MR4+3h0/o4LCYQN5vOcrCAkczsNtAuVO0OnWA==
+-----END RSA PRIVATE KEY-----
--- /dev/null
+94825A52EA8A27F1
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIEazCCA1MCCQCUglpS6oon8TANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJI
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEPMA0GA1UEBwwGU3plZ2VkMQ4wDAYDVQQK
+DAVNeSBDQTERMA8GA1UEAwwIbXljYS5vcmcxHDAaBgkqhkiG9w0BCQEWDW15Y2FA
+bXljYS5vcmcwHhcNMTgwNjI4MTA0NjA3WhcNMjgwNjI1MTA0NjA3WjB7MQswCQYD
+VQQGEwJIVTETMBEGA1UECAwKU29tZS1TdGF0ZTEPMA0GA1UEBwwGU3plZ2VkMRAw
+DgYDVQQKDAdUcnVzdGVkMRIwEAYDVQQDDAlsb2NhbGhvc3QxIDAeBgkqhkiG9w0B
+CQEWEXRydXN0ZWRAbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEApd/5D3T9EWTLcJLTk8ayjc+GdSZBiRNYo4JSACf4LSrTBOif4UN/3PZi
+02wmPesPFyPY86cqJGi/7IVxaXX2stKLBRa+ZE7Pp7T9tIjkxx/Rw1GMEHLSjJM4
+JMBUJ2Vb6a0jLPAvNqO9jiXeaw6XJVtvXJrE71zVOj0R1Ttq0b3VQ10oQgZVfaRy
+xjMFD2sTMFo7ADkGw+XUqvp0ZMleeOk2yKuflvQkr/BUHzncepBtsMdxGb8Xm58Z
+QbVodLlbCD+NAoRpTnVphVxSpGsYRfLNfEHWYA8CD+1J3nPTAYU9t7AxZYPsqcHW
+GHc2A6badnwLsg4jNbUGx4bOS2Jwtf5uVQxPLHobI4lMFAZXBBHHuySP3O9WTPB8
+m/SHRFP2TBLARJX4DCpisaeZ2f0kshdUCZaxKCKoiiQ0Eo826iRJItiAOx+Uo3E4
+VP9+qkphOjPW23ERw8EDY5Cm///Pp4q/vlGICTn3peoxDnYcy+FDPvbw+dakQPtK
+IxurQC80RqV3f+W6LhVx3uZQYN2FkfOhQaMbfdq+jB6dcrXbh1FUPwa00eaPdfXz
+Fq1xWpfzE6GrjThijC0HkGrUT6ThQVG0nrHDhzbKw+27FUDkhwnOrNtCJy1GgS9m
+TUD1CvoDfdRSvqP4N1zrxNK4PNnYuN8m/xcycn8i7aMroQFEGSECAwEAATANBgkq
+hkiG9w0BAQsFAAOCAQEAd5MuhS49EtJo/dYnLS6MdHQ9Afwc5dlE7375hx1++cDg
+rV2XD1RuMovZpwCi58RPTsD+lp9QB/60SkW/85Dvbh7Xmh/u5Cr6J0/drVQpBj7U
+++9dVFPs0nHmxkYxC7ZYM+NX1cwbcfLYf9dpjA88tIcVatnFjVoGqaJpZzyd7vRv
+UESF9EG1rLAtla36absMwg/rGxH+Rl0If662lCiHHu7jN+lu2uBP8tQ4tWlIxybp
+wcEpJqpqN7WnMwFuuriUL3p8zcglsWwIqccKi3M/lYS2uLvHBhF/44W06RM0zwxg
+oFr+K2SlC17Xr+A29kL+OmtFdgrVIQAhVZX02v3IkA==
+-----END CERTIFICATE-----
+++ /dev/null
------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-----
--- /dev/null
+-----BEGIN CERTIFICATE REQUEST-----
+MIIEwDCCAqgCAQAwezELMAkGA1UEBhMCSFUxEzARBgNVBAgMClNvbWUtU3RhdGUx
+DzANBgNVBAcMBlN6ZWdlZDEQMA4GA1UECgwHVHJ1c3RlZDESMBAGA1UEAwwJbG9j
+YWxob3N0MSAwHgYJKoZIhvcNAQkBFhF0cnVzdGVkQGxvY2FsaG9zdDCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXf+Q90/RFky3CS05PGso3PhnUmQYkT
+WKOCUgAn+C0q0wTon+FDf9z2YtNsJj3rDxcj2POnKiRov+yFcWl19rLSiwUWvmRO
+z6e0/bSI5Mcf0cNRjBBy0oyTOCTAVCdlW+mtIyzwLzajvY4l3msOlyVbb1yaxO9c
+1To9EdU7atG91UNdKEIGVX2kcsYzBQ9rEzBaOwA5BsPl1Kr6dGTJXnjpNsirn5b0
+JK/wVB853HqQbbDHcRm/F5ufGUG1aHS5Wwg/jQKEaU51aYVcUqRrGEXyzXxB1mAP
+Ag/tSd5z0wGFPbewMWWD7KnB1hh3NgOm2nZ8C7IOIzW1BseGzkticLX+blUMTyx6
+GyOJTBQGVwQRx7skj9zvVkzwfJv0h0RT9kwSwESV+AwqYrGnmdn9JLIXVAmWsSgi
+qIokNBKPNuokSSLYgDsflKNxOFT/fqpKYToz1ttxEcPBA2OQpv//z6eKv75RiAk5
+96XqMQ52HMvhQz728PnWpED7SiMbq0AvNEald3/lui4Vcd7mUGDdhZHzoUGjG33a
+vowenXK124dRVD8GtNHmj3X18xatcVqX8xOhq404YowtB5Bq1E+k4UFRtJ6xw4c2
+ysPtuxVA5IcJzqzbQictRoEvZk1A9Qr6A33UUr6j+Ddc68TSuDzZ2LjfJv8XMnJ/
+Iu2jK6EBRBkhAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAgEAd88r+jJGHsPmBfhy
+ucNhCIK9VOh+kjlbfSnX0m6VJkNoqxJFx8mZ/fWlwUUW7Ff3WsmeDWEs/s5N6A3+
+NRAwPsuBrFImN/CeCbq0u4SU4+KJObZjmJjWhbXBgzYZQrtG/LvwOUceesDzgSj1
+qKfwSpafEYNeGtRWMcv02ypG7+h9Hbpqr2RpEe0Jgi3LAgW11wJzve/rLpDU3PKP
+DsZzx7GvkcWAuqxv3jTH68vJOEmHxUKNSybnvCGHCDcA/f5k0bROOO7RSJ1TQOKr
+dYLEMssil69gd/n2GpmXHmYjWx2LRlwuJp7Hm4GOjdmketu6bLotWH+R8lwBFuvH
+kDRGaBA2uHmFhtgokKult5zpCiIDw4FHfbC43dg63jGD3k6LrzrxbGbxZUb7tpFZ
+z9XJxdFPgzI6eOiiHD3SJikZoeox5AmUDCZOmsrF6Ex2iiTXxbIWfSqaImK8xZp4
+fUx6fDKy24SU+rrGqX8oxABOootPwdT/lsCVB4b/IdtzAugPf1dRDIHYWteohlc8
+4CVebKr0QyaQxH7fBRcTQmVNlJhzYfE6GcXa49G1AzXpEs6Eb3iPPRKRTNTssmZv
+ycHkTmWjoWLK1b1wEKK7jY17EXuIbxozIYCVoMXTEeUJtcB8lwt2gBDlASxfQYtB
+J8BmS9FN25iWTk5xW52UnpniwDk=
+-----END CERTIFICATE REQUEST-----
--- /dev/null
+-----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-----
+++ /dev/null
------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-----
--- /dev/null
+/* 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.
+ */
+
+Object.freeze(process);
+throw new Error("Some error");
--- /dev/null
+/* 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');
+
+function readfile(fileName) {
+ return new Promise(function(resolve, reject) {
+ throw function() {}(), Buffer;
+ });
+};
+
+try {
+ readfile(readfile).then(function(value) {
+ loadfi([], 0);
+ }).prototype(function(e) {});
+ assert(false);
+} catch (ex) {
+ assert(ex instanceof TypeError);
+}
--- /dev/null
+/* 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 array_src = [65, 66, 67];
+var buff = Buffer.from(array_src, 0, 3);
+assert.equal(buff.toString(), "ABC");
+var buff2 = Buffer.from(array_src, 0, -3);
+// Buffer.from(string, encoding)
+var string_utf = "ABC";
+var buff3 = Buffer.from(string_utf, 'utf8');
+assert.equal(buff3.toString(), "ABC");
+
+var string_hex = "414243";
+var buff4 = Buffer.from(string_hex, 'hex');
+assert.equal(buff4.toString(), "ABC");
+
+// Buffer.from(Buffer)
+var buffer_src = new Buffer([0x41, 0x42, 0x43]);
+var buff5 = Buffer.from(buffer_src);
+assert.equal(buff5.toString(), "ABC");
+
+var buff_undef = new Buffer(10);
+var buff6 = Buffer.from(buff_undef);
+assert.equal(buff6.toString(), buff_undef.toString());
+
+// Corner case tests
+var obj = {};
+var num = 5;
+assert.throws(function() { var buffer = Buffer.from(obj); },
+ TypeError);
+assert.throws(function() { var buffer = Buffer.from(num); },
+ TypeError);
--- /dev/null
+/* 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 source = new ArrayBuffer(10);
+
+//creation tests
+var buff1 = Buffer.from(source, 0, 10);
+assert.equal(buff1.length, 10);
+var buff2 = Buffer.from(source, 3, 7);
+assert.throws(function() { var buffer = buffer.from(source, 3, 10) })
+assert.equal(buff2.length, 7);
+var buff3 = Buffer.from(source, 10, 0);
+assert.equal(buff3.length, 0);
+var buff4 = Buffer.from(source, 0, 0);
+assert.equal(buff4.length, 0);
+assert.throws(function() { var buffer = Buffer.from(source, 0, 1000); },
+ RangeError);
+assert.throws(function() { var buffer = Buffer.from(source, 1000, 9); },
+ RangeError);
+assert.throws(function() { var buffer = Buffer.from(source, 1000, 1000); },
+ RangeError);
+
+var buff5 = Buffer.from(source, undefined, 10);
+assert.equal(buff5.length, 10);
+var buff6 = Buffer.from(source, undefined, 0);
+assert.equal(buff6.length, 0);
+
+var buff7 = Buffer.from(source, undefined, -10);
+assert.equal(buff7.length, 0);
+var buff8 = Buffer.from(source, 0, undefined);
+assert.equal(buff8.length, 10);
+var buff9 = Buffer.from(source, 10, undefined);
+assert.equal(buff9.length, 0);
+assert.throws(function() {var buffer = Buffer.from(source, -10, undefined); },
+ RangeError);
+var buff10 = Buffer.from(source, undefined, undefined);
+assert.equal(buff10.length, 10);
+
+var buff11 = Buffer.from(source, NaN, 10);
+assert.equal(buff11.length, 10);
+var buff12 = Buffer.from(source, NaN, 0);
+assert.equal(buff12.length, 0);
+var buff13 = Buffer.from(source, NaN, -10);
+assert.equal(buff13.length, 0);
+
+var buff14 = Buffer.from(source, 0, NaN);
+assert.equal(buff14.length, 0);
+
+var buff15 = Buffer.from(source, 10, NaN);
+assert.equal(buff15.length, 0);
+assert.throws(function() { var buffer = Buffer.from(source, -10, NaN); },
+ RangeError);
+
+//value checks
+var typed_source1 = new Uint8Array([65, 66]);
+var arr_buff = Buffer.from(typed_source1.buffer, 0, 2);
+assert.equal(arr_buff.toString('utf-8'), 'AB');
+
+var typed_source2 = new Uint16Array([65, 66]);
+var arr_buff2 = Buffer.from(typed_source2.buffer, 0, 1);
+var arr_buff3 = Buffer.from(typed_source2.buffer, 2, 1);
+assert.equal(arr_buff2.toString(), 'A');
+assert.equal(arr_buff3.toString(), 'B');
+
+var typed_source3 = new Uint8Array([42, 43]);
+var arr_buff4 = Buffer.from(typed_source3.buffer, 0, 2);
+assert.equal(arr_buff4.toString('hex'), '2a2b');
--- /dev/null
+/* 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.
+ */
+
+/* Related issue: https://github.com/Samsung/iotjs/issues/1379 */
+
+var assert = require('assert');
+
+/* The global Buffer by default is a function */
+assert.strictEqual(typeof(Buffer), "function");
+
+var backup_buffer = Buffer;
+
+/* Modify the global Buffer */
+Buffer++;
+
+/**
+ * The ++ operation will change the value of the "Buffer" variable.
+ * Thus the type shouldn't be a function now.
+ */
+assert.notStrictEqual(typeof(Buffer), "function");
+
+/**
+ * Still the creation of buffer should work.
+ * Using an already saved buffer reference
+ */
+var new_buffer = backup_buffer("OK");
+
+assert.equal(new_buffer.length, 2);
+assert.equal(new_buffer.toString(), "OK");
--- /dev/null
+/* 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 crypto = require('crypto');
+var assert = require('assert');
+
+var hash = crypto.createHash('sha1');
+
+assert.throws(function() { var err_hash = crypto.createHash('sadf'); });
+
+hash.update('Hello IoT.js');
+
+assert.equal(hash.digest('hex'), '4f5cf1945efb60f400c23172edb4e36b47f5a25e');
+assert.throws(function() { hash.digest('hex'); });
+
+var hash2 = crypto.createHash('sha1');
+hash2.update('Hello IoT.js');
+hash2.update(' v2');
+
+assert.equal(hash2.digest('base64'), 'DBnLTkxZ70AgUzCjZ7FTv91AWZw=');
--- /dev/null
+/* 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 crypto = require('crypto');
+var fs = require('fs');
+
+var hash = crypto.createHash('sha256');
+hash.update('Hello IoT.js');
+
+assert.equal(hash.digest('hex'),
+ '23a1b938002c83a74b887d0a447c990' +
+ '5e83bab00459bcfd0bad548623b942e20');
+
+/*
+ This test requires a key file, which can be generated using the following
+ steps:
+ openssl genrsa -aes128 -passout pass:<passphrase> -out private.pem 2048
+ openssl rsa -in private.pem -passin pass:<passphrase> -pubout -out public.pem
+
+ Recreating this test with your own data requires you to have (a) key file(s)
+ with a public and a private key in them. The private key is used to sign the
+ data.
+ The public key is used to verify that the signature was done with the
+ appropriate private key.
+
+ To generate the rsa-sha256 signature you need to execute these lines:
+ Creating an sha256 signature
+ openssl dgst -sha256 -sign <privatekeyfile> -out <signed.sha256> <inputfile>
+ Creating a base64 encoded signature
+ openssl base64 -in <signed.sha256> -out <signature.sha256>
+
+ To verify the signature, you need:
+ - The <signature.sha256> file,
+ - The public key, most likely from the public.pem file,
+ - The <inputfile> which contains the data, or you can just copy and paste,
+ the data and give it to the `verify.update()` function.
+
+ Having created the `verify` object, just call the `.verify(pubkey, signature)`
+ on it, and you are ready to go.
+*/
+
+var pubKey = fs.readFileSync(process.cwd() + '/resources/crypto_public.pem');
+var verify = crypto.createVerify('sha256');
+verify.update('Hello IoT.js\n');
+var res = verify.verify(pubKey, 'JkFnOrBQGXYlpmlcMuS5EwyJ44WY/kW5sFwb8DRgAoo7' +
+ 'RmxYPKgyo/OrZ0YAcY5xpxbVZzS7ftxz7N4q+Ouufg6s' +
+ 'NSzmIimBPLV+afX4Qb8jOV0edCmeBKZaHQrMWpisWXF/' +
+ 'bZKS1yiMij2NGSJYXWhjRzreIeVNVv/b0phHHeK2r2tT' +
+ '9T+XA+rdgHlIOb+r/FT/VWopr+vd+8I0fjxpP/S8lZ5u' +
+ 'HSF9jZ5TFdIEYMWchKit4Eyw7/VAWRlJNNKVxTmuM337' +
+ '+rP9oLKiFUeoM6jrE10LxGnIpelvyNV+MHfo11I1GAMK' +
+ 'jsOuye9JZ8/hQPg+KLWH/l/xZlUD2fZNNg==');
+assert.equal(res, true);
// Test with empty hostname.
dns.lookup('', 4, function(err, ip, family) {
- assert.notEqual(err, null);
+ if (process.platform === "windows") {
+ /* On windows the empty dns name can be resolved. */
+ assert.equal(err, null);
+ assert.notEqual(ip, null);
+ assert.notEqual(family, null);
+ } else {
+ assert.notEqual(err, null);
+ }
});
// Test with non string hostname.
--- /dev/null
+/* 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 fs = require('fs');
+var assert = require('assert');
+
+if (fs.createReadStream === undefined || fs.createWriteStream === undefined) {
+ process.exit(0);
+}
+
+var inputFile = process.cwd() + '/resources/tobeornottobe.txt';
+
+var res;
+var expected =
+ "To be, or not to be, that is the Question:\n" +
+ "Whether ’tis Nobler in the mind to ſuffer\n" +
+ "The Slings and Arrows of outragious Fortune,\n" +
+ "Or to take Armes against a Sea of troubles,\n" +
+ "And by opposing end them: to dye, to ſleepe\n" +
+ "No more; and by a sleep, to say we end\n" +
+ "The Heart-ake, and the thouſand Naturall ſhockes\n" +
+ 'That Flesh is there too? "Tis a consummation\n' +
+ "Deuoutly to be wiſh'd. To dye to sleepe,\n" +
+ "To sleep, perchance to Dream; I, there's the rub,\n" +
+ "For in that sleep of death, what dreams may come,\n" +
+ "When we haue ſhufflel’d off this mortall coile,\n" +
+ "Muſt giue us pause. There's the respect\n" +
+ "That makes Calamity of long life:\n" +
+ "For who would beare the Whips and Scornes of time,\n" +
+ "The Oppreſſors wrong, the poore mans Contumely,\n" +
+ "The pangs of diſpriz’d Loue, the Lawes delay,\n" +
+ "The inſolence of Office, and the Spurnes\n" +
+ "That patient merit of the vnworthy takes,\n" +
+ "When he himſelfe might his Quietus make\n" +
+ "With a bare Bodkin? Who would theſe Fardles beare\n" +
+ "To grunt and ſweat vnder a weary life,\n" +
+ "But that the dread of ſomething after death,\n" +
+ "The vndiſcouered Countrey, from whoſe Borne\n" +
+ "No Traueller returnes, Puzels the will,\n" +
+ "And makes vs rather beare those illes we haue,\n" +
+ "Then flye to others that we know not of.\n" +
+ "Thus Conſcience does make Cowards of vs all,\n" +
+ "And thus the Natiue hew of Resolution\n" +
+ "Is ſicklied o’re, with the pale caſt of Thought,\n" +
+ "And enterprizes of great pith and moment,\n" +
+ "With this regard their Currants turne away,\n" +
+ "And looſe the name of Action. Soft you now,\n" +
+ "The faire Ophelia? Nimph, in thy Orizons\n" +
+ "Be all my ſinnes remembred.";
+
+var readableFileStream = fs.createReadStream(inputFile);
+
+readableFileStream.on('data', function(data) {
+ res = data;
+});
+
+process.on('exit', function() {
+ assert.equal(res, expected);
+});
--- /dev/null
+/* 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 fs = require('fs');
+var assert = require('assert');
+
+if (fs.createReadStream === undefined || fs.createWriteStream === undefined) {
+ process.exit(0);
+}
+
+var inputFileName = process.cwd() + '/resources/tobeornottobe.txt';
+var outputFileName = process.cwd() + '/tmp/test_fs4.txt';
+
+var buff1 = new Buffer(2048);
+var buff2 = new Buffer(2048);
+
+// Get the correct content of the input for later checking.
+fs.open(inputFileName, 'r', 0666, function(err, fd) {
+ if (err) {
+ throw err;
+ }
+
+ fs.read(fd, buff1, 0, buff1.length, 0, function(err, bytesRead, buffer) {
+ if (err) {
+ throw err;
+ }
+
+ fs.close(fd, onclose);
+ });
+});
+
+function onclose(err) {
+ if (err) {
+ throw err;
+ }
+
+ var readableFileStream = fs.createReadStream(inputFileName);
+ var writableFileStream = fs.createWriteStream(outputFileName);
+
+ writableFileStream.on('ready', function() {
+ readableFileStream.pipe(writableFileStream);
+ });
+
+ writableFileStream.on('close', check_output);
+}
+
+function check_output() {
+ // Read the output for checking.
+ fs.open(outputFileName, 'r', function(err, fd) {
+ if (err) {
+ throw err;
+ }
+
+ fs.read(fd, buff2, 0, buff2.length, 0, function(err, bytesRead, buffer) {
+ if (err) {
+ throw err;
+ }
+
+ fs.close(fd, function(err) {
+ if (err) {
+ throw err;
+ }
+ })
+ });
+ });
+}
+
+process.on('exit', function() {
+ assert.equal(buff1.toString(), buff2.toString(),
+ 'File contents do not match');
+});
--- /dev/null
+/* 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 fs = require('fs');
+var assert = require('assert');
+
+if (fs.createReadStream === undefined || fs.createWriteStream === undefined) {
+ process.exit(0);
+}
+
+var dir = (process.platform === 'tizenrt') ? '/mnt/' : process.cwd() + '/tmp/';
+var outputFile = dir + 'test_fs5.txt';
+var testData = 'WriteStream test';
+
+var writableFileStream = fs.createWriteStream(outputFile);
+
+writableFileStream.on('ready', function() {
+ writableFileStream.write(testData);
+});
+
+var buff = new Buffer(64);
+writableFileStream.on('close', function() {
+ // Check output correctness
+ fs.open(outputFile, 'r', 0666, function(err, fd) {
+ if (err) {
+ throw err;
+ }
+
+ fs.read(fd, buff, 0, buff.length, 0, function(err, bytesRead, buffer) {
+ if (err) {
+ throw err;
+ }
+
+ assert.equal(buff.toString(), testData, 'Incorrect data in output file');
+
+ fs.close(fd, function(err) {
+ if (err) {
+ throw err;
+ }
+ });
+ });
+ })
+});
--- /dev/null
+/* 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 gpio = require('gpio');
+
+// ------ Test API existance
+assert.assert(gpio.DIRECTION,
+ 'gpio module does not provide \'DIRECTION\' property');
+assert.notEqual(gpio.DIRECTION.IN, undefined);
+assert.notEqual(gpio.DIRECTION.OUT, undefined);
+
+assert.assert(gpio.EDGE,
+ 'gpio module does not provide \'EDGE\' property');
+assert.notEqual(gpio.EDGE.NONE, undefined);
+assert.notEqual(gpio.EDGE.RISING, undefined);
+assert.notEqual(gpio.EDGE.FALLING, undefined);
+assert.notEqual(gpio.EDGE.BOTH, undefined);
+
+assert.assert(gpio.MODE,
+ 'gpio module does not provide \'MODE\' property');
+assert.notEqual(gpio.MODE.NONE, undefined);
+if (process.platform === 'nuttx') {
+ assert.notEqual(gpio.MODE.PULLUP, undefined);
+ assert.notEqual(gpio.MODE.PULLDOWN, undefined);
+ assert.notEqual(gpio.MODE.FLOAT, undefined);
+ assert.notEqual(gpio.MODE.PUSHPULL, undefined);
+ assert.notEqual(gpio.MODE.OPENDRAIN, undefined);
+}
+
+assert.equal(typeof gpio.open, 'function',
+ 'gpio does not provide \'open\' function');
+assert.equal(typeof gpio.openSync, 'function',
+ 'gpio does not provide \'openSync\' function');
+
+
+function check_gpiopin(gpiopin) {
+ assert.equal(typeof pin.setDirectionSync, 'function',
+ '\'gpiopin\' does not provide \'setDirectionSync\' function');
+ assert.equal(typeof pin.write, 'function',
+ '\'gpiopin\' does not provide \'write\' function');
+ assert.equal(typeof pin.writeSync, 'function',
+ '\'gpiopin\' does not provide \'writeSync\' function');
+ assert.equal(typeof pin.read, 'function',
+ '\'gpiopin\' does not provide \'read\' function');
+ assert.equal(typeof pin.readSync, 'function',
+ '\'gpiopin\' does not provide \'readSync\' function');
+ assert.equal(typeof pin.close, 'function',
+ '\'gpiopin\' does not provide \'close\' function');
+ assert.equal(typeof pin.closeSync, 'function',
+ '\'gpiopin\' does not provide \'closeSync\' function');
+}
+
+// ------ Test synchronous GPIO pin opening
+assert.throws(
+ function() {
+ gpio.openSync({pin: 0, direction: 123});
+ },
+ TypeError
+);
+
+assert.throws(
+ function() {
+ gpio.openSync({pin: 0, direction: {}});
+ },
+ TypeError
+);
+
+assert.throws(
+ function() {
+ gpio.openSync({pin: 0, direction: 'out'});
+ },
+ TypeError
+);
+
+assert.throws(
+ function() {
+ gpio.openSync({pin: 0, edge: 123});
+ },
+ TypeError
+);
+
+assert.throws(
+ function() {
+ gpio.openSync({pin: 0, edge: {}});
+ },
+ TypeError
+);
+
+assert.throws(
+ function() {
+ gpio.openSync({pin: 0, edge: 'rising'});
+ },
+ TypeError
+);
+
+assert.throws(
+ function() {
+ gpio.openSync({pin: '12'});
+ },
+ TypeError
+);
+
+assert.throws(
+ function() {
+ gpio.openSync({pin: {}});
+ },
+ TypeError
+);
+
+assert.throws(
+ function() {
+ gpio.openSync({pin: -12});
+ },
+ TypeError
+);
+
+var pin = gpio.openSync({pin: 0, direction: gpio.DIRECTION.OUT});
+check_gpiopin(pin);
+pin.closeSync();
+
+assert.throws( // close twice
+ function() {
+ pin.closeSync();
+ },
+ Error
+);
+
+pin = gpio.openSync({pin: 0, direction: gpio.DIRECTION.IN});
+check_gpiopin(pin);
+pin.closeSync();
+
+pin = gpio.openSync({pin: 0});
+check_gpiopin(pin);
+
+assert.doesNotThrow(function() {
+ pin.setDirectionSync(gpio.DIRECTION.OUT)
+});
+
+assert.throws(
+ function() {
+ pin.setDirectionSync(123);
+ },
+ TypeError
+);
+
+assert.throws(
+ function() {
+ pin.setDirectionSync('out');
+ },
+ Error
+);
+
+assert.throws(
+ function() {
+ pin.setDirectionSync({});
+ },
+ Error
+);
+
+assert.doesNotThrow(
+ function() {
+ pin.writeSync(true);
+ pin.writeSync(false);
+ pin.writeSync(0);
+ pin.writeSync(1);
+ pin.writeSync(123);
+ pin.writeSync(-123);
+ }
+);
+
+assert.doesNotThrow(
+ function() {
+ pin.write(true, function(err) {
+ assert.assert(err === null, 'gpio.write failed: ' + err);
+ write_cb1 = true;
+ });
+ pin.write(false, function(err) {
+ assert.assert(err === null, 'gpio.write failed: ' + err);
+ write_cb2 = true;
+ });
+ pin.write(0, function(err) {
+ assert.assert(err === null, 'gpio.write failed: ' + err);
+ write_cb3 = true;
+ });
+ pin.write(1, function(err) {
+ assert.assert(err === null, 'gpio.write failed: ' + err);
+ write_cb4 = true;
+ });
+ pin.write(123, function(err) {
+ assert.assert(err === null, 'gpio.write failed: ' + err);
+ write_cb5 = true;
+ });
+ pin.write(-123, function(err) {
+ assert.assert(err === null, 'gpio.write failed: ' + err);
+ write_cb6 = true;
+ });
+ }
+);
+
+assert.throws(
+ function() {
+ pin.writeSync('true');
+ },
+ Error
+);
+
+assert.throws(
+ function() {
+ pin.writeSync({});
+ },
+ Error
+);
+
+assert.throws(
+ function() {
+ gpio.write({});
+ },
+ Error
+);
+
+assert.throws(
+ function() {
+ gpio.write('true');
+ },
+ Error
+);
+
+pin.write('true', function(err) {
+ assert.assert(err, 'gpio.write did not fail as expected');
+});
+
+pin.write({}, function(err) {
+ assert.assert(err, 'gpio.write did not fail as expected');
+});
+
+// ------ Test asynchronous GPIO pin opening
+
+var async_pin1 = gpio.open(
+ {
+ pin: 0,
+ direction: gpio.DIRECTION.OUT
+ },
+ function(err, async_pin2) {
+ open_cb1 = true;
+ assert.assert(err === null, 'gpio.open failed: ' + err);
+ assert.assert(async_pin1);
+ assert.assert(async_pin2);
+ assert.assert(async_pin1 === async_pin2,
+ 'return value and callback parameters are not equal');
+ check_gpiopin(async_pin2);
+ async_pin2.close(function(err) {
+ close_cb1 = true;
+ assert.assert(err === null, 'gpio.close failed: ' + err);
+ });
+ }
+);
+
+gpio.open(
+ {
+ pin: 0,
+ direction: gpio.DIRECTION.IN
+ },
+ function(err, async_pin) {
+ open_cb2 = true;
+ assert.assert(err === null, 'gpio.open failed: ' + err);
+ check_gpiopin(async_pin);
+ async_pin.close(function(err) {
+ close_cb2 = true;
+ assert.assert(err === null, 'gpio.close failed: ' + err);
+ });
+ }
+);
+
+gpio.open(
+ { pin: 0 },
+ function(err, async_pin) {
+ open_cb3 = true;
+ assert.assert(err === null, 'gpio.open failed: ' + err);
+ check_gpiopin(async_pin);
+ async_pin.close(function(err) {
+ close_cb3 = true;
+ assert.assert(err === null, 'gpio.close failed: ' + err);
+ });
+ }
+);
+
+process.on('exit', function(code) {
+ if (code === 0) {
+ assert.assert(open_cb1, 'callback of \'gpio.open\' was not called');
+ assert.assert(close_cb1, 'callback of \'gpio.close\' was not called');
+ assert.assert(open_cb2, 'callback of \'gpio.open\' was not called');
+ assert.assert(close_cb2, 'callback of \'gpio.close\' was not called');
+ assert.assert(open_cb3, 'callback of \'gpio.open\' was not called');
+ assert.assert(close_cb3, 'callback of \'gpio.close\' was not called');
+
+ assert.assert(write_cb1, 'callback of \'gpio.write\' was not called');
+ assert.assert(write_cb2, 'callback of \'gpio.write\' was not called');
+ assert.assert(write_cb3, 'callback of \'gpio.write\' was not called');
+ assert.assert(write_cb4, 'callback of \'gpio.write\' was not called');
+ assert.assert(write_cb5, 'callback of \'gpio.write\' was not called');
+ assert.assert(write_cb6, 'callback of \'gpio.write\' was not called');
+ }
+ pin.closeSync();
+});
--- /dev/null
+/* 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 gpio = require('gpio');
+var pin = require('tools/systemio_common').pin;
+
+var gpioPin = gpio.openSync({
+ pin: pin.led,
+ direction: gpio.DIRECTION.OUT,
+});
+
+console.log('GPIO input test. Press the button.');
+gpioPin.setDirectionSync(gpio.DIRECTION.IN);
+var loop = setInterval(function() {
+ var value = gpioPin.readSync();
+ console.log('GpioPin value:', value);
+}, 500);
+
+setTimeout(function() {
+ clearInterval(loop);
+
+ console.log('GPIO output test. Led is on for 5000ms.');
+ gpioPin.setDirectionSync(gpio.DIRECTION.OUT);
+ gpioPin.writeSync(1);
+ setTimeout(function() {
+ gpioPin.writeSync(0);
+ }, 5000);
+}, 5000);
+
--- /dev/null
+/* 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 fs = require('fs');
+var http_sign = require('http_signature');
+var assert = require('assert');
+
+var key = fs.readFileSync(process.cwd() + '/resources/http_signature_key.key');
+
+// This is an example request of a Samsung C2C demo
+var sampleRequest = { "headers": {
+ "Content-Type":"application/json",
+ "Accept":"application/json",
+ "Authorization":"Signature keyId=\"http_signature_key\"," +
+ "signature=\"mJUG2ceYWCGww2tXrVJywQUqQvaWbkWpAx4xSfqZD9Gr" +
+ "G12N8pVysa/nl18kEKe2Sbd00c50qyF/xH5hKtxFyyUYBxY5cOrdt+7W" +
+ "1EmctaGGIDOnZA/qZcXcnTBZsp8k68XI/6HxwIxHVUntAd2vxJvqzibB" +
+ "TZLHAhTRVCoAqHzjHe0kybv5oebbMASaNEhZTLslQYQUOYqVzE+4Ecen" +
+ "Vxrlk2wpjjFjnBdxd/Ek34FTOcWMoPKjpj1ja+hfet2Em8YzF+aeHrBR" +
+ "t7FTt7r/GkYfuwm9M0XYSY1JvnvCKxIU20YXKbZ+KINBaUXDwEKapUvm" +
+ "bDFuLi3arJcDigWIOA==\",headers=\"(request-target) digest" +
+ " date\",algorithm=\"rsa-sha256\"",
+ "Date":"Tue, 28 Aug 2018 15:28:59 UTC",
+ "Digest":"SHA-256=52eIrPP0TxhlUVwnChuVLj6qFmbl5dYdMIvUr+DlZ0A=",
+ "X-ST-CORRELATION":"b7891162-2084-da6e-da84-401be50cd534",
+ "X-B3-TraceId":"fb04fc10f3088f10",
+ "X-B3-SpanId":"c6245b1a3c934a0d",
+ "X-B3-ParentSpanId":"989731b1f545e7d1",
+ "X-B3-Sampled":"1",
+ "content-length":"344",
+ "host":"example.host.com",
+ "user-agent":"AHC/2.1",
+ "X-Forwarded-Proto":"https",
+ "X-Forwarded-For":"52.14.6.245" },
+ "method": "POST",
+ "url": "/",
+ "httpVersion": "1.1",
+ };
+
+
+var parsedRequest = http_sign.parseRequest(sampleRequest);
+assert.equal(http_sign.verifySignature(parsedRequest, key), true);
--- /dev/null
+/* 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 i2c = require('i2c');
+
+// ------ Test API existance
+assert.equal(typeof i2c.open, 'function',
+ 'i2c does not provide \'open\' function');
+assert.equal(typeof i2c.openSync, 'function',
+ 'i2c does not provide \'openSync\' function');
+
+function check_i2cbus(i2cbus) {
+ assert.equal(typeof i2cbus.write, 'function',
+ '\'i2cpin\' does not provide \'write\' function');
+ assert.equal(typeof i2cbus.writeSync, 'function',
+ '\'i2cpin\' does not provide \'writeSync\' function');
+ assert.equal(typeof i2cbus.read, 'function',
+ '\'i2cpin\' does not provide \'read\' function');
+ assert.equal(typeof i2cbus.readSync, 'function',
+ '\'i2cpin\' does not provide \'readSync\' function');
+ assert.equal(typeof i2cbus.close, 'function',
+ '\'i2cpin\' does not provide \'close\' function');
+ assert.equal(typeof i2cbus.closeSync, 'function',
+ '\'i2cpin\' does not provide \'closeSync\' function');
+}
+
+// ------ Test synchronous I2C Bus opening
+assert.throws(
+ function() {
+ i2c.openSync({address: '0x0'});
+ },
+ TypeError
+);
+
+assert.throws(
+ function() {
+ i2c.openSync('0x0');
+ },
+ Error
+);
+
+assert.throws(
+ function() {
+ i2c.openSync({});
+ },
+ TypeError
+);
+
+var bus = i2c.openSync({address: 0x23});
+check_i2cbus(bus);
+
+assert.doesNotThrow(
+ function() {
+ bus.writeSync([0x10, 123, -12]);
+ read_result = bus.readSync(5);
+ }
+);
+
+assert.throws(
+ function() {
+ bus.writeSync(0x23);
+ },
+ Error
+);
+
+assert.throws(
+ function() {
+ bus.writeSync(null);
+ },
+ Error
+);
+
+assert.throws(
+ function() {
+ bus.readSync('5');
+ },
+ Error
+);
+
+assert.throws(
+ function() {
+ bus.readSync(null);
+ },
+ Error
+);
+
+assert.throws(
+ function() {
+ bus.readSync([5]);
+ },
+ Error
+);
+
+assert.throws(
+ function() {
+ bus.readSync({});
+ },
+ Error
+);
+
+assert.assert(Array.isArray(read_result));
+assert.strictEqual(read_result.length, 5);
+
+bus.closeSync();
+
+// ------ Test asynchronous I2C Bus opening
+i2c.open({address: 0x0}, function(open_err, async_bus) {
+ assert.equal(open_err, null);
+ open_cb1 = true;
+
+ assert.throws(
+ function() {
+ async_bus.read(null);
+ },
+ Error
+ );
+
+ assert.throws(
+ function() {
+ async_bus.write(null);
+ },
+ Error
+ );
+
+ async_bus.write([0x10, 123, -12], function(write_err) {
+ assert.equal(write_err, null);
+ write_cb1 = true;
+
+ async_bus.read(5, function(read_err, res) {
+ assert.equal(read_err, null);
+ read_cb1 = true;
+ assert.assert(Array.isArray(res));
+ assert.strictEqual(res.length, 5);
+
+ async_bus.close(function(close_err) {
+ assert.equal(close_err, null);
+ close_cb1 = true;
+ });
+ });
+ });
+});
+
+process.on('exit', function(code) {
+ if (code === 0) {
+ assert.assert(open_cb1, 'callback of \'i2c.open\' was not called');
+ assert.assert(close_cb1, 'callback of \'i2c.close\' was not called');
+
+ assert.assert(read_cb1, 'callback of \'i2cbus.read\' was not called');
+ assert.assert(write_cb1, 'callback of \'i2cbus.write\' was not called');
+ }
+});
+
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_dir = "dynamicmodule/build/" + process.platform + "/";
+var dynamicmodule_name = "dynamicmodule";
var dynamicmodule_path = dynamicmodule_dir + dynamicmodule_name + ".iotjs";
assert.assert(fs.existsSync(dynamicmodule_path),
--- /dev/null
+/* 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 mqtt = require('mqtt');
+var assert = require('assert');
+
+var connected = false;
+var subscribed = false;
+
+// The number of the variable is the qos level (0-2)
+
+var msg0 = 'hello iotjs 1';
+var msg1 = 'hello iotjs 2';
+var msg2 = 'hello iotjs 3';
+
+var published0 = false;
+var published1 = false;
+var published2 = false;
+
+var received0 = false;
+var received1 = false;
+var received2 = false;
+
+var subClientOpts = {
+ clientId: 'iotjs-mqtt-test-sub',
+ host: 'test.mosquitto.org',
+ port: 1883,
+ keepalive: 30,
+};
+
+var pubClientOpts = {
+ clientId: 'iotjs-mqtt-test-pub',
+ port: 1883,
+ keepalive: 30
+};
+
+var pubClient;
+
+var subClient = mqtt.connect(subClientOpts, function() {
+ connected = true;
+
+ subClient.subscribe('iotjs-test-topic', { qos:2 }, function() {
+ subscribed = true;
+
+ pubClient = mqtt.connect('test.mosquitto.org', pubClientOpts, function() {
+ pubClient.publish('iotjs-test-topic', msg0, { qos:0 }, function() {
+ published0 = true;
+ });
+
+ pubClient.publish('iotjs-test-topic', msg1, { qos:1 }, function() {
+ published1 = true;
+ });
+
+ pubClient.publish('iotjs-test-topic', msg2, { qos:2 }, function() {
+ published2 = true;
+ });
+ });
+ });
+
+ subClient.on('message', function(data) {
+ var str = data.message.toString();
+
+ if (str == msg0) {
+ received0 = true;
+ }
+
+ if (str == msg1) {
+ received1 = true;
+ }
+
+ if (str == msg2) {
+ received2 = true;
+ }
+
+ if (received0 && received1 && received2) {
+ subClient.end();
+ pubClient.end();
+ }
+ });
+});
+
+process.on('exit', function() {
+ assert.equal(connected, true);
+ assert.equal(subscribed, true);
+ assert.equal(published0, true);
+ assert.equal(published1, true);
+ assert.equal(published2, true);
+ assert.equal(received0, true);
+ assert.equal(received1, true);
+ assert.equal(received2, true);
+});
--- /dev/null
+/* 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 stream = require('stream');
+var mqtt = require('mqtt');
+var assert = require('assert');
+var fs = require('fs');
+
+var duplex = new stream.Duplex();
+
+var connect_state = 0;
+var recv_count = 0;
+var fragment_index = 0;
+
+// Message we send is always the same, but it is fragmented in different ways
+var fragments = [
+ // Basic message:
+ '3014000d67656e6572616c2f746f70696368656c6c6f',
+
+ // One message in three fragments
+ '30',
+ '14',
+ '000d67656e6572616c2f746f70696368656c6c6f',
+
+ // One message in four fragments
+ '30',
+ '14',
+ '00',
+ '0d67656e6572616c2f746f70696368656c6c6f',
+
+ // One message in five fragments
+ '30',
+ '14',
+ '00',
+ '0d67656e6572616c2f746f70696368656c6c',
+ '6f',
+
+ // Two connected messages
+ '3014000d67656e6572616c2f746f70696368656c6c6f' +
+ '3014000d67656e6572616c2f746f70696368656c6c6f',
+
+ // Two messages in three fragments
+ '3014000d67656e6572616c2f74',
+ '6f70696368656c6c6f3014000d67656e65',
+ '72616c2f746f70696368656c6c6f',
+
+ // Two messages in three fragments
+ '3014000d67656e6572616c2f746f70696368656c6c6f30',
+ '14',
+ '000d67656e6572616c2f746f70696368656c6c6f',
+
+ // A 132 byte long message
+ '30',
+ '87',
+ '01',
+ '000d67656e6572616c2f746f706963',
+ '68656c6c6f68656c6c6f68656c6c6f68656c6c6f',
+ '68656c6c6f68656c6c6f68656c6c6f68656c6c6f' +
+ '68656c6c6f68656c6c6f68656c6c6f68656c6c6f' +
+ '68656c6c6f68656c6c6f68656c6c6f68656c6c6f',
+ '68656c6c6f68656c6c6f68656c6c6f68656c6c6f' +
+ '68656c6c6f68656c6c6f68656c6c6f68656c6c6f'
+];
+
+function send_fragment() {
+ duplex.push(new Buffer(fragments[fragment_index], 'hex'));
+
+ if (++fragment_index < fragments.length) {
+ process.nextTick(send_fragment);
+ } else {
+ duplex.end();
+ }
+}
+
+duplex._write = function(chunk, callback, onwrite) {
+ onwrite();
+
+ switch (connect_state) {
+ case 0:
+ assert.equal(chunk.toString('hex'),
+ '100f00044d5154540402001e0003636c69');
+
+ process.nextTick(function() {
+ duplex.push(new Buffer('20020000', 'hex'));
+ });
+ break;
+
+ case 1:
+ assert.equal(chunk.toString('hex'),
+ '82120000000d67656e6572616c2f746f70696300');
+
+ process.nextTick(function() {
+ duplex.push(new Buffer('9003000002', 'hex'));
+ process.nextTick(send_fragment);
+ });
+ break;
+
+ default:
+ throw new RangeError("Unknown connection state")
+ break;
+ }
+
+ connect_state++;
+};
+
+duplex._readyToWrite();
+
+var mqtt_client = mqtt.connect({
+ clientId: 'cli',
+ keepalive: 30,
+ socket: duplex,
+}, function() {
+ /* Just subscribe a random topic. */
+ mqtt_client.subscribe('general/topic');
+});
+
+mqtt_client.on('message', function(data) {
+ if (recv_count < 10) {
+ assert.equal(data.message.toString(), 'hello');
+ } else {
+ var str = '';
+ for (var i = 0; i < 24; i++)
+ str += 'hello';
+ assert.equal(data.message.toString(), str);
+ }
+
+ recv_count++;
+});
+
+mqtt_client.on('finish', function(data) {
+ assert.equal(recv_count, 11);
+});
res.setHeader('h' + (5 + i), 'h' + (5 + i));
}
+ res.setHeader('content-length', 0);
+
res.end(function(){
server.close();
});
assert.equal(res.headers['h1'], 'h1');
assert.equal(res.headers['h2'], undefined);
assert.equal(res.headers['h3'], 'h3prime');
+ assert.equal(res.headers['content-length'], 0);
var endHandler = function(){
checkReqFinish = true;
--- /dev/null
+/* 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 http = require('http');
+
+assert(http.METHODS instanceof Array, 'http.METHODS should be an array');
+
+for (var idx in http.METHODS) {
+ assert(typeof(http.METHODS[idx]) === 'string',
+ 'Elements of the http.METHODS should be strings. ' +
+ 'Found an invalid element, index: ' + idx);
+}
+
+/* Test if at least the basic HTTP methods should be supported */
+var main_methods = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD'];
+for (var idx in main_methods) {
+ var method_name = main_methods[idx];
+ assert.notEqual(http.METHODS.indexOf(method_name), -1,
+ 'http.METHODS is missing the value: ' + method_name);
+}
--- /dev/null
+/* 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 http = require('http');
+
+var response_message = 'DATA';
+var response_got = 'NOT THIS';
+
+/*
+ * Test if 'subclassing' the IncomingMessage
+ * and ServerResponse is correctly propagated.
+ */
+function newIncomingMessage() {
+ http.IncomingMessage.apply(this, arguments);
+};
+newIncomingMessage.prototype = Object.create(http.IncomingMessage.prototype);
+newIncomingMessage.prototype.extra_field = 'found';
+newIncomingMessage.prototype.waitForBody = function() {
+ var chunks = [];
+ this.on('data', function(chunk) {
+ chunks.push(chunk);
+ });
+ this.on('end', function() {
+ this.emit('full_body', Buffer.concat(chunks));
+ });
+};
+
+
+function newServerResponse() {
+ http.ServerResponse.apply(this, arguments);
+};
+newServerResponse.prototype = Object.create(http.ServerResponse.prototype);
+newServerResponse.prototype.sendJSON = function (obj) {
+ var message_body = JSON.stringify(obj);
+ this.setHeader('Content-Length', message_body.length);
+ this.setHeader('Content-Type', 'application/json');
+ this.writeHead(200);
+ this.end(message_body);
+};
+
+var serveropts = {
+ IncomingMessage: newIncomingMessage,
+ ServerResponse: newServerResponse,
+};
+
+var server = http.createServer(serveropts, function (req, res) {
+ assert.equal(req.method, 'POST', 'Incorrect request method detected');
+ assert.equal(req.url, '/put_msg', 'Incorrect request url detected');
+ assert.assert(req instanceof http.IncomingMessage,
+ 'Request is not instance of http.IncomingMessage');
+ assert.assert(req instanceof newIncomingMessage,
+ 'Request is not instance of the new Request object');
+ assert.equal(req.extra_field, 'found',
+ 'No "extra_field" property on the request instance');
+
+ req.waitForBody();
+ req.on('full_body', function(body) {
+ assert.assert(body instanceof Buffer);
+ assert.equal(body.toString(), 'DEMO');
+
+ res.sendJSON({message: response_message});
+ });
+});
+
+server.listen(3001);
+
+var demo_msg = 'DEMO';
+var options = {
+ method : 'POST',
+ port : 3001,
+ path : '/put_msg',
+ headers: {
+ 'Content-Length': demo_msg.length,
+ },
+};
+var req = http.request(options, function (response){
+ var content_type =
+ response.headers['Content-Type'] || response.headers['content-type']
+ assert.equal(content_type, 'application/json',
+ 'Incorrect content type returned by the server');
+
+ var chunks = []
+ response.on('data', function(chunk) {
+ chunks.push(chunk);
+ });
+ response.on('end', function() {
+ var body = JSON.parse(Buffer.concat(chunks).toString());
+ assert.assert('message' in body, 'No "message" key in response JSON');
+ response_got = body.message;
+
+ server.close();
+ });
+});
+
+req.end(demo_msg);
+
+process.on('exit', function() {
+ assert.equal(response_got, response_message,
+ 'Invalid response returned from the demo server');
+});
--- /dev/null
+/* 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 http = require('http');
+
+var response_message = 'DATA';
+var response_got = 'NOT THIS';
+
+/*
+ * Test if 'subclassing' the IncomingMessage
+ * and ServerResponse is propagated correctly.
+ */
+function newIncomingMessage() {
+ http.IncomingMessage.apply(this, arguments);
+};
+newIncomingMessage.prototype = Object.create(http.IncomingMessage.prototype);
+newIncomingMessage.prototype.extra_field = 'found';
+newIncomingMessage.prototype.waitForBody = function() {
+ var chunks = [];
+ this.on('data', function(chunk) {
+ chunks.push(chunk);
+ });
+ this.on('end', function() {
+ this.emit('full_body', Buffer.concat(chunks));
+ });
+};
+
+
+var serveropts = {
+ IncomingMessage: newIncomingMessage,
+};
+
+var server = http.createServer(serveropts, function (req, res) {
+ assert.equal(req.method, 'POST', 'Incorrect request method detected');
+ assert.equal(req.url, '/put_msg', 'Incorrect request url detected');
+ assert.assert(req instanceof http.IncomingMessage,
+ 'Request is not instance of http.IncomingMessage');
+ assert.assert(req instanceof newIncomingMessage,
+ 'Request is not instance of the new Request object');
+ assert.equal(req.extra_field, 'found',
+ 'No "extra_field" property on the request instance');
+
+ req.waitForBody();
+ req.on('full_body', function(body) {
+ assert.assert(body instanceof Buffer);
+ assert.equal(body.toString(), 'DEMO');
+
+ var message_body = JSON.stringify({message: response_message});
+ res.setHeader('Content-Length', message_body.length);
+ res.setHeader('Content-Type', 'application/json');
+ res.writeHead(200);
+ res.end(message_body);
+ });
+});
+
+server.listen(3001);
+
+var demo_msg = 'DEMO';
+var options = {
+ method : 'POST',
+ port : 3001,
+ path : '/put_msg',
+ headers: {
+ 'Content-Length': demo_msg.length,
+ },
+};
+var req = http.request(options, function (response){
+ var content_type =
+ response.headers['Content-Type'] || response.headers['content-type']
+ assert.equal(content_type, 'application/json',
+ 'Incorrect content type returned by the server');
+
+ var chunks = []
+ response.on('data', function(chunk) {
+ chunks.push(chunk);
+ });
+ response.on('end', function() {
+ var body = JSON.parse(Buffer.concat(chunks).toString());
+ assert.assert('message' in body, 'No "message" key in response JSON');
+ response_got = body.message;
+
+ server.close();
+ });
+});
+
+req.end(demo_msg);
+
+process.on('exit', function() {
+ assert.equal(response_got, response_message,
+ 'Invalid response returned from the demo server');
+});
--- /dev/null
+/* 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 http = require('http');
+
+var response_message = 'DATA';
+var response_got = 'NOT THIS';
+
+/*
+ * Test if 'subclassing' the ServerResponse is propagated correctly.
+ */
+function newServerResponse() {
+ http.ServerResponse.apply(this, arguments);
+};
+newServerResponse.prototype = Object.create(http.ServerResponse.prototype);
+newServerResponse.prototype.sendJSON = function (obj) {
+ var message_body = JSON.stringify(obj);
+ this.setHeader('Content-Length', message_body.length);
+ this.setHeader('Content-Type', 'application/json');
+ this.writeHead(200);
+ this.end(message_body);
+};
+
+var serveropts = {
+ ServerResponse: newServerResponse,
+};
+
+var server = http.createServer(serveropts, function (req, res) {
+ assert.equal(req.method, 'POST', 'Incorrect request method detected');
+ assert.equal(req.url, '/put_msg', 'Incorrect request url detected');
+ assert.assert(req instanceof http.IncomingMessage,
+ 'Request is not instance of http.IncomingMessage');
+
+ var chunks = [];
+ req.on('data', function(chunk) {
+ chunks.push(chunk);
+ });
+ req.on('end', function() {
+ var body = Buffer.concat(chunks);
+ assert.equal(body.toString(), 'DEMO');
+
+ res.sendJSON({message: response_message});
+ });
+});
+
+server.listen(3001);
+
+var demo_msg = 'DEMO';
+var options = {
+ method : 'POST',
+ port : 3001,
+ path : '/put_msg',
+ headers: {
+ 'Content-Length': demo_msg.length,
+ },
+};
+var req = http.request(options, function (response){
+ var content_type =
+ response.headers['Content-Type'] || response.headers['content-type']
+ assert.equal(content_type, 'application/json',
+ 'Incorrect content type returned by the server');
+
+ var chunks = []
+ response.on('data', function(chunk) {
+ chunks.push(chunk);
+ });
+ response.on('end', function() {
+ var body = JSON.parse(Buffer.concat(chunks).toString());
+ assert.assert('message' in body, 'No "message" key in response JSON');
+ response_got = body.message;
+
+ server.close();
+ });
+});
+
+req.end(demo_msg);
+
+process.on('exit', function() {
+ assert.equal(response_got, response_message,
+ 'Invalid response returned from the demo server');
+});
--- /dev/null
+/* 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 http = require('http');
+var assert = require('assert');
+
+var clientMessage = new Buffer([0xE6, 0x7F, 0x3, 0x6, 0x7]);
+var serverMessage = new Buffer([0x3, 0x7F, 0x6, 0x7, 0xE6]);
+var serverReceived;
+var clientReceived;
+
+var server = http.createServer(function(req, res) {
+ var received = [];
+ req.on('data', function(data) {
+ received.push(data);
+ });
+ req.on('end', function() {
+ serverReceived = Buffer.concat(received);
+ res.end(serverMessage);
+ });
+}).listen(8383, 5);
+
+var reqOpts = {
+ method: 'POST',
+ port: 8383,
+ path: '/',
+ headers: {'Content-Length': clientMessage.length},
+};
+
+var clientReq = http.request(reqOpts, function(res) {
+ var response = [];
+
+ res.on('data', function(data) {
+ response.push(data);
+ });
+
+ res.on('end', function() {
+ clientReceived = Buffer.concat(response);
+ server.close();
+ });
+});
+
+clientReq.end(clientMessage);
+
+process.on('exit', function() {
+ assert.equal(serverReceived.compare(clientMessage), 0);
+ assert.equal(clientReceived.compare(serverMessage), 0);
+});
--- /dev/null
+/* 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 http = require('http');
+
+var server = http.createServer(function(request, response) {
+ // the http version in IoT.js is hardcoded to 1.1
+ assert.equal(request.httpVersion, "1.1",
+ "incorrect http version returned via the http request object");
+
+ response.writeHead(200);
+ response.end();
+});
+server.listen(3008, 5);
+
+var request = http.request({
+ method: 'HEAD',
+ port: 3008,
+ path: '/'
+}, function(response) {
+ assert.equal(response.statusCode, 200);
+
+ response.on('end', function() {
+ server.close();
+ });
+})
+request.end();
--- /dev/null
+/* 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 http = require('http');
+var https = require('https');
+
+var response_message = 'DATA';
+var response_got = 'NOT THIS';
+
+/*
+ * Test if 'subclassing' the IncomingMessage
+ * and ServerResponse is correctly propagated.
+ */
+function newIncomingMessage() {
+ http.IncomingMessage.apply(this, arguments);
+};
+newIncomingMessage.prototype = Object.create(http.IncomingMessage.prototype);
+newIncomingMessage.prototype.extra_field = 'found';
+newIncomingMessage.prototype.waitForBody = function() {
+ var chunks = [];
+ this.on('data', function(chunk) {
+ chunks.push(chunk);
+ });
+ this.on('end', function() {
+ this.emit('full_body', Buffer.concat(chunks));
+ });
+};
+
+
+function newServerResponse() {
+ http.ServerResponse.apply(this, arguments);
+};
+newServerResponse.prototype = Object.create(http.ServerResponse.prototype);
+newServerResponse.prototype.sendJSON = function (obj) {
+ var message_body = JSON.stringify(obj);
+ this.setHeader('Content-Length', message_body.length);
+ this.setHeader('Content-Type', 'application/json');
+ this.writeHead(200);
+ this.end(message_body);
+};
+
+var serveropts = {
+ IncomingMessage: newIncomingMessage,
+ ServerResponse: newServerResponse,
+
+ key: fs.readFileSync(process.cwd() + '/resources/my_key.key'),
+ cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt')
+};
+
+var server = https.createServer(serveropts, function (req, res) {
+ assert.equal(req.method, 'POST', 'Incorrect request method detected');
+ assert.equal(req.url, '/put_msg', 'Incorrect request url detected');
+ assert.assert(req instanceof http.IncomingMessage,
+ 'Request is not instance of http.IncomingMessage');
+ assert.assert(req instanceof newIncomingMessage,
+ 'Request is not instance of the new Request object');
+ assert.equal(req.extra_field, 'found',
+ 'No "extra_field" property on the request instance');
+
+ req.waitForBody();
+ req.on('full_body', function(body) {
+ assert.assert(body instanceof Buffer);
+ assert.equal(body.toString(), 'DEMO');
+
+ res.sendJSON({message: response_message});
+ });
+});
+
+server.listen(3001);
+
+var demo_msg = 'DEMO';
+var options = {
+ method : 'POST',
+ port : 3001,
+ path : '/put_msg',
+ headers: {
+ 'Content-Length': demo_msg.length,
+ },
+ rejectUnauthorized: false
+};
+var req = https.request(options, function (response){
+ var content_type =
+ response.headers['Content-Type'] || response.headers['content-type']
+ assert.equal(content_type, 'application/json',
+ 'Incorrect content type returned by the server');
+
+ var chunks = []
+ response.on('data', function(chunk) {
+ chunks.push(chunk);
+ });
+ response.on('end', function() {
+ var body = JSON.parse(Buffer.concat(chunks).toString());
+ assert.assert('message' in body, 'No "message" key in response JSON');
+ response_got = body.message;
+
+ server.close();
+ });
+});
+
+req.end(demo_msg);
+
+process.on('exit', function() {
+ assert.equal(response_got, response_message,
+ 'Invalid response returned from the demo server');
+});
var fs = require('fs');
var server_options = {
- key: fs.readFileSync('resources/my_key.pem').toString(),
- cert: fs.readFileSync('resources/my_crt.pem').toString()
+ key: fs.readFileSync(process.cwd() + '/resources/my_key.key').toString(),
+ cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt').toString()
};
var server = https.createServer(server_options, function(req, res) {
console.log('invalid path');
}
-assert.equal(process.cwd(), '/');
+var newPath = process.cwd();
+if (process.platform === "windows") {
+ /* check if the path is in format: <Drive Letter>:\ */
+ assert.equal(newPath.substr(1), ':\\');
+} else {
+ assert.equal(newPath, '/');
+}
process.chdir(currentPath);
--- /dev/null
+/* 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 net = require('net');
+var stream = require('stream');
+var Duplex = stream.Duplex;
+var Readable = stream.Readable;
+var Writable = stream.Writable;
+
+var readable = new Readable();
+
+var msg = [];
+var resp = [];
+
+// Test case 1: basic data correctness.
+var dest1 = new Writable();
+
+msg.push('Hello');
+
+dest1._write = function(chunk, callback, onwrite) {
+ resp.push(chunk.toString());
+}
+
+dest1._readyToWrite();
+
+readable.pipe(dest1);
+readable.push(msg[0]);
+readable.unpipe(dest1);
+
+// Test case 2: serial piping.
+var dest2 = new Duplex();
+var dest3 = new Duplex();
+var dest4 = new Duplex();
+
+msg.push('data');
+
+dest2._write = function(chunk, callback, onwrite) {
+ this.push(chunk);
+ resp.push(chunk.toString());
+}
+
+dest3._write = function(chunk, callback, onwrite) {
+ this.push(chunk);
+ resp.push(chunk.toString());
+}
+
+dest4._write = function(chunk, callback, onwrite) {
+ resp.push(chunk.toString());
+}
+
+dest2._readyToWrite();
+dest3._readyToWrite();
+dest4._readyToWrite();
+
+readable.pipe(dest2).pipe(dest3).pipe(dest4);
+readable.push(msg[1]);
+readable.unpipe(dest2);
+dest2.unpipe(dest3);
+dest3.unpipe(dest4);
+
+// Test case 3: unpipe test.
+var dest5 = new Writable();
+
+var dest5_write_called = false;
+dest5._write = function(chunk, callback, onwrite) {
+ dest5_write_called = true;
+}
+
+dest5._readyToWrite();
+
+readable.pipe(dest5);
+readable.unpipe(dest5);
+readable.push('foo');
+
+// Test case 4: pushing data to the readable stream
+// before piping it.
+var readable2 = new Readable();
+var dest6 = new Writable();
+msg.push('data before pipe');
+
+dest6._write = function(chunk, callback, onwrite) {
+ resp.push(chunk.toString());
+}
+
+dest6._readyToWrite();
+
+readable2.push(msg[2]);
+readable2.pipe(dest6);
+readable2.unpipe(dest6);
+
+// Test case 5: piping multiple destinations to a single Readable
+var readable3 = new Readable();
+msg.push('Multiple pipe test');
+
+var dest7 = new Writable();
+var dest8 = new Duplex();
+
+dest7._write = function(chunk, callback, onwrite) {
+ resp.push(chunk.toString());
+}
+
+dest8._write = function(chunk, callback, onwrite) {
+ resp.push(chunk.toString());
+}
+
+dest7._readyToWrite();
+dest8._readyToWrite();
+
+readable.pipe(dest7);
+readable.pipe(dest8);
+readable.push(msg[3]);
+readable.unpipe(dest7);
+readable.unpipe(dest8);
+
+// Test case 6: piping with net.Socket source
+msg.push('Hello from the server');
+
+var server = net.createServer({}, function(socket) {
+ socket.write(msg[4]);
+});
+server.listen(8080);
+
+var dest9 = new Duplex();
+
+dest9._write = function(chunk, callback, onwrite) {
+ resp.push(chunk.toString());
+ this.emit('_write_done');
+}
+
+// This is needed to make sure that the order of the results in the resp
+// array is correct.
+dest9.on('_write_done', testCase7);
+
+dest9._readyToWrite();
+
+var socket = new net.Socket();
+socket.pipe(dest9);
+
+socket.on('data', function(data) {
+ socket.end();
+});
+
+socket.on('end', function() {
+ socket.unpipe(dest9);
+ server.close();
+});
+
+socket.connect({'port': 8080});
+
+// Test case 7: piping with net.Socket destination
+function testCase7() {
+ msg.push('Hello from the socket');
+
+ var server2 = net.createServer({}, function(socket) {
+ socket.on('data', function(data) {
+ resp.push(data.toString());
+ socket.end();
+ });
+ });
+ server2.listen(8081);
+
+ var socket2 = new net.Socket();
+
+ socket2.on('data', function(data) {
+ socket2.write(data);
+ });
+
+ socket2.on('end', function() {
+ server2.close();
+ });
+
+ var readable4 = new Readable();
+ readable4.pipe(socket2);
+ socket2.connect({'port': 8081});
+ readable4.push(msg[5]);
+ readable4.unpipe(socket2);
+ socket2.end();
+}
+
+// checking the results
+process.on('exit', function() {
+ assert.equal(msg[0], resp[0], 'Basic data correctness test failed');
+ assert.equal(msg[1], resp[1], 'Serial pipe test failed');
+ assert.equal(msg[1], resp[2], 'Serial pipe test failed');
+ assert.equal(msg[1], resp[3], 'Serial pipe test failed');
+ assert.equal(dest5_write_called, false, 'Unpipe test failed');
+ assert.equal(msg[2], resp[4], 'Incorrect data when pushing to the ' +
+ 'readable stream before piping');
+ assert.equal(msg[3], resp[5], 'Multiple piping test failed');
+ assert.equal(msg[3], resp[6], 'Multiple piping test failed');
+ assert.equal(msg[4], resp[7], 'net.Socket source piping test failed');
+ assert.equal(msg[5], resp[8], 'net.Socket destination piping test failed');
+});
+++ /dev/null
-/* 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);
-});
--- /dev/null
+/* 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 tls = require('tls');
+
+var tlsClientError_caught = false;
+var socket_handshake_error_caught = false;
+
+var port = 8080;
+
+var server_options = {
+ rejectUnauthorized: false,
+ isServer: true
+}
+
+var server = tls.createServer(server_options, function(socket) {
+}).listen(port, function() {});
+
+server.on('tlsClientError', function(error) {
+ tlsClientError_caught = error instanceof Error;
+ server.close();
+});
+
+var socket_options = {
+ host: '127.0.0.1',
+ port: port,
+ rejectUnauthorized: false
+}
+
+var socket = tls.connect(socket_options, function() {});
+
+socket.on('error', function(error) {
+ socket_handshake_error_caught = error instanceof Error;
+});
+
+function createServerFailed(server_options) {
+ assert.throws(function() {
+ return tls.createServer(server_options);
+ });
+}
+
+createServerFailed({key: 0});
+createServerFailed({cert: null});
+createServerFailed({key: false, cert: 7});
+createServerFailed({ca: true});
+
+process.on('exit', function() {
+ assert.equal(tlsClientError_caught, true);
+ assert.equal(socket_handshake_error_caught, true);
+});
--- /dev/null
+/* 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 tls = require('tls');
+
+var expected_client_msg = 'Client hello';
+var expected_server_msg = 'Server hello';
+var client_message = '';
+var server_message = '';
+var server_closed = false;
+var server_handshake_done = false;
+var error_caught = false;
+var handshake_done = false;
+
+var port = 8080;
+
+var server_options = {
+ key: fs.readFileSync(process.cwd() + '/resources/my_key.key').toString(),
+ cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt'),
+ rejectUnauthorized: false,
+ isServer: true
+};
+
+var server = tls.createServer(server_options, function(socket1) {
+ socket1.write('Server hello');
+
+ socket1.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 socket_options = {
+ host: '127.0.0.1',
+ port: port,
+ rejectUnauthorized: false
+}
+
+var socket1 = tls.connect(socket_options, function() {});
+
+socket1.on('secureConnect', function() {
+ handshake_done = true;
+});
+
+socket1.on('end', function() {
+ server.close();
+});
+
+socket1.on('data', function(data) {
+ server_message += data.toString();
+ socket1.write('Client hello');
+ socket1.end();
+});
+
+var socket2 = tls.connect({host: '127.123.123.123', port: 444}, function() {
+ socket2.end();
+});
+
+socket2.on('error', function(err) {
+ error_caught = true;
+});
+
+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);
+});
--- /dev/null
+/* 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 tls = require('tls');
+
+var expected_client_msg = 'Client hello';
+var expected_server_msg = 'Server hello';
+var client_message = '';
+var server_message = '';
+var server_closed = false;
+var server_handshake_done = false;
+var handshake_done = false;
+
+var port = 8080;
+
+var server_options = {
+ key: fs.readFileSync(process.cwd() + '/resources/my_key.key').toString(),
+ cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt'),
+ rejectUnauthorized: false,
+ isServer: true
+};
+
+var server = tls.createServer(server_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 socket1 = tls.connect(port);
+
+socket1.on('secureConnect', function() {
+ handshake_done = true;
+});
+
+socket1.on('data', function(data) {
+ server_message = data.toString();
+ socket1.write('Client hello');
+ socket1.end();
+});
+
+var socket2 = tls.connect(port, 'localhost');
+
+socket2.on('secureConnect', function() {
+ handshake_done = true;
+});
+
+socket2.on('data', function(data) {
+ server_message = data.toString();
+ socket2.write('Client hello');
+ socket2.end();
+});
+
+var socket3 = tls.connect(port, function() {});
+
+socket3.on('secureConnect', function() {
+ handshake_done = true;
+});
+
+socket3.on('data', function(data) {
+ server_message = data.toString();
+ socket3.write('Client hello');
+ socket3.end();
+});
+
+socket3.on('end', function() {
+ server.close();
+});
+
+process.on('exit', function() {
+ 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);
+});
--- /dev/null
+/* 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 tls = require('tls');
+
+var expected_client_msg = 'Client hello';
+var expected_server_msg = 'Server hello';
+var client_message = '';
+var server_message = '';
+var server_closed = false;
+var server_handshake_done = false;
+var handshake_done = false;
+
+var port = 8080;
+
+var server_options = {
+ key: fs.readFileSync(process.cwd() + '/resources/my_key.key').toString(),
+ cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt'),
+ rejectUnauthorized: false,
+ isServer: true
+};
+
+var server = tls.createServer(server_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 socket_options = {
+ rejectUnauthorized: false,
+}
+
+var socket1 = tls.connect(port, 'localhost', socket_options);
+
+socket1.on('secureConnect', function() {
+ handshake_done = true;
+});
+
+socket1.on('data', function(data) {
+ server_message = data.toString();
+ socket1.write('Client hello');
+ socket1.end();
+});
+
+var socket2 = tls.connect(port, 'localhost', socket_options, function() {});
+
+socket1.on('secureConnect', function() {
+ handshake_done = true;
+});
+
+socket2.on('data', function(data) {
+ server_message = data.toString();
+ socket2.write('Client hello');
+ socket2.end();
+});
+
+var socket3 = tls.connect(port, 'localhost', function() {});
+
+socket3.on('secureConnect', function(){
+ handshake_done = true;
+});
+
+socket3.on('data', function(data) {
+ server_message = data.toString();
+ socket3.write('Client hello');
+ socket3.end();
+});
+
+socket3.on('end', function() {
+ server.close();
+});
+
+process.on('exit', function() {
+ 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);
+});
--- /dev/null
+/* 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.
+ */
+
+/*
+ For this test, we created a certificate authority, and signed
+ a certificate request with it. Here are the steps taken:
+
+ 1) created a secret rsa key for ourselves
+
+ openssl genrsa -out my_key.key 2048
+
+ Verify (dump): openssl rsa -in my_key.key -noout -text
+
+ 2) created a secret rsa key for our certificate authority (CA)
+
+ openssl genrsa -out my_ca.key 2048
+
+ Verify (dump): openssl rsa -in my_ca.key -noout -text
+
+ 3) created a certificate signing request (CSR),
+ which is signed by the CA later
+
+ openssl req -new -key my_key.pem -out my_csr.csr
+
+ Country Name (2 letter code) [AU]:HU
+ State or Province Name (full name) [Some-State]:
+ Locality Name (eg, city) []:Szeged
+ Organization Name (eg, company) [Internet Widgits Pty Ltd]:Trusted
+ Organizational Unit Name (eg, section) []:
+ Common Name (e.g. server FQDN or YOUR name) []:localhost
+ Email Address []:trusted@localhost
+
+ Please enter the following 'extra' attributes
+ to be sent with your certificate request
+ A challenge password []:ch+llenGe
+ An optional company name []:
+
+ Verify (dump): openssl req -in my_csr.csr -noout -text
+
+ 4) created a self-signed certificate for the CA
+
+ openssl req -new -x509 -key my_ca.key -out my_ca.crt
+
+ Country Name (2 letter code) [AU]:HU
+ State or Province Name (full name) [Some-State]:
+ Locality Name (eg, city) []:Szeged
+ Organization Name (eg, company) [Internet Widgits Pty Ltd]:My CA
+ Organizational Unit Name (eg, section) []:
+ Common Name (e.g. server FQDN or YOUR name) []:myca.org
+ Email Address []:myca@myca.org
+
+ Verify (dump): openssl x509 -in my_ca.crt -noout -text
+
+ 5) sign our certificate signing request
+
+ openssl x509 -req -in my_csr.csr -CA my_ca.crt -CAkey my_ca.key \
+ -CAcreateserial -out my_crt.crt
+
+ Note: A my_ca.srl file is also created to record the already
+ issued serial numbers. This file is needed for future
+ certificate signings.
+
+ Verify (dump): openssl x509 -in my_crt.crt -noout -text
+*/
+
+var tls = require('tls');
+var assert = require('assert');
+var fs = require('fs');
+
+var port = 8080;
+
+var server_message = '';
+
+var options = {
+ key: fs.readFileSync(process.cwd() + '/resources/my_key.key').toString(),
+ cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt')
+};
+
+var server = tls.createServer(options, function(socket) {
+ socket.write('Server hello');
+}).listen(port);
+
+var sockOpts = {
+ // The my_crt.crt certificate was issued for localhost as server FQDN
+ // Anything else here (e.g. 127.0.0.1) makes the handshake failed
+ host: 'localhost',
+ port: port,
+ rejectUnauthorized: true,
+ ca: fs.readFileSync(process.cwd() + '/resources/my_ca.crt')
+}
+
+var socket = tls.connect(sockOpts, function() {
+ socket.on('data', function(data) {
+ server_message += data.toString();
+ socket.end();
+ server.close();
+ });
+});
+
+process.on('exit', function() {
+ assert.equal(server_message, 'Server hello');
+});
--- /dev/null
+/* 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 stream = require('stream');
+var tls = require('tls');
+var assert = require('assert');
+var fs = require('fs');
+
+var tls1_message = 'Hello, this is tls1';
+var tls1_expected_message = tls1_message;
+var tls2_message = 'Hello, this is tls2';
+var tls2_expected_message = tls2_message;
+var tls1_received_message = '';
+var tls2_received_message = '';
+var tls1_received_encrypted = '';
+var tls2_received_encrypted = '';
+
+var handshake_done = false;
+var tls1_ended = false;
+var tls2_ended = false;
+
+var duplex1 = new stream.Duplex();
+var duplex2 = new stream.Duplex();
+
+duplex1._write = function(chunk, callback, onwrite) {
+ duplex2.push(chunk);
+ onwrite();
+};
+
+duplex2._write = function(chunk, callback, onwrite) {
+ duplex1.push(chunk);
+ onwrite();
+};
+
+duplex1._readyToWrite();
+duplex2._readyToWrite();
+
+var server_opts = {
+ key: fs.readFileSync(process.cwd() + '/resources/my_key.key').toString(),
+ cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt').toString(),
+ isServer: true,
+ rejectUnauthorized: false,
+};
+
+var client_opts = {
+ rejectUnauthorized: false,
+};
+
+var tls1 = new tls.TLSSocket(duplex1, server_opts);
+var tls2 = new tls.TLSSocket(duplex2, client_opts);
+
+tls2.on('secureConnect', function() {
+ handshake_done = true;
+});
+
+tls1.on('data', function(data) {
+ tls1_received_message += data.toString();
+ tls1.end();
+});
+
+tls1._socket.on('data', function(data) {
+ tls1_received_encrypted += data.toString('hex');
+});
+
+tls2.on('data', function(data) {
+ tls2_received_message += data.toString();
+ tls2.write(tls2_message);
+});
+
+tls2._socket.on('data', function(data) {
+ tls2_received_encrypted += data.toString('hex');
+});
+
+tls1.on('end', function() {
+ tls1_ended = true;
+ tls2.end();
+});
+
+tls2.on('end', function() {
+ tls2_ended = true;
+});
+
+tls1.write(tls1_message);
+
+process.on('exit', function() {
+ assert.equal(tls1_received_message === tls2_expected_message, true);
+ assert.equal(tls2_received_message === tls1_expected_message, true);
+ assert.equal(tls1_received_encrypted === tls2_message, false);
+ assert.equal(tls2_received_encrypted === tls1_message, false);
+ assert.equal(handshake_done === true, true);
+ assert.equal(tls1_ended === true, true);
+ assert.equal(tls2_ended === true, true);
+});
--- /dev/null
+/* 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 ws = require('websocket');
+var assert = require('assert');
+
+var websocket = new ws.Websocket();
+
+var connected = false;
+var message_sent = 'Hello IoT.js WebSocket';
+var message_received = null;
+var ping_sent = 'IoT.js ping message';
+var ping_received = null;
+var close_string = 'Connection successfully closed';
+
+websocket.connect('ws://echo.websocket.org', 80, '/', function() {
+ connected = true;
+
+ this.on('message', function(msg){
+ message_received = msg.toString();
+ });
+
+ this.ping(ping_sent, true, function(msg) {
+ ping_received = msg.toString();
+ });
+
+ this.on('close', function(msg) {
+ assert.equal(msg.code, '1000');
+ assert.equal(msg.reason, close_string);
+ });
+
+ this.send(message_sent, {mask: true, binary: false})
+ this.close(close_string, 1000);
+});
+
+
+process.on('exit', function() {
+ assert.equal(connected, true);
+ assert.equal(message_received, message_sent);
+ assert.equal(ping_sent, ping_received);
+});
--- /dev/null
+/* 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 websocket = require('websocket');
+var assert = require('assert');
+var http = require('http');
+
+var client = new websocket.Websocket();
+var client2 = new websocket.Websocket();
+var client3 = new websocket.Websocket();
+var message_sent = 'Hello IoT.js WebSocket';
+var ping_sent = 'IoT.js ping message';
+var close_string = 'Connection successfully closed';
+var close_code = 1000;
+
+function listener(ws) {
+ ws.on('message', function(msg) {
+ assert.equal(message_sent, msg.toString(),
+ 'Message received by the Server');
+ // echo
+ ws.send(msg.toString(), {mask: true, binary: false});
+ });
+ ws.on('ping', function(msg) {
+ assert.equal(ping_sent, msg.toString(),
+ 'Ping received by the Server');
+ });
+}
+
+
+// Test two clients connection
+var options = {
+ port: 8081,
+};
+
+var wss = new websocket.Server(options, listener);
+var address = wss.address();
+
+wss.on('close', function(msg) {
+ assert.equal(close_string, msg.reason,
+ 'Close reason received by the Server1');
+ assert.equal(close_code, msg.code,
+ 'Close code received by the Server1');
+ assert.equal(address.address, '0.0.0.0', 'Address of Server1');
+ assert.equal(address.family, 'IPv4', 'Ip family of Server1');
+ assert.equal(address.port, '8081', 'Port of Server1');
+});
+
+client.connect('ws://localhost', 8081, '/', function() {
+ this.on('message', function(msg) {
+ assert.equal(message_sent, msg.toString(),
+ 'Message received by the Client1');
+ });
+
+ this.ping(ping_sent, true, function(msg) {
+ assert.equal(ping_sent, msg.toString(),
+ 'Ping received by the Client1');
+ });
+
+ this.on('close', function(msg) {
+ assert.equal(close_string, msg.reason,
+ 'Close reason received by the Client1');
+ assert.equal(close_code, msg.code,
+ 'Close code received by the Client1');
+ });
+
+ // Client2 connect
+ client2.connect('ws://localhost', 8081, '/');
+ client2.on('open', function() {
+ // Broadcast then terminate all clients and close the server
+ wss.broadcast(message_sent);
+ wss.close();
+ });
+
+ this.send(message_sent, {mask: true, binary: false});
+});
+
+
+// Test http server upgrade to websocket
+var httpServer = http.createServer().listen(8082);
+
+options = {
+ server: httpServer,
+};
+
+var wss2 = new websocket.Server(options, listener);
+
+wss2.on('close', function(msg) {
+ assert.equal(close_string, msg.reason,
+ 'Close reason received by the Server2');
+ assert.equal(close_code, msg.code,
+ 'Close code received by the Server2');
+});
+
+client3.connect('ws://localhost', 8082, '/', function() {
+ this.on('message', function(msg) {
+ assert.equal(message_sent, msg.toString(),
+ 'Message received by the Client3');
+ wss2.close();
+ });
+
+ this.ping(ping_sent, true, function(msg) {
+ assert.equal(ping_sent, msg.toString(),
+ 'Ping received by the Client3');
+ });
+
+ this.on('close', function(msg) {
+ assert.equal(close_string, msg.reason,
+ 'Close reason received by the Client3');
+ assert.equal(close_code, msg.code,
+ 'Close code received by the Client3');
+ });
+
+ this.send(message_sent, {mask: true, binary: false});
+});
--- /dev/null
+/* 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 websocket = require('websocket');
+var assert = require('assert');
+var fs = require('fs');
+var tls = require('tls');
+var key = fs.readFileSync(process.cwd() +
+ '/resources/my_key.key').toString();
+var cert = fs.readFileSync(process.cwd() +
+ '/resources/my_crt.crt');
+
+var client = new websocket.Websocket();
+var client2 = new websocket.Websocket();
+var client3 = new websocket.Websocket();
+var message_sent = 'Hello IoT.js WebSocket';
+var ping_sent = 'IoT.js ping message';
+var close_string = 'Connection successfully closed';
+var close_code = 1000;
+
+function listener(ws) {
+ ws.on('message', function(msg) {
+ assert.equal(message_sent, msg.toString(),
+ 'Message received by the Server');
+ // echo
+ ws.send(msg.toString(), {mask: true, binary: false});
+ });
+ ws.on('ping', function(msg) {
+ assert.equal(ping_sent, msg.toString(),
+ 'Ping received by the Server');
+ });
+}
+
+
+// Test two clients connection
+var options = {
+ port: 8081,
+ secure: true,
+ key: key,
+ cert: cert,
+};
+
+var wss = new websocket.Server(options, listener);
+var address = wss.address();
+
+wss.on('close', function(msg) {
+ assert.equal(close_string, msg.reason,
+ 'Close reason received by the Server1');
+ assert.equal(close_code, msg.code,
+ 'Close code received by the Server1');
+ assert.equal(address.address, '0.0.0.0', 'Address of Server1');
+ assert.equal(address.family, 'IPv4', 'Ip family of Server1');
+ assert.equal(address.port, '8081', 'Port of Server1');
+});
+
+client.connect('wss://localhost', 8081, '/', function() {
+ this.on('message', function(msg) {
+ assert.equal(message_sent, msg.toString(),
+ 'Message received by the Client1');
+ });
+
+ this.ping(ping_sent, true, function(msg) {
+ assert.equal(ping_sent, msg.toString(),
+ 'Ping received by the Client1');
+ });
+
+ this.on('close', function(msg) {
+ assert.equal(close_string, msg.reason,
+ 'Close reason received by the Client1');
+ assert.equal(close_code, msg.code,
+ 'Close code received by the Client1');
+ });
+
+ // Client2 connect
+ client2.connect('wss://localhost', 8081, '/');
+ client2.on('open', function() {
+ // Broadcast then terminate all clients and close the server
+ wss.broadcast(message_sent);
+ wss.close();
+ });
+
+ this.send(message_sent, {mask: true, binary: false});
+});
+
+
+// Test tls server upgrade to websocket
+var tlsOptions = {
+ key: key,
+ cert: cert,
+ isServer: true,
+};
+
+var tlsServer = tls.createServer(tlsOptions).listen(8082);
+
+options = {
+ server: tlsServer,
+};
+
+var wss2 = new websocket.Server(options, listener);
+
+wss2.on('close', function(msg) {
+ assert.equal(close_string, msg.reason,
+ 'Close reason received by the Server2');
+ assert.equal(close_code, msg.code,
+ 'Close code received by the Server2');
+});
+
+client3.connect('wss://localhost', 8082, '/', function() {
+ this.on('message', function(msg) {
+ assert.equal(message_sent, msg.toString(),
+ 'Message received by the Client3');
+ wss2.close();
+ });
+
+ this.ping(ping_sent, true, function(msg) {
+ assert.equal(ping_sent, msg.toString(),
+ 'Ping received by the Client3');
+ });
+
+ this.on('close', function(msg) {
+ assert.equal(close_string, msg.reason,
+ 'Close reason received by the Client3');
+ assert.equal(close_code, msg.code,
+ 'Close code received by the Client3');
+ });
+
+ this.send(message_sent, {mask: true, binary: false});
+});
+++ /dev/null
-{
- "run_pass": [
- { "name": "test_iotjs_promise.js" },
- { "name": "test_iotjs_promise_chain_calls.js" }
- ]
-}
+++ /dev/null
-{
- "external_modules": [
- { "name": "test-external-module1.js" },
- { "name": "test-external-module2.js" }
- ]
-}
+++ /dev/null
-{
- "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" }
- ]
-}
+++ /dev/null
-{
- "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" }
- ]
-}
+++ /dev/null
-{
- "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" }
- ]
-}
{
- "run_pass": [
- { "name": "test_adc.js", "skip": ["all"], "reason": "need to setup test environment" },
- { "name": "test_assert.js" },
- { "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.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": ["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": ["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" },
- { "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": ["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" },
- { "name": "test_fs_readfile_sync.js" },
- { "name": "test_fs_rename.js", "skip": ["nuttx"], "reason": "depends on the type of the memory (testrunner uses Read Only Memory)" },
- { "name": "test_fs_rename_sync.js", "skip": ["nuttx"], "reason": "depends on the type of the memory (testrunner uses Read Only Memory)" },
- { "name": "test_fs_stat.js" },
- { "name": "test_fs_write.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" },
- { "name": "test_fs_writefile.js", "skip": ["nuttx"], "reason": "depends on the type of the memory (testrunner uses Read Only Memory)" },
- { "name": "test_fs_writefile_sync.js", "skip": ["nuttx"], "reason": "depends on the type of the memory (testrunner uses Read Only Memory)" },
- { "name": "test_fs_writefile_unlink.js", "skip": ["nuttx"], "reason": "depends on the type of the memory (testrunner uses Read Only Memory)" },
- { "name": "test_fs_writefile_unlink_sync.js", "skip": ["nuttx"], "reason": "depends on the type of the memory (testrunner uses Read Only Memory)" },
- { "name": "test_fs_event.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" },
- { "name": "test_fs_open_read.js" },
- { "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": "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": ["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" },
- { "name": "test_net_9.js" },
- { "name": "test_net_10.js" },
- { "name": "test_net_connect.js" },
- { "name": "test_net_headers.js" },
- { "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": ["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_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" },
- { "name": "test_process_exit.js" },
- { "name": "test_process_experimental_off.js", "skip": ["experimental"], "reason": "needed if testing stablity is set with stable" },
- { "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_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": "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_timers_arguments.js" },
- { "name": "test_timers_error.js" },
- { "name": "test_timers_simple.js", "timeout": 10 },
- { "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" }
+ "run_pass": [
+ {
+ "name": "test_adc.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "adc"
+ ]
+ },
+ {
+ "name": "test_assert.js"
+ },
+ {
+ "name": "test_ble_advertisement.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "ble"
+ ]
+ },
+ {
+ "name": "test_ble_setservices.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "ble"
+ ]
+ },
+ {
+ "name": "test_ble_setservices_central.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "run it with nodejs after running test_ble_setservices.js"
+ },
+ {
+ "name": "test_buffer.js"
+ },
+ {
+ "name": "test_buffer_from.js"
+ },
+ {
+ "name": "test_buffer_from_arraybuffer.js",
+ "required-features": [
+ "ArrayBuffer"
+ ]
+ },
+ {
+ "name": "test_buffer_str_conv.js"
+ },
+ {
+ "name": "test_buffer_inmutability_creation.js"
+ },
+ {
+ "name": "test_console.js",
+ "required-modules": [
+ "console"
+ ]
+ },
+ {
+ "name": "test_crypto.js",
+ "required-modules": [
+ "crypto"
+ ]
+ },
+ {
+ "name": "test_crypto_tls.js",
+ "required-modules": [
+ "crypto",
+ "fs",
+ "tls"
+ ]
+ },
+ {
+ "name": "test_dgram_1_server_1_client.js",
+ "required-modules": [
+ "dgram"
+ ]
+ },
+ {
+ "name": "test_dgram_1_server_n_clients.js",
+ "skip": [
+ "linux"
+ ],
+ "reason": "[linux]: flaky on Travis",
+ "required-modules": [
+ "dgram"
+ ]
+ },
+ {
+ "name": "test_dgram_address.js",
+ "required-modules": [
+ "dgram"
+ ]
+ },
+ {
+ "name": "test_dgram_broadcast.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "dgram"
+ ]
+ },
+ {
+ "name": "test_dgram_multicast_membership.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "dgram"
+ ]
+ },
+ {
+ "name": "test_dgram_multicast_set_multicast_loop.js",
+ "required-modules": [
+ "dgram"
+ ]
+ },
+ {
+ "name": "test_dgram_setttl_client.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "dgram"
+ ]
+ },
+ {
+ "name": "test_dgram_setttl_server.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "dgram"
+ ]
+ },
+ {
+ "name": "test_dns.js",
+ "required-modules": [
+ "net"
+ ]
+ },
+ {
+ "name": "test_dns_lookup.js",
+ "required-modules": [
+ "dns"
+ ]
+ },
+ {
+ "name": "test_events.js",
+ "required-modules": [
+ "events"
+ ]
+ },
+ {
+ "name": "test_events_assert_emit_error.js",
+ "required-modules": [
+ "events"
+ ]
+ },
+ {
+ "name": "test_events_uncaught_error.js",
+ "required-modules": [
+ "events"
+ ]
+ },
+ {
+ "name": "test_fs_exists.js",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_exists_sync.js",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_fstat.js",
+ "skip": [
+ "nuttx",
+ "tizenrt"
+ ],
+ "reason": "not implemented for nuttx/TizenRT",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_fstat_sync.js",
+ "skip": [
+ "nuttx",
+ "tizenrt"
+ ],
+ "reason": "not implemented for nuttx/TizenRT",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_mkdir_rmdir.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "[nuttx]: implemented, run manually in default configuration",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_open_close.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "not implemented for nuttx",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_read_stream.js",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_readdir.js",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_readfile.js",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_readfile_sync.js",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_rename.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "depends on the type of the memory (testrunner uses Read Only Memory)",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_rename_sync.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "depends on the type of the memory (testrunner uses Read Only Memory)",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_stat.js",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_stream_pipe.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "flaky on Travis",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_write.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "not implemented for nuttx",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_write_stream.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "depends on the type of the memory (testrunner uses Read Only Memory)",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_writefile.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "depends on the type of the memory (testrunner uses Read Only Memory)",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_writefile_sync.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "depends on the type of the memory (testrunner uses Read Only Memory)",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_writefile_unlink.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "depends on the type of the memory (testrunner uses Read Only Memory)",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_writefile_unlink_sync.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "depends on the type of the memory (testrunner uses Read Only Memory)",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_event.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "not implemented for nuttx",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_open_read.js",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_open_read_sync_1.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "not implemented for nuttx",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_open_read_sync_2.js",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_fs_open_read_sync_3.js",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_gpio_api.js",
+ "skip": [
+ "linux", "nuttx", "tizen", "tizenrt"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "gpio"
+ ]
+ },
+ {
+ "name": "test_gpio_direction.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "gpio"
+ ]
+ },
+ {
+ "name": "test_gpio_input.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "gpio"
+ ]
+ },
+ {
+ "name": "test_gpio_output.js",
+ "skip": [
+ "linux", "nuttx", "tizen", "tizenrt"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "gpio"
+ ]
+ },
+ {
+ "name": "test_http_signature.js",
+ "required-modules": [
+ "http_signature"
+ ]
+ },
+ {
+ "name": "test_i2c_api.js",
+ "skip": [
+ "linux", "nuttx", "tizen", "tizenrt"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "i2c"
+ ]
+ },
+ {
+ "name": "test_i2c_gy30.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "i2c"
+ ]
+ },
+ {
+ "name": "test_iotjs_promise.js",
+ "required-features": [
+ "Promise"
+ ]
+ },
+ {
+ "name": "test_iotjs_promise_chain_calls.js",
+ "required-modules": [
+ "fs"
+ ],
+ "required-features": [
+ "Promise"
+ ]
+ },
+ {
+ "name": "test_module_cache.js"
+ },
+ {
+ "name": "test_module_json.js"
+ },
+ {
+ "name": "test_module_require.js"
+ },
+ {
+ "name": "test_module_dynamicload.js",
+ "skip": [
+ "darwin",
+ "mock",
+ "nuttx",
+ "tizenrt",
+ "windows"
+ ],
+ "reason": "embedded, macos, and windows does not support dynamic loading",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "test_mqtt.js",
+ "required-modules": [
+ "mqtt"
+ ]
+ },
+ {
+ "name": "test_mqtt_frags.js",
+ "required-modules": [
+ "mqtt"
+ ]
+ },
+ {
+ "name": "test_net_1.js",
+ "required-modules": [
+ "net"
+ ]
+ },
+ {
+ "name": "test_net_2.js",
+ "required-modules": [
+ "net"
+ ]
+ },
+ {
+ "name": "test_net_3.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "[nuttx]: requires too many socket descriptors and too large buffers",
+ "required-modules": [
+ "net"
+ ]
+ },
+ {
+ "name": "test_net_4.js",
+ "required-modules": [
+ "net",
+ "timers"
+ ]
+ },
+ {
+ "name": "test_net_5.js",
+ "required-modules": [
+ "net",
+ "timers"
+ ]
+ },
+ {
+ "name": "test_net_6.js",
+ "required-modules": [
+ "net",
+ "timers"
+ ]
+ },
+ {
+ "name": "test_net_7.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "requires too many socket descriptors",
+ "required-modules": [
+ "net",
+ "timers"
+ ]
+ },
+ {
+ "name": "test_net_8.js",
+ "required-modules": [
+ "net",
+ "timers"
+ ]
+ },
+ {
+ "name": "test_net_9.js",
+ "required-modules": [
+ "net"
+ ]
+ },
+ {
+ "name": "test_net_10.js",
+ "required-modules": [
+ "net"
+ ]
+ },
+ {
+ "name": "test_net_connect.js",
+ "required-modules": [
+ "net"
+ ]
+ },
+ {
+ "name": "test_net_headers.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_http_get.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_http_outgoing_buffer.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_http_methods.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_http_response_twice.js",
+ "required-modules": [
+ "http",
+ "net"
+ ]
+ },
+ {
+ "name": "test_net_http_request_response.js",
+ "skip": [
+ "nuttx"
+ ],
+ "reason": "not implemented for nuttx",
+ "required-modules": [
+ "http",
+ "net"
+ ]
+ },
+ {
+ "name": "test_net_http_request_http_version.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_http_status_codes.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_http_modified_request.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_http_modified_response.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_http_modified_req_resp.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_httpclient_error.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_httpclient_parse_error.js",
+ "required-modules": [
+ "http",
+ "net"
+ ]
+ },
+ {
+ "name": "test_net_httpclient_timeout_1.js",
+ "required-modules": [
+ "http",
+ "net"
+ ]
+ },
+ {
+ "name": "test_net_httpclient_timeout_2.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_http_server_timeout.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_http_server.js",
+ "required-modules": [
+ "http"
+ ]
+ },
+ {
+ "name": "test_net_https_get.js",
+ "timeout": 10,
+ "required-modules": [
+ "https"
+ ]
+ },
+ {
+ "name": "test_net_https_post_status_codes.js",
+ "timeout": 10,
+ "required-modules": [
+ "https"
+ ]
+ },
+ {
+ "name": "test_net_https_request_response.js",
+ "timeout": 10,
+ "required-modules": [
+ "https",
+ "http",
+ "net"
+ ]
+ },
+ {
+ "name": "test_net_https_modified_req_resp.js",
+ "required-modules": [
+ "https",
+ "http",
+ "net"
+ ]
+ },
+ {
+ "name": "test_net_https_timeout.js",
+ "timeout": 10,
+ "required-modules": [
+ "https"
+ ]
+ },
+ {
+ "name": "test_net_https_server.js",
+ "timeout": 10,
+ "required-modules": [
+ "https",
+ "fs"
+ ]
+ },
+ {
+ "name": "test_process.js"
+ },
+ {
+ "name": "test_process_chdir.js"
+ },
+ {
+ "name": "test_process_cwd.js"
+ },
+ {
+ "name": "test_process_exit.js"
+ },
+ {
+ "name": "test_process_experimental_off.js",
+ "skip": [
+ "experimental"
+ ],
+ "reason": "needed if testing stablity is set with stable"
+ },
+ {
+ "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_uncaught_order.js"
+ },
+ {
+ "name": "test_process_uncaught_simple.js"
+ },
+ {
+ "name": "test_pwm_async.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "pwm"
+ ]
+ },
+ {
+ "name": "test_pwm_sync.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "pwm"
+ ]
+ },
+ {
+ "name": "test_spi.js",
+ "skip": [
+ "linux"
+ ],
+ "reason": "Different env on Linux desktop/travis/rpi",
+ "required-modules": [
+ "spi"
+ ]
+ },
+ {
+ "name": "test_spi_buffer_async.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "spi"
+ ]
+ },
+ {
+ "name": "test_spi_buffer_sync.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "spi"
+ ]
+ },
+ {
+ "name": "test_spi_mcp3008.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "spi"
+ ]
+ },
+ {
+ "name": "test_stream.js",
+ "required-modules": [
+ "stream"
+ ]
+ },
+ {
+ "name": "test_stream_duplex.js",
+ "required-modules": [
+ "stream"
+ ]
+ },
+ {
+ "name": "test_stream_pipe.js",
+ "required-modules": [
+ "stream"
+ ]
+ },
+ {
+ "name": "test_timers_arguments.js"
+ },
+ {
+ "name": "test_timers_error.js"
+ },
+ {
+ "name": "test_timers_simple.js",
+ "timeout": 10
+ },
+ {
+ "name": "test_tizen_app_control.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "tizen"
+ ]
+ },
+ {
+ "name": "test_tls_1.js",
+ "required-modules": [
+ "tls",
+ "fs"
+ ]
+ },
+ {
+ "name": "test_tls_2.js",
+ "required-modules": [
+ "tls",
+ "fs"
+ ]
+ },
+ {
+ "name": "test_tls_3.js",
+ "required-modules": [
+ "tls",
+ "fs"
+ ]
+ },
+ {
+ "name": "test_tls_4.js",
+ "required-modules": [
+ "tls",
+ "fs"
+ ]
+ },
+ {
+ "name": "test_tls_ca.js",
+ "required-modules": [
+ "tls",
+ "fs"
+ ]
+ },
+ {
+ "name": "test_tls_stream_duplex.js",
+ "required-modules": [
+ "tls",
+ "fs",
+ "stream"
+ ]
+ },
+ {
+ "name": "test_uart.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "uart"
+ ]
+ },
+ {
+ "name": "test_uart_api.js",
+ "required-modules": [
+ "uart"
+ ]
+ },
+ {
+ "name": "test_util.js",
+ "required-modules": [
+ "util"
+ ]
+ },
+ {
+ "name": "test_websocket.js",
+ "required-modules": [
+ "websocket"
+ ]
+ },
+ {
+ "name": "test_websocket_server.js",
+ "required-modules": [
+ "websocket"
+ ]
+ },
+ {
+ "name": "test_websocket_server_secure.js",
+ "required-modules": [
+ "websocket",
+ "tls"
+ ]
+ }
],
"run_pass/issue": [
- { "name": "issue-133.js" },
- { "name": "issue-137.js" },
- { "name": "issue-198.js" },
- { "name": "issue-223.js" },
- { "name": "issue-266.js" },
- { "name": "issue-323.js" },
- { "name": "issue-816.js" },
- { "name": "issue-1046.js" },
- { "name": "issue-1077.js" },
- { "name": "issue-1101.js", "skip": ["all"], "reason": "need to setup test environment" },
- { "name": "issue-1348.js" },
- { "name": "issue-1485.js" },
- { "name": "issue-1507.js" },
- { "name": "issue-1557.js" }
+ {
+ "name": "issue-133.js"
+ },
+ {
+ "name": "issue-137.js"
+ },
+ {
+ "name": "issue-198.js"
+ },
+ {
+ "name": "issue-223.js",
+ "required-modules": [
+ "net"
+ ]
+ },
+ {
+ "name": "issue-266.js",
+ "required-modules": [
+ "net"
+ ]
+ },
+ {
+ "name": "issue-323.js",
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "name": "issue-816.js",
+ "required-modules": [
+ "buffer"
+ ]
+ },
+ {
+ "name": "issue-1046.js",
+ "required-modules": [
+ "buffer"
+ ]
+ },
+ {
+ "name": "issue-1077.js"
+ },
+ {
+ "name": "issue-1101.js",
+ "skip": [
+ "all"
+ ],
+ "reason": "need to setup test environment",
+ "required-modules": [
+ "uart"
+ ]
+ },
+ {
+ "name": "issue-1348.js"
+ },
+ {
+ "name": "issue-1463.js",
+ "required-features": [
+ "Promise"
+ ]
+ },
+ {
+ "name": "issue-1485.js"
+ },
+ {
+ "name": "issue-1507.js",
+ "required-modules": [
+ "console"
+ ]
+ },
+ {
+ "name": "issue-1557.js"
+ }
],
- "run_fail": [
- { "name": "test_assert_equal.js", "expected-failure": true },
- { "name": "test_assert_fail.js", "expected-failure": true },
- { "name": "test_assert_notequal.js", "expected-failure": true },
- { "name": "test_events_emit_error.js", "expected-failure": true },
- { "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 },
- { "name": "test_process_exitcode_var.js", "expected-failure": true },
- { "name": "test_process_explicit_exit.js", "expected-failure": true },
- { "name": "test_process_implicit_exit.js", "expected-failure": true },
- { "name": "test_timers_issue_1353.js", "expected-failure": true }
+ "run_fail": [
+ {
+ "name": "test_assert_equal.js",
+ "expected-failure": true
+ },
+ {
+ "name": "test_assert_fail.js",
+ "expected-failure": true
+ },
+ {
+ "name": "test_assert_notequal.js",
+ "expected-failure": true
+ },
+ {
+ "name": "test_events_emit_error.js",
+ "expected-failure": true,
+ "required-modules": [
+ "events"
+ ]
+ },
+ {
+ "name": "test_fs_callbacks_called.js",
+ "expected-failure": true,
+ "required-modules": [
+ "fs"
+ ]
+ },
+ {
+ "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,
+ "required-modules": [
+ "dns"
+ ]
+ },
+ {
+ "name": "test-issue-1360.js",
+ "expected-failure": true
+ },
+ {
+ "name": "test-issue-1570.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
+ },
+ {
+ "name": "test_process_exitcode_var.js",
+ "expected-failure": true
+ },
+ {
+ "name": "test_process_explicit_exit.js",
+ "expected-failure": true
+ },
+ {
+ "name": "test_process_implicit_exit.js",
+ "expected-failure": true
+ },
+ {
+ "name": "test_timers_issue_1353.js",
+ "expected-failure": true
+ }
],
"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" },
- { "name": "test-net-bind-twice.js" },
- { "name": "test-net-end-without-connect.js" },
- { "name": "test-net-keepalive.js" },
- { "name": "test-timers-clear-null-does-not-throw-error.js" }
+ {
+ "name": "test-assert.js",
+ "required-modules": [
+ "fs",
+ "stream"
+ ]
+ },
+ {
+ "name": "test-module-circular.js",
+ "required-modules": [
+ "fs",
+ "stream"
+ ]
+ },
+ {
+ "name": "test-http-catch-uncaughtexception.js",
+ "required-modules": [
+ "http",
+ "fs",
+ "stream"
+ ]
+ },
+ {
+ "name": "test-http-status-message.js",
+ "required-modules": [
+ "http",
+ "net",
+ "fs",
+ "stream"
+ ]
+ },
+ {
+ "name": "test-http-write-head.js",
+ "required-modules": [
+ "http",
+ "fs",
+ "stream"
+ ]
+ },
+ {
+ "name": "test-net-bind-twice.js",
+ "required-modules": [
+ "net",
+ "fs",
+ "stream"
+ ]
+ },
+ {
+ "name": "test-net-end-without-connect.js",
+ "required-modules": [
+ "net",
+ "fs",
+ "stream"
+ ]
+ },
+ {
+ "name": "test-net-keepalive.js",
+ "required-modules": [
+ "net",
+ "fs",
+ "stream"
+ ]
+ },
+ {
+ "name": "test-timers-clear-null-does-not-throw-error.js",
+ "required-modules": [
+ "fs",
+ "stream"
+ ]
+ }
+ ],
+ "external_modules": [
+ {
+ "name": "test-external-module1.js",
+ "required-modules": [
+ "mymodule1"
+ ]
+ },
+ {
+ "name": "test-external-module2.js",
+ "required-modules": [
+ "mymodule2"
+ ]
+ }
]
}
--- /dev/null
+/* 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.
+ */
+
+/* Just for the testrunner to get runtime information about the build. */
+var builtins = process.builtin_modules;
+
+if (process.env.IOTJS_ENV.indexOf("experimental") > -1)
+ stability = "experimental"
+else
+ stability = "stable"
+
+/* Check if certain es2015 features are available */
+function hasFeatures(object, features) {
+ supported = true;
+
+ for (feature in features) {
+ supported = supported && object.hasOwnProperty(features[feature]);
+ }
+
+ return supported;
+}
+
+function hasArrowFunction() {
+ try {
+ eval("a => {}");
+ return true;
+ } catch(e) {}
+
+ return false;
+}
+
+var features = {};
+
+var typedArrayFeatures = [
+ 'Int8Array',
+ 'Uint8Array',
+ 'Uint8ClampedArray',
+ 'Int168Array',
+ 'Uint16Array',
+ 'Int32Array',
+ 'Uint32Array',
+ 'Float32Array',
+ 'Float64Array'
+];
+
+if (hasFeatures(global, ['Promise']))
+ features.Promise = true;
+
+if (hasFeatures(global, ['ArrayBuffer']))
+ features.ArrayBuffer = true;
+
+if (hasFeatures(global, typedArrayFeatures))
+ features.TypedArray = true;
+
+if (hasArrowFunction())
+ features.ArrowFunction = true;
+
+result = {
+ 'builtins': builtins,
+ 'features': features,
+ 'stability': stability
+}
+
+console.log(JSON.stringify(result))
sudo apt-get update -q
sudo apt-get install -q -y \
- cmake gcc valgrind clang-format-3.8
+ cmake gcc valgrind clang-format-3.9
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.executor import Terminal
from common_py.system.platform import Platform
platform = Platform()
choices=[None, 'artik10', 'stm32f4dis', 'rpi2', 'rpi3', 'artik05x'],
default=None, help='Specify the target board (default: %(default)s).')
iotjs_group.add_argument('--target-os',
- choices=['linux', 'darwin', 'osx', 'nuttx', 'tizen', 'tizenrt',
- 'openwrt'],
+ choices=['linux', 'darwin', 'osx', 'mock', 'nuttx', 'tizen', 'tizenrt',
+ 'openwrt', 'windows'],
default=platform.os(),
help='Specify the target OS (default: %(default)s).')
- iotjs_group.add_argument('--testsets',
- help='Specify the additional testsets file for IoT.js')
jerry_group = parser.add_argument_group('Arguments of JerryScript',
action='store_true', default=False,
help='Enable JerryScript heap statistics')
jerry_group.add_argument('--jerry-profile',
- choices=['es5.1', 'es2015-subset'], default='es5.1',
- help='Specify the profile for JerryScript (default: %(default)s).')
+ metavar='FILE', action='store', default='es5.1',
+ help='Specify the profile for JerryScript (default: %(default)s). '
+ 'Possible values are "es5.1", "es2015-subset" or an absolute '
+ 'path to a custom JerryScript profile file.')
jerry_group.add_argument('--js-backtrace',
choices=['ON', 'OFF'], type=str.upper,
help='Enable/disable backtrace information of JavaScript code '
'(default: ON in debug and OFF in release build)')
-
options = parser.parse_args(argv)
options.config = build_config
if options.target_os in ['nuttx', 'tizenrt']:
options.buildlib = True
if not options.sysroot:
- ex.fail('--sysroot needed for nuttx target')
+ ex.fail('--sysroot needed for %s target' % options.target_os)
options.sysroot = fs.abspath(options.sysroot)
if not fs.exists(options.sysroot):
if options.target_os == 'darwin':
options.no_check_valgrind = True
+ # Switch to no-snapshot mode on windows for now.
+ # TODO: After Jerry update this could be removed.
+ if options.target_os == 'windows':
+ options.no_snapshot = True
+
if options.target_board in ['rpi2', 'rpi3', 'artik10', 'artik05x']:
options.no_check_valgrind = True
cmake_path = fs.join(path.PROJECT_ROOT, 'cmake', 'config', '%s.cmake')
options.cmake_toolchain_file = cmake_path % options.target_tuple
- # Specify the file of JerryScript profile.
- options.jerry_profile = fs.join(path.JERRY_PROFILE_ROOT,
- options.jerry_profile + '.profile')
+ # Set the default value of '--js-backtrace' if it is not defined.
+ if not options.js_backtrace:
+ if options.buildtype == 'debug':
+ options.js_backtrace = "ON"
+ else:
+ options.js_backtrace = "OFF"
def print_progress(msg):
if options.target_os == 'tizenrt':
include_dirs.append('%s/../framework/include/iotbus' % options.sysroot)
+ elif options.target_os == 'windows':
+ cmake_args.append("-GVisual Studio 15 2017")
include_dirs.extend(options.external_include_dir)
cmake_args.append("-DEXTERNAL_INCLUDE_DIR='%s'" % (' '.join(include_dirs)))
cmake_opt = [
'-B%s' % options.build_root,
'-H%s' % path.PROJECT_ROOT,
- "-DCMAKE_TOOLCHAIN_FILE='%s'" % options.cmake_toolchain_file,
+ "-DCMAKE_TOOLCHAIN_FILE=%s" % options.cmake_toolchain_file,
'-DCMAKE_BUILD_TYPE=%s' % options.buildtype.capitalize(),
'-DTARGET_ARCH=%s' % options.target_arch,
'-DTARGET_OS=%s' % options.target_os,
'-DTARGET_BOARD=%s' % options.target_board,
- '-DPLATFORM_DESCRIPTOR=%s' % options.target_tuple,
'-DENABLE_LTO=%s' % get_on_off(options.jerry_lto), # --jerry-lto
'-DENABLE_SNAPSHOT=%s' % get_on_off(not options.no_snapshot),
'-DBUILD_LIB_ONLY=%s' % get_on_off(options.buildlib), # --buildlib
# --jerry-heaplimit
if options.jerry_heaplimit:
cmake_opt.append('-DMEM_HEAP_SIZE_KB=%d' % options.jerry_heaplimit)
+ if options.jerry_heaplimit > 512:
+ cmake_opt.append("-DEXTRA_JERRY_CMAKE_PARAMS='%s'" %
+ "-DFEATURE_CPOINTER_32_BIT=ON")
# --jerry-heap-section
if options.jerry_heap_section:
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)
# Run cmake.
ex.check_run_cmd('cmake', cmake_opt)
- run_make(options, options.build_root)
+ if options.target_os == 'windows':
+ print("\nPlease open the iot.js solution file in Visual Studio!")
+ else:
+ run_make(options, options.build_root)
def run_checktest(options):
iotjs = fs.join(options.build_root, 'bin', 'iotjs')
cmd = fs.join(path.TOOLS_ROOT, 'testrunner.py')
- args = [iotjs]
-
- # testsets
- if options.testsets:
- args.append('--testsets=' + options.testsets);
+ args = [iotjs, "--platform=%s" % options.target_os]
if options.run_test == "quiet":
args.append('--quiet')
adjust_options(options)
if options.clean:
- print_progress('Clear build directory')
+ print_progress('Clear build directories')
+ test_build_root = fs.join(path.TEST_ROOT,
+ 'dynamicmodule',
+ 'build',
+ options.target_os)
+ fs.rmtree(test_build_root)
fs.rmtree(options.build_root)
# Perform init-submodule.
build_iotjs(options)
- print("\n%sIoT.js Build Succeeded!!%s\n" % (ex._TERM_GREEN, ex._TERM_EMPTY))
+ Terminal.pprint("\nIoT.js Build Succeeded!!\n", Terminal.green)
# Run tests.
if options.run_test:
print("Skip unit tests - build target is library\n")
elif (options.host_tuple == options.target_tuple or
(options.host_tuple == 'x86_64-linux' and
- options.target_tuple == 'i686-linux')):
+ options.target_tuple == 'i686-linux') or
+ (options.host_tuple == 'x86_64-linux' and
+ options.target_tuple == 'x86_64-mock')):
run_checktest(options)
else:
print("Skip unit tests - target-host pair is not allowed\n")
else:
- print("\n%sTo run tests use '--run-test' "
- "or one of the folowing commands:%s"
- % (ex._TERM_BLUE, ex._TERM_EMPTY))
+ Terminal.pprint("\nTo run tests use '--run-test' "
+ "or one of the folowing commands:",
+ Terminal.blue)
print("\n tools/testrunner.py %s/%s/%s/bin/iotjs\n"
% (options.builddir, options.target_tuple, options.buildtype))
# See the License for the specific language governing permissions and
# limitations under the License.
-if [[ -n "${TRAVIS_PULL_REQUEST_SLUG}" &&
- "${TRAVIS_PULL_REQUEST_SLUG}" != "${TRAVIS_REPO_SLUG}" ]]; then
- echo "Skip: The pull request from ${TRAVIS_PULL_REQUEST_SLUG} is an \
- external one. It's not supported yet in Travis-CI";
+if [[ "${TRAVIS_REPO_SLUG}" == "Samsung/iotjs"
+ && ${TRAVIS_BRANCH} == "master"
+ && ${TRAVIS_EVENT_TYPE} == "push" ]]
+then
+ git fetch --unshallow
+ build-wrapper-linux-x86-64 --out-dir bw-output ./tools/build.py
+ sonar-scanner
else
- git fetch --unshallow;
- build-wrapper-linux-x86-64 --out-dir bw-output ./tools/build.py;
- sonar-scanner;
+ echo "Skip: The pull request from ${TRAVIS_PULL_REQUEST_SLUG} is an \
+ external one. It's not supported yet in Travis-CI"
fi
from check_license import CheckLicenser
from common_py.system.filesystem import FileSystem as fs
from common_py.system.executor import Executor as ex
+from common_py.system.executor import Terminal
def parse_option():
self._extensions = extensions
self._skip_files = skip_files
self._options = options
- self._check_clang_format("clang-format-3.8")
+ self._check_clang_format("clang-format-3.9")
def _check_clang_format(self, base):
clang_format = spawn.find_executable(base)
if not clang_format:
clang_format = spawn.find_executable("clang-format")
if clang_format:
- print("%sUsing %s instead of %s%s"
- % (ex._TERM_YELLOW, clang_format, base, ex._TERM_EMPTY))
+ Terminal.pprint(
+ "Using %s instead of %s" % (clang_format, base),
+ Terminal.yellow)
else:
- print("%sNo %s found, skipping checks!%s"
- % (ex._TERM_RED, base, ex._TERM_EMPTY))
+ Terminal.pprint("No %s found, skipping checks!" % base,
+ Terminal.red)
self._clang_format = clang_format
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))
+ Terminal.pprint('No node found,', Terminal.red)
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))
+ Terminal.pprint('No eslint found.', Terminal.red)
def check(self):
self.error_count = 0
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))
+ msg_color = Terminal.red if total_errors > 0 else Terminal.green
+ Terminal.pprint("* total errors: %d" % (total_errors), msg_color)
print()
if total_errors:
+++ /dev/null
-/* 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');
-
-function Logger(path) {
- this.text_colors = {
- red: "\033[1;31m",
- yellow: "\033[1;33m",
- green: "\033[1;32m",
- blue: "\033[1;34m",
- empty: "\033[0m",
- };
- this.status = {
- pass: "pass",
- skip: "skip",
- fail: "fail",
- timeout: "timeout",
- summary: "summary"
- }
- this.path = path;
-
- return this;
-}
-
-Logger.prototype.message = function (msg, status) {
- if (this.path) {
- // FIXME : After fs.appendFile is implemented, it should be replaced.
- var data = fs.readFileSync(this.path);
- var newData = data + msg + "\n";
- fs.writeFileSync(this.path, new Buffer(newData));
- }
- if (status == this.status.pass) {
- console.log(this.text_colors.green + msg + this.text_colors.empty);
- } else if (status == this.status.skip) {
- console.log(this.text_colors.yellow + msg + this.text_colors.empty);
- } else if (status == this.status.fail || status == this.status.timeout){
- console.log(this.text_colors.red + msg + this.text_colors.empty);
- } else if (status == this.status.summary){
- console.log(this.text_colors.blue + msg + this.text_colors.empty);
- } else {
- console.log(msg);
- }
-}
-
-module.exports.Logger = Logger;
+++ /dev/null
-/* 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');
-
-function Console() {
- return this;
-}
-
-Console.prototype.log =
-Console.prototype.info =
-Console.prototype.warn =
-Console.prototype.error = function() {
- /* Do Nothing */
-};
-
-module.exports = new Console();
+++ /dev/null
-/* 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 util = require('util');
-
-function Option(arg, value, default_value, help) {
- this.arg = arg;
- this.value = value;
- this.default_value = default_value;
- this.help = help;
-
- return this;
-}
-
-Option.prototype.printHelp = function() {
- console.log("\t" + this.arg + "=[" + this.value + "](default: " +
- this.default_value + ") : " + this.help);
-}
-
-function OptionParser() {
- this.options = [];
- return this;
-}
-
-OptionParser.prototype.addOption = function(arg, value, default_value, help) {
- var option = new Option(arg, value, default_value, help);
- this.options.push(option);
-}
-
-OptionParser.prototype.parse = function() {
- var options = {};
-
- for (var idx in this.options) {
- var option = this.options[idx];
- var default_value = option.default_value;
- if (default_value !== "") {
- options[option.arg] = default_value;
- }
- }
-
- for (var aIdx = 2; aIdx < process.argv.length; aIdx++) {
- var option = process.argv[aIdx];
- var arg_val = option.split("=");
-
- if (arg_val.length != 2 || !arg_val[0] || !arg_val[1]) {
- return null;
- }
-
- var arg = arg_val[0];
- var val = arg_val[1];
- var found = false;
-
- if (arg === "default-timeout") {
- // Transform to number, or use default value.
- val = util.stringToNumber(val, options[arg]);
- }
-
- for (var oIdx in this.options) {
- if (arg == this.options[oIdx].arg) {
- options[arg] = val;
- found = true;
- break;
- }
- }
-
- if (!found)
- return null;
- }
-
- return options;
-}
-
-OptionParser.prototype.printHelp = function() {
- console.log(process.argv[1]);
- console.log("\noptional arguments");
- for (var idx in this.options) {
- this.options[idx].printHelp();
- }
-}
-
-
-module.exports.OptionParser = OptionParser;
+++ /dev/null
-/* 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.
- */
-
-function absolutePath(path) {
- // FIXME: On NuttX side, when dealing with file, path should be absolute.
- // So workaround this problem, test driver converts relative path
- // to absolute one.
- return process.cwd() + '/' + path;
-}
-
-function join() {
- var path = Array.prototype.join.call(arguments, '/');
- return path;
-}
-
-function Watch() {
- this.reset();
-}
-
-Watch.prototype.reset = function() {
- this.startTime = 0;
- this.elapsedTime = 0;
-}
-
-Watch.prototype.delta = function() {
- if (this.startTime) {
- this.elapsedTime = (Date.now() - this.startTime) / 1000;
- }
-
- this.startTime = Date.now();
-
- return this.elapsedTime;
-}
-
-module.exports.absolutePath = absolutePath;
-module.exports.join = join;
-module.exports.Watch = Watch;
BUILD_CONFIG_PATH = fs.join(PROJECT_ROOT, 'build.config')
# IoT.js build information.
-BUILD_INFO_PATH = fs.join(TOOLS_ROOT, 'iotjs_build_info.js')
+BUILD_INFO_PATH = fs.join(TEST_ROOT, 'tools', 'iotjs_build_info.js')
from __future__ import print_function
+import collections
+import os
import subprocess
+_colors = {
+ "empty": "\033[0m",
+ "red": "\033[1;31m",
+ "green": "\033[1;32m",
+ "yellow": "\033[1;33m",
+ "blue": "\033[1;34m"
+}
+
+if "TERM" not in os.environ:
+ # if there is no "TERM" environment variable
+ # assume that we can't output colors.
+ # So reset the ANSI color escapes.
+ _colors = _colors.fromkeys(_colors, "")
+
+_TerminalType = collections.namedtuple('Terminal', _colors.keys())
+class _Terminal(_TerminalType):
+
+ def pprint(self, text, color=_colors["empty"]):
+ print("%s%s%s" % (color, text, self.empty))
+
+Terminal = _Terminal(**_colors)
+
class Executor(object):
- _TERM_RED = "\033[1;31m"
- _TERM_YELLOW = "\033[1;33m"
- _TERM_GREEN = "\033[1;32m"
- _TERM_BLUE = "\033[1;34m"
- _TERM_EMPTY = "\033[0m"
@staticmethod
def cmd_line(cmd, args=[]):
@staticmethod
def print_cmd_line(cmd, args=[]):
- print("%s%s%s" % (Executor._TERM_BLUE, Executor.cmd_line(cmd, args),
- Executor._TERM_EMPTY))
+ Terminal.pprint(Executor.cmd_line(cmd, args), Terminal.blue)
print()
@staticmethod
def fail(msg):
print()
- print("%s%s%s" % (Executor._TERM_RED, msg, Executor._TERM_EMPTY))
+ Terminal.pprint(msg, Terminal.red)
print()
exit(1)
# limitations under the License.
import os
-
+import sys
class Platform(object):
def __init__(self):
- _os, _, _, _, _arch = os.uname()
+ if sys.platform == "win32":
+ _os = "windows"
+ _arch = "i686" # TODO: allow x86_64 also
+ else:
+ _os, _, _, _, _arch = os.uname()
self._os = _os
self._arch = _arch
+++ /dev/null
-/* 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.
- */
-
-/* Just for the testrunner to get runtime information about the build. */
-var builtins = process.builtin_modules;
-
-if (process.env.IOTJS_ENV.indexOf("experimental") > -1)
- stability = "experimental"
-else
- stability = "stable"
-
-result = {
- 'builtins': builtins,
- 'stability': stability
-}
-
-console.log(JSON.stringify(result))
from common_py.system.filesystem import FileSystem as fs
from common_py import path
+
+def normalize_str(text):
+ if not isinstance(text, str):
+ return text.decode('utf-8')
+
+ return text
+
+
def regroup(l, n):
return [l[i:i+n] for i in range(0, len(l), n)]
return re.sub('\n+', '\n', re.sub('\n +', '\n', code))
-def force_str(string):
- if not isinstance(string, str):
- return string.decode('utf-8')
- else:
- return string
-
-
-def parse_literals(code):
- JERRY_SNAPSHOT_VERSION = 12
- JERRY_SNAPSHOT_MAGIC = 0x5952524A
-
- literals = set()
- # header format:
- # uint32_t magic
- # uint32_t version
- # uint32_t global opts
- # uint32_t literal table offset
- header = struct.unpack('I' * 4, code[0:4 * 4])
- if header[0] != JERRY_SNAPSHOT_MAGIC:
- print('Incorrect snapshot format! Magic number is incorrect')
- exit(1)
- if header[1] != JERRY_SNAPSHOT_VERSION:
- print ('Please check jerry snapshot version (Last confirmed: %d)'
- % JERRY_SNAPSHOT_VERSION)
- exit(1)
-
- code_ptr = header[3] + 4
-
- while code_ptr < len(code):
- length = struct.unpack('H', code[code_ptr : code_ptr + 2])[0]
- code_ptr = code_ptr + 2
- if length == 0:
- continue
- if length < 32:
- item = struct.unpack('%ds' % length,
- code[code_ptr : code_ptr + length])
- literals.add(force_str(item[0]))
- code_ptr = code_ptr + length + (length % 2)
-
- return literals
-
-
LICENSE = '''
/* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors
*
return code
-def get_snapshot_contents(js_path, snapshot_tool):
+def get_snapshot_contents(js_path, snapshot_tool, literals=None):
""" Convert the given module with the snapshot generator
and return the resulting bytes.
"""
if module_name != "iotjs":
fwrapped.write("});\n")
-
- ret = subprocess.call([snapshot_tool,
- "generate",
- "-o", snapshot_path,
- wrapped_path])
+ cmd = [snapshot_tool, "generate", "-o", snapshot_path]
+ if literals:
+ cmd.extend(["--static", "--load-literals-list-format", literals])
+ ret = subprocess.call(cmd + [wrapped_path])
fs.remove(wrapped_path)
if ret != 0:
- msg = "Failed to dump %s: - %d" % (js_path, ret)
- print("%s%s%s" % ("\033[1;31m", msg, "\033[0m"))
- fs.remove(snapshot_path)
- exit(1)
+ if literals == None:
+ msg = "Failed to dump %s: - %d" % (js_path, ret)
+ print("%s%s%s" % ("\033[1;31m", msg, "\033[0m"))
+ exit(1)
+ else:
+ print("Unable to create static snapshot from '%s'. Falling back "
+ "to normal snapshot." % js_path)
return snapshot_path
return code
-def js2c(buildtype, js_modules, snapshot_tool=None, verbose=False):
- is_debug_mode = (buildtype == "debug")
+def get_literals_from_snapshots(snapshot_tool, snapshot_list):
+ literals_path = fs.join(path.SRC_ROOT, 'js', 'literals.list')
+ cmd = [snapshot_tool, "litdump", "-o", literals_path]
+ cmd.extend(snapshot_list)
+
+ ret = subprocess.call(cmd)
+
+ if ret != 0:
+ msg = "Failed to dump the literals: - %d" % ret
+ print("%s%s%s" % ("\033[1;31m", msg, "\033[0m"))
+ exit(1)
+
+ return literals_path
+
+
+def read_literals(literals_path):
+ literals_set = set()
+ with open(literals_path, 'rb') as fin:
+ num = ''
+ while True:
+ c = normalize_str(fin.read(1))
+ if not c:
+ break
+ elif c == ' ':
+ text = normalize_str(fin.read(int(num)))
+ literals_set.add(text)
+ num = ''
+ else:
+ num += c
+
+ return literals_set
+
+
+def write_literals_to_file(literals_set, literals_path):
+ sorted_lit = sorted(literals_set, key=lambda x: (len(x), x))
+ with open(literals_path, 'wb') as flit:
+ for lit in sorted_lit:
+ entry = "%d %s\n" % (len(lit), lit)
+ flit.write(entry.encode('utf-8'))
+
+
+def js2c(options, js_modules):
+ is_debug_mode = (options.buildtype == "debug")
+ snapshot_tool = options.snapshot_tool
no_snapshot = (snapshot_tool == None)
+ verbose = options.verbose
magic_string_set = set()
str_const_regex = re.compile('^#define IOTJS_MAGIC_STRING_\w+\s+"(\w+)"$')
snapshot_infos = []
js_module_names = []
- for idx, module in enumerate(sorted(js_modules)):
- [name, js_path] = module.split('=', 1)
- js_module_names.append(name)
- if verbose:
- print('Processing module: %s' % name)
+ if no_snapshot:
+ for idx, module in enumerate(sorted(js_modules)):
+ [name, js_path] = module.split('=', 1)
+ js_module_names.append(name)
+ if verbose:
+ print('Processing module: %s' % name)
- if no_snapshot:
code = get_js_contents(js_path, is_debug_mode)
code_string = format_code(code, 1)
NAME_UPPER=name.upper(),
SIZE=len(code),
CODE=code_string))
- else:
+ modules_struct = [
+ ' {{ {0}_n, {0}_s, SIZE_{1} }},'.format(name, name.upper())
+ for name in sorted(js_module_names)
+ ]
+ modules_struct.append(' { NULL, NULL, 0 }')
+ native_struct_h = NATIVE_STRUCT_H
+ else:
+ # Generate snapshot files from JS files
+ for idx, module in enumerate(sorted(js_modules)):
+ [name, js_path] = module.split('=', 1)
+ js_module_names.append(name)
+ if verbose:
+ print('Processing (1st phase) module: %s' % name)
code_path = get_snapshot_contents(js_path, snapshot_tool)
info = {'name': name, 'path': code_path, 'idx': idx}
snapshot_infos.append(info)
+ # Get the literal list from the snapshots
+ if verbose:
+ print('Creating literal list file for static snapshot '
+ 'creation')
+ literals_path = get_literals_from_snapshots(snapshot_tool,
+ [info['path'] for info in snapshot_infos])
+ magic_string_set |= read_literals(literals_path)
+ # Update the literals list file
+ write_literals_to_file(magic_string_set, literals_path)
+
+ # Generate static-snapshots if possible
+ for idx, module in enumerate(sorted(js_modules)):
+ [name, js_path] = module.split('=', 1)
+ if verbose:
+ print('Processing (2nd phase) module: %s' % name)
+
+ get_snapshot_contents(js_path, snapshot_tool, literals_path)
+
fout_h.write(MODULE_SNAPSHOT_VARIABLES_H.format(NAME=name))
fout_c.write(MODULE_SNAPSHOT_VARIABLES_C.format(NAME=name,
IDX=idx))
+ fs.remove(literals_path)
- if no_snapshot:
- modules_struct = [
- ' {{ {0}_n, {0}_s, SIZE_{1} }},'.format(name, name.upper())
- for name in sorted(js_module_names)
- ]
- modules_struct.append(' { NULL, NULL, 0 }')
- else:
+ # Merge the snapshot files
code = merge_snapshots(snapshot_infos, snapshot_tool)
code_string = format_code(code, 1)
- magic_string_set |= parse_literals(code)
name = 'iotjs_js_modules'
fout_h.write(MODULE_VARIABLES_H.format(NAME=name))
for info in snapshot_infos
]
modules_struct.append(' { NULL, 0 }')
-
- if no_snapshot:
- native_struct_h = NATIVE_STRUCT_H
- else:
native_struct_h = NATIVE_SNAPSHOT_STRUCT_H
fout_h.write(native_struct_h)
sorted_strings = sorted(magic_string_set, key=lambda x: (len(x), x))
for idx, magic_string in enumerate(sorted_strings):
magic_text = repr(magic_string)[1:-1]
- magic_text = magic_text.replace('"', '\"')
+ magic_text = magic_text.replace('"', '\\"')
fout_magic_str.write(' MAGICSTR_EX_DEF(MAGIC_STR_%d, "%s") \\\n'
% (idx, magic_text))
else:
print('Using "%s" as snapshot tool' % options.snapshot_tool)
- modules = options.modules.replace(',', ' ').split()
- js2c(options.buildtype, modules, options.snapshot_tool, options.verbose)
+ modules = options.modules.split(',')
+ js2c(options, modules)
import argparse
import json
+import multiprocessing
import os
-import signal
import subprocess
import sys
import time
+try:
+ import queue
+except ImportError:
+ # Backwards compatibility
+ import Queue as queue
+
+
from collections import OrderedDict
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.executor import Executor
+from common_py.system.executor import Terminal
from common_py.system.platform import Platform
-from jsonmerge import Merger
-
# Defines the folder that will contain the coverage info.
# The path must be consistent with the measure_coverage.sh script.
"""
)
-JSON_SCHEMA = {
- "properties": {
- "run_pass": {
- "mergeStrategy": "arrayMergeById",
- "mergeOptions": { "idRef": "name"}
- }
- }
-}
-
# Append coverage source to the appropriate test.
def append_coverage_code(testfile, coverage):
if not coverage:
class Reporter(object):
@staticmethod
- def message(msg="", color=ex._TERM_EMPTY):
- print("%s%s%s" % (color, msg, ex._TERM_EMPTY))
+ def message(msg="", color=Terminal.empty):
+ print("%s%s%s" % (color, msg, Terminal.empty))
@staticmethod
def report_testset(testset):
Reporter.message()
- Reporter.message("Testset: %s" % testset, ex._TERM_BLUE)
+ Reporter.message("Testset: %s" % testset, Terminal.blue)
@staticmethod
def report_pass(test, time):
- Reporter.message(" PASS: %s (%ss)" % (test, time), ex._TERM_GREEN)
+ Reporter.message(" PASS: %s (%ss)" % (test, time), Terminal.green)
@staticmethod
def report_fail(test, time):
- Reporter.message(" FAIL: %s (%ss)" % (test, time), ex._TERM_RED)
+ Reporter.message(" FAIL: %s (%ss)" % (test, time), Terminal.red)
@staticmethod
def report_timeout(test):
- Reporter.message(" TIMEOUT: %s" % test, ex._TERM_RED)
+ Reporter.message(" TIMEOUT: %s" % test, Terminal.red)
@staticmethod
def report_skip(test, reason):
if reason:
skip_message += " (Reason: %s)" % reason
- Reporter.message(skip_message, ex._TERM_YELLOW)
+ Reporter.message(skip_message, Terminal.yellow)
@staticmethod
def report_configuration(testrunner):
@staticmethod
def report_final(results):
Reporter.message()
- Reporter.message("Finished with all tests:", ex._TERM_BLUE)
- Reporter.message(" PASS: %d" % results["pass"], ex._TERM_GREEN)
- Reporter.message(" FAIL: %d" % results["fail"], ex._TERM_RED)
- Reporter.message(" TIMEOUT: %d" % results["timeout"], ex._TERM_RED)
- Reporter.message(" SKIP: %d" % results["skip"], ex._TERM_YELLOW)
-
-
-class TimeoutException(Exception):
- pass
-
-
-def alarm_handler(signum, frame):
- raise TimeoutException
+ Reporter.message("Finished with all tests:", Terminal.blue)
+ Reporter.message(" PASS: %d" % results["pass"], Terminal.green)
+ Reporter.message(" FAIL: %d" % results["fail"], Terminal.red)
+ Reporter.message(" TIMEOUT: %d" % results["timeout"], Terminal.red)
+ Reporter.message(" SKIP: %d" % results["skip"], Terminal.yellow)
class TestRunner(object):
def __init__(self, options):
+ self._process_pool = multiprocessing.Pool(processes=1)
self.iotjs = fs.abspath(options.iotjs)
self.quiet = options.quiet
- self.testsets = options.testsets
+ self.platform = options.platform
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)
+ self._msg_queue = multiprocessing.Queue(1)
if options.skip_modules:
self.skip_modules = options.skip_modules.split(",")
# Process the iotjs build information.
- iotjs_output = ex.check_run_cmd_output(self.iotjs,
- [path.BUILD_INFO_PATH])
+ iotjs_output = Executor.check_run_cmd_output(self.iotjs,
+ [path.BUILD_INFO_PATH])
build_info = json.loads(iotjs_output)
- self.builtins = build_info["builtins"]
+ self.builtins = set(build_info["builtins"])
+ self.features = set(build_info["features"])
self.stability = build_info["stability"]
- # Define own alarm handler to handle timeout.
- signal.signal(signal.SIGALRM, alarm_handler)
def run(self):
Reporter.report_configuration(self)
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)
continue
# Show the output.
- if not self.quiet:
- print(output, end="")
+ if not self.quiet and output:
+ print(output.decode("utf8"), end="")
is_normal_run = (not expected_failure and exitcode == 0)
- is_expected_fail = (expected_failure and exitcode <= 2)
+ is_expected_fail = (expected_failure and exitcode in [1, 2])
if is_normal_run or is_expected_fail:
Reporter.report_pass(test["name"], runtime)
self.results["pass"] += 1
Reporter.report_fail(test["name"], runtime)
self.results["fail"] += 1
+ @staticmethod
+ def run_subprocess(parent_queue, command):
+ process = subprocess.Popen(args=command,
+ cwd=path.TEST_ROOT,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ stdout = process.communicate()[0]
+ exitcode = process.returncode
+
+ parent_queue.put_nowait([exitcode, stdout])
def run_test(self, testfile, timeout):
command = [self.iotjs, testfile]
command = ["valgrind"] + valgrind_options + command
- signal.alarm(timeout)
-
try:
+ process = multiprocessing.Process(target=TestRunner.run_subprocess,
+ args=(self._msg_queue, command,))
start = time.time()
- process = subprocess.Popen(args=command,
- cwd=path.TEST_ROOT,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- env=self._environment)
-
- stdout = process.communicate()[0]
- exitcode = process.returncode
+ process.start()
+ process.join(timeout)
runtime = round((time.time() - start), 2)
- signal.alarm(0)
+ if process.is_alive():
+ raise multiprocessing.TimeoutError("Test still running")
+
+ # At this point the queue must have data!
+ # If not then it is also a timeout event
+ exitcode, stdout = self._msg_queue.get_nowait()
- except TimeoutException:
- process.kill()
+ except (multiprocessing.TimeoutError, queue.Full):
+ process.terminate()
return -1, None, None
return exitcode, stdout, runtime
def skip_test(self, test):
- skip_list = test.get("skip", [])
+ skip_list = set(test.get("skip", []))
# Skip by the `skip` attribute in testsets.json file.
- for i in ["all", Platform().os(), self.stability]:
+ for i in ["all", self.platform, self.stability]:
if i in skip_list:
return True
- name_parts = test["name"][0:-3].split('_')
+ required_modules = set(test.get("required-modules", []))
+ required_features = set(test.get("required-features", []))
- # Test filename does not start with 'test_' so we'll just
- # assume we support it.
- if name_parts[0] != 'test':
- return False
+ unsupported_modules = required_modules - self.builtins
+ unsupported_features = required_features - self.features
+ skipped_modules = required_modules.intersection(skip_list)
- tested_module = name_parts[1]
+ # Skip the test if the tested module requires a module
+ # which is not compiled into the binary
+ if unsupported_modules:
+ test["reason"] = "Required module(s) unsupported by iotjs build: "
+ test["reason"] += ', '.join(sorted(unsupported_modules))
+ return True
- # Skip the test if it requires a module that is defined by
- # the `--skip-modules` flag.
- if tested_module in self.skip_modules:
- test["reason"] = "the required module is skipped by testrunner"
+ # Skip the test if it requires a module that is skipped by the
+ # testrunner
+ if skipped_modules:
+ test["reason"] = "Required module(s) skipped by testrunner: "
+ test["reason"] += ', '.join(sorted(skipped_modules))
return True
- # Skip the test if it requires a module that is not
- # compiled into the binary.
- if tested_module not in self.builtins:
- test["reason"] = "unsupported module by iotjs build"
+ # Skip the test if it uses features which are
+ # unavailable in the current iotjs build
+ if unsupported_features:
+ test["reason"] = "Required feature(s) unsupported by iotjs build: "
+ test["reason"] += ', '.join(sorted(unsupported_features))
return True
return False
parser.add_argument("iotjs", action="store",
help="path to the iotjs binary file")
+ parser.add_argument('--platform', default=Platform().os(),
+ help='Specify the platform (default: %(default)s)')
parser.add_argument("--quiet", action="store_true", default=False,
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,
# IoT.js path in docker
DOCKER_IOTJS_PATH = fs.join(DOCKER_ROOT_PATH, 'work_space/iotjs')
+# Node server path in docker
+DOCKER_NODE_SERVER_PATH = fs.join(DOCKER_ROOT_PATH, 'work_space/node_server')
+
DOCKER_TIZENRT_PATH = fs.join(DOCKER_ROOT_PATH, 'TizenRT')
DOCKER_TIZENRT_OS_PATH = fs.join(DOCKER_TIZENRT_PATH, 'os')
DOCKER_TIZENRT_OS_TOOLS_PATH = fs.join(DOCKER_TIZENRT_OS_PATH, 'tools')
-DOCKER_NUTTX_PATH =fs.join(DOCKER_ROOT_PATH, 'nuttx')
+DOCKER_NUTTX_PATH = fs.join(DOCKER_ROOT_PATH, 'nuttx')
+DOCKER_NUTTX_TOOLS_PATH = fs.join(DOCKER_NUTTX_PATH, 'tools')
+DOCKER_NUTTX_APPS_PATH = fs.join(DOCKER_ROOT_PATH, 'apps')
DOCKER_NAME = 'iotjs_docker'
BUILDTYPES = ['debug', 'release']
-TIZENRT_TAG = '1.1_Public_Release'
+TIZENRT_TAG = '2.0_Public_M2'
# Common buildoptions for sanitizer jobs.
BUILDOPTIONS_SANITIZER = [
'--no-check-valgrind',
'--no-snapshot',
'--profile=test/profiles/host-linux.profile',
- '--testsets=testsets-host-linux.json',
'--run-test=full',
'--target-arch=i686'
]
ex.check_run_cmd('docker', ['run', '-dit', '--privileged',
'--name', DOCKER_NAME, '-v',
'%s:%s' % (TRAVIS_BUILD_PATH, DOCKER_IOTJS_PATH),
- 'iotjs/ubuntu:0.6'])
+ '--add-host', 'test.mosquitto.org:127.0.0.1',
+ '--add-host', 'echo.websocket.org:127.0.0.1',
+ '--add-host', 'httpbin.org:127.0.0.1',
+ 'iotjs/ubuntu:0.9'])
-def exec_docker(cwd, cmd):
+def exec_docker(cwd, cmd, env=[], is_background=False):
exec_cmd = 'cd %s && ' % cwd + ' '.join(cmd)
- ex.check_run_cmd('docker', [
- 'exec', '-it', DOCKER_NAME, 'bash', '-c', exec_cmd])
+ if is_background:
+ docker_args = ['exec', '-dit']
+ else:
+ docker_args = ['exec', '-it']
+
+ for e in env:
+ docker_args.append('-e')
+ docker_args.append(e)
+
+ docker_args += [DOCKER_NAME, 'bash', '-c', exec_cmd]
+ ex.check_run_cmd('docker', docker_args)
-def set_release_config_tizenrt():
+def start_mosquitto_server():
+ exec_docker(DOCKER_ROOT_PATH, ['mosquitto', '-d'])
+
+def start_node_server():
+ exec_docker(DOCKER_NODE_SERVER_PATH, ['node', 'server.js'], [], True)
+
+def set_config_tizenrt(buildtype):
exec_docker(DOCKER_ROOT_PATH, [
- 'cp', 'tizenrt_release_config',
+ 'cp',
+ fs.join(DOCKER_IOTJS_PATH,
+ 'config/tizenrt/artik05x/configs/',
+ buildtype, 'defconfig'),
fs.join(DOCKER_TIZENRT_OS_PATH, '.config')])
-def build_iotjs(buildtype, args=[]):
+def build_iotjs(buildtype, args=[], env=[]):
exec_docker(DOCKER_IOTJS_PATH, [
'./tools/build.py',
'--clean',
- '--buildtype=' + buildtype] + args)
+ '--buildtype=' + buildtype] + args, env)
if __name__ == '__main__':
if os.getenv('RUN_DOCKER') == 'yes':
run_docker()
+ start_mosquitto_server()
+ start_node_server()
test = os.getenv('OPTS')
if test == 'host-linux':
build_iotjs(buildtype, [
'--cmake-param=-DENABLE_MODULE_ASSERT=ON',
'--run-test=full',
- '--profile=profiles/minimal.profile',
- '--testsets=testsets-minimal.json'])
+ '--profile=profiles/minimal.profile'])
for buildtype in BUILDTYPES:
build_iotjs(buildtype, [
'--run-test=full',
- '--profile=test/profiles/host-linux.profile',
- '--testsets=testsets-host-linux.json'])
+ '--profile=test/profiles/host-linux.profile'])
+
+ elif test == 'mock-linux':
+ for buildtype in BUILDTYPES:
+ build_iotjs(buildtype, [
+ '--run-test=full',
+ '--target-os=mock',
+ '--profile=test/profiles/mock-linux.profile'])
elif test == 'rpi2':
for buildtype in BUILDTYPES:
'--profile=test/profiles/rpi2-linux.profile'])
elif test == 'artik053':
+ exec_docker(DOCKER_TIZENRT_PATH, ['git', 'fetch', '--tags'])
# Checkout specified tag
exec_docker(DOCKER_TIZENRT_PATH, ['git', 'checkout', TIZENRT_TAG])
# Set configure
'./configure.sh', 'artik053/iotjs'])
for buildtype in BUILDTYPES:
- if buildtype == 'release':
- set_release_config_tizenrt()
+ set_config_tizenrt(buildtype)
exec_docker(DOCKER_TIZENRT_OS_PATH, [
- 'make', 'IOTJS_ROOT_DIR=' + DOCKER_IOTJS_PATH,
- 'IOTJS_BUILD_OPTION='
- '--profile=test/profiles/tizenrt.profile'])
+ 'make', 'IOTJS_ROOT_DIR=%s' % DOCKER_IOTJS_PATH,
+ 'IOTJS_BUILD_OPTION="--buildtype=%s '
+ '--profile=test/profiles/tizenrt.profile"' % buildtype
+ ])
elif test == 'stm32f4dis':
+ # Copy the application files to apps/system/iotjs.
+ exec_docker(DOCKER_ROOT_PATH, [
+ 'cp', '-r',
+ fs.join(DOCKER_IOTJS_PATH,'config/nuttx/stm32f4dis/app/'),
+ fs.join(DOCKER_NUTTX_APPS_PATH, 'system/iotjs/')])
+
+ exec_docker(DOCKER_ROOT_PATH, [
+ 'cp', '-r',
+ fs.join(DOCKER_IOTJS_PATH,
+ 'config/nuttx/stm32f4dis/config.travis'),
+ fs.join(DOCKER_NUTTX_PATH,
+ 'configs/stm32f4discovery/usbnsh/defconfig')])
+
for buildtype in BUILDTYPES:
+ exec_docker(DOCKER_NUTTX_PATH, ['make', 'distclean'])
+ exec_docker(DOCKER_NUTTX_TOOLS_PATH,
+ ['./configure.sh', 'stm32f4discovery/usbnsh'])
exec_docker(DOCKER_NUTTX_PATH, ['make', 'clean'])
exec_docker(DOCKER_NUTTX_PATH, ['make', 'context'])
# Build IoT.js
elif test == "misc":
ex.check_run_cmd('tools/check_signed_off.sh', ['--travis'])
-
- exec_docker(DOCKER_IOTJS_PATH, ['tools/check_tidy.py'])
+ ex.check_run_cmd('tools/check_tidy.py')
elif test == "external-modules":
for buildtype in BUILDTYPES:
build_iotjs(buildtype, [
'--run-test=full',
- '--testsets=testsets-external-modules.json',
'--profile=test/profiles/host-linux.profile',
'--external-modules=test/external_modules/'
'mymodule1,test/external_modules/mymodule2',
for buildtype in BUILDTYPES:
build_iotjs(buildtype, [
'--run-test=full',
- '--jerry-profile=es2015-subset',
- '--testsets=testsets-es2015.json'])
+ '--jerry-profile=es2015-subset'])
elif test == "no-snapshot":
for buildtype in BUILDTYPES:
'--run-test=full',
'--buildtype=' + buildtype,
'--clean',
- '--profile=test/profiles/host-darwin.profile',
- '--testsets=testsets-host-linux.json'])
+ '--profile=test/profiles/host-darwin.profile'])
elif test == "asan":
- ex.check_run_cmd('./tools/build.py', [
- '--compile-flag=-fsanitize=address',
- '--compile-flag=-O2'
- ] + BUILDOPTIONS_SANITIZER)
+ build_iotjs('debug', [
+ '--compile-flag=-fsanitize=address',
+ '--compile-flag=-O2'
+ ] + BUILDOPTIONS_SANITIZER,
+ ['ASAN_OPTIONS=detect_stack_use_after_return=1:'
+ 'check_initialization_order=true:strict_init_order=true',
+ 'TIMEOUT=600'])
elif test == "ubsan":
- ex.check_run_cmd('./tools/build.py', [
- '--compile-flag=-fsanitize=undefined'
- ] + BUILDOPTIONS_SANITIZER)
+ build_iotjs('debug', [
+ '--compile-flag=-fsanitize=undefined'
+ ] + BUILDOPTIONS_SANITIZER,
+ ['UBSAN_OPTIONS=print_stacktrace=1', 'TIMEOUT=600'])
elif test == "coverity":
ex.check_run_cmd('./tools/build.py', ['--clean'])