mirror of
https://github.com/postgres/postgres.git
synced 2025-07-27 12:41:57 +03:00
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:
@ -23,7 +23,6 @@ OBJS = \
|
|||||||
makefuncs.o \
|
makefuncs.o \
|
||||||
multibitmapset.o \
|
multibitmapset.o \
|
||||||
nodeFuncs.o \
|
nodeFuncs.o \
|
||||||
nodes.o \
|
|
||||||
outfuncs.o \
|
outfuncs.o \
|
||||||
params.o \
|
params.o \
|
||||||
print.o \
|
print.o \
|
||||||
|
@ -7,7 +7,6 @@ backend_sources += files(
|
|||||||
'makefuncs.c',
|
'makefuncs.c',
|
||||||
'multibitmapset.c',
|
'multibitmapset.c',
|
||||||
'nodeFuncs.c',
|
'nodeFuncs.c',
|
||||||
'nodes.c',
|
|
||||||
'params.c',
|
'params.c',
|
||||||
'print.c',
|
'print.c',
|
||||||
'read.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;
|
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
|
* MemoryContextAllocExtended
|
||||||
* Allocate space within the specified context using the given flags.
|
* Allocate space within the specified context using the given flags.
|
||||||
|
@ -1060,30 +1060,6 @@ extern void ExceptionalCondition(const char *conditionName,
|
|||||||
} while (0)
|
} 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.
|
* Macros for range-checking float values before converting to integer.
|
||||||
* We must be careful here that the boundary values are expressed exactly
|
* 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
|
* !WARNING!: Avoid using newNode directly. You should be using the
|
||||||
* macro makeNode. eg. to create a Query node, use makeNode(Query)
|
* 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 */
|
Assert(size >= sizeof(Node)); /* need the tag, at least */
|
||||||
#define newNode(size, tag) \
|
result = (Node *) palloc0(size);
|
||||||
({ Node *_result; \
|
result->type = tag;
|
||||||
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__ */
|
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#define makeNode(_type_) ((_type_ *) newNode(sizeof(_type_),T_##_type_))
|
#define makeNode(_type_) ((_type_ *) newNode(sizeof(_type_),T_##_type_))
|
||||||
#define NodeSetTag(nodeptr,t) (((Node*)(nodeptr))->type = (t))
|
#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 *MemoryContextAlloc(MemoryContext context, Size size);
|
||||||
extern void *MemoryContextAllocZero(MemoryContext context, Size size);
|
extern void *MemoryContextAllocZero(MemoryContext context, Size size);
|
||||||
extern void *MemoryContextAllocZeroAligned(MemoryContext context, Size size);
|
|
||||||
extern void *MemoryContextAllocExtended(MemoryContext context,
|
extern void *MemoryContextAllocExtended(MemoryContext context,
|
||||||
Size size, int flags);
|
Size size, int flags);
|
||||||
extern void *MemoryContextAllocAligned(MemoryContext context,
|
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 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)))
|
#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. */
|
/* Higher-limit allocators. */
|
||||||
extern void *MemoryContextAllocHuge(MemoryContext context, Size size);
|
extern void *MemoryContextAllocHuge(MemoryContext context, Size size);
|
||||||
extern pg_nodiscard void *repalloc_huge(void *pointer, Size size);
|
extern pg_nodiscard void *repalloc_huge(void *pointer, Size size);
|
||||||
|
Reference in New Issue
Block a user