Skip to content

Commit 79051f8

Browse files
committed
[GR-51810] Native small integer cache.
PullRequest: graalpython/3191
2 parents 27db537 + 298f286 commit 79051f8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+743
-341
lines changed

graalpython/com.oracle.graal.python.cext/include/cpython/pystate.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2020, 2023, Oracle and/or its affiliates.
1+
/* Copyright (c) 2020, 2024, Oracle and/or its affiliates.
22
* Copyright (C) 1996-2020 Python Software Foundation
33
*
44
* Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
@@ -205,6 +205,13 @@ struct _ts {
205205

206206
/* The bottom-most frame on the stack. */
207207
_PyCFrame root_cframe;
208+
209+
/* GraalVM change: We add field 'small_ints' which roughly corresponds to
210+
field '_PyRuntimeState._Py_global_objects.small_ints'. We do so because
211+
we maintain the runtime state in Java objects and don't want to allocate
212+
the large structures and arrays where for us, most fields will be zero.
213+
*/
214+
PyObject **small_ints;
208215
};
209216

210217

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/* Copyright (c) 2024, Oracle and/or its affiliates.
2+
* Copyright (C) 1996-2023 Python Software Foundation
3+
*
4+
* Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
5+
*/
6+
#ifndef Py_INTERNAL_CEVAL_H
7+
#define Py_INTERNAL_CEVAL_H
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
#ifndef Py_BUILD_CORE
13+
# error "this header requires Py_BUILD_CORE define"
14+
#endif
15+
16+
/* Forward declarations */
17+
struct pyruntimestate;
18+
struct _ceval_runtime_state;
19+
20+
/* WASI has limited call stack. Python's recursion limit depends on code
21+
layout, optimization, and WASI runtime. Wasmtime can handle about 700-750
22+
recursions, sometimes less. 600 is a more conservative limit. */
23+
#ifndef Py_DEFAULT_RECURSION_LIMIT
24+
# ifdef __wasi__
25+
# define Py_DEFAULT_RECURSION_LIMIT 600
26+
# else
27+
# define Py_DEFAULT_RECURSION_LIMIT 1000
28+
# endif
29+
#endif
30+
31+
// #include "pycore_interp.h" // PyInterpreterState.eval_frame
32+
// #include "pycore_pystate.h" // _PyThreadState_GET()
33+
34+
35+
extern void _Py_FinishPendingCalls(PyThreadState *tstate);
36+
extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *);
37+
// extern void _PyEval_InitState(struct _ceval_state *, PyThread_type_lock);
38+
// extern void _PyEval_FiniState(struct _ceval_state *ceval);
39+
PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp);
40+
PyAPI_FUNC(int) _PyEval_AddPendingCall(
41+
PyInterpreterState *interp,
42+
int (*func)(void *),
43+
void *arg);
44+
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyInterpreterState *interp);
45+
#ifdef HAVE_FORK
46+
extern PyStatus _PyEval_ReInitThreads(PyThreadState *tstate);
47+
#endif
48+
49+
// Used by sys.call_tracing()
50+
extern PyObject* _PyEval_CallTracing(PyObject *func, PyObject *args);
51+
52+
// Used by sys.get_asyncgen_hooks()
53+
extern PyObject* _PyEval_GetAsyncGenFirstiter(void);
54+
extern PyObject* _PyEval_GetAsyncGenFinalizer(void);
55+
56+
// Used by sys.set_asyncgen_hooks()
57+
extern int _PyEval_SetAsyncGenFirstiter(PyObject *);
58+
extern int _PyEval_SetAsyncGenFinalizer(PyObject *);
59+
60+
// Used by sys.get_coroutine_origin_tracking_depth()
61+
// and sys.set_coroutine_origin_tracking_depth()
62+
extern int _PyEval_GetCoroutineOriginTrackingDepth(void);
63+
extern int _PyEval_SetCoroutineOriginTrackingDepth(int depth);
64+
65+
extern void _PyEval_Fini(void);
66+
67+
68+
extern PyObject* _PyEval_GetBuiltins(PyThreadState *tstate);
69+
extern PyObject* _PyEval_BuiltinsFromGlobals(
70+
PyThreadState *tstate,
71+
PyObject *globals);
72+
73+
74+
/* GraalVM change
75+
static inline PyObject*
76+
_PyEval_EvalFrame(PyThreadState *tstate, struct _PyInterpreterFrame *frame, int throwflag)
77+
{
78+
if (tstate->interp->eval_frame == NULL) {
79+
return _PyEval_EvalFrameDefault(tstate, frame, throwflag);
80+
}
81+
return tstate->interp->eval_frame(tstate, frame, throwflag);
82+
}
83+
*/
84+
85+
extern PyObject*
86+
_PyEval_Vector(PyThreadState *tstate,
87+
PyFunctionObject *func, PyObject *locals,
88+
PyObject* const* args, size_t argcount,
89+
PyObject *kwnames);
90+
91+
extern int _PyEval_ThreadsInitialized(struct pyruntimestate *runtime);
92+
extern PyStatus _PyEval_InitGIL(PyThreadState *tstate);
93+
extern void _PyEval_FiniGIL(PyInterpreterState *interp);
94+
95+
extern void _PyEval_ReleaseLock(PyThreadState *tstate);
96+
97+
extern void _PyEval_DeactivateOpCache(void);
98+
99+
100+
/* --- _Py_EnterRecursiveCall() ----------------------------------------- */
101+
102+
#ifdef USE_STACKCHECK
103+
/* With USE_STACKCHECK macro defined, trigger stack checks in
104+
_Py_CheckRecursiveCall() on every 64th call to _Py_EnterRecursiveCall. */
105+
static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
106+
return (tstate->recursion_remaining-- <= 0
107+
|| (tstate->recursion_remaining & 63) == 0);
108+
}
109+
#else
110+
static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
111+
return tstate->recursion_remaining-- <= 0;
112+
}
113+
#endif
114+
115+
PyAPI_FUNC(int) _Py_CheckRecursiveCall(
116+
PyThreadState *tstate,
117+
const char *where);
118+
119+
static inline int _Py_EnterRecursiveCallTstate(PyThreadState *tstate,
120+
const char *where) {
121+
return (_Py_MakeRecCheck(tstate) && _Py_CheckRecursiveCall(tstate, where));
122+
}
123+
124+
static inline int _Py_EnterRecursiveCall(const char *where) {
125+
/* GraalVM change
126+
PyThreadState *tstate = _PyThreadState_GET();
127+
*/
128+
PyThreadState *tstate = PyThreadState_GET();
129+
return _Py_EnterRecursiveCallTstate(tstate, where);
130+
}
131+
132+
static inline void _Py_LeaveRecursiveCallTstate(PyThreadState *tstate) {
133+
tstate->recursion_remaining++;
134+
}
135+
136+
static inline void _Py_LeaveRecursiveCall(void) {
137+
/* GraalVM change
138+
PyThreadState *tstate = _PyThreadState_GET();
139+
*/
140+
PyThreadState *tstate = PyThreadState_GET();
141+
_Py_LeaveRecursiveCallTstate(tstate);
142+
}
143+
144+
extern struct _PyInterpreterFrame* _PyEval_GetFrame(void);
145+
146+
extern PyObject* _Py_MakeCoro(PyFunctionObject *func);
147+
148+
#ifdef __cplusplus
149+
}
150+
#endif
151+
#endif /* !Py_INTERNAL_CEVAL_H */
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/* Copyright (c) 2024, Oracle and/or its affiliates.
2+
* Copyright (C) 1996-2023 Python Software Foundation
3+
*
4+
* Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
5+
*/
6+
#ifndef Py_INTERNAL_GLOBAL_OBJECTS_H
7+
#define Py_INTERNAL_GLOBAL_OBJECTS_H
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
#ifndef Py_BUILD_CORE
13+
# error "this header requires Py_BUILD_CORE define"
14+
#endif
15+
16+
/* GraalVM change
17+
#include "pycore_gc.h" // PyGC_Head
18+
#include "pycore_global_strings.h" // struct _Py_global_strings
19+
*/
20+
21+
22+
// These would be in pycore_long.h if it weren't for an include cycle.
23+
#define _PY_NSMALLPOSINTS 257
24+
#define _PY_NSMALLNEGINTS 5
25+
26+
27+
// Only immutable objects should be considered runtime-global.
28+
// All others must be per-interpreter.
29+
30+
#define _Py_GLOBAL_OBJECT(NAME) \
31+
_PyRuntime.global_objects.NAME
32+
#define _Py_SINGLETON(NAME) \
33+
_Py_GLOBAL_OBJECT(singletons.NAME)
34+
35+
struct _Py_global_objects {
36+
struct {
37+
/* Small integers are preallocated in this array so that they
38+
* can be shared.
39+
* The integers that are preallocated are those in the range
40+
* -_PY_NSMALLNEGINTS (inclusive) to _PY_NSMALLPOSINTS (exclusive).
41+
*/
42+
/* GraalVM change
43+
PyLongObject small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS];
44+
45+
PyBytesObject bytes_empty;
46+
struct {
47+
PyBytesObject ob;
48+
char eos;
49+
} bytes_characters[256];
50+
51+
struct _Py_global_strings strings;
52+
53+
_PyGC_Head_UNUSED _tuple_empty_gc_not_used;
54+
PyTupleObject tuple_empty;
55+
*/
56+
} singletons;
57+
};
58+
59+
60+
#ifdef __cplusplus
61+
}
62+
#endif
63+
#endif /* !Py_INTERNAL_GLOBAL_OBJECTS_H */

graalpython/com.oracle.graal.python.cext/include/internal/pycore_long.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2022, 2023, Oracle and/or its affiliates.
1+
/* Copyright (c) 2022, 2024, Oracle and/or its affiliates.
22
* Copyright (C) 1996-2022 Python Software Foundation
33
*
44
* Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
@@ -13,19 +13,30 @@ extern "C" {
1313
# error "this header requires Py_BUILD_CORE define"
1414
#endif
1515

16-
// GraalVM change: use our own globals instead of interpreter state
17-
PyAPI_DATA(PyObject*) _PyTruffle_Zero;
18-
PyAPI_DATA(PyObject*) _PyTruffle_One;
16+
#include "pycore_global_objects.h" // _PY_NSMALLNEGINTS
17+
18+
/* other API */
19+
20+
/* GraalVM change
21+
#define _PyLong_SMALL_INTS _Py_SINGLETON(small_ints)
22+
*/
23+
#define _PyLong_SMALL_INT_PTRS (PyThreadState_GET()->small_ints)
1924

2025
// Return a borrowed reference to the zero singleton.
2126
// The function cannot return NULL.
2227
static inline PyObject* _PyLong_GetZero(void)
23-
{ return _PyTruffle_Zero; }
28+
/* GraalVM change
29+
{ return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS]; }
30+
*/
31+
{ return _PyLong_SMALL_INT_PTRS[_PY_NSMALLNEGINTS]; }
2432

2533
// Return a borrowed reference to the one singleton.
2634
// The function cannot return NULL.
2735
static inline PyObject* _PyLong_GetOne(void)
28-
{ return _PyTruffle_One; }
36+
/* GraalVM change
37+
{ return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS+1]; }
38+
*/
39+
{ return _PyLong_SMALL_INT_PTRS[_PY_NSMALLNEGINTS+1]; }
2940

3041
static inline PyObject* _PyLong_FromUnsignedChar(unsigned char i)
3142
{

graalpython/com.oracle.graal.python.cext/src/capi.c

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -257,17 +257,20 @@ PyObject* _Py_EllipsisObjectReference;
257257
PyObject* _Py_NoneStructReference;
258258
PyObject* _Py_NotImplementedStructReference;
259259

260-
PyObject* _PyTruffle_Zero;
261-
PyObject* _PyTruffle_One;
260+
#ifndef GRAALVM_PYTHON_LLVM_MANAGED
261+
THREAD_LOCAL PyThreadState *tstate_current = NULL;
262+
#endif /* GRAALVM_PYTHON_LLVM_MANAGED */
262263

263264
static void initialize_globals() {
265+
#ifndef GRAALVM_PYTHON_LLVM_MANAGED
266+
// store the thread state into a thread local variable
267+
tstate_current = GraalPyTruffleThreadState_Get(&tstate_current);
268+
#endif /* GRAALVM_PYTHON_LLVM_MANAGED */
264269
_Py_NoneStructReference = GraalPyTruffle_None();
265270
_Py_NotImplementedStructReference = GraalPyTruffle_NotImplemented();
266271
_Py_EllipsisObjectReference = GraalPyTruffle_Ellipsis();
267272
_Py_TrueStructReference = (struct _longobject*)GraalPyTruffle_True();
268273
_Py_FalseStructReference = (struct _longobject*)GraalPyTruffle_False();
269-
_PyTruffle_Zero = GraalPyTruffleLong_Zero();
270-
_PyTruffle_One = GraalPyTruffleLong_One();
271274
}
272275

273276
/* internal functions to avoid unnecessary managed <-> native conversions */
@@ -422,26 +425,6 @@ PyAPI_FUNC(void) PyTruffle_DECREF(PyObject* obj) {
422425
Py_DECREF(obj);
423426
}
424427

425-
/** to be used from Java code only; calls ADDREF */
426-
PyAPI_FUNC(Py_ssize_t) PyTruffle_ADDREF(intptr_t ptr, Py_ssize_t value) {
427-
PyObject* obj = (PyObject*) ptr; // avoid type attachment at the interop boundary
428-
#ifdef ASSERTIONS
429-
if (obj->ob_refcnt & 0xFFFFFFFF00000000L) {
430-
char buf[1024];
431-
sprintf(buf, "suspicious refcnt value during managed adjustment for %p (%zd 0x%zx + %zd)\n", obj, obj->ob_refcnt, obj->ob_refcnt, value);
432-
Py_FatalError(buf);
433-
}
434-
if ((obj->ob_refcnt + value) <= 0) {
435-
char buf[1024];
436-
sprintf(buf, "refcnt reached zero during managed adjustment for %p (%zd 0x%zx + %zd)\n", obj, obj->ob_refcnt, obj->ob_refcnt, value);
437-
Py_FatalError(buf);
438-
}
439-
// printf("refcnt value during managed adjustment for %p (%zd 0x%zx + %zd)\n", obj, obj->ob_refcnt, obj->ob_refcnt, value);
440-
#endif // ASSERTIONS
441-
442-
return (obj->ob_refcnt += value);
443-
}
444-
445428
/** to be used from Java code only; calls DECREF */
446429
PyAPI_FUNC(Py_ssize_t) PyTruffle_SUBREF(intptr_t ptr, Py_ssize_t value) {
447430
PyObject* obj = (PyObject*) ptr; // avoid type attachment at the interop boundary
@@ -680,6 +663,11 @@ PyAPI_FUNC(int) WriteObjectMember(void* object, Py_ssize_t offset, PyObject* val
680663
return 0;
681664
}
682665

666+
PyAPI_FUNC(int) WritePointerMember(void* object, Py_ssize_t offset, void* value) {
667+
WriteMember(object, offset, value, void*);
668+
return 0;
669+
}
670+
683671
PyAPI_FUNC(int) WriteCharMember(void* object, Py_ssize_t offset, char value) {
684672
WriteMember(object, offset, value, char);
685673
return 0;
@@ -770,8 +758,8 @@ PyAPI_FUNC(void) truffle_memcpy_bytes(void *dest, size_t dest_offset, void *src,
770758
memcpy(dest + dest_offset, src + src_offset, len);
771759
}
772760

773-
PyAPI_FUNC(void*) truffle_calloc(size_t size) {
774-
return calloc(1, size);
761+
PyAPI_FUNC(void*) truffle_calloc(size_t count, size_t elsize) {
762+
return calloc(count, elsize);
775763
}
776764

777765
// avoid problems with calling "void" intrinsics via interop
@@ -880,7 +868,7 @@ void initialize_hashes();
880868
// defined in 'floatobject.c'
881869
void _PyFloat_InitState(PyInterpreterState* state);
882870

883-
TruffleContext* TRUFFLE_CONTEXT;
871+
Py_LOCAL_SYMBOL TruffleContext* TRUFFLE_CONTEXT;
884872

885873
PyAPI_FUNC(void) initialize_graal_capi(TruffleEnv* env, void* (*getBuiltin)(int id)) {
886874
clock_t t = clock();
@@ -893,9 +881,6 @@ PyAPI_FUNC(void) initialize_graal_capi(TruffleEnv* env, void* (*getBuiltin)(int
893881
PyTruffle_Log(PY_TRUFFLE_LOG_FINE, "initialize_builtins: %fs", ((double) (clock() - t)) / CLOCKS_PER_SEC);
894882
Py_Truffle_Options = GraalPyTruffle_Native_Options();
895883

896-
// this will set PythonContext.nativeNull and is required to be first
897-
GraalPyTruffle_Register_NULL(NULL);
898-
899884
initialize_builtin_types_and_structs();
900885
// initialize global variables like '_Py_NoneStruct', etc.
901886
initialize_globals();

0 commit comments

Comments
 (0)