PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/rpython/memory/gctransform/transform.py

https://bitbucket.org/pypy/pypy/
Python | 606 lines | 495 code | 92 blank | 19 comment | 94 complexity | a0ab3bc74b46a5544a8c033ff0aa3a6d MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.rtyper.lltypesystem import lltype, llmemory
  2. from rpython.flowspace.model import (
  3. SpaceOperation, Variable, Constant, checkgraph)
  4. from rpython.translator.unsimplify import insert_empty_block
  5. from rpython.translator.unsimplify import insert_empty_startblock
  6. from rpython.translator.unsimplify import starts_with_empty_block
  7. from rpython.translator.backendopt.support import var_needsgc
  8. from rpython.translator.backendopt import inline
  9. from rpython.translator.backendopt.canraise import RaiseAnalyzer
  10. from rpython.translator.backendopt.ssa import DataFlowFamilyBuilder
  11. from rpython.translator.backendopt.constfold import constant_fold_graph
  12. from rpython.rtyper.llannotation import lltype_to_annotation
  13. from rpython.rtyper import rmodel
  14. from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator
  15. from rpython.rtyper.rtyper import LowLevelOpList
  16. from rpython.rtyper.rbuiltin import gen_cast
  17. from rpython.rlib.rarithmetic import ovfcheck
  18. from rpython.rtyper.lltypesystem.lloperation import llop
  19. from rpython.translator.simplify import cleanup_graph
  20. class GcHighLevelOp(object):
  21. def __init__(self, gct, op, index, llops):
  22. self.gctransformer = gct
  23. self.spaceop = op
  24. self.index = index
  25. self.llops = llops
  26. def livevars_after_op(self):
  27. gct = self.gctransformer
  28. return [
  29. var for var in gct.livevars
  30. if gct.var_last_needed_in[var] > self.index]
  31. def current_op_keeps_alive(self):
  32. gct = self.gctransformer
  33. return [
  34. var for var in self.spaceop.args
  35. if gct.var_last_needed_in.get(var) == self.index]
  36. def dispatch(self):
  37. gct = self.gctransformer
  38. opname = self.spaceop.opname
  39. v_result = self.spaceop.result
  40. meth = getattr(gct, 'gct_' + opname, gct.default)
  41. meth(self)
  42. if var_needsgc(v_result):
  43. gct.livevars.append(v_result)
  44. if opname not in ('direct_call', 'indirect_call'):
  45. gct.push_alive(v_result, self.llops)
  46. def rename(self, newopname):
  47. self.llops.append(
  48. SpaceOperation(newopname, self.spaceop.args, self.spaceop.result))
  49. def inputargs(self):
  50. return self.spaceop.args
  51. def genop(self, opname, args, resulttype=None, resultvar=None):
  52. assert resulttype is None or resultvar is None
  53. if resultvar is None:
  54. return self.llops.genop(opname, args,
  55. resulttype=resulttype)
  56. else:
  57. newop = SpaceOperation(opname, args, resultvar)
  58. self.llops.append(newop)
  59. return resultvar
  60. def cast_result(self, var):
  61. v_result = self.spaceop.result
  62. resulttype = v_result.concretetype
  63. curtype = var.concretetype
  64. if curtype == resulttype:
  65. self.genop('same_as', [var], resultvar=v_result)
  66. else:
  67. v_new = gen_cast(self.llops, resulttype, var)
  68. assert v_new != var
  69. self.llops[-1].result = v_result
  70. # ________________________________________________________________
  71. class BaseGCTransformer(object):
  72. finished_helpers = False
  73. curr_block = None
  74. def __init__(self, translator, inline=False):
  75. self.translator = translator
  76. self.seen_graphs = set()
  77. self.prepared = False
  78. self.minimal_transform = set()
  79. if translator:
  80. self.mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
  81. else:
  82. self.mixlevelannotator = None
  83. self.inline = inline
  84. if translator and inline:
  85. self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping()
  86. self.graphs_to_inline = {}
  87. self.graph_dependencies = {}
  88. self.ll_finalizers_ptrs = []
  89. if self.MinimalGCTransformer:
  90. self.minimalgctransformer = self.MinimalGCTransformer(self)
  91. else:
  92. self.minimalgctransformer = None
  93. def get_lltype_of_exception_value(self):
  94. exceptiondata = self.translator.rtyper.exceptiondata
  95. return exceptiondata.lltype_of_exception_value
  96. def need_minimal_transform(self, graph):
  97. self.seen_graphs.add(graph)
  98. self.minimal_transform.add(graph)
  99. def inline_helpers(self, graphs):
  100. from rpython.translator.backendopt.inline import iter_callsites
  101. raise_analyzer = RaiseAnalyzer(self.translator)
  102. for graph in graphs:
  103. to_enum = []
  104. for called, block, i in iter_callsites(graph, None):
  105. if called in self.graphs_to_inline:
  106. to_enum.append(called)
  107. must_constfold = False
  108. for inline_graph in to_enum:
  109. try:
  110. inline.inline_function(self.translator, inline_graph, graph,
  111. self.lltype_to_classdef,
  112. raise_analyzer,
  113. cleanup=False)
  114. must_constfold = True
  115. except inline.CannotInline as e:
  116. print 'CANNOT INLINE:', e
  117. print '\t%s into %s' % (inline_graph, graph)
  118. cleanup_graph(graph)
  119. if must_constfold:
  120. constant_fold_graph(graph)
  121. def compute_borrowed_vars(self, graph):
  122. # the input args are borrowed, and stay borrowed for as long as they
  123. # are not merged with other values.
  124. var_families = DataFlowFamilyBuilder(graph).get_variable_families()
  125. borrowed_reps = {}
  126. for v in graph.getargs():
  127. borrowed_reps[var_families.find_rep(v)] = True
  128. # no support for returning borrowed values so far
  129. retvar = graph.getreturnvar()
  130. def is_borrowed(v1):
  131. return (var_families.find_rep(v1) in borrowed_reps
  132. and v1 is not retvar)
  133. return is_borrowed
  134. def transform_block(self, block, is_borrowed):
  135. llops = LowLevelOpList()
  136. self.curr_block = block
  137. self.livevars = [var for var in block.inputargs
  138. if var_needsgc(var) and not is_borrowed(var)]
  139. allvars = [var for var in block.getvariables() if var_needsgc(var)]
  140. self.var_last_needed_in = dict.fromkeys(allvars, 0)
  141. for i, op in enumerate(block.operations):
  142. for var in op.args:
  143. if not var_needsgc(var):
  144. continue
  145. self.var_last_needed_in[var] = i
  146. for link in block.exits:
  147. for var in link.args:
  148. if not var_needsgc(var):
  149. continue
  150. self.var_last_needed_in[var] = len(block.operations) + 1
  151. for i, op in enumerate(block.operations):
  152. hop = GcHighLevelOp(self, op, i, llops)
  153. hop.dispatch()
  154. if len(block.exits) != 0: # i.e not the return block
  155. assert not block.canraise
  156. deadinallexits = set(self.livevars)
  157. for link in block.exits:
  158. deadinallexits.difference_update(set(link.args))
  159. for var in deadinallexits:
  160. self.pop_alive(var, llops)
  161. for link in block.exits:
  162. livecounts = dict.fromkeys(set(self.livevars) - deadinallexits, 1)
  163. for v, v2 in zip(link.args, link.target.inputargs):
  164. if is_borrowed(v2):
  165. continue
  166. if v in livecounts:
  167. livecounts[v] -= 1
  168. elif var_needsgc(v):
  169. # 'v' is typically a Constant here, but it can be
  170. # a borrowed variable going into a non-borrowed one
  171. livecounts[v] = -1
  172. self.links_to_split[link] = livecounts
  173. block.operations[:] = llops
  174. self.livevars = None
  175. self.var_last_needed_in = None
  176. self.curr_block = None
  177. def transform_graph(self, graph):
  178. if graph in self.minimal_transform:
  179. if self.minimalgctransformer:
  180. self.minimalgctransformer.transform_graph(graph)
  181. self.minimal_transform.remove(graph)
  182. return
  183. if graph in self.seen_graphs:
  184. return
  185. self.seen_graphs.add(graph)
  186. self.links_to_split = {} # link -> vars to pop_alive across the link
  187. # for sanity, we need an empty block at the start of the graph
  188. inserted_empty_startblock = False
  189. if not starts_with_empty_block(graph):
  190. insert_empty_startblock(graph)
  191. inserted_empty_startblock = True
  192. is_borrowed = self.compute_borrowed_vars(graph)
  193. for block in graph.iterblocks():
  194. self.transform_block(block, is_borrowed)
  195. for link, livecounts in self.links_to_split.iteritems():
  196. llops = LowLevelOpList()
  197. for var, livecount in livecounts.iteritems():
  198. for i in range(livecount):
  199. self.pop_alive(var, llops)
  200. for i in range(-livecount):
  201. self.push_alive(var, llops)
  202. if llops:
  203. if link.prevblock.exitswitch is None:
  204. link.prevblock.operations.extend(llops)
  205. else:
  206. insert_empty_block(link, llops)
  207. # remove the empty block at the start of the graph, which should
  208. # still be empty (but let's check)
  209. if starts_with_empty_block(graph) and inserted_empty_startblock:
  210. old_startblock = graph.startblock
  211. graph.startblock = graph.startblock.exits[0].target
  212. checkgraph(graph)
  213. self.links_to_split = None
  214. v = Variable('vanishing_exc_value')
  215. v.concretetype = self.get_lltype_of_exception_value()
  216. llops = LowLevelOpList()
  217. self.pop_alive(v, llops)
  218. graph.exc_cleanup = (v, list(llops))
  219. return is_borrowed # xxx for tests only
  220. def annotate_helper(self, ll_helper, ll_args, ll_result, inline=False):
  221. assert not self.finished_helpers
  222. args_s = map(lltype_to_annotation, ll_args)
  223. s_result = lltype_to_annotation(ll_result)
  224. graph = self.mixlevelannotator.getgraph(ll_helper, args_s, s_result)
  225. # the produced graphs does not need to be fully transformed
  226. self.need_minimal_transform(graph)
  227. if inline:
  228. self.graphs_to_inline[graph] = True
  229. FUNCTYPE = lltype.FuncType(ll_args, ll_result)
  230. return self.mixlevelannotator.graph2delayed(graph, FUNCTYPE=FUNCTYPE)
  231. def inittime_helper(self, ll_helper, ll_args, ll_result, inline=True):
  232. ptr = self.annotate_helper(ll_helper, ll_args, ll_result, inline=inline)
  233. return Constant(ptr, lltype.typeOf(ptr))
  234. def annotate_finalizer(self, ll_finalizer, ll_args, ll_result):
  235. fptr = self.annotate_helper(ll_finalizer, ll_args, ll_result)
  236. self.ll_finalizers_ptrs.append(fptr)
  237. return fptr
  238. def finish_helpers(self, backendopt=True):
  239. if self.translator is not None:
  240. self.mixlevelannotator.finish_annotate()
  241. if self.translator is not None:
  242. self.mixlevelannotator.finish_rtype()
  243. if backendopt:
  244. self.mixlevelannotator.backend_optimize()
  245. self.finished_helpers = True
  246. # Make sure that the database also sees all finalizers now.
  247. # It is likely that the finalizers need special support there
  248. newgcdependencies = self.ll_finalizers_ptrs
  249. return newgcdependencies
  250. def finish_tables(self):
  251. pass
  252. def get_finish_tables(self):
  253. return self.finish_tables
  254. def finish(self, backendopt=True):
  255. self.finish_helpers(backendopt=backendopt)
  256. self.finish_tables()
  257. def transform_generic_set(self, hop):
  258. opname = hop.spaceop.opname
  259. v_new = hop.spaceop.args[-1]
  260. v_old = hop.genop('g' + opname[1:],
  261. hop.inputargs()[:-1],
  262. resulttype=v_new.concretetype)
  263. self.push_alive(v_new, hop.llops)
  264. hop.rename('bare_' + opname)
  265. self.pop_alive(v_old, hop.llops)
  266. def push_alive(self, var, llops):
  267. pass
  268. def pop_alive(self, var, llops):
  269. pass
  270. def var_needs_set_transform(self, var):
  271. return False
  272. def default(self, hop):
  273. hop.llops.append(hop.spaceop)
  274. def gct_setfield(self, hop):
  275. if self.var_needs_set_transform(hop.spaceop.args[-1]):
  276. self.transform_generic_set(hop)
  277. else:
  278. hop.rename('bare_' + hop.spaceop.opname)
  279. gct_setarrayitem = gct_setfield
  280. gct_setinteriorfield = gct_setfield
  281. gct_raw_store = gct_setfield
  282. gct_getfield = default
  283. def gct_zero_gc_pointers_inside(self, hop):
  284. pass
  285. def gct_gc_writebarrier_before_copy(self, hop):
  286. # We take the conservative default and return False here, meaning
  287. # that rgc.ll_arraycopy() will do the copy by hand (i.e. with a
  288. # 'for' loop). Subclasses that have their own logic, or that don't
  289. # need any kind of write barrier, may return True.
  290. op = hop.spaceop
  291. hop.genop("same_as",
  292. [rmodel.inputconst(lltype.Bool, False)],
  293. resultvar=op.result)
  294. def gct_gc_pin(self, hop):
  295. op = hop.spaceop
  296. hop.genop("same_as",
  297. [rmodel.inputconst(lltype.Bool, False)],
  298. resultvar=op.result)
  299. def gct_gc_unpin(self, hop):
  300. pass
  301. def gct_gc__is_pinned(self, hop):
  302. op = hop.spaceop
  303. hop.genop("same_as",
  304. [rmodel.inputconst(lltype.Bool, False)],
  305. resultvar=op.result)
  306. def gct_gc_identityhash(self, hop):
  307. # must be implemented in the various GCs
  308. raise NotImplementedError
  309. def gct_gc_id(self, hop):
  310. # this assumes a non-moving GC. Moving GCs need to override this
  311. hop.rename('cast_ptr_to_int')
  312. def gct_gc_heap_stats(self, hop):
  313. from rpython.memory.gc.base import ARRAY_TYPEID_MAP
  314. return hop.cast_result(rmodel.inputconst(lltype.Ptr(ARRAY_TYPEID_MAP),
  315. lltype.nullptr(ARRAY_TYPEID_MAP)))
  316. def get_prebuilt_hash(self, obj):
  317. return None
  318. class MinimalGCTransformer(BaseGCTransformer):
  319. def __init__(self, parenttransformer):
  320. BaseGCTransformer.__init__(self, parenttransformer.translator)
  321. self.parenttransformer = parenttransformer
  322. def push_alive(self, var, llops):
  323. pass
  324. def pop_alive(self, var, llops):
  325. pass
  326. def gct_malloc(self, hop):
  327. flags = hop.spaceop.args[1].value
  328. flavor = flags['flavor']
  329. assert flavor == 'raw'
  330. assert not flags.get('zero')
  331. return self.parenttransformer.gct_malloc(hop)
  332. def gct_malloc_varsize(self, hop):
  333. flags = hop.spaceop.args[1].value
  334. flavor = flags['flavor']
  335. assert flavor == 'raw'
  336. assert not flags.get('zero')
  337. return self.parenttransformer.gct_malloc_varsize(hop)
  338. def gct_free(self, hop):
  339. flags = hop.spaceop.args[1].value
  340. flavor = flags['flavor']
  341. assert flavor == 'raw'
  342. return self.parenttransformer.gct_free(hop)
  343. BaseGCTransformer.MinimalGCTransformer = MinimalGCTransformer
  344. MinimalGCTransformer.MinimalGCTransformer = None
  345. # ________________________________________________________________
  346. def mallocHelpers():
  347. class _MallocHelpers(object):
  348. def _freeze_(self):
  349. return True
  350. mh = _MallocHelpers()
  351. def _ll_malloc_fixedsize(size):
  352. result = mh.allocate(size)
  353. if not result:
  354. raise MemoryError()
  355. return result
  356. mh._ll_malloc_fixedsize = _ll_malloc_fixedsize
  357. def _ll_compute_size(length, size, itemsize):
  358. try:
  359. varsize = ovfcheck(itemsize * length)
  360. tot_size = ovfcheck(size + varsize)
  361. except OverflowError:
  362. raise MemoryError()
  363. return tot_size
  364. _ll_compute_size._always_inline_ = True
  365. def _ll_malloc_varsize_no_length(length, size, itemsize):
  366. tot_size = _ll_compute_size(length, size, itemsize)
  367. result = mh.allocate(tot_size)
  368. if not result:
  369. raise MemoryError()
  370. return result
  371. mh._ll_malloc_varsize_no_length = _ll_malloc_varsize_no_length
  372. mh.ll_malloc_varsize_no_length = _ll_malloc_varsize_no_length
  373. def ll_malloc_varsize(length, size, itemsize, lengthoffset):
  374. result = mh.ll_malloc_varsize_no_length(length, size, itemsize)
  375. (result + lengthoffset).signed[0] = length
  376. return result
  377. mh.ll_malloc_varsize = ll_malloc_varsize
  378. def _ll_malloc_varsize_no_length_zero(length, size, itemsize):
  379. tot_size = _ll_compute_size(length, size, itemsize)
  380. result = mh.allocate(tot_size)
  381. if not result:
  382. raise MemoryError()
  383. llmemory.raw_memclear(result, tot_size)
  384. return result
  385. mh.ll_malloc_varsize_no_length_zero = _ll_malloc_varsize_no_length_zero
  386. return mh
  387. class GCTransformer(BaseGCTransformer):
  388. def __init__(self, translator, inline=False):
  389. super(GCTransformer, self).__init__(translator, inline=inline)
  390. mh = mallocHelpers()
  391. mh.allocate = llmemory.raw_malloc
  392. ll_raw_malloc_fixedsize = mh._ll_malloc_fixedsize
  393. ll_raw_malloc_varsize_no_length = mh.ll_malloc_varsize_no_length
  394. ll_raw_malloc_varsize = mh.ll_malloc_varsize
  395. ll_raw_malloc_varsize_no_length_zero = mh.ll_malloc_varsize_no_length_zero
  396. stack_mh = mallocHelpers()
  397. stack_mh.allocate = lambda size: llop.stack_malloc(llmemory.Address, size)
  398. ll_stack_malloc_fixedsize = stack_mh._ll_malloc_fixedsize
  399. if self.translator:
  400. self.raw_malloc_fixedsize_ptr = self.inittime_helper(
  401. ll_raw_malloc_fixedsize, [lltype.Signed], llmemory.Address)
  402. self.raw_malloc_varsize_no_length_ptr = self.inittime_helper(
  403. ll_raw_malloc_varsize_no_length, [lltype.Signed]*3, llmemory.Address, inline=False)
  404. self.raw_malloc_varsize_ptr = self.inittime_helper(
  405. ll_raw_malloc_varsize, [lltype.Signed]*4, llmemory.Address, inline=False)
  406. self.raw_malloc_varsize_no_length_zero_ptr = self.inittime_helper(
  407. ll_raw_malloc_varsize_no_length_zero, [lltype.Signed]*3, llmemory.Address, inline=False)
  408. self.stack_malloc_fixedsize_ptr = self.inittime_helper(
  409. ll_stack_malloc_fixedsize, [lltype.Signed], llmemory.Address)
  410. def gct_malloc(self, hop, add_flags=None):
  411. TYPE = hop.spaceop.result.concretetype.TO
  412. assert not TYPE._is_varsize()
  413. flags = hop.spaceop.args[1].value
  414. flavor = flags['flavor']
  415. meth = getattr(self, 'gct_fv_%s_malloc' % flavor, None)
  416. assert meth, "%s has no support for malloc with flavor %r" % (self, flavor)
  417. c_size = rmodel.inputconst(lltype.Signed, llmemory.sizeof(TYPE))
  418. v_raw = meth(hop, flags, TYPE, c_size)
  419. hop.cast_result(v_raw)
  420. def gct_fv_raw_malloc(self, hop, flags, TYPE, c_size):
  421. v_raw = hop.genop("direct_call", [self.raw_malloc_fixedsize_ptr, c_size],
  422. resulttype=llmemory.Address)
  423. if flags.get('zero'):
  424. hop.genop("raw_memclear", [v_raw, c_size])
  425. if flags.get('track_allocation', True):
  426. hop.genop("track_alloc_start", [v_raw])
  427. return v_raw
  428. def gct_fv_stack_malloc(self, hop, flags, TYPE, c_size):
  429. v_raw = hop.genop("direct_call", [self.stack_malloc_fixedsize_ptr, c_size],
  430. resulttype=llmemory.Address)
  431. if flags.get('zero'):
  432. hop.genop("raw_memclear", [v_raw, c_size])
  433. return v_raw
  434. def gct_malloc_varsize(self, hop, add_flags=None):
  435. flags = hop.spaceop.args[1].value
  436. if add_flags:
  437. flags.update(add_flags)
  438. flavor = flags['flavor']
  439. meth = getattr(self, 'gct_fv_%s_malloc_varsize' % flavor, None)
  440. assert meth, "%s has no support for malloc_varsize with flavor %r" % (self, flavor)
  441. return self.varsize_malloc_helper(hop, flags, meth, [])
  442. def gct_gc_add_memory_pressure(self, hop):
  443. if hasattr(self, 'raw_malloc_memory_pressure_ptr'):
  444. op = hop.spaceop
  445. size = op.args[0]
  446. return hop.genop("direct_call",
  447. [self.raw_malloc_memory_pressure_ptr,
  448. size])
  449. def varsize_malloc_helper(self, hop, flags, meth, extraargs):
  450. def intconst(c): return rmodel.inputconst(lltype.Signed, c)
  451. op = hop.spaceop
  452. TYPE = op.result.concretetype.TO
  453. assert TYPE._is_varsize()
  454. if isinstance(TYPE, lltype.Struct):
  455. ARRAY = TYPE._flds[TYPE._arrayfld]
  456. else:
  457. ARRAY = TYPE
  458. assert isinstance(ARRAY, lltype.Array)
  459. c_const_size = intconst(llmemory.sizeof(TYPE, 0))
  460. c_item_size = intconst(llmemory.sizeof(ARRAY.OF))
  461. if ARRAY._hints.get("nolength", False):
  462. c_offset_to_length = None
  463. else:
  464. if isinstance(TYPE, lltype.Struct):
  465. offset_to_length = llmemory.FieldOffset(TYPE, TYPE._arrayfld) + \
  466. llmemory.ArrayLengthOffset(ARRAY)
  467. else:
  468. offset_to_length = llmemory.ArrayLengthOffset(ARRAY)
  469. c_offset_to_length = intconst(offset_to_length)
  470. args = [hop] + extraargs + [flags, TYPE,
  471. op.args[-1], c_const_size, c_item_size, c_offset_to_length]
  472. v_raw = meth(*args)
  473. hop.cast_result(v_raw)
  474. def gct_fv_raw_malloc_varsize(self, hop, flags, TYPE, v_length, c_const_size, c_item_size,
  475. c_offset_to_length):
  476. if flags.get('add_memory_pressure', False):
  477. if hasattr(self, 'raw_malloc_memory_pressure_varsize_ptr'):
  478. hop.genop("direct_call",
  479. [self.raw_malloc_memory_pressure_varsize_ptr,
  480. v_length, c_item_size])
  481. if c_offset_to_length is None:
  482. if flags.get('zero'):
  483. fnptr = self.raw_malloc_varsize_no_length_zero_ptr
  484. else:
  485. fnptr = self.raw_malloc_varsize_no_length_ptr
  486. v_raw = hop.genop("direct_call",
  487. [fnptr, v_length, c_const_size, c_item_size],
  488. resulttype=llmemory.Address)
  489. else:
  490. if flags.get('zero'):
  491. raise NotImplementedError("raw zero varsize malloc with length field")
  492. v_raw = hop.genop("direct_call",
  493. [self.raw_malloc_varsize_ptr, v_length,
  494. c_const_size, c_item_size, c_offset_to_length],
  495. resulttype=llmemory.Address)
  496. if flags.get('track_allocation', True):
  497. hop.genop("track_alloc_start", [v_raw])
  498. return v_raw
  499. def gct_free(self, hop):
  500. op = hop.spaceop
  501. flags = op.args[1].value
  502. flavor = flags['flavor']
  503. v = op.args[0]
  504. if flavor == 'raw':
  505. v = hop.genop("cast_ptr_to_adr", [v], resulttype=llmemory.Address)
  506. if flags.get('track_allocation', True):
  507. hop.genop("track_alloc_stop", [v])
  508. hop.genop('raw_free', [v])
  509. else:
  510. assert False, "%s has no support for free with flavor %r" % (self, flavor)
  511. def gct_gc_can_move(self, hop):
  512. return hop.cast_result(rmodel.inputconst(lltype.Bool, False))
  513. def gct_shrink_array(self, hop):
  514. return hop.cast_result(rmodel.inputconst(lltype.Bool, False))