| author | |
| committer | |
| log | e41b58ddc3e20144d30bba8c1387df5aa5fd6c5e |
| tree | 2aee9d8b7085704906f67e4e403bfaad29c06cf4 |
| parent | 1eaf180dd04efcf65ef981b1e1064658b5ec09c3 |
6 files changed, 138 insertions(+), 50 deletions(-)
lib/libcxxabi/src/aix_state_tab_eh.inc+42-8| ... | @@ -14,6 +14,10 @@ | ... | @@ -14,6 +14,10 @@ |
| 14 | #include <stdio.h> | 14 | #include <stdio.h> |
| 15 | #include <sys/debug.h> | 15 | #include <sys/debug.h> |
| 16 | 16 | ||
| 17 | #if !__has_cpp_attribute(clang::optnone) | ||
| 18 | #error This file requires clang::optnone attribute support | ||
| 19 | #endif | ||
| 20 | |||
| 17 | /* | 21 | /* |
| 18 | The legacy IBM xlC and xlclang++ compilers use the state table for EH | 22 | The legacy IBM xlC and xlclang++ compilers use the state table for EH |
| 19 | instead of the range table. Destructors, or addresses of the possible catch | 23 | instead of the range table. Destructors, or addresses of the possible catch |
| ... | @@ -183,10 +187,6 @@ enum FSMMagic : uint32_t { | ... | @@ -183,10 +187,6 @@ enum FSMMagic : uint32_t { |
| 183 | number3 = 0x1cedbeef // State table generated by xlclang++ compiler. | 187 | number3 = 0x1cedbeef // State table generated by xlclang++ compiler. |
| 184 | }; | 188 | }; |
| 185 | 189 | ||
| 186 | constexpr uint32_t REG_EXCP_OBJ = 14; // Register to pass the address of the exception | ||
| 187 | // object from the personality to xlclang++ | ||
| 188 | // compiled code. | ||
| 189 | |||
| 190 | constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free | 190 | constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free |
| 191 | // virtual bases, don't delete object. | 191 | // virtual bases, don't delete object. |
| 192 | 192 | ||
| ... | @@ -555,8 +555,16 @@ __xlcxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionCl | ... | @@ -555,8 +555,16 @@ __xlcxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionCl |
| 555 | if (actions & _UA_CLEANUP_PHASE) { | 555 | if (actions & _UA_CLEANUP_PHASE) { |
| 556 | // Phase 2 cleanup: | 556 | // Phase 2 cleanup: |
| 557 | if (results.reason == _URC_HANDLER_FOUND) { | 557 | if (results.reason == _URC_HANDLER_FOUND) { |
| 558 | // Store the address of unwind_exception in the stack field | ||
| 559 | // reserved for compilers (SP + 3 * sizeof(uintptr_t)) in the stack of | ||
| 560 | // the caller of the function containing the landing pad (within the link | ||
| 561 | // area for the call to the latter) for __xlc_exception_handle() | ||
| 562 | // to retrieve when it is called by the landing pad. | ||
| 563 | uintptr_t *currentSP = reinterpret_cast<uintptr_t*>(_Unwind_GetGR(context, 1)); | ||
| 564 | uintptr_t *callersSP = reinterpret_cast<uintptr_t*>(currentSP[0]); | ||
| 565 | callersSP[3] = reinterpret_cast<uintptr_t>(unwind_exception); | ||
| 566 | _LIBCXXABI_TRACE_STATETAB("Handshake: set unwind_exception=%p in stack=%p\n", reinterpret_cast<void*>(unwind_exception), reinterpret_cast<void*>(callersSP)); | ||
| 558 | // Jump to the handler. | 567 | // Jump to the handler. |
| 559 | _Unwind_SetGR(context, REG_EXCP_OBJ, reinterpret_cast<uintptr_t>(unwind_exception)); | ||
| 560 | _Unwind_SetIP(context, results.landingPad); | 568 | _Unwind_SetIP(context, results.landingPad); |
| 561 | return _URC_INSTALL_CONTEXT; | 569 | return _URC_INSTALL_CONTEXT; |
| 562 | } | 570 | } |
| ... | @@ -633,12 +641,38 @@ _LIBCXXABI_FUNC_VIS void __xlc_throw_badexception() { | ... | @@ -633,12 +641,38 @@ _LIBCXXABI_FUNC_VIS void __xlc_throw_badexception() { |
| 633 | __cxa_throw(newexception, const_cast<std::type_info*>(&typeid(std::bad_exception)), 0); | 641 | __cxa_throw(newexception, const_cast<std::type_info*>(&typeid(std::bad_exception)), 0); |
| 634 | } | 642 | } |
| 635 | 643 | ||
| 644 | // force_a_stackframe | ||
| 645 | // This function is called by __xlc_exception_handle() to ensure a stack frame | ||
| 646 | // is created for __xlc_exception_handle(). | ||
| 647 | __attribute__((noinline, optnone)) | ||
| 648 | static void force_a_stackframe() {} | ||
| 649 | |||
| 636 | // __xlc_exception_handle | 650 | // __xlc_exception_handle |
| 637 | // This function is for xlclang++. It returns the address of the exception | 651 | // This function is for xlclang++. It returns the address of the exception |
| 638 | // object set in gpr14 by the personality routine for xlclang++ compiled code. | 652 | // object stored in the reserved field in the stack of the caller of the |
| 653 | // function that calls __xlc_exception_handle() (within the link area for the | ||
| 654 | // call to the latter). The address is stored by the personality routine for | ||
| 655 | // xlclang++ compiled code. The implementation of __xlc_exception_handle() | ||
| 656 | // assumes a stack frame is created for it. The following ensures this | ||
| 657 | // assumption holds true: 1) a call to force_a_stackframe() is made inside | ||
| 658 | // __xlc_exception_handle() to make it non-leaf; and 2) optimizations are | ||
| 659 | // disabled for this function with attribute 'optnone'. Note: this function | ||
| 660 | // may not work as expected if these are changed. | ||
| 661 | __attribute__((optnone)) | ||
| 639 | _LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() { | 662 | _LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() { |
| 640 | uintptr_t exceptionObject; | 663 | // Make a call to force_a_stackframe() so that the compiler creates a stack |
| 641 | asm("mr %0, 14" : "=r"(exceptionObject)); | 664 | // frame for this function. |
| 665 | force_a_stackframe(); | ||
| 666 | |||
| 667 | // Get the SP of this function, i.e., __xlc_exception_handle(). | ||
| 668 | uintptr_t *lastStack; | ||
| 669 | asm("mr %0, 1" : "=r"(lastStack)); | ||
| 670 | // Get the SP of the caller of __xlc_exception_handle(). | ||
| 671 | uintptr_t *callerStack = reinterpret_cast<uintptr_t*>(lastStack[0]); | ||
| 672 | // Get the SP of the caller of the caller. | ||
| 673 | uintptr_t *callerStack2 = reinterpret_cast<uintptr_t*>(callerStack[0]); | ||
| 674 | uintptr_t exceptionObject = callerStack2[3]; | ||
| 675 | _LIBCXXABI_TRACE_STATETAB("Handshake: exceptionObject=%p from stack=%p\n", reinterpret_cast<void*>(exceptionObject), reinterpret_cast<void*>(callerStack2)); | ||
| 642 | return exceptionObject; | 676 | return exceptionObject; |
| 643 | } | 677 | } |
| 644 | 678 |
lib/libcxxabi/src/cxa_demangle.cpp+1-4| ... | @@ -386,15 +386,12 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) { | ... | @@ -386,15 +386,12 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) { |
| 386 | 386 | ||
| 387 | int InternalStatus = demangle_success; | 387 | int InternalStatus = demangle_success; |
| 388 | Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); | 388 | Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); |
| 389 | OutputBuffer O; | ||
| 390 | |||
| 391 | Node *AST = Parser.parse(); | 389 | Node *AST = Parser.parse(); |
| 392 | 390 | ||
| 393 | if (AST == nullptr) | 391 | if (AST == nullptr) |
| 394 | InternalStatus = demangle_invalid_mangled_name; | 392 | InternalStatus = demangle_invalid_mangled_name; |
| 395 | else if (!initializeOutputBuffer(Buf, N, O, 1024)) | ||
| 396 | InternalStatus = demangle_memory_alloc_failure; | ||
| 397 | else { | 393 | else { |
| 394 | OutputBuffer O(Buf, N); | ||
| 398 | assert(Parser.ForwardTemplateRefs.empty()); | 395 | assert(Parser.ForwardTemplateRefs.empty()); |
| 399 | AST->print(O); | 396 | AST->print(O); |
| 400 | O += '\0'; | 397 | O += '\0'; |
lib/libcxxabi/src/cxa_guard_impl.h+5-1| ... | @@ -5,6 +5,7 @@ | ... | @@ -5,6 +5,7 @@ |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // | 6 | // |
| 7 | //===----------------------------------------------------------------------===// | 7 | //===----------------------------------------------------------------------===// |
| 8 | |||
| 8 | #ifndef LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H | 9 | #ifndef LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H |
| 9 | #define LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H | 10 | #define LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H |
| 10 | 11 | ||
| ... | @@ -54,9 +55,12 @@ | ... | @@ -54,9 +55,12 @@ |
| 54 | # endif | 55 | # endif |
| 55 | #endif | 56 | #endif |
| 56 | 57 | ||
| 58 | #include <__threading_support> | ||
| 59 | #include <cstdint> | ||
| 60 | #include <cstring> | ||
| 57 | #include <limits.h> | 61 | #include <limits.h> |
| 58 | #include <stdlib.h> | 62 | #include <stdlib.h> |
| 59 | #include <__threading_support> | 63 | |
| 60 | #ifndef _LIBCXXABI_HAS_NO_THREADS | 64 | #ifndef _LIBCXXABI_HAS_NO_THREADS |
| 61 | # if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB) | 65 | # if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB) |
| 62 | # pragma comment(lib, "pthread") | 66 | # pragma comment(lib, "pthread") |
lib/libcxxabi/src/demangle/ItaniumDemangle.h+26-6| ... | @@ -26,6 +26,7 @@ | ... | @@ -26,6 +26,7 @@ |
| 26 | #include <cstdlib> | 26 | #include <cstdlib> |
| 27 | #include <cstring> | 27 | #include <cstring> |
| 28 | #include <limits> | 28 | #include <limits> |
| 29 | #include <new> | ||
| 29 | #include <utility> | 30 | #include <utility> |
| 30 | 31 | ||
| 31 | DEMANGLE_NAMESPACE_BEGIN | 32 | DEMANGLE_NAMESPACE_BEGIN |
| ... | @@ -369,6 +370,10 @@ public: | ... | @@ -369,6 +370,10 @@ public: |
| 369 | VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) | 370 | VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) |
| 370 | : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} | 371 | : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} |
| 371 | 372 | ||
| 373 | const Node *getTy() const { return Ty; } | ||
| 374 | StringView getExt() const { return Ext; } | ||
| 375 | const Node *getTA() const { return TA; } | ||
| 376 | |||
| 372 | template <typename Fn> void match(Fn F) const { F(Ty, Ext, TA); } | 377 | template <typename Fn> void match(Fn F) const { F(Ty, Ext, TA); } |
| 373 | 378 | ||
| 374 | void printLeft(OutputBuffer &OB) const override { | 379 | void printLeft(OutputBuffer &OB) const override { |
| ... | @@ -417,6 +422,9 @@ public: | ... | @@ -417,6 +422,9 @@ public: |
| 417 | Child_->ArrayCache, Child_->FunctionCache), | 422 | Child_->ArrayCache, Child_->FunctionCache), |
| 418 | Quals(Quals_), Child(Child_) {} | 423 | Quals(Quals_), Child(Child_) {} |
| 419 | 424 | ||
| 425 | Qualifiers getQuals() const { return Quals; } | ||
| 426 | const Node *getChild() const { return Child; } | ||
| 427 | |||
| 420 | template<typename Fn> void match(Fn F) const { F(Child, Quals); } | 428 | template<typename Fn> void match(Fn F) const { F(Child, Quals); } |
| 421 | 429 | ||
| 422 | bool hasRHSComponentSlow(OutputBuffer &OB) const override { | 430 | bool hasRHSComponentSlow(OutputBuffer &OB) const override { |
| ... | @@ -585,6 +593,8 @@ public: | ... | @@ -585,6 +593,8 @@ public: |
| 585 | : Node(KPointerType, Pointee_->RHSComponentCache), | 593 | : Node(KPointerType, Pointee_->RHSComponentCache), |
| 586 | Pointee(Pointee_) {} | 594 | Pointee(Pointee_) {} |
| 587 | 595 | ||
| 596 | const Node *getPointee() const { return Pointee; } | ||
| 597 | |||
| 588 | template<typename Fn> void match(Fn F) const { F(Pointee); } | 598 | template<typename Fn> void match(Fn F) const { F(Pointee); } |
| 589 | 599 | ||
| 590 | bool hasRHSComponentSlow(OutputBuffer &OB) const override { | 600 | bool hasRHSComponentSlow(OutputBuffer &OB) const override { |
| ... | @@ -1070,6 +1080,9 @@ public: | ... | @@ -1070,6 +1080,9 @@ public: |
| 1070 | VectorType(const Node *BaseType_, const Node *Dimension_) | 1080 | VectorType(const Node *BaseType_, const Node *Dimension_) |
| 1071 | : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_) {} | 1081 | : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_) {} |
| 1072 | 1082 | ||
| 1083 | const Node *getBaseType() const { return BaseType; } | ||
| 1084 | const Node *getDimension() const { return Dimension; } | ||
| 1085 | |||
| 1073 | template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); } | 1086 | template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); } |
| 1074 | 1087 | ||
| 1075 | void printLeft(OutputBuffer &OB) const override { | 1088 | void printLeft(OutputBuffer &OB) const override { |
| ... | @@ -3019,14 +3032,21 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() { | ... | @@ -3019,14 +3032,21 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() { |
| 3019 | if (numLeft() < 2) | 3032 | if (numLeft() < 2) |
| 3020 | return nullptr; | 3033 | return nullptr; |
| 3021 | 3034 | ||
| 3022 | auto Op = std::lower_bound( | 3035 | // We can't use lower_bound as that can link to symbols in the C++ library, |
| 3023 | &Ops[0], &Ops[NumOps], First, | 3036 | // and this must remain independant of that. |
| 3024 | [](const OperatorInfo &Op_, const char *Enc_) { return Op_ < Enc_; }); | 3037 | size_t lower = 0u, upper = NumOps - 1; // Inclusive bounds. |
| 3025 | if (Op == &Ops[NumOps] || *Op != First) | 3038 | while (upper != lower) { |
| 3039 | size_t middle = (upper + lower) / 2; | ||
| 3040 | if (Ops[middle] < First) | ||
| 3041 | lower = middle + 1; | ||
| 3042 | else | ||
| 3043 | upper = middle; | ||
| 3044 | } | ||
| 3045 | if (Ops[lower] != First) | ||
| 3026 | return nullptr; | 3046 | return nullptr; |
| 3027 | 3047 | ||
| 3028 | First += 2; | 3048 | First += 2; |
| 3029 | return Op; | 3049 | return &Ops[lower]; |
| 3030 | } | 3050 | } |
| 3031 | 3051 | ||
| 3032 | // <operator-name> ::= See parseOperatorEncoding() | 3052 | // <operator-name> ::= See parseOperatorEncoding() |
| ... | @@ -5099,7 +5119,7 @@ template <> | ... | @@ -5099,7 +5119,7 @@ template <> |
| 5099 | struct FloatData<long double> | 5119 | struct FloatData<long double> |
| 5100 | { | 5120 | { |
| 5101 | #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ | 5121 | #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ |
| 5102 | defined(__wasm__) || defined(__riscv) | 5122 | defined(__wasm__) || defined(__riscv) || defined(__loongarch__) |
| 5103 | static const size_t mangled_size = 32; | 5123 | static const size_t mangled_size = 32; |
| 5104 | #elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) | 5124 | #elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) |
| 5105 | static const size_t mangled_size = 16; | 5125 | static const size_t mangled_size = 16; |
lib/libcxxabi/src/demangle/Utility.h+3-22| ... | @@ -69,7 +69,9 @@ class OutputBuffer { | ... | @@ -69,7 +69,9 @@ class OutputBuffer { |
| 69 | 69 | ||
| 70 | public: | 70 | public: |
| 71 | OutputBuffer(char *StartBuf, size_t Size) | 71 | OutputBuffer(char *StartBuf, size_t Size) |
| 72 | : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} | 72 | : Buffer(StartBuf), BufferCapacity(Size) {} |
| 73 | OutputBuffer(char *StartBuf, size_t *SizePtr) | ||
| 74 | : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {} | ||
| 73 | OutputBuffer() = default; | 75 | OutputBuffer() = default; |
| 74 | // Non-copyable | 76 | // Non-copyable |
| 75 | OutputBuffer(const OutputBuffer &) = delete; | 77 | OutputBuffer(const OutputBuffer &) = delete; |
| ... | @@ -77,12 +79,6 @@ public: | ... | @@ -77,12 +79,6 @@ public: |
| 77 | 79 | ||
| 78 | operator StringView() const { return StringView(Buffer, CurrentPosition); } | 80 | operator StringView() const { return StringView(Buffer, CurrentPosition); } |
| 79 | 81 | ||
| 80 | void reset(char *Buffer_, size_t BufferCapacity_) { | ||
| 81 | CurrentPosition = 0; | ||
| 82 | Buffer = Buffer_; | ||
| 83 | BufferCapacity = BufferCapacity_; | ||
| 84 | } | ||
| 85 | |||
| 86 | /// If a ParameterPackExpansion (or similar type) is encountered, the offset | 82 | /// If a ParameterPackExpansion (or similar type) is encountered, the offset |
| 87 | /// into the pack that we're currently printing. | 83 | /// into the pack that we're currently printing. |
| 88 | unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); | 84 | unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); |
| ... | @@ -198,21 +194,6 @@ public: | ... | @@ -198,21 +194,6 @@ public: |
| 198 | ScopedOverride &operator=(const ScopedOverride &) = delete; | 194 | ScopedOverride &operator=(const ScopedOverride &) = delete; |
| 199 | }; | 195 | }; |
| 200 | 196 | ||
| 201 | inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB, | ||
| 202 | size_t InitSize) { | ||
| 203 | size_t BufferSize; | ||
| 204 | if (Buf == nullptr) { | ||
| 205 | Buf = static_cast<char *>(std::malloc(InitSize)); | ||
| 206 | if (Buf == nullptr) | ||
| 207 | return false; | ||
| 208 | BufferSize = InitSize; | ||
| 209 | } else | ||
| 210 | BufferSize = *N; | ||
| 211 | |||
| 212 | OB.reset(Buf, BufferSize); | ||
| 213 | return true; | ||
| 214 | } | ||
| 215 | |||
| 216 | DEMANGLE_NAMESPACE_END | 197 | DEMANGLE_NAMESPACE_END |
| 217 | 198 | ||
| 218 | #endif | 199 | #endif |
lib/libcxxabi/src/fallback_malloc.cpp+61-9| ... | @@ -15,6 +15,7 @@ | ... | @@ -15,6 +15,7 @@ |
| 15 | #endif | 15 | #endif |
| 16 | #endif | 16 | #endif |
| 17 | 17 | ||
| 18 | #include <assert.h> | ||
| 18 | #include <stdlib.h> // for malloc, calloc, free | 19 | #include <stdlib.h> // for malloc, calloc, free |
| 19 | #include <string.h> // for memset | 20 | #include <string.h> // for memset |
| 20 | #include <new> // for std::__libcpp_aligned_{alloc,free} | 21 | #include <new> // for std::__libcpp_aligned_{alloc,free} |
| ... | @@ -63,11 +64,28 @@ char heap[HEAP_SIZE] __attribute__((aligned)); | ... | @@ -63,11 +64,28 @@ char heap[HEAP_SIZE] __attribute__((aligned)); |
| 63 | typedef unsigned short heap_offset; | 64 | typedef unsigned short heap_offset; |
| 64 | typedef unsigned short heap_size; | 65 | typedef unsigned short heap_size; |
| 65 | 66 | ||
| 67 | // On both 64 and 32 bit targets heap_node should have the following properties | ||
| 68 | // Size: 4 | ||
| 69 | // Alignment: 2 | ||
| 66 | struct heap_node { | 70 | struct heap_node { |
| 67 | heap_offset next_node; // offset into heap | 71 | heap_offset next_node; // offset into heap |
| 68 | heap_size len; // size in units of "sizeof(heap_node)" | 72 | heap_size len; // size in units of "sizeof(heap_node)" |
| 69 | }; | 73 | }; |
| 70 | 74 | ||
| 75 | // All pointers returned by fallback_malloc must be at least aligned | ||
| 76 | // as RequiredAligned. Note that RequiredAlignment can be greater than | ||
| 77 | // alignof(std::max_align_t) on 64 bit systems compiling 32 bit code. | ||
| 78 | struct FallbackMaxAlignType { | ||
| 79 | } __attribute__((aligned)); | ||
| 80 | const size_t RequiredAlignment = alignof(FallbackMaxAlignType); | ||
| 81 | |||
| 82 | static_assert(alignof(FallbackMaxAlignType) % sizeof(heap_node) == 0, | ||
| 83 | "The required alignment must be evenly divisible by the sizeof(heap_node)"); | ||
| 84 | |||
| 85 | // The number of heap_node's that can fit in a chunk of memory with the size | ||
| 86 | // of the RequiredAlignment. On 64 bit targets NodesPerAlignment should be 4. | ||
| 87 | const size_t NodesPerAlignment = alignof(FallbackMaxAlignType) / sizeof(heap_node); | ||
| 88 | |||
| 71 | static const heap_node* list_end = | 89 | static const heap_node* list_end = |
| 72 | (heap_node*)(&heap[HEAP_SIZE]); // one past the end of the heap | 90 | (heap_node*)(&heap[HEAP_SIZE]); // one past the end of the heap |
| 73 | static heap_node* freelist = NULL; | 91 | static heap_node* freelist = NULL; |
| ... | @@ -82,10 +100,23 @@ heap_offset offset_from_node(const heap_node* ptr) { | ... | @@ -82,10 +100,23 @@ heap_offset offset_from_node(const heap_node* ptr) { |
| 82 | sizeof(heap_node)); | 100 | sizeof(heap_node)); |
| 83 | } | 101 | } |
| 84 | 102 | ||
| 103 | // Return a pointer to the first address, 'A', in `heap` that can actually be | ||
| 104 | // used to represent a heap_node. 'A' must be aligned so that | ||
| 105 | // '(A + sizeof(heap_node)) % RequiredAlignment == 0'. On 64 bit systems this | ||
| 106 | // address should be 12 bytes after the first 16 byte boundary. | ||
| 107 | heap_node* getFirstAlignedNodeInHeap() { | ||
| 108 | heap_node* node = (heap_node*)heap; | ||
| 109 | const size_t alignNBytesAfterBoundary = RequiredAlignment - sizeof(heap_node); | ||
| 110 | size_t boundaryOffset = reinterpret_cast<size_t>(node) % RequiredAlignment; | ||
| 111 | size_t requiredOffset = alignNBytesAfterBoundary - boundaryOffset; | ||
| 112 | size_t NElemOffset = requiredOffset / sizeof(heap_node); | ||
| 113 | return node + NElemOffset; | ||
| 114 | } | ||
| 115 | |||
| 85 | void init_heap() { | 116 | void init_heap() { |
| 86 | freelist = (heap_node*)heap; | 117 | freelist = getFirstAlignedNodeInHeap(); |
| 87 | freelist->next_node = offset_from_node(list_end); | 118 | freelist->next_node = offset_from_node(list_end); |
| 88 | freelist->len = HEAP_SIZE / sizeof(heap_node); | 119 | freelist->len = static_cast<heap_size>(list_end - freelist); |
| 89 | } | 120 | } |
| 90 | 121 | ||
| 91 | // How big a chunk we allocate | 122 | // How big a chunk we allocate |
| ... | @@ -109,23 +140,44 @@ void* fallback_malloc(size_t len) { | ... | @@ -109,23 +140,44 @@ void* fallback_malloc(size_t len) { |
| 109 | for (p = freelist, prev = 0; p && p != list_end; | 140 | for (p = freelist, prev = 0; p && p != list_end; |
| 110 | prev = p, p = node_from_offset(p->next_node)) { | 141 | prev = p, p = node_from_offset(p->next_node)) { |
| 111 | 142 | ||
| 112 | if (p->len > nelems) { // chunk is larger, shorten, and return the tail | 143 | // Check the invariant that all heap_nodes pointers 'p' are aligned |
| 113 | heap_node* q; | 144 | // so that 'p + 1' has an alignment of at least RequiredAlignment |
| 145 | assert(reinterpret_cast<size_t>(p + 1) % RequiredAlignment == 0); | ||
| 146 | |||
| 147 | // Calculate the number of extra padding elements needed in order | ||
| 148 | // to split 'p' and create a properly aligned heap_node from the tail | ||
| 149 | // of 'p'. We calculate aligned_nelems such that 'p->len - aligned_nelems' | ||
| 150 | // will be a multiple of NodesPerAlignment. | ||
| 151 | size_t aligned_nelems = nelems; | ||
| 152 | if (p->len > nelems) { | ||
| 153 | heap_size remaining_len = static_cast<heap_size>(p->len - nelems); | ||
| 154 | aligned_nelems += remaining_len % NodesPerAlignment; | ||
| 155 | } | ||
| 114 | 156 | ||
| 115 | p->len = static_cast<heap_size>(p->len - nelems); | 157 | // chunk is larger and we can create a properly aligned heap_node |
| 158 | // from the tail. In this case we shorten 'p' and return the tail. | ||
| 159 | if (p->len > aligned_nelems) { | ||
| 160 | heap_node* q; | ||
| 161 | p->len = static_cast<heap_size>(p->len - aligned_nelems); | ||
| 116 | q = p + p->len; | 162 | q = p + p->len; |
| 117 | q->next_node = 0; | 163 | q->next_node = 0; |
| 118 | q->len = static_cast<heap_size>(nelems); | 164 | q->len = static_cast<heap_size>(aligned_nelems); |
| 119 | return (void*)(q + 1); | 165 | void* ptr = q + 1; |
| 166 | assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0); | ||
| 167 | return ptr; | ||
| 120 | } | 168 | } |
| 121 | 169 | ||
| 122 | if (p->len == nelems) { // exact size match | 170 | // The chunk is the exact size or the chunk is larger but not large |
| 171 | // enough to split due to alignment constraints. | ||
| 172 | if (p->len >= nelems) { | ||
| 123 | if (prev == 0) | 173 | if (prev == 0) |
| 124 | freelist = node_from_offset(p->next_node); | 174 | freelist = node_from_offset(p->next_node); |
| 125 | else | 175 | else |
| 126 | prev->next_node = p->next_node; | 176 | prev->next_node = p->next_node; |
| 127 | p->next_node = 0; | 177 | p->next_node = 0; |
| 128 | return (void*)(p + 1); | 178 | void* ptr = p + 1; |
| 179 | assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0); | ||
| 180 | return ptr; | ||
| 129 | } | 181 | } |
| 130 | } | 182 | } |
| 131 | return NULL; // couldn't find a spot big enough | 183 | return NULL; // couldn't find a spot big enough |