From 015b05db5f6373ab93104bf262a2814e9db5511a Mon Sep 17 00:00:00 2001 From: rhuanjl Date: Tue, 14 Feb 2023 17:27:24 +0000 Subject: [PATCH] Update Memory handling to support Apple Silicon - Memory page size on apple arm64 is 16kb - This change caused ushort overflows - minor edits to orders of operations to fix - New assembler file for arm64_SAVE_REGISTERS --- lib/Common/Core/SysInfo.h | 12 +++++- lib/Common/Memory/CMakeLists.txt | 5 +++ lib/Common/Memory/CustomHeap.cpp | 9 +++++ lib/Common/Memory/Recycler.inl | 7 +++- .../Memory/RecyclerWriteBarrierManager.h | 8 ++++ .../Memory/SmallFinalizableHeapBlock.cpp | 7 ++-- lib/Common/Memory/SmallLeafHeapBlock.cpp | 3 +- lib/Common/Memory/SmallNormalHeapBlock.cpp | 5 ++- .../Memory/arm64/arm64_SAVE_REGISTERS.S | 39 +++++++++++++++++++ 9 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 lib/Common/Memory/arm64/arm64_SAVE_REGISTERS.S diff --git a/lib/Common/Core/SysInfo.h b/lib/Common/Core/SysInfo.h index cf94a01ff64..6b925f537c0 100644 --- a/lib/Common/Core/SysInfo.h +++ b/lib/Common/Core/SysInfo.h @@ -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. //------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -62,7 +63,11 @@ class AutoSystemInfo : public SYSTEM_INFO #ifdef _WIN32 static HMODULE GetCRTHandle(); #endif +#if defined(__APPLE__) && defined(_M_ARM64) + static DWORD const PageSize = 16384; +#else static DWORD const PageSize = 4096; +#endif static size_t const MaxPageCount = SIZE_MAX / PageSize; @@ -136,7 +141,12 @@ class AutoSystemInfo : public SYSTEM_INFO // For Prefast where it doesn't like symbolic constants +#if defined(__APPLE__) && defined(_M_ARM64) +CompileAssert(AutoSystemInfo::PageSize == 16384); +#define __in_ecount_pagesize __in_ecount(16384) +#define __in_ecount_twopagesize __in_ecount(32768) +#else CompileAssert(AutoSystemInfo::PageSize == 4096); #define __in_ecount_pagesize __in_ecount(4096) #define __in_ecount_twopagesize __in_ecount(8192) - +#endif diff --git a/lib/Common/Memory/CMakeLists.txt b/lib/Common/Memory/CMakeLists.txt index 7d141d2eca8..775c658aa77 100644 --- a/lib/Common/Memory/CMakeLists.txt +++ b/lib/Common/Memory/CMakeLists.txt @@ -45,6 +45,11 @@ if(CC_TARGETS_AMD64) amd64/XDataAllocator.cpp amd64/amd64_SAVE_REGISTERS.S ) +elseif(CC_TARGETS_ARM64) + set (CCM_SOURCE_FILES ${CCM_SOURCE_FILES} + arm64/XDataAllocator.cpp + arm64/arm64_SAVE_REGISTERS.S + ) elseif(CC_TARGETS_ARM) set (CCM_SOURCE_FILES ${CCM_SOURCE_FILES} arm/XDataAllocator.cpp diff --git a/lib/Common/Memory/CustomHeap.cpp b/lib/Common/Memory/CustomHeap.cpp index a84b63bed64..12a30e7aa25 100644 --- a/lib/Common/Memory/CustomHeap.cpp +++ b/lib/Common/Memory/CustomHeap.cpp @@ -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. //------------------------------------------------------------------------------------------------------- #include "CommonMemoryPch.h" @@ -294,7 +295,11 @@ BOOL Heap::ProtectAllocationWithExecuteReadWrite(Allo } else { + #if defined(__APPLE__) && defined(_M_ARM64) + protectFlags = PAGE_READWRITE; // PAGE_EXECUTE_READWRITE banned on Apple Silicon + #else protectFlags = PAGE_EXECUTE_READWRITE; + #endif } return this->ProtectAllocation(allocation, protectFlags, PAGE_EXECUTE_READ, addressInPage); } @@ -311,7 +316,11 @@ BOOL Heap::ProtectAllocationWithExecuteReadOnly(__in { protectFlags = PAGE_EXECUTE_READ; } + #if defined(__APPLE__) && defined(_M_ARM64) + return this->ProtectAllocation(allocation, protectFlags, PAGE_READWRITE, addressInPage); // PAGE_EXECUTE_READWRITE banned on Apple Silicon + #else return this->ProtectAllocation(allocation, protectFlags, PAGE_EXECUTE_READWRITE, addressInPage); + #endif } template diff --git a/lib/Common/Memory/Recycler.inl b/lib/Common/Memory/Recycler.inl index ca217acef41..df4dbf2300e 100644 --- a/lib/Common/Memory/Recycler.inl +++ b/lib/Common/Memory/Recycler.inl @@ -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 @@ -587,8 +588,10 @@ SmallHeapBlockT::GetAddressBitIndex(void * objectAddress) { Assert(HeapInfo::IsAlignedAddress(objectAddress)); - ushort offset = (ushort)(::Math::PointerCastToIntegralTruncate(objectAddress) % (TBlockAttributes::PageCount * AutoSystemInfo::PageSize)); - offset = offset >> HeapConstants::ObjectAllocationShift; + ushort offset = (ushort)( + (::Math::PointerCastToIntegralTruncate(objectAddress) + % (TBlockAttributes::PageCount * AutoSystemInfo::PageSize)) + >> HeapConstants::ObjectAllocationShift); Assert(offset <= USHRT_MAX); Assert(offset <= TBlockAttributes::MaxAddressBit); diff --git a/lib/Common/Memory/RecyclerWriteBarrierManager.h b/lib/Common/Memory/RecyclerWriteBarrierManager.h index 61d8ecf2dc8..7ffd8707f72 100644 --- a/lib/Common/Memory/RecyclerWriteBarrierManager.h +++ b/lib/Common/Memory/RecyclerWriteBarrierManager.h @@ -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 @@ -211,10 +212,17 @@ class RecyclerWriteBarrierManager static DWORD GetWriteBarrier(void * address); #endif +#if defined(__APPLE__) && defined(_M_ARM64) + static size_t const s_WriteBarrierPageSize = 16384; + static uint const s_BitArrayCardTableShift = 9; + static uint const s_BytesPerCardBit = 1 << s_BitArrayCardTableShift; // 512 = 1 << 9 + static uint const s_BytesPerCard = s_BytesPerCardBit * 32; // 16k +#else static size_t const s_WriteBarrierPageSize = 4096; static uint const s_BitArrayCardTableShift = 7; static uint const s_BytesPerCardBit = 1 << s_BitArrayCardTableShift; // 128 = 1 << 7 static uint const s_BytesPerCard = s_BytesPerCardBit * 32; // 4K = 1 << 12 = 128 << 5 +#endif private: diff --git a/lib/Common/Memory/SmallFinalizableHeapBlock.cpp b/lib/Common/Memory/SmallFinalizableHeapBlock.cpp index 50981986bd5..4b19c5aba08 100644 --- a/lib/Common/Memory/SmallFinalizableHeapBlock.cpp +++ b/lib/Common/Memory/SmallFinalizableHeapBlock.cpp @@ -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. //------------------------------------------------------------------------------------------------------- #include "CommonMemoryPch.h" @@ -14,7 +15,7 @@ SmallFinalizableWithBarrierHeapBlockT::New(HeapBucketTsizeCat <= USHRT_MAX); ushort objectSize = (ushort)bucket->sizeCat; - ushort objectCount = (ushort)(TBlockAttributes::PageCount * AutoSystemInfo::PageSize) / objectSize; + ushort objectCount = (ushort)((TBlockAttributes::PageCount * AutoSystemInfo::PageSize) / objectSize); return NoMemProtectHeapNewNoThrowPlusPrefixZ(Base::GetAllocPlusSize(objectCount), SmallFinalizableWithBarrierHeapBlockT, bucket, objectSize, objectCount); } @@ -39,7 +40,7 @@ SmallRecyclerVisitedHostHeapBlockT::New(HeapBucketTsizeCat <= USHRT_MAX); ushort objectSize = (ushort)bucket->sizeCat; - ushort objectCount = (ushort)(TBlockAttributes::PageCount * AutoSystemInfo::PageSize) / objectSize; + ushort objectCount = (ushort)((TBlockAttributes::PageCount * AutoSystemInfo::PageSize) / objectSize); return NoMemProtectHeapNewNoThrowPlusPrefixZ(Base::GetAllocPlusSize(objectCount), SmallRecyclerVisitedHostHeapBlockT, bucket, objectSize, objectCount); } @@ -62,7 +63,7 @@ SmallFinalizableHeapBlockT::New(HeapBucketTsizeCat <= USHRT_MAX); ushort objectSize = (ushort)bucket->sizeCat; - ushort objectCount = (ushort)(TBlockAttributes::PageCount * AutoSystemInfo::PageSize) / objectSize; + ushort objectCount = (ushort)((TBlockAttributes::PageCount * AutoSystemInfo::PageSize) / objectSize); return NoMemProtectHeapNewNoThrowPlusPrefixZ(Base::GetAllocPlusSize(objectCount), SmallFinalizableHeapBlockT, bucket, objectSize, objectCount); } diff --git a/lib/Common/Memory/SmallLeafHeapBlock.cpp b/lib/Common/Memory/SmallLeafHeapBlock.cpp index d60e8f2a4ae..d6d21a835a9 100644 --- a/lib/Common/Memory/SmallLeafHeapBlock.cpp +++ b/lib/Common/Memory/SmallLeafHeapBlock.cpp @@ -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. //------------------------------------------------------------------------------------------------------- #include "CommonMemoryPch.h" @@ -13,7 +14,7 @@ SmallLeafHeapBlockT::New(HeapBucketTsizeCat <= USHRT_MAX); ushort objectSize = (ushort)bucket->sizeCat; - ushort objectCount = (ushort)(TBlockAttributes::PageCount * AutoSystemInfo::PageSize) / objectSize; + ushort objectCount = (ushort)((TBlockAttributes::PageCount * AutoSystemInfo::PageSize) / objectSize); return NoMemProtectHeapNewNoThrowPlusPrefixZ(Base::GetAllocPlusSize(objectCount), SmallLeafHeapBlockT, bucket, objectSize, objectCount); } diff --git a/lib/Common/Memory/SmallNormalHeapBlock.cpp b/lib/Common/Memory/SmallNormalHeapBlock.cpp index 318f07997db..53398912bda 100644 --- a/lib/Common/Memory/SmallNormalHeapBlock.cpp +++ b/lib/Common/Memory/SmallNormalHeapBlock.cpp @@ -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. //------------------------------------------------------------------------------------------------------- #include "CommonMemoryPch.h" @@ -13,7 +14,7 @@ SmallNormalHeapBlockT::New(HeapBucketTsizeCat <= USHRT_MAX); ushort objectSize = (ushort)bucket->sizeCat; - ushort objectCount = (ushort)(TBlockAttributes::PageCount * AutoSystemInfo::PageSize) / objectSize; + ushort objectCount = (ushort)((TBlockAttributes::PageCount * AutoSystemInfo::PageSize) / objectSize); HeapBlockType blockType = (TBlockAttributes::IsSmallBlock ? HeapBlock::SmallNormalBlockType : HeapBlock::MediumNormalBlockType); return NoMemProtectHeapNewNoThrowPlusPrefixZ(Base::GetAllocPlusSize(objectCount), SmallNormalHeapBlockT, bucket, objectSize, objectCount, blockType); @@ -29,7 +30,7 @@ SmallNormalWithBarrierHeapBlockT::New(HeapBucketTsizeCat <= USHRT_MAX); ushort objectSize = (ushort)bucket->sizeCat; - ushort objectCount = (ushort)(TBlockAttributes::PageCount * AutoSystemInfo::PageSize) / objectSize; + ushort objectCount = (ushort)((TBlockAttributes::PageCount * AutoSystemInfo::PageSize) / objectSize); HeapBlockType blockType = (TBlockAttributes::IsSmallBlock ? HeapBlock::SmallNormalBlockWithBarrierType : HeapBlock::MediumNormalBlockWithBarrierType); return NoMemProtectHeapNewNoThrowPlusPrefixZ(Base::GetAllocPlusSize(objectCount), SmallNormalWithBarrierHeapBlockT, bucket, objectSize, objectCount, blockType); diff --git a/lib/Common/Memory/arm64/arm64_SAVE_REGISTERS.S b/lib/Common/Memory/arm64/arm64_SAVE_REGISTERS.S new file mode 100644 index 00000000000..28c035a4470 --- /dev/null +++ b/lib/Common/Memory/arm64/arm64_SAVE_REGISTERS.S @@ -0,0 +1,39 @@ +;------------------------------------------------------------------------------------------------------- +; 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 "unixasmmacros.inc" + +//void arm64_SAVE_REGISTERS(registers) +// +// This method pushes the 16 general purpose registers into the passed in array. +// By convention, the stack pointer will always be stored at registers[0] +// +// void* registers[16]; +// arm64_SAVE_REGISTERS(registers); +// +.p2align 2 +.globl C_FUNC(arm64_SAVE_REGISTERS) +C_FUNC(arm64_SAVE_REGISTERS): + ; Can't use sp with stp so mov to a volatile register + ; and then store onto passed in array + mov x17, sp + str x17, [x0, #0x00] + str x1, [x0, #0x08] + stp x2, x3, [x0, #0x10] + stp x4, x5, [x0, #0x20] + stp x6, x7, [x0, #0x30] + stp x8, x9, [x0, #0x40] + stp x10, x11, [x0, #0x50] + stp x12, x13, [x0, #0x60] + stp x14, x15, [x0, #0x70] + stp x16, x19, [x0, #0x80] + stp x20, x21, [x0, #0x90] + stp x22, x23, [x0, #0xA0] + stp x24, x25, [x0, #0xB0] + stp x26, x27, [x0, #0xC0] + str x28, [x0, #0xD0] + + br lr