diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d2a3eb69b..c2b2a9ca29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,7 +234,7 @@ project (Jerry CXX C ASM) set(FLAGS_COMMON_RELEASE "-Os -nostdlib") # Unit tests - set(FLAGS_COMMON_UNITTESTS "-O3 -nodefaultlibs") + set(FLAGS_COMMON_UNITTESTS "-O3 -nostdlib") # Include directories # Core interface @@ -310,8 +310,9 @@ project (Jerry CXX C ASM) add_subdirectory(plugins) # Targets declaration + string(TOLOWER "${PLATFORM_EXT}" PLATFORM_L) + function(declare_targets_for_build_mode BUILD_MODE) - string(TOLOWER "${PLATFORM_EXT}" PLATFORM_L) set(TARGET_NAME ${BUILD_MODE_PREFIX_${BUILD_MODE}}.${PLATFORM_L}) set(PLUGINS_TARGET_NAME ${BUILD_MODE_PREFIX_${BUILD_MODE}}.plugins.${PLATFORM_L}.lib) set(LIBC_TARGET_NAME ${BUILD_MODE_PREFIX_${BUILD_MODE}}.jerry-libc.${PLATFORM_L}.lib) @@ -424,6 +425,7 @@ project (Jerry CXX C ASM) set(TARGET_NAME unit-${TARGET_NAME}) set(CORE_TARGET_NAME unittests.jerry-core) + set(LIBC_TARGET_NAME unittests.jerry-libc.${PLATFORM_L}.lib) set(FDLIBM_TARGET_NAME unittests.jerry-fdlibm${SUFFIX_THIRD_PARTY_LIB}) add_executable(${TARGET_NAME} ${SOURCE_UNIT_TEST_MAIN}) @@ -432,7 +434,8 @@ project (Jerry CXX C ASM) set_property(TARGET ${TARGET_NAME} PROPERTY LINK_FLAGS "${COMPILE_FLAGS_JERRY} ${CXX_FLAGS_JERRY} ${FLAGS_COMMON_UNITTESTS} ${LINKER_FLAGS_COMMON}") target_include_directories(${TARGET_NAME} PRIVATE ${INCLUDE_CORE_INTERFACE}) - target_link_libraries(${TARGET_NAME} ${CORE_TARGET_NAME} ${FDLIBM_TARGET_NAME} ${PREFIX_IMPORTED_LIB}libc + target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${INCLUDE_LIBC_INTERFACE}) + target_link_libraries(${TARGET_NAME} ${CORE_TARGET_NAME} ${LIBC_TARGET_NAME} ${FDLIBM_TARGET_NAME} ${PREFIX_IMPORTED_LIB}libgcc ${PREFIX_IMPORTED_LIB}libgcc_eh) add_cppcheck_target(${TARGET_NAME}) diff --git a/build/configs/toolchain_linux_armv7l-el.cmake b/build/configs/toolchain_linux_armv7l-el.cmake new file mode 100644 index 0000000000..13f06769a8 --- /dev/null +++ b/build/configs/toolchain_linux_armv7l-el.cmake @@ -0,0 +1,21 @@ +# 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. + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR armv7l-el) + +set(CMAKE_C_COMPILER arm-linux-gnueabi-gcc) +set(CMAKE_CXX_COMPILER arm-linux-gnueabi-g++) + +set(FLAGS_COMMON_ARCH -mlittle-endian -mthumb) diff --git a/build/configs/toolchain_linux_armv7l-hf.cmake b/build/configs/toolchain_linux_armv7l-hf.cmake index 9f7405d935..a5205a510a 100644 --- a/build/configs/toolchain_linux_armv7l-hf.cmake +++ b/build/configs/toolchain_linux_armv7l-hf.cmake @@ -13,9 +13,14 @@ # limitations under the License. set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_PROCESSOR armv7l) +set(CMAKE_SYSTEM_PROCESSOR armv7l-hf) set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++) -set(FLAGS_COMMON_ARCH -mlittle-endian -mthumb) +# +# Limit fpu to VFPv3 with d0-d15 registers +# +# If this is changed, setjmp / longjmp for ARMv7 should be updated accordingly +# +set(FLAGS_COMMON_ARCH -mlittle-endian -mthumb -mfpu=vfpv3-d16) diff --git a/build/configs/toolchain_mcu_stm32f3.cmake b/build/configs/toolchain_mcu_stm32f3.cmake index efa3980a7b..0844f43f41 100644 --- a/build/configs/toolchain_mcu_stm32f3.cmake +++ b/build/configs/toolchain_mcu_stm32f3.cmake @@ -15,7 +15,7 @@ include(CMakeForceCompiler) set(CMAKE_SYSTEM_NAME MCU) -set(CMAKE_SYSTEM_PROCESSOR armv7l) +set(CMAKE_SYSTEM_PROCESSOR armv7l-hf) set(CMAKE_SYSTEM_VERSION STM32F3) set(FLAGS_COMMON_ARCH -mlittle-endian -mthumb -mcpu=cortex-m4 -march=armv7e-m -mfpu=fpv4-sp-d16 -mfloat-abi=hard) diff --git a/build/configs/toolchain_mcu_stm32f4.cmake b/build/configs/toolchain_mcu_stm32f4.cmake index 967d3778cb..9ca1453487 100644 --- a/build/configs/toolchain_mcu_stm32f4.cmake +++ b/build/configs/toolchain_mcu_stm32f4.cmake @@ -15,7 +15,7 @@ include(CMakeForceCompiler) set(CMAKE_SYSTEM_NAME MCU) -set(CMAKE_SYSTEM_PROCESSOR armv7l) +set(CMAKE_SYSTEM_PROCESSOR armv7l-hf) set(CMAKE_SYSTEM_VERSION STM32F4) set(FLAGS_COMMON_ARCH -mlittle-endian -mthumb -mcpu=cortex-m4 -march=armv7e-m -mfpu=fpv4-sp-d16 -mfloat-abi=hard) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-math.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-math.cpp index 7b472442aa..061cc1e603 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-math.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-math.cpp @@ -25,8 +25,9 @@ #include "ecma-objects.h" #include "ecma-objects-general.h" #include "ecma-try-catch-macro.h" -#include "jrt.h" #include "fdlibm-math.h" +#include "jrt.h" +#include "jrt-libc-includes.h" #ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_MATH_BUILTIN @@ -528,26 +529,24 @@ ecma_builtin_math_object_pow (ecma_value_t this_arg __attr_unused___, /**< 'this static ecma_completion_value_t ecma_builtin_math_object_random (ecma_value_t this_arg __attr_unused___) /**< 'this' argument */ { - /* Implementation of George Marsaglia's XorShift random number generator */ - TODO (/* Check for license issues */); - - static uint32_t word1 = 1455997910; - static uint32_t word2 = 1999515274; - static uint32_t word3 = 1234451287; - static uint32_t word4 = 1949149569; - - uint32_t intermediate = word1 ^ (word1 << 11); - intermediate ^= intermediate >> 8; - - word1 = word2; - word2 = word3; - word3 = word4; - - word4 ^= word4 >> 19; - word4 ^= intermediate; + uint32_t rnd = 1; + uint32_t reps_count; +#if RAND_MAX < 0x100 + reps_count = 4; +#elif RAND_MAX < 0x10000 + reps_count = 2; +#else /* RAND_MAX < 0x10000 */ + reps_count = 1; +#endif /* RAND_MAX >= 0x10000 */ + + for (uint32_t i = 0; i < reps_count; i++) + { + uint32_t next_rand = (uint32_t) rand (); + rnd *= next_rand; + } const uint32_t max_uint32 = (uint32_t) -1; - ecma_number_t rand = (ecma_number_t) word4; + ecma_number_t rand = (ecma_number_t) rnd; rand /= (ecma_number_t) max_uint32; rand *= (ecma_number_t) (max_uint32 - 1) / (ecma_number_t) max_uint32; diff --git a/jerry-libc/CMakeLists.txt b/jerry-libc/CMakeLists.txt index f384d926f0..19791eff25 100644 --- a/jerry-libc/CMakeLists.txt +++ b/jerry-libc/CMakeLists.txt @@ -30,8 +30,10 @@ set(COMPILE_FLAGS_LIBC "${COMPILE_FLAGS_JERRY} ${C_FLAGS_JERRY}") # Architecture-specific # x86_64 set(DEFINES_LIBC_X86_64 __TARGET_HOST_x64) - # ARMv7 - set(DEFINES_LIBC_ARMV7 __TARGET_HOST_ARMv7) + # ARMv7-hf + set(DEFINES_LIBC_ARMV7_HF __TARGET_HOST_ARMv7 __TARGET_HOST_ARMv7_HARD_FLOAT) + # ARMv7-el + set(DEFINES_LIBC_ARMV7_EL __TARGET_HOST_ARMv7 __TARGET_HOST_ARMv7_SOFT_FLOAT) # x86 set(DEFINES_LIBC_X86 __TARGET_HOST_x86) @@ -50,15 +52,6 @@ set(COMPILE_FLAGS_LIBC "${COMPILE_FLAGS_JERRY} ${C_FLAGS_JERRY}") set(INCLUDE_LIBC_INTERFACE ${CMAKE_SOURCE_DIR}/jerry-libc/include) set(INCLUDE_LIBC_INTERFACE ${INCLUDE_LIBC_INTERFACE} PARENT_SCOPE) - # Platform-specific - # Linux - set(INCLUDE_LIBC_LINUX target/linux) - # MCU - # STM32F3 - set(INCLUDE_LIBC_MCU_STM32F3 target/mcu-stubs) - # STM32F4 - set(INCLUDE_LIBC_MCU_STM32F4 target/mcu-stubs) - # Third-party # Platform-specific # Linux @@ -102,8 +95,10 @@ set(COMPILE_FLAGS_LIBC "${COMPILE_FLAGS_JERRY} ${C_FLAGS_JERRY}") # Architecture-specific configuration if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") set(DEFINES_LIBC ${DEFINES_LIBC} ${DEFINES_LIBC_X86_64}) - elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l") - set(DEFINES_LIBC ${DEFINES_LIBC} ${DEFINES_LIBC_ARMV7}) + elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l-hf") + set(DEFINES_LIBC ${DEFINES_LIBC} ${DEFINES_LIBC_ARMV7_HF}) + elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l-el") + set(DEFINES_LIBC ${DEFINES_LIBC} ${DEFINES_LIBC_ARMV7_EL}) elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86") set(DEFINES_LIBC ${DEFINES_LIBC} ${DEFINES_LIBC_X86}) else() @@ -148,3 +143,4 @@ set(COMPILE_FLAGS_LIBC "${COMPILE_FLAGS_JERRY} ${C_FLAGS_JERRY}") declare_targets_for_build_mode(DEBUG) declare_targets_for_build_mode(RELEASE) + declare_targets_for_build_mode(UNITTESTS) diff --git a/jerry-libc/arch/arm-v7.h b/jerry-libc/arch/arm-v7.h new file mode 100644 index 0000000000..21ae8f9084 --- /dev/null +++ b/jerry-libc/arch/arm-v7.h @@ -0,0 +1,179 @@ +/* Copyright 2014-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. + */ + +#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}; + +/* + * ldr argc ([sp + 0x0]) -> r0 + * add argv (sp + 0x4) -> r1 + * + * bl main + * + * bl exit + * + * infinite loop + */ +#define _START \ + 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. + */ +#ifdef __TARGET_HOST_ARMv7_HARD_FLOAT +# 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 /* !__TARGET_HOST_ARMv7_HARD_FLOAT */ +# define _STORE_VFP_S16_S31_IF_HARD_FLOAT +# define _LOAD_VFP_S16_S31_IF_HARD_FLOAT +#endif /* !__TARGET_HOST_ARMv7_HARD_FLOAT */ + +/* + * 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 */ diff --git a/jerry-libc/target/linux/asm_x86.h b/jerry-libc/arch/x86-32.h similarity index 53% rename from jerry-libc/target/linux/asm_x86.h rename to jerry-libc/arch/x86-32.h index 2370a3904a..e1538107ca 100644 --- a/jerry-libc/target/linux/asm_x86.h +++ b/jerry-libc/arch/x86-32.h @@ -92,6 +92,17 @@ pop %edi; \ ret; +/* + * push argv (%esp + 4) + * push argc ([%esp + 0x4]) + * + * call main + * + * push main_ret (%eax) + * call exit + * + * infinite loop + */ #define _START \ mov %esp, %eax; \ add $4, %eax; \ @@ -103,7 +114,100 @@ \ 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 */ diff --git a/jerry-libc/arch/x86-64.h b/jerry-libc/arch/x86-64.h new file mode 100644 index 0000000000..5e53da604f --- /dev/null +++ b/jerry-libc/arch/x86-64.h @@ -0,0 +1,188 @@ +/* Copyright 2014-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. + */ + +#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; + +/* + * mov argc ([%rsp]) -> %rdi + * mov argv (%rsp + 0x8) -> %rsi + * + * call main + * + * mov main_ret (%rax) -> %rdi + * call exit + * + * infinite loop + */ +#define _START \ + 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 */ diff --git a/jerry-libc/include/setjmp.h b/jerry-libc/include/setjmp.h new file mode 100644 index 0000000000..89071eb9e3 --- /dev/null +++ b/jerry-libc/include/setjmp.h @@ -0,0 +1,60 @@ +/* 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. + */ + +#ifndef JERRY_LIBC_SETJMP_H +#define JERRY_LIBC_SETJMP_H + +#ifdef __cplusplus +# define EXTERN_C "C" +#else /* !__cplusplus */ +# define 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 (8 * 4 + 16 * 4 bytes): + * - r4 - r11 + * - s16 - s31 (if hardfp enabled) + * + * See also: + * setjmp, longjmp + */ +typedef uint64_t jmp_buf[12]; + +extern EXTERN_C int setjmp (jmp_buf env); +extern EXTERN_C void longjmp (jmp_buf env, int val); + +#endif /* !JERRY_LIBC_SETJMP_H */ diff --git a/jerry-libc/include/stdlib.h b/jerry-libc/include/stdlib.h index c9cfe6a17d..0c3f2e5efa 100644 --- a/jerry-libc/include/stdlib.h +++ b/jerry-libc/include/stdlib.h @@ -25,4 +25,15 @@ extern EXTERN_C void __attribute__ ((noreturn)) exit (int); extern EXTERN_C void __attribute__ ((noreturn)) abort (void); +/** + * Maximum integer that could be returned by random number generator + * + * See also: + * rand + */ +#define RAND_MAX (0x7fffffffu) + +extern EXTERN_C int rand (void); +extern EXTERN_C void srand (unsigned int); + #endif /* !JERRY_LIBC_STDLIB_H */ diff --git a/jerry-libc/jerry-libc.c b/jerry-libc/jerry-libc.c index 79cd500aff..16ccd32019 100644 --- a/jerry-libc/jerry-libc.c +++ b/jerry-libc/jerry-libc.c @@ -24,6 +24,11 @@ #include "jerry-libc-defs.h" +/** + * State of pseudo-random number generator + */ +static unsigned int libc_random_gen_state[4] = { 1455997910, 1999515274, 1234451287, 1949149569 }; + /** * Standard file descriptors */ @@ -197,6 +202,12 @@ int strncmp (const char *s1, const char *s2, size_t n) { size_t i; + + if (n == 0) + { + return 0; + } + if (s1 == NULL) { if (s2 != NULL) @@ -320,3 +331,38 @@ isxdigit (int c) { return isdigit (c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } + +/** + * Generate pseudo-random integer + * + * Note: + * The function implements George Marsaglia's XorShift random number generator + * + * @return integer in range [0; RAND_MAX] + */ +int +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; + + uint32_t ret = libc_random_gen_state[3] % (RAND_MAX + 1u); + + return (int32_t) ret; +} /* rand */ + +/** + * Initialize pseudo-random number generator with the specified seed value + */ +void +srand (unsigned int seed) /**< new seed */ +{ + libc_random_gen_state[3] = seed; +} /* srand */ diff --git a/jerry-libc/target/linux/asm_arm.h b/jerry-libc/target/linux/asm_arm.h deleted file mode 100644 index c1ae263ee3..0000000000 --- a/jerry-libc/target/linux/asm_arm.h +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright 2014-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. - */ - -#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}; - -#define _START \ - ldr r0, [sp, #0]; \ - add r1, sp, #4; \ - bl main; \ - \ - bl exit; \ - 1: \ - b 1b - -#endif /* !ASM_ARM_H */ diff --git a/jerry-libc/target/linux/asm_x64.h b/jerry-libc/target/linux/asm_x64.h deleted file mode 100644 index e709199f8e..0000000000 --- a/jerry-libc/target/linux/asm_x64.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright 2014-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. - */ - -#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; - -#define _START \ - mov (%rsp), %rdi; \ - mov %rsp, %rsi; \ - add $8, %rsi; \ - callq main; \ - \ - mov %rax, %rdi; \ - callq exit; \ - 1: \ - jmp 1b - -#endif /* !ASM_X64_H */ diff --git a/jerry-libc/target/linux/jerry-asm.S b/jerry-libc/target/linux/jerry-asm.S index 69fc3c74b9..93a00cb851 100644 --- a/jerry-libc/target/linux/jerry-asm.S +++ b/jerry-libc/target/linux/jerry-asm.S @@ -1,9 +1,9 @@ #ifdef __TARGET_HOST_x64 -# include "asm_x64.h" +# include "arch/x86-64.h" #elif defined (__TARGET_HOST_x86) -# include "asm_x86.h" +# include "arch/x86-32.h" #elif defined (__TARGET_HOST_ARMv7) -# include "asm_arm.h" +# include "arch/arm-v7.h" #else /* !__TARGET_HOST_x64 && !__TARGET_HOST_x86 && !__TARGET_HOST_ARMv7 */ # error "!__TARGET_HOST_x64 && !__TARGET_HOST_x86 && !__TARGET_HOST_ARMv7" #endif /* !__TARGET_HOST_x64 && !__TARGET_HOST_x86 && !__TARGET_HOST_ARMv7 */ @@ -38,3 +38,33 @@ syscall_3_asm: SYSCALL_3 .size syscall_3_asm, . - syscall_3_asm +/** + * setjmp (jmp_buf env) + * + * See also: + * longjmp + * + * @return 0 - if returns from direct call, + * nonzero - if returns after longjmp. + */ +.global setjmp +.type setjmp, %function +setjmp: + _SETJMP +.size setjmp, . - 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 + */ +.global longjmp +.type longjmp, %function +longjmp: + _LONGJMP +.size longjmu, . - setjmp diff --git a/jerry-libc/target/linux/jerry-libc-target.c b/jerry-libc/target/linux/jerry-libc-target.c index 4013ecde7f..11ee90ec07 100644 --- a/jerry-libc/target/linux/jerry-libc-target.c +++ b/jerry-libc/target/linux/jerry-libc-target.c @@ -29,15 +29,6 @@ #include #include -#ifdef __TARGET_HOST_x64 -# include "asm_x64.h" -#elif defined (__TARGET_HOST_x86) -# include "asm_x86.h" -#elif defined (__TARGET_HOST_ARMv7) -# include "asm_arm.h" -#else /* !__TARGET_HOST_x64 && !__TARGET_HOST_x86 && !__TARGET_HOST_ARMv7 */ -# error "!__TARGET_HOST_x64 && !__TARGET_HOST_x86 && !__TARGET_HOST_ARMv7 " -#endif /* !__TARGET_HOST_x64 && !__TARGET_HOST_x86 && !__TARGET_HOST_ARMv7 */ #include "jerry-libc-defs.h" LIBC_UNREACHABLE_STUB_FOR (int raise (int sig_no __attr_unused___)) @@ -331,7 +322,7 @@ ftell (FILE * fp) /**< stream pointer */ /** * fread * - * @return number of bytes read + * @return number of elements read */ size_t fread (void *ptr, /**< address of buffer to read to */ @@ -342,6 +333,11 @@ fread (void *ptr, /**< address of buffer to read to */ long int ret; size_t bytes_read = 0; + if (size == 0) + { + return 0; + } + do { ret = syscall_3 (__NR_read, @@ -353,13 +349,13 @@ fread (void *ptr, /**< address of buffer to read to */ } while (bytes_read != size * nmemb && ret != 0); - return bytes_read; + return bytes_read / size; } /* fread */ /** * fwrite * - * @return number of bytes written + * @return number of elements written */ size_t fwrite (const void *ptr, /**< data to write */ @@ -369,6 +365,11 @@ fwrite (const void *ptr, /**< data to write */ { size_t bytes_written = 0; + if (size == 0) + { + return 0; + } + do { long int ret = syscall_3 (__NR_write, @@ -380,7 +381,7 @@ fwrite (const void *ptr, /**< data to write */ } while (bytes_written != size * nmemb); - return bytes_written; + return bytes_written / size; } /* fwrite */ // FIXME diff --git a/tests/unit/test-api.cpp b/tests/unit/test-api.cpp index 9636fd049a..0e2bea50c6 100644 --- a/tests/unit/test-api.cpp +++ b/tests/unit/test-api.cpp @@ -218,6 +218,8 @@ const jerry_api_char_ptr_t magic_string_items[] = int main (void) { + TEST_INIT (); + jerry_init (JERRY_FLAG_EMPTY); bool is_ok; diff --git a/tests/unit/test-common.h b/tests/unit/test-common.h index 3b32553fc0..5d13907971 100644 --- a/tests/unit/test-common.h +++ b/tests/unit/test-common.h @@ -19,13 +19,12 @@ #include "jrt.h" #include +#include #include #include #include #include -using namespace std; - /** * Verify that unit tests are built with all debug checks enabled */ @@ -33,21 +32,32 @@ using namespace std; # error "defined (JERRY_NDEBUG) || defined (JERRY_DISABLE_HEAVY_DEBUG) in a unit test" #endif /* JERRY_NDEBUG || JERRY_DISABLE_HEAVY_DEBUG */ -#define TEST_RANDOMIZE() \ +/** + * Test initialization statement that should be included + * at the beginning of main function in every unit test. + */ +#define TEST_INIT() \ do \ { \ - struct timeval current_time; \ - gettimeofday (¤t_time, NULL); \ - \ - time_t seconds = current_time.tv_sec; \ - suseconds_t microseconds = current_time.tv_usec; \ - \ - uint32_t seed = (uint32_t) (seconds + microseconds); \ - \ - printf ("TEST_RANDOMIZE: seed is %u\n", seed); \ - \ + FILE *f_rnd = fopen ("/dev/urandom", "r"); \ + \ + if (f_rnd == NULL) \ + { \ + return 1; \ + } \ + \ + uint32_t seed; \ + \ + size_t bytes_read = fread (&seed, 1, sizeof (seed), f_rnd); \ + \ + fclose (f_rnd); \ + \ + if (bytes_read != sizeof (seed)) \ + { \ + return 1; \ + } \ + \ srand (seed); \ -} \ -while (0) +} while (0) #endif /* TEST_COMMON_H */ diff --git a/tests/unit/test-heap.cpp b/tests/unit/test-heap.cpp index 78700d6b01..bb062d6dda 100644 --- a/tests/unit/test-heap.cpp +++ b/tests/unit/test-heap.cpp @@ -82,7 +82,7 @@ int main (int __attr_unused___ argc, char __attr_unused___ **argv) { - TEST_RANDOMIZE (); + TEST_INIT (); mem_heap_init (test_native_heap, sizeof (test_native_heap)); diff --git a/tests/unit/test-literal-storage.cpp b/tests/unit/test-literal-storage.cpp index 28b9a2cccc..db21a2b3b2 100644 --- a/tests/unit/test-literal-storage.cpp +++ b/tests/unit/test-literal-storage.cpp @@ -58,7 +58,7 @@ int main (int __attr_unused___ argc, char __attr_unused___ **argv) { - TEST_RANDOMIZE (); + TEST_INIT (); const ecma_char_t *ptrs[test_sub_iters]; ecma_number_t numbers[test_sub_iters]; diff --git a/tests/unit/test-longjmp.cpp b/tests/unit/test-longjmp.cpp new file mode 100644 index 0000000000..a9ad08ab3d --- /dev/null +++ b/tests/unit/test-longjmp.cpp @@ -0,0 +1,82 @@ +/* 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. + */ + +#include "test-common.h" + +#define TEST_MAX_DEPTH 10 +#define TEST_ITERATIONS_NUM 256 + +jmp_buf buffers[TEST_MAX_DEPTH]; + +static void +test_setjmp_longjmp (volatile int depth) +{ + if (depth != TEST_MAX_DEPTH) + { + int a = 1, b = 2, c = 3; + + int array[256]; + for (int i = 0; i < 256; i++) + { + array[i] = i; + } + + (void) a; + (void) b; + (void) c; + (void) array; + + int k = setjmp (buffers[depth]); + + if (k == 0) + { + test_setjmp_longjmp (depth + 1); + } + else + { + JERRY_ASSERT (k == depth + 1); + + JERRY_ASSERT (a == 1); + JERRY_ASSERT (b == 2); + JERRY_ASSERT (c == 3); + + for (int i = 0; i < 256; i++) + { + JERRY_ASSERT (array[i] == i); + } + } + } + else + { + int t = rand () % depth; + JERRY_ASSERT (t >= 0 && t < depth); + + longjmp (buffers[t], t + 1); + } +} + +int +main (int __attr_unused___ argc, + char __attr_unused___ **argv) +{ + TEST_INIT (); + + for (int i = 0; i < TEST_ITERATIONS_NUM; i++) + { + test_setjmp_longjmp (0); + } + + return 0; +} /* main */ diff --git a/tests/unit/test-number-to-string.cpp b/tests/unit/test-number-to-string.cpp index e736a02fda..31cf8393f0 100644 --- a/tests/unit/test-number-to-string.cpp +++ b/tests/unit/test-number-to-string.cpp @@ -25,6 +25,8 @@ int main (int __attr_unused___ argc, char __attr_unused___ **argv) { + TEST_INIT (); + const ecma_char_t* zt_strings[] = { (const ecma_char_t*) "1", diff --git a/tests/unit/test-parser.cpp b/tests/unit/test-parser.cpp index 2721e68b69..e30867a5ea 100644 --- a/tests/unit/test-parser.cpp +++ b/tests/unit/test-parser.cpp @@ -69,6 +69,8 @@ int main (int __attr_unused___ argc, char __attr_unused___ **argv) { + TEST_INIT (); + char program[] = "a=1;var a;"; bool is_ok; diff --git a/tests/unit/test-pool.cpp b/tests/unit/test-pool.cpp index d22d190a6f..1c8b8d2222 100644 --- a/tests/unit/test-pool.cpp +++ b/tests/unit/test-pool.cpp @@ -37,7 +37,7 @@ int main (int __attr_unused___ argc, char __attr_unused___ **argv) { - TEST_RANDOMIZE (); + TEST_INIT (); for (uint32_t i = 0; i < test_iters; i++) { diff --git a/tests/unit/test-poolman.cpp b/tests/unit/test-poolman.cpp index 2076bd6761..c7598e61ae 100644 --- a/tests/unit/test-poolman.cpp +++ b/tests/unit/test-poolman.cpp @@ -37,7 +37,7 @@ int main (int __attr_unused___ argc, char __attr_unused___ **argv) { - TEST_RANDOMIZE (); + TEST_INIT (); mem_init (); diff --git a/tests/unit/test-recordset.cpp b/tests/unit/test-recordset.cpp index 86e4b93777..c2a39098ed 100644 --- a/tests/unit/test-recordset.cpp +++ b/tests/unit/test-recordset.cpp @@ -213,7 +213,7 @@ int main (int __attr_unused___ argc, char __attr_unused___ **argv) { - TEST_RANDOMIZE (); + TEST_INIT (); mem_init (); diff --git a/tests/unit/test-string-to-number.cpp b/tests/unit/test-string-to-number.cpp index fd46982077..23e617ef57 100644 --- a/tests/unit/test-string-to-number.cpp +++ b/tests/unit/test-string-to-number.cpp @@ -25,6 +25,8 @@ int main (int __attr_unused___ argc, char __attr_unused___ **argv) { + TEST_INIT (); + const ecma_char_t* zt_strings[] = { (const ecma_char_t*) "1",