@@ -98,6 +98,11 @@ def always_true(tkn: Token | None) -> bool:
9898 return False
9999 return tkn .text in {"true" , "1" }
100100
101+ NON_ESCAPING_DEALLOCS = {
102+ "_PyFloat_ExactDealloc" ,
103+ "_PyLong_ExactDealloc" ,
104+ "_PyUnicode_ExactDealloc" ,
105+ }
101106
102107class Emitter :
103108 out : CWriter
@@ -116,7 +121,7 @@ def __init__(self, out: CWriter):
116121 "SAVE_STACK" : self .save_stack ,
117122 "RELOAD_STACK" : self .reload_stack ,
118123 "PyStackRef_CLOSE" : self .stackref_close ,
119- "PyStackRef_CLOSE_SPECIALIZED" : self .stackref_close_no_escape ,
124+ "PyStackRef_CLOSE_SPECIALIZED" : self .stackref_close_specialized ,
120125 "PyStackRef_AsPyObjectSteal" : self .stackref_steal ,
121126 "DISPATCH" : self .dispatch ,
122127 "INSTRUCTION_SIZE" : self .instruction_size ,
@@ -295,11 +300,31 @@ def kill(
295300 return True
296301
297302 def stackref_kill (
303+ self ,
304+ name : Token ,
305+ storage : Storage ,
306+ escapes : bool
307+ ) -> bool :
308+ live = ""
309+ for var in reversed (storage .inputs ):
310+ if var .name == name .text :
311+ if live and escapes :
312+ raise analysis_error (
313+ f"Cannot close '{ name .text } ' when "
314+ f"'{ live } ' is still live" , name )
315+ var .defined = False
316+ break
317+ if var .defined :
318+ live = var .name
319+ return True
320+
321+ def stackref_close (
298322 self ,
299323 tkn : Token ,
300324 tkn_iter : TokenIterator ,
325+ uop : Uop ,
301326 storage : Storage ,
302- escapes : bool
327+ inst : Instruction | None ,
303328 ) -> bool :
304329 self .out .emit (tkn )
305330 tkn = next (tkn_iter )
@@ -308,42 +333,60 @@ def stackref_kill(
308333 name = next (tkn_iter )
309334 self .out .emit (name )
310335 if name .kind == "IDENTIFIER" :
311- live = ""
312- for var in reversed (storage .inputs ):
313- if var .name == name .text :
314- if live and escapes :
315- raise analysis_error (
316- f"Cannot close '{ name .text } ' when "
317- f"'{ live } ' is still live" , name )
318- var .defined = False
319- break
320- if var .defined :
321- live = var .name
336+ return self .stackref_kill (name , storage , True )
322337 rparen = emit_to (self .out , tkn_iter , "RPAREN" )
323338 self .emit (rparen )
324339 return True
325340
326- def stackref_close (
341+ def stackref_close_specialized (
327342 self ,
328343 tkn : Token ,
329344 tkn_iter : TokenIterator ,
330345 uop : Uop ,
331346 storage : Storage ,
332347 inst : Instruction | None ,
333348 ) -> bool :
334- return self .stackref_kill (tkn , tkn_iter , storage , True )
335349
336- def stackref_close_no_escape (
350+ self .out .emit (tkn )
351+ tkn = next (tkn_iter )
352+ assert tkn .kind == "LPAREN"
353+ self .out .emit (tkn )
354+ name = next (tkn_iter )
355+ self .out .emit (name )
356+ comma = next (tkn_iter )
357+ if comma .kind != "COMMA" :
358+ raise analysis_error ("Expected comma" , comma )
359+ self .out .emit (comma )
360+ dealloc = next (tkn_iter )
361+ if dealloc .kind != "IDENTIFIER" :
362+ raise analysis_error ("Expected identifier" , dealloc )
363+ self .out .emit (dealloc )
364+ if name .kind == "IDENTIFIER" :
365+ escapes = dealloc .text not in NON_ESCAPING_DEALLOCS
366+ return self .stackref_kill (name , storage , escapes )
367+ rparen = emit_to (self .out , tkn_iter , "RPAREN" )
368+ self .emit (rparen )
369+ return True
370+
371+ def stackref_steal (
337372 self ,
338373 tkn : Token ,
339374 tkn_iter : TokenIterator ,
340375 uop : Uop ,
341376 storage : Storage ,
342377 inst : Instruction | None ,
343378 ) -> bool :
344- return self .stackref_kill (tkn , tkn_iter , storage , False )
345-
346- stackref_steal = stackref_close_no_escape
379+ self .out .emit (tkn )
380+ tkn = next (tkn_iter )
381+ assert tkn .kind == "LPAREN"
382+ self .out .emit (tkn )
383+ name = next (tkn_iter )
384+ self .out .emit (name )
385+ if name .kind == "IDENTIFIER" :
386+ return self .stackref_kill (name , storage , False )
387+ rparen = emit_to (self .out , tkn_iter , "RPAREN" )
388+ self .emit (rparen )
389+ return True
347390
348391 def sync_sp (
349392 self ,
0 commit comments