aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/libsupc++/new_opa.cc
blob: abb7451fafeca9ff2c39c8b81f0047de75afa0b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Support routines for the -*- C++ -*- dynamic memory management.

// Copyright (C) 1997-2018 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
// GCC is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3, or (at your option)
// any later version.
//
// GCC is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

#include <bits/c++config.h>
#include <stdlib.h>
#include <stdint.h>
#include <bits/exception_defines.h>
#include <bit>
#include "new"

#if !_GLIBCXX_HAVE_ALIGNED_ALLOC && !_GLIBCXX_HAVE__ALIGNED_MALLOC \
  && !_GLIBCXX_HAVE_POSIX_MEMALIGN && _GLIBCXX_HAVE_MEMALIGN
# if _GLIBCXX_HOSTED && __has_include(<malloc.h>)
// Some C libraries declare memalign in <malloc.h>
#  include <malloc.h>
# else
extern "C" void *memalign(std::size_t boundary, std::size_t size);
# endif
#endif

using std::new_handler;
using std::bad_alloc;

namespace __gnu_cxx {
#if _GLIBCXX_HAVE_ALIGNED_ALLOC
using ::aligned_alloc;
#elif _GLIBCXX_HAVE__ALIGNED_MALLOC
static inline void*
aligned_alloc (std::size_t al, std::size_t sz)
{ return _aligned_malloc(sz, al); }
#elif _GLIBCXX_HAVE_POSIX_MEMALIGN
static inline void*
aligned_alloc (std::size_t al, std::size_t sz)
{
  void *ptr;
  // posix_memalign has additional requirement, not present on aligned_alloc:
  // The value of alignment shall be a power of two multiple of sizeof(void *).
  if (al < sizeof(void*))
    al = sizeof(void*);
  int ret = posix_memalign (&ptr, al, sz);
  if (ret == 0)
    return ptr;
  return nullptr;
}
#elif _GLIBCXX_HAVE_MEMALIGN
static inline void*
aligned_alloc (std::size_t al, std::size_t sz)
{
#ifdef __sun
  // Solaris 10 memalign requires that alignment is greater than or equal to
  // the size of a word.
  if (al < sizeof(int))
    al = sizeof(int);
#endif
  return memalign (al, sz);
}
#else // !HAVE__ALIGNED_MALLOC && !HAVE_POSIX_MEMALIGN && !HAVE_MEMALIGN
// The C library doesn't provide any aligned allocation functions, define one.
// This is a modified version of code from gcc/config/i386/gmm_malloc.h
static inline void*
aligned_alloc (std::size_t al, std::size_t sz)
{
  // We need extra bytes to store the original value returned by malloc.
  if (al < sizeof(void*))
    al = sizeof(void*);
  void* const malloc_ptr = malloc(sz + al);
  if (!malloc_ptr)
    return nullptr;
  // Align to the requested value, leaving room for the original malloc value.
  void* const aligned_ptr = (void *) (((uintptr_t) malloc_ptr + al) & -al);

  // Store the original malloc value where it can be found by operator delete.
  ((void **) aligned_ptr)[-1] = malloc_ptr;

  return aligned_ptr;
}
#endif
} // namespace __gnu_cxx

_GLIBCXX_WEAK_DEFINITION void *
operator new (std::size_t sz, std::align_val_t al)
{
  std::size_t align = (std::size_t)al;

  /* Alignment must be a power of two.  */
  /* XXX This should be checked by the compiler (PR 86878).  */
  if (__builtin_expect (!std::__ispow2(align), false))
    _GLIBCXX_THROW_OR_ABORT(bad_alloc());

  /* malloc (0) is unpredictable; avoid it.  */
  if (__builtin_expect (sz == 0, false))
    sz = 1;

#if _GLIBCXX_HAVE_ALIGNED_ALLOC
# ifdef _AIX
  /* AIX 7.2.0.0 aligned_alloc incorrectly has posix_memalign's requirement
   * that alignment is a multiple of sizeof(void*).  */
  if (align < sizeof(void*))
    align = sizeof(void*);
# endif
  /* C11: the value of size shall be an integral multiple of alignment.  */
  sz = (sz + align - 1) & ~(align - 1);
#endif

  void *p;

  while ((p = __gnu_cxx::aligned_alloc (align, sz)) == nullptr)
    {
      new_handler handler = std::get_new_handler ();
      if (! handler)
	_GLIBCXX_THROW_OR_ABORT(bad_alloc());
      handler ();
    }

  return p;
}