Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ if(CC_USES_SYSTEM_ARCH_SH OR NOT CHAKRACORE_BUILD_SH)
set(CC_TARGETS_ARM_SH 1)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(CC_TARGETS_ARM64_SH 1)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
set(CC_TARGETS_ARM64_SH 1)
endif()
unset(CC_USES_SYSTEM_ARCH_SH CACHE)
endif()
Expand All @@ -73,7 +75,7 @@ elseif(CC_TARGETS_ARM64_SH)
add_definitions(-D_ARM64_=1)
add_definitions(-D__arm64__=1)
set(CC_TARGETS_ARM64 1)
set(CMAKE_SYSTEM_PROCESSOr "arm64")
set(CMAKE_SYSTEM_PROCESSOR "arm64")
elseif(CC_TARGETS_X86_SH)
set(CC_TARGETS_X86 1)
set(CMAKE_SYSTEM_PROCESSOR "i386")
Expand Down Expand Up @@ -306,6 +308,14 @@ elseif(CC_TARGETS_ARM64)
if(CC_TARGET_OS_OSX)
add_compile_options(-arch arm64)
endif()
if (CC_TARGET_OS_LINUX)
# arm64 .S mostly use ; comments, not accepted by GNU assembler.
# In lieu of converting them all, just strip these comments during build.
set(CMAKE_ASM_COMPILE_OBJECT
"sed -e 's/\;.*//g' <SOURCE> > <OBJECT_DIR>/$$(basename <SOURCE>)"
"<CMAKE_ASM_COMPILER> <DEFINES> <INCLUDES> -I $$(dirname <SOURCE>) <FLAGS> -o <OBJECT> -c <OBJECT_DIR>/$$(basename <SOURCE>)"
)
endif()
else()
message(FATAL_ERROR "Only AMD64, ARM, ARM64 and I386 are supported")
endif()
Expand Down
1 change: 1 addition & 0 deletions ContributionAgreement.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ This agreement has been signed by:
|Ryoichi Kaida| camcam-lemon|
|Lukas Kurz| ShortDevelopment|
|Paul Pluzhnikov|EmployedRussian|
|Ivan Krasilnikov|ivankra|
4 changes: 2 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ if [[ $ARCH =~ "x86" ]]; then
elif [[ $ARCH =~ "arm" ]]; then
ARCH="-DCC_TARGETS_ARM_SH=1"
echo "Compile Target : arm"
elif [[ $ARCH =~ "arm64" ]]; then
elif [[ $ARCH =~ "arm64" || $ARCH =~ "aarch64" ]]; then
ARCH="-DCC_TARGETS_ARM64_SH=1"
echo "Compile Target : arm64"
elif [[ $ARCH =~ "amd64" ]]; then
Expand All @@ -634,7 +634,7 @@ fi
echo Generating $BUILD_TYPE build
echo $EXTRA_DEFINES
cmake $CMAKE_GEN -DCHAKRACORE_BUILD_SH=ON $CC_PREFIX $CMAKE_ICU $LTO $LTTNG \
$STATIC_LIBRARY $ARCH $TARGET_OS \ $ENABLE_CC_XPLAT_TRACE $EXTRA_DEFINES \
$STATIC_LIBRARY $ARCH $TARGET_OS $ENABLE_CC_XPLAT_TRACE $EXTRA_DEFINES \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE $SANITIZE $NO_JIT $CMAKE_INTL \
$WITHOUT_FEATURES $WB_FLAG $WB_ARGS $CMAKE_EXPORT_COMPILE_COMMANDS \
$LIBS_ONLY_BUILD $VALGRIND $BUILD_RELATIVE_DIRECTORY $CCACHE_NAME
Expand Down
12 changes: 10 additions & 2 deletions lib/Common/Common/NumberUtilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ namespace Js

};

#ifdef __clang__
typedef uint32 uint32_aliased __attribute__((__may_alias__));
typedef double double_aliased __attribute__((__may_alias__));
#else
typedef uint32 uint32_aliased;
typedef double double_aliased;
#endif

class NumberUtilities : public NumberUtilitiesBase
{
public:
Expand All @@ -92,8 +100,8 @@ namespace Js
static uint32 MulLu(uint32 lu1, uint32 lu2, uint32 *pluHi);
static int AddLu(uint32 *plu1, uint32 lu2);

static uint32 &LuHiDbl(double &dbl);
static uint32 &LuLoDbl(double &dbl);
static uint32_aliased &LuHiDbl(double_aliased &dbl);
static uint32_aliased &LuLoDbl(double_aliased &dbl);
static INT64 TryToInt64(double d);
static bool IsValidTryToInt64(__int64 value); // Whether TryToInt64 resulted in a valid value.

Expand Down
29 changes: 18 additions & 11 deletions lib/Common/Common/NumberUtilities.inl
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,29 @@

namespace Js
{
NUMBER_UTIL_INLINE uint32 &NumberUtilities::LuHiDbl(double &dbl)
union DoubleAccessor
{
double d;
struct
{
#if defined(__BIG_ENDIAN__)
return ((uint32 *)&dbl)[0];
#else //!BIG_ENDIAN
return ((uint32 *)&dbl)[1];
#endif //!BIG_ENDIAN
uint32 hi;
uint32 lo;
#else
uint32 lo;
uint32 hi;
#endif
} u;
};

NUMBER_UTIL_INLINE uint32_aliased &NumberUtilities::LuHiDbl(double_aliased &dbl)
{
return reinterpret_cast<DoubleAccessor*>(&dbl)->u.hi;
}

NUMBER_UTIL_INLINE uint32 &NumberUtilities::LuLoDbl(double &dbl)
NUMBER_UTIL_INLINE uint32_aliased &NumberUtilities::LuLoDbl(double_aliased &dbl)
{
#if defined(__BIG_ENDIAN__)
return ((uint32 *)&dbl)[1];
#else //!BIG_ENDIAN
return ((uint32 *)&dbl)[0];
#endif //!BIG_ENDIAN
return reinterpret_cast<DoubleAccessor*>(&dbl)->u.lo;
}

#if defined(_M_X64) && defined(_MSC_VER) && !defined(__clang__)
Expand Down
3 changes: 2 additions & 1 deletion lib/Common/Core/CommonTypedefs.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
Expand All @@ -26,7 +27,7 @@ typedef unsigned long ulong;

typedef signed char sbyte;

typedef __int8 int8;
typedef signed __int8 int8;
typedef __int16 int16;
typedef __int32 int32;
typedef __int64 int64;
Expand Down
5 changes: 5 additions & 0 deletions lib/Common/arm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,9 @@ extern "C" VOID arm64_SAVE_REGISTERS(void*);
*/

const DWORD ReturnAddrOffsetFromFramePtr = 1;
#ifdef __linux__
// Linux ARM64 appears to have some extra 8 byte padding.
const DWORD ArgOffsetFromFramePtr = 4;
#else
const DWORD ArgOffsetFromFramePtr = 2;
#endif
19 changes: 19 additions & 0 deletions lib/Runtime/Language/Arguments.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
va_list _vl; \
va_start(_vl, callInfo); \
Js::Var* va = (Js::Var*)_vl
#elif defined(_ARM64_) && defined(__linux__)
// AAPCS64 (Linux ARM64 ABI) reference:
// https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#appendix-variable-argument-lists
#define DECLARE_ARGS_VARARRAY(va, ...) \
va_list _vl; \
va_start(_vl, callInfo); \
Js::Var* va = (Js::Var*)_vl.__stack + 2; \
Assert(*reinterpret_cast<Js::CallInfo*>(va - 1) == callInfo)
#else
// We use a custom calling convention to invoke JavascriptMethod based on
// System ABI. At entry of JavascriptMethod the stack layout is:
Expand Down Expand Up @@ -84,8 +92,19 @@ inline int _count_args(const T1&, const T2&, const T3&, const T4&, const T5&, Js
#define CALL_ENTRYPOINT_NOASSERT(entryPoint, function, callInfo, ...) \
entryPoint(function, callInfo, ##__VA_ARGS__)
#elif defined (_ARM64_)
#ifdef __linux__
// Linux ARM64 uses AAPCS64: first 8 args in x0-x7, rest via stack.
// Fill x2-x7 with nulls here to force the expected stack layout:
// [RetAddr] [function] [callInfo] [args...]
#define CALL_ENTRYPOINT_NOASSERT(entryPoint, function, callInfo, ...) \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect this to break the JavascriptStackWalker, I saw you said it was "fragile", what's the status?

Copy link
Contributor Author

@ivankra ivankra Dec 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The single hard-coded constant ArgOffsetFromFramePtr that JavascriptStackWalker relies on feels rather fragile to me. For now, I set ArgOffsetFromFramePtr=4 - I see 8 extra bytes of what seems like padding or saved registers. But I'd expect it to break with different compilers and optimization flags by analogy with my experience with DECLARE_ARGS_VARARRAY - at first (before I found va_list.__stack) I was trying to fixing it by trying different offsets in _get_va(), but it just kept breaking between optimized and debug builds.

JavascriptStackWalker in JIT-less builds so far works for me with clang 19, 20, and 22, both optimized and debug builds. Perhaps because it only needs to deal with a few specific call sites in this mode. When JIT is enabled it is crashing, but because JIT wasn't supported on macOS, I didn't investigate these crashes further.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JIT crash is not remarkable, the ARM JIT contains significant windows specific logic that needs re-writing for Linux/macOS including the way function entry and exit is setup and the managing of the stack layout.

For calling JS functions in the interpreter we go via arm64_CallFunction to set the stack exactly the way we need for the stack walker and argument handling to work: https://github.com/chakra-core/ChakraCore/blob/master/lib/Runtime/Library/arm64/arm64_CallFunction.S

entryPoint(function, callInfo, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, \
function, callInfo, ##__VA_ARGS__)
#else
// macOS has own bespoke vararg cc (DarwinPCS), varargs always passed via stack.
// Duplicate function/callInfo so they are pushed onto stack as part of varargs.
#define CALL_ENTRYPOINT_NOASSERT(entryPoint, function, callInfo, ...) \
entryPoint(function, callInfo, function, callInfo, ##__VA_ARGS__)
#endif
#else
#error CALL_ENTRYPOINT_NOASSERT not yet implemented
#endif
Expand Down
6 changes: 4 additions & 2 deletions lib/Runtime/Language/SimdInt32x4Operation.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -63,11 +64,12 @@ namespace Js
SIMDValue SIMDInt32x4Operation::OpFromFloat32x4(const SIMDValue& v, bool &throws)
{
SIMDValue result = { 0 };
const int MIN_INT = 0x80000000, MAX_INT = 0x7FFFFFFF;
const float MIN_INT = -2147483648.0f;
const float MAX_INT_PLUS_1 = 2147483648.0f; // exact float

for (uint i = 0; i < 4; i++)
{
if (v.f32[i] >= MIN_INT && v.f32[i] <= MAX_INT)
if (v.f32[i] >= MIN_INT && v.f32[i] < MAX_INT_PLUS_1)
{
result.u32[i] = (int)(v.f32[i]);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2257,14 +2257,14 @@ DEFINE_ISXLOCALEAVAILABLE(PR, uloc)
Field(ScriptContext *) sc;
Field(UNumberFormatFields *) fields;

static const UNumberFormatFields UnsetField = static_cast<UNumberFormatFields>(0xFFFFFFFF);
static const uint8_t UnsetField = 0xFF;

JavascriptString *GetPartTypeString(UNumberFormatFields field)
{
JavascriptLibrary *library = sc->GetLibrary();

// this is outside the switch because MSVC doesn't like that UnsetField is not a valid enum value
if (field == UnsetField)
if ((static_cast<uint32_t>(field) & 0xFF) == UnsetField)
{
return library->GetIntlLiteralPartString();
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Runtime/Library/JavascriptError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ namespace Js

if (FACILITY_CONTROL == HRESULT_FACILITY(hr) || FACILITY_JSCRIPT == HRESULT_FACILITY(hr))
{
#if !(defined(_M_ARM) && defined(__clang__))
#if !((defined(_M_ARM) || defined(_M_ARM64)) && defined(__clang__))
if (argList != nullptr)
#endif
{
Expand Down
3 changes: 3 additions & 0 deletions lib/Runtime/PlatformAgnostic/ChakraPlatform.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
Expand All @@ -20,5 +21,7 @@
#include "PlatformAgnostic/AssemblyCommon.h"

#if !defined(_WIN32) && defined(DEBUG)
// This define from sal.h conflicts with Linux's signal.h
#undef __reserved
#include <signal.h> // raise(SIGINT)
#endif
3 changes: 3 additions & 0 deletions lib/Runtime/PlatformAgnostic/Platform/Linux/PerfTrace.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "Common.h"
#include "Runtime.h"
#include "ChakraPlatform.h"

// This define from sal.h conflicts with Linux's signal.h
#undef __reserved
#include <signal.h>
#include <errno.h>
#include <unistd.h>
Expand Down
16 changes: 16 additions & 0 deletions pal/inc/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ Module Name:
#include <ctype.h>
#endif

// On some Linux distros, these system headers and their dependencies
// (included through unicode headers in ChakraICU.h during ICU-enabled
// builds in particular) contain macros like `#undef wcslen`, which
// conflict with our PAL_* macros. As a workaround, include these system
// headers early in front of our PAL_* definitions, so that when they
// are included again later on, they would not undefine our macros.
#if defined(PLATFORM_UNIX) && defined(HAS_ICU) && defined(PAL_STDCPP_COMPAT) && __cplusplus >= 201703L
#include <cwchar>
#include <string>
#include <string_view>
#endif

#if !defined(static_assert)
#define static_assert _Static_assert
#endif
Expand Down Expand Up @@ -2998,7 +3010,11 @@ typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
// Integer registers
//

#ifdef __linux__
/* +0x004 */ DWORD PState;
#else
/* +0x004 */ DWORD Cpsr; // NZVF + DAIF + CurrentEL + SPSel
#endif
/* +0x008 */ union {
struct {
DWORD64 X0;
Expand Down
26 changes: 12 additions & 14 deletions pal/inc/pal_mstypes.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

/*++





--*/
//-------------------------------------------------------------------------------------------------------
// ChakraCore/Pal
// Contains portions (c) copyright Microsoft, portions copyright (c) the .NET Foundation and Contributors
// and edits (c) copyright the ChakraCore Contributors.
// See THIRD-PARTY-NOTICES.txt in the project root for .NET Foundation license
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////
// Extensions to the usual posix header files
Expand Down Expand Up @@ -168,7 +163,10 @@ extern "C" {

#define __int32 int
#define __int16 short int
#define __int8 char // assumes char is signed
// NB: signedness depends on platform and ABI, usually signed,
// BUT: Linux arm64 ABI uses unsigned char, for example.
// It should be always used with an explicit signed/unsigned prefix.
#define __int8 char

#endif // _MSC_VER

Expand All @@ -183,7 +181,7 @@ typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int8 int8_t;
typedef signed __int8 int8_t;
#define __int8_t_defined

typedef unsigned __int8 uint8_t;
Expand Down
6 changes: 5 additions & 1 deletion pal/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,12 @@ if(CC_TARGETS_AMD64 OR CC_TARGETS_X86)
arch/i386/asmhelpers.S
)
elseif(PAL_CMAKE_PLATFORM_ARCH_ARM64)
if(CC_TARGET_OS_OSX)
set(PLATFORM_SOURCES ${PLATFORM_SOURCES}
arch/arm64/dispatchexceptionwrapper.S
)
endif()
set(ARCH_SOURCES
arch/arm64/dispatchexceptionwrapper.S
arch/arm64/context2.S
arch/arm64/debugbreak.S
)
Expand Down
13 changes: 9 additions & 4 deletions pal/src/include/pal/context.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
//-------------------------------------------------------------------------------------------------------
// ChakraCore/Pal
// Contains portions (c) copyright Microsoft, portions copyright (c) the .NET Foundation and Contributors
// and edits (c) copyright the ChakraCore Contributors.
// See THIRD-PARTY-NOTICES.txt in the project root for .NET Foundation license
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

/* Module Name:
include/pal/context.h
Expand Down Expand Up @@ -187,7 +190,9 @@ typedef ucontext_t native_context_t;
#define MCREG_Sp(mc) ((mc).sp)
#define MCREG_Pc(mc) ((mc).pc)
#define MCREG_PState(mc) ((mc).pstate)
#ifndef __linux__
#define MCREG_Cpsr(mc) ((mc).cpsr)
#endif
#else
// For FreeBSD, as found in x86/ucontext.h
#define MCREG_Rbp(mc) ((mc).mc_rbp)
Expand Down
4 changes: 3 additions & 1 deletion pal/src/misc/sysinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ SET_DEFAULT_DEBUG_CHANNEL(MISC);
#ifdef __LINUX__
// There is no reasonable way to get the max. value for the VAS on
// Linux, so just hardcode the ABI values for 64 and 32bits.
#ifdef LINUX64
#if defined(_M_ARM64)
#define MAX_PROCESS_VA_SPACE_LINUX (1ull << 48)
#elif defined(LINUX64)
// The hardware limit for x86-64 CPUs is 256TB, but the practical
// limit at the moment for Linux kernels is 128TB. See for example:
// https://access.redhat.com/articles/rhel-limits
Expand Down
Loading