Simplify newNode() by removing special cases
- Remove MemoryContextAllocZeroAligned(). It was supposed to be a faster version of MemoryContextAllocZero(), but modern compilers turn the MemSetLoop() into a call to memset() anyway, making it more or less identical to MemoryContextAllocZero(). That was the only user of MemSetTest, MemSetLoop, so remove those too, as well as palloc0fast(). - Convert newNode() to a static inline function. When this was originally originally written, it was written as a macro because testing showed that gcc didn't inline the size check as we intended. Modern compiler versions do, and now that it just calls palloc0() there is no size-check to inline anyway. One nice effect is that the palloc0() takes one less argument than MemoryContextAllocZeroAligned(), which saves a few instructions in the callers of newNode(). Reviewed-by: Peter Eisentraut, Tom Lane, John Naylor, Thomas Munro Discussion: https://www.postgresql.org/message-id/b51f1fa7-7e6a-4ecc-936d-90a8a1659e7c@iki.fi
This commit is contained in:
parent
2084701364
commit
3c080fb4fa
|
@ -23,7 +23,6 @@ OBJS = \
|
|||
makefuncs.o \
|
||||
multibitmapset.o \
|
||||
nodeFuncs.o \
|
||||
nodes.o \
|
||||
outfuncs.o \
|
||||
params.o \
|
||||
print.o \
|
||||
|
|
|
@ -7,7 +7,6 @@ backend_sources += files(
|
|||
'makefuncs.c',
|
||||
'multibitmapset.c',
|
||||
'nodeFuncs.c',
|
||||
'nodes.c',
|
||||
'params.c',
|
||||
'print.c',
|
||||
'read.c',
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* nodes.c
|
||||
* support code for nodes (now that we have removed the home-brew
|
||||
* inheritance system, our support code for nodes is much simpler)
|
||||
*
|
||||
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/backend/nodes/nodes.c
|
||||
*
|
||||
* HISTORY
|
||||
* Andrew Yu Oct 20, 1994 file creation
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "nodes/nodes.h"
|
||||
|
||||
/*
|
||||
* Support for newNode() macro
|
||||
*
|
||||
* In a GCC build there is no need for the global variable newNodeMacroHolder.
|
||||
* However, we create it anyway, to support the case of a non-GCC-built
|
||||
* loadable module being loaded into a GCC-built backend.
|
||||
*/
|
||||
|
||||
Node *newNodeMacroHolder;
|
|
@ -1091,44 +1091,6 @@ MemoryContextAllocZero(MemoryContext context, Size size)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryContextAllocZeroAligned
|
||||
* MemoryContextAllocZero where length is suitable for MemSetLoop
|
||||
*
|
||||
* This might seem overly specialized, but it's not because newNode()
|
||||
* is so often called with compile-time-constant sizes.
|
||||
*/
|
||||
void *
|
||||
MemoryContextAllocZeroAligned(MemoryContext context, Size size)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
Assert(MemoryContextIsValid(context));
|
||||
AssertNotInCriticalSection(context);
|
||||
|
||||
if (!AllocSizeIsValid(size))
|
||||
elog(ERROR, "invalid memory alloc request size %zu", size);
|
||||
|
||||
context->isReset = false;
|
||||
|
||||
ret = context->methods->alloc(context, size);
|
||||
if (unlikely(ret == NULL))
|
||||
{
|
||||
MemoryContextStats(TopMemoryContext);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory"),
|
||||
errdetail("Failed on request of size %zu in memory context \"%s\".",
|
||||
size, context->name)));
|
||||
}
|
||||
|
||||
VALGRIND_MEMPOOL_ALLOC(context, ret, size);
|
||||
|
||||
MemSetLoop(ret, 0, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryContextAllocExtended
|
||||
* Allocate space within the specified context using the given flags.
|
||||
|
|
|
@ -1060,30 +1060,6 @@ extern void ExceptionalCondition(const char *conditionName,
|
|||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* MemSetTest/MemSetLoop are a variant version that allow all the tests in
|
||||
* MemSet to be done at compile time in cases where "val" and "len" are
|
||||
* constants *and* we know the "start" pointer must be word-aligned.
|
||||
* If MemSetTest succeeds, then it is okay to use MemSetLoop, otherwise use
|
||||
* MemSetAligned. Beware of multiple evaluations of the arguments when using
|
||||
* this approach.
|
||||
*/
|
||||
#define MemSetTest(val, len) \
|
||||
( ((len) & LONG_ALIGN_MASK) == 0 && \
|
||||
(len) <= MEMSET_LOOP_LIMIT && \
|
||||
MEMSET_LOOP_LIMIT != 0 && \
|
||||
(val) == 0 )
|
||||
|
||||
#define MemSetLoop(start, val, len) \
|
||||
do \
|
||||
{ \
|
||||
long * _start = (long *) (start); \
|
||||
long * _stop = (long *) ((char *) _start + (Size) (len)); \
|
||||
\
|
||||
while (_start < _stop) \
|
||||
*_start++ = 0; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Macros for range-checking float values before converting to integer.
|
||||
* We must be careful here that the boundary values are expressed exactly
|
||||
|
|
|
@ -139,39 +139,18 @@ typedef struct Node
|
|||
*
|
||||
* !WARNING!: Avoid using newNode directly. You should be using the
|
||||
* macro makeNode. eg. to create a Query node, use makeNode(Query)
|
||||
*
|
||||
* Note: the size argument should always be a compile-time constant, so the
|
||||
* apparent risk of multiple evaluation doesn't matter in practice.
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
static inline Node *
|
||||
newNode(size_t size, NodeTag tag)
|
||||
{
|
||||
Node *result;
|
||||
|
||||
/* With GCC, we can use a compound statement within an expression */
|
||||
#define newNode(size, tag) \
|
||||
({ Node *_result; \
|
||||
AssertMacro((size) >= sizeof(Node)); /* need the tag, at least */ \
|
||||
_result = (Node *) palloc0fast(size); \
|
||||
_result->type = (tag); \
|
||||
_result; \
|
||||
})
|
||||
#else
|
||||
|
||||
/*
|
||||
* There is no way to dereference the palloc'ed pointer to assign the
|
||||
* tag, and also return the pointer itself, so we need a holder variable.
|
||||
* Fortunately, this macro isn't recursive so we just define
|
||||
* a global variable for this purpose.
|
||||
*/
|
||||
extern PGDLLIMPORT Node *newNodeMacroHolder;
|
||||
|
||||
#define newNode(size, tag) \
|
||||
( \
|
||||
AssertMacro((size) >= sizeof(Node)), /* need the tag, at least */ \
|
||||
newNodeMacroHolder = (Node *) palloc0fast(size), \
|
||||
newNodeMacroHolder->type = (tag), \
|
||||
newNodeMacroHolder \
|
||||
)
|
||||
#endif /* __GNUC__ */
|
||||
Assert(size >= sizeof(Node)); /* need the tag, at least */
|
||||
result = (Node *) palloc0(size);
|
||||
result->type = tag;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define makeNode(_type_) ((_type_ *) newNode(sizeof(_type_),T_##_type_))
|
||||
#define NodeSetTag(nodeptr,t) (((Node*)(nodeptr))->type = (t))
|
||||
|
|
|
@ -70,7 +70,6 @@ extern PGDLLIMPORT MemoryContext CurrentMemoryContext;
|
|||
*/
|
||||
extern void *MemoryContextAlloc(MemoryContext context, Size size);
|
||||
extern void *MemoryContextAllocZero(MemoryContext context, Size size);
|
||||
extern void *MemoryContextAllocZeroAligned(MemoryContext context, Size size);
|
||||
extern void *MemoryContextAllocExtended(MemoryContext context,
|
||||
Size size, int flags);
|
||||
extern void *MemoryContextAllocAligned(MemoryContext context,
|
||||
|
@ -109,19 +108,6 @@ extern void pfree(void *pointer);
|
|||
#define repalloc_array(pointer, type, count) ((type *) repalloc(pointer, sizeof(type) * (count)))
|
||||
#define repalloc0_array(pointer, type, oldcount, count) ((type *) repalloc0(pointer, sizeof(type) * (oldcount), sizeof(type) * (count)))
|
||||
|
||||
/*
|
||||
* The result of palloc() is always word-aligned, so we can skip testing
|
||||
* alignment of the pointer when deciding which MemSet variant to use.
|
||||
* Note that this variant does not offer any advantage, and should not be
|
||||
* used, unless its "sz" argument is a compile-time constant; therefore, the
|
||||
* issue that it evaluates the argument multiple times isn't a problem in
|
||||
* practice.
|
||||
*/
|
||||
#define palloc0fast(sz) \
|
||||
( MemSetTest(0, sz) ? \
|
||||
MemoryContextAllocZeroAligned(CurrentMemoryContext, sz) : \
|
||||
MemoryContextAllocZero(CurrentMemoryContext, sz) )
|
||||
|
||||
/* Higher-limit allocators. */
|
||||
extern void *MemoryContextAllocHuge(MemoryContext context, Size size);
|
||||
extern pg_nodiscard void *repalloc_huge(void *pointer, Size size);
|
||||
|
|
Loading…
Reference in New Issue