@@ -607,12 +607,22 @@ PyInterpreterState_GetDict(PyInterpreterState *interp)
607
607
return interp -> dict ;
608
608
}
609
609
610
- /* Size of data stack
611
- * Experimentally this can be set as low as 12k and have all the tests
612
- * pass (64bit linux). */
613
- #define DATA_STACK_SIZE (62*1024)
614
- /* Additional stack space for error recovery */
615
- #define DATA_STACK_HEADROOM (2*1024)
610
+ /* Minimum size of data stack chunk */
611
+ #define DATA_STACK_CHUNK_SIZE (16*1024)
612
+
613
+ static _PyStackChunk *
614
+ allocate_chunk (int size_in_bytes , _PyStackChunk * previous )
615
+ {
616
+ assert (size_in_bytes % sizeof (PyObject * * ) == 0 );
617
+ _PyStackChunk * res = _PyObject_VirtualAlloc (size_in_bytes );
618
+ if (res == NULL ) {
619
+ return NULL ;
620
+ }
621
+ res -> previous = previous ;
622
+ res -> size = size_in_bytes ;
623
+ res -> top = 0 ;
624
+ return res ;
625
+ }
616
626
617
627
static PyThreadState *
618
628
new_threadstate (PyInterpreterState * interp , int init )
@@ -665,15 +675,14 @@ new_threadstate(PyInterpreterState *interp, int init)
665
675
666
676
tstate -> context = NULL ;
667
677
tstate -> context_ver = 1 ;
668
- size_t total_size = (DATA_STACK_SIZE + DATA_STACK_HEADROOM );
669
- tstate -> datastack_base = _PyObject_VirtualAlloc (sizeof (PyObject * )* total_size );
670
- if (tstate -> datastack_base == NULL ) {
678
+ tstate -> datastack_chunk = allocate_chunk (DATA_STACK_CHUNK_SIZE , NULL );
679
+ if (tstate -> datastack_chunk == NULL ) {
671
680
PyMem_RawFree (tstate );
672
681
return NULL ;
673
682
}
674
- tstate -> datastack_top = tstate -> datastack_base ;
675
- tstate -> datastack_hard_limit = tstate -> datastack_base + total_size ;
676
- tstate -> datastack_soft_limit = tstate -> datastack_base + DATA_STACK_SIZE ;
683
+ /* If top points to entry 0, then _PyThreadState_PopLocals willl try to pop this chunk */
684
+ tstate -> datastack_top = & tstate -> datastack_chunk -> data [ 1 ] ;
685
+ tstate -> datastack_limit = ( PyObject * * )((( char * ) tstate -> datastack_chunk ) + DATA_STACK_CHUNK_SIZE ) ;
677
686
678
687
if (init ) {
679
688
_PyThreadState_Init (tstate );
@@ -932,7 +941,7 @@ _PyThreadState_Delete(PyThreadState *tstate, int check_current)
932
941
}
933
942
}
934
943
tstate_delete_common (tstate , gilstate );
935
- _PyObject_VirtualFree (tstate -> datastack_base , sizeof ( PyObject * ) * DATA_STACK_SIZE );
944
+ _PyObject_VirtualFree (tstate -> datastack_chunk , tstate -> datastack_chunk -> size );
936
945
PyMem_RawFree (tstate );
937
946
}
938
947
@@ -1985,28 +1994,34 @@ _Py_GetConfig(void)
1985
1994
return _PyInterpreterState_GetConfig (tstate -> interp );
1986
1995
}
1987
1996
1997
+ #define MINIMUM_OVERHEAD 1000
1998
+
1988
1999
PyObject * *
1989
- _PyThreadState_PushLocals (PyThreadState * tstate , int size )
2000
+ _PyThreadState_PushLocals (PyThreadState * tstate , size_t size )
1990
2001
{
1991
2002
PyObject * * res = tstate -> datastack_top ;
1992
2003
PyObject * * top = res + size ;
1993
- if (top >= tstate -> datastack_soft_limit ) {
1994
- if (top >= tstate -> datastack_hard_limit ) {
1995
- if (tstate -> recursion_headroom ) {
1996
- Py_FatalError ("Cannot recover from data-stack overflow." );
1997
- }
1998
- else {
1999
- Py_FatalError ("Rapid data-stack overflow." );
2000
- }
2004
+ if (top >= tstate -> datastack_limit ) {
2005
+ size_t allocate_size = DATA_STACK_CHUNK_SIZE ;
2006
+ while (allocate_size < sizeof (PyObject * )* (size + MINIMUM_OVERHEAD )) {
2007
+ allocate_size *= 2 ;
2001
2008
}
2002
- tstate -> recursion_headroom ++ ;
2003
- _PyErr_Format (tstate , PyExc_RecursionError ,
2004
- "data stack overflow" );
2005
- tstate -> recursion_headroom -- ;
2006
- return NULL ;
2009
+ _PyStackChunk * new = allocate_chunk (allocate_size , tstate -> datastack_chunk );
2010
+ if (new == NULL ) {
2011
+ _PyErr_SetString (tstate , PyExc_MemoryError , "Out of memory" );
2012
+ return NULL ;
2013
+ }
2014
+ printf ("Pushing chunk\n" );
2015
+ tstate -> datastack_chunk -> top = tstate -> datastack_top - & tstate -> datastack_chunk -> data [0 ];
2016
+ tstate -> datastack_chunk = new ;
2017
+ tstate -> datastack_limit = (PyObject * * )(((char * )new ) + allocate_size );
2018
+ res = & new -> data [0 ];
2019
+ tstate -> datastack_top = res + size ;
2020
+ }
2021
+ else {
2022
+ tstate -> datastack_top = top ;
2007
2023
}
2008
- tstate -> datastack_top = top ;
2009
- for (Py_ssize_t i = 0 ; i < size ; i ++ ) {
2024
+ for (size_t i = 0 ; i < size ; i ++ ) {
2010
2025
res [i ] = NULL ;
2011
2026
}
2012
2027
return res ;
@@ -2015,8 +2030,19 @@ _PyThreadState_PushLocals(PyThreadState *tstate, int size)
2015
2030
void
2016
2031
_PyThreadState_PopLocals (PyThreadState * tstate , PyObject * * locals )
2017
2032
{
2018
- assert (tstate -> datastack_top >= locals );
2019
- tstate -> datastack_top = locals ;
2033
+ if (locals == & tstate -> datastack_chunk -> data [0 ]) {
2034
+ printf ("Popping chunk\n" );
2035
+ _PyStackChunk * chunk = tstate -> datastack_chunk ;
2036
+ _PyStackChunk * previous = chunk -> previous ;
2037
+ tstate -> datastack_top = & previous -> data [previous -> top ];
2038
+ tstate -> datastack_chunk = previous ;
2039
+ _PyObject_VirtualFree (chunk , chunk -> size );
2040
+ tstate -> datastack_limit = (PyObject * * )(((char * )tstate -> datastack_chunk ) + DATA_STACK_CHUNK_SIZE );
2041
+ }
2042
+ else {
2043
+ assert (tstate -> datastack_top >= locals );
2044
+ tstate -> datastack_top = locals ;
2045
+ }
2020
2046
}
2021
2047
2022
2048
0 commit comments