tree_ir.py 77 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955
  1. # NOTE: NOP_LITERAL abuses a mechanic of the modelverse kernel. Specifically,
  2. # whenever the `ModelverseKernel.execute_yields` method returns `None`, then
  3. # the server built around it takes that as a hint that an instruction's phase
  4. # has been completed. The server interrupts the kernel's thread of execution
  5. # when it remarks that an instruction has completed a phase (i.e., when `None`
  6. # is returned by `ModelverseKernel.execute_yields`) and proceeds to check for
  7. # input and output.
  8. #
  9. # In assembly language, a nop is usually used as a point at which a thread of
  10. # execution can be terminated. It follows from the paragraph above that what
  11. # the interpreter does is more or less equivalent to placing nops after every
  12. # instruction. It is worthwhile to remark that JIT-compiled code cannot rely
  13. # on the kernel to interrupt the thread of execution automatically during a
  14. # jitted function's execution -- jitted functions are considered equivalent
  15. # to a single instruction as far as the kernel is concerned. A nop will be
  16. # inserted _after_ the function call (if it is called from interpreted code)
  17. # but that does not suffice for IO, which needs the input/output processing
  18. # to be performed during function execution.
  19. #
  20. # For this reason, the JIT must strategically interrupt the execution of the
  21. # functions it compiles. In other words, it must insert its own nops.
  22. # Here comes the interesting part: a nop is equivalent to `yield None`,
  23. # because that will persuade `ModelverseKernel.execute_yields` to relay the
  24. # `None` marker value to the server, without terminating the current
  25. # generator.
  26. # Let's just agree to disagree on map vs list comprehensions, pylint.
  27. # pylint: disable=I0011,W0141
  28. import modelverse_jit.source_map as source_map
  29. import sys
  30. PROFILING = False
  31. NOP_LITERAL = None
  32. """A literal that results in a nop during which execution may be interrupted
  33. when yielded."""
  34. UNKNOWN_RESULT_TYPE = 'unknown'
  35. """The result type for instructions that produce either primitive values or
  36. references to nodes."""
  37. PRIMITIVE_RESULT_TYPE = 'primitive'
  38. """The result type for instructions that produce primitive values."""
  39. NODE_RESULT_TYPE = 'node'
  40. """The result type for instructions that produce references to nodes."""
  41. NO_RESULT_TYPE = 'nothing'
  42. """The result type for instructions that no result."""
  43. def result_type_intersection(first_type, second_type):
  44. """Computes the intersection of the given result types."""
  45. if first_type == second_type:
  46. return first_type
  47. elif ((first_type == PRIMITIVE_RESULT_TYPE and second_type == UNKNOWN_RESULT_TYPE)
  48. or (first_type == UNKNOWN_RESULT_TYPE and second_type == PRIMITIVE_RESULT_TYPE)):
  49. return PRIMITIVE_RESULT_TYPE
  50. elif ((first_type == NODE_RESULT_TYPE and second_type == UNKNOWN_RESULT_TYPE)
  51. or (first_type == UNKNOWN_RESULT_TYPE and second_type == NODE_RESULT_TYPE)):
  52. return NODE_RESULT_TYPE
  53. else:
  54. return NO_RESULT_TYPE
  55. def result_type_union(first_type, second_type):
  56. """Computes the union of the given result types."""
  57. if first_type == second_type:
  58. return first_type
  59. elif ((first_type == PRIMITIVE_RESULT_TYPE and second_type == NO_RESULT_TYPE)
  60. or (first_type == NO_RESULT_TYPE and second_type == PRIMITIVE_RESULT_TYPE)):
  61. return PRIMITIVE_RESULT_TYPE
  62. elif ((first_type == NODE_RESULT_TYPE and second_type == NO_RESULT_TYPE)
  63. or (first_type == NO_RESULT_TYPE and second_type == NODE_RESULT_TYPE)):
  64. return NODE_RESULT_TYPE
  65. else:
  66. return UNKNOWN_RESULT_TYPE
  67. class Instruction(object):
  68. """A base class for instructions. An instruction is essentially a syntax
  69. node that must first be defined, and can only then be used."""
  70. def __init__(self):
  71. self.result_type_cache = None
  72. self.has_definition_cache = None
  73. def get_result_type(self):
  74. """Gets this instruction's result type."""
  75. if self.result_type_cache is None:
  76. self.result_type_cache = self.get_result_type_impl()
  77. return self.result_type_cache
  78. def has_result(self):
  79. """Tells if this instruction computes a result."""
  80. return self.get_result_type() != NO_RESULT_TYPE
  81. def has_definition(self):
  82. """Tells if this instruction requires a definition."""
  83. if self.has_definition_cache is None:
  84. self.has_definition_cache = self.has_definition_impl()
  85. return self.has_definition_cache
  86. def get_result_type_impl(self):
  87. """Gets this instruction's result type."""
  88. return PRIMITIVE_RESULT_TYPE
  89. def has_definition_impl(self):
  90. """Tells if this instruction requires a definition."""
  91. return True
  92. def get_result_name_override(self, code_generator):
  93. """Gets a value that overrides the code generator's result name for this
  94. instruction if it is not None."""
  95. return None
  96. def has_result_temporary(self):
  97. """Tells if this instruction stores its result in a temporary."""
  98. return self.has_result()
  99. def generate_python_def(self, code_generator):
  100. """Generates a Python statement that executes this instruction.
  101. The statement is appended immediately to the code generator."""
  102. if self.has_definition():
  103. raise NotImplementedError()
  104. else:
  105. code_generator.append_line('pass')
  106. def generate_python_use(self, code_generator):
  107. """Generates a Python expression that retrieves this instruction's
  108. result. The expression is returned as a string."""
  109. if self.has_result():
  110. return code_generator.get_result_name(self)
  111. else:
  112. return 'None'
  113. def get_children(self):
  114. """Gets this instruction's sequence of child instructions."""
  115. raise NotImplementedError()
  116. def create(self, new_children):
  117. """Creates a new instruction of this type from the given sequence of child instructions."""
  118. raise NotImplementedError()
  119. def simplify_node(self):
  120. """Applies basic simplification to this instruction only."""
  121. return self
  122. def simplify(self):
  123. """Applies basic simplification to this instruction and all of its children."""
  124. # This fairly convoluted one-liner first simplifies all children, then creates
  125. # an instruction from the simplified children, and finally simplifies that top-level
  126. # instruction.
  127. return self.create([c.simplify() for c in self.get_children()]).simplify_node()
  128. def __str__(self):
  129. code_generator = PythonGenerator()
  130. self.generate_python_def(code_generator)
  131. return str(code_generator)
  132. class PythonGenerator(object):
  133. """Generates Python code from instructions."""
  134. def __init__(self, combine_state_definitions=True):
  135. self.code = []
  136. self.state_definitions = []
  137. self.state_definition_names = set()
  138. self.indentation_string = ' ' * 4
  139. self.indentation = 0
  140. self.result_name_dict = {}
  141. self.combine_state_definitions = combine_state_definitions
  142. self.source_map_builder = source_map.SourceMapBuilder()
  143. def append(self, text):
  144. """Appends the given string to this code generator."""
  145. self.flush_state_definitions()
  146. self.code.append(text)
  147. for _ in range(text.count('\n')):
  148. self.source_map_builder.append_line()
  149. def append_indentation(self):
  150. """Appends indentation to the code generator."""
  151. self.append(self.indentation_string * self.indentation)
  152. def append_line(self, line=None):
  153. """Appends the indentation string followed by the given string (if any)
  154. and a newline to the code generator."""
  155. self.append_indentation()
  156. if line is not None:
  157. self.append(line)
  158. self.append('\n')
  159. def increase_indentation(self):
  160. """Increases the code generator's indentation by one indent."""
  161. self.flush_state_definitions()
  162. self.indentation += 1
  163. def decrease_indentation(self):
  164. """Decreases the code generator's indentation by one indent."""
  165. self.flush_state_definitions()
  166. self.indentation -= 1
  167. def get_result_name(self, instruction, advised_name=None):
  168. """Gets the name of the given instruction's result variable."""
  169. if instruction not in self.result_name_dict:
  170. override_name = instruction.get_result_name_override(self)
  171. if override_name is not None:
  172. self.result_name_dict[instruction] = override_name
  173. elif advised_name is not None:
  174. self.result_name_dict[instruction] = advised_name
  175. else:
  176. self.result_name_dict[instruction] = \
  177. 'tmp' + str(len(self.result_name_dict))
  178. result = self.result_name_dict[instruction]
  179. if result in self.state_definition_names:
  180. # This might mean that we're trying to access a name that is
  181. # defined by the current block of state definitions. So we need
  182. # to flush the state definitions now.
  183. self.flush_state_definitions()
  184. return result
  185. def append_definition(self, lhs, rhs):
  186. """Defines the first instruction's result variable as the second
  187. instruction's result."""
  188. self.append_line(
  189. self.get_result_name(lhs) + ' = ' + rhs.generate_python_use(self))
  190. def append_move_definition(self, lhs, rhs):
  191. """First defines the second instruction, then defines the first
  192. instruction as the result of the second."""
  193. if rhs.has_definition():
  194. # Retrieve the result name for the lhs.
  195. lhs_result_name = self.get_result_name(lhs)
  196. # Encourage the rhs to take on the same result name as the lhs.
  197. rhs_result_name = self.get_result_name(rhs, lhs_result_name)
  198. # Generate the rhs' definition.
  199. rhs.generate_python_def(self)
  200. # Only perform an assignment if it's truly necessary.
  201. if lhs_result_name != rhs_result_name or not rhs.has_result_temporary():
  202. self.append_definition(lhs, rhs)
  203. else:
  204. self.append_definition(lhs, rhs)
  205. def append_state_definition(self, lhs, opcode, args):
  206. """Appends a definition that queries the modelverse state."""
  207. result_name = self.get_result_name(lhs)
  208. request_tuple = '(%s, [%s])' % (
  209. repr(opcode),
  210. ', '.join([arg_i.generate_python_use(self) for arg_i in args]))
  211. self.state_definitions.append((result_name, request_tuple))
  212. self.state_definition_names.add(result_name)
  213. if not self.combine_state_definitions:
  214. self.flush_state_definitions()
  215. def flush_state_definitions(self):
  216. """Flushes the list of state-access definitions to the generated code."""
  217. state_defs = self.state_definitions
  218. if len(state_defs) > 0:
  219. # Clear state_definitions _before_ calling append_line, because append_line
  220. # will call flush_state_definitions. Clearing state_definitions afterward
  221. # will result in infinite recursion.
  222. self.state_definitions = []
  223. self.state_definition_names = set()
  224. if len(state_defs) == 1:
  225. self.append_line('%s, = yield [%s]' % state_defs[0])
  226. else:
  227. self.append_line(
  228. "%s = yield [%s]" % (
  229. ', '.join([name for name, _ in state_defs]),
  230. ', '.join([def_val for _, def_val in state_defs])))
  231. def __str__(self):
  232. self.flush_state_definitions()
  233. return ''.join(self.code)
  234. class VoidInstruction(Instruction):
  235. """A base class for instructions that do not return a value."""
  236. def get_result_type_impl(self):
  237. """Gets this instruction's result type."""
  238. return NO_RESULT_TYPE
  239. def get_children(self):
  240. """Gets this instruction's sequence of child instructions."""
  241. return []
  242. def create(self, new_children):
  243. """Creates a new instruction of this type from the given sequence of child instructions."""
  244. return self
  245. class EmptyInstruction(VoidInstruction):
  246. """Represents the empty instruction, which does nothing."""
  247. def has_definition_impl(self):
  248. """Tells if this instruction requires a definition."""
  249. return False
  250. def __repr__(self):
  251. return "EmptyInstruction()"
  252. class SelectInstruction(Instruction):
  253. """Represents a select-instruction: an instruction that defines one of two
  254. child instructions, and sets its result to the defined child's result."""
  255. def __init__(self, condition, if_clause, else_clause):
  256. Instruction.__init__(self)
  257. self.condition = condition
  258. self.if_clause = if_clause
  259. self.else_clause = else_clause
  260. def get_result_type_impl(self):
  261. """Gets this instruction's result type."""
  262. return result_type_intersection(
  263. self.if_clause.get_result_type(),
  264. self.else_clause.get_result_type())
  265. def simplify_node(self):
  266. """Applies basic simplification to this instruction only."""
  267. if isinstance(self.condition, LiteralInstruction):
  268. return self.if_clause if self.condition.literal else self.else_clause
  269. else:
  270. return SelectInstruction(self.condition, self.if_clause, self.else_clause)
  271. def get_children(self):
  272. """Gets this instruction's sequence of child instructions."""
  273. return [self.condition, self.if_clause, self.else_clause]
  274. def create(self, new_children):
  275. """Creates a new instruction of this type from the given sequence of child instructions."""
  276. condition, if_clause, else_clause = new_children
  277. return SelectInstruction(condition, if_clause, else_clause)
  278. def generate_python_if(self, code_generator, is_elif=False):
  279. """Generates Python code for this instruction."""
  280. if_has_result = self.has_result()
  281. if self.condition.has_definition():
  282. self.condition.generate_python_def(code_generator)
  283. code_generator.append_line(
  284. ('elif ' if is_elif else 'if ') +
  285. self.condition.generate_python_use(code_generator) + ':')
  286. code_generator.increase_indentation()
  287. if if_has_result:
  288. code_generator.append_move_definition(self, self.if_clause)
  289. else:
  290. self.if_clause.generate_python_def(code_generator)
  291. code_generator.decrease_indentation()
  292. else_has_def = self.else_clause.has_definition()
  293. if else_has_def or if_has_result:
  294. if (isinstance(self.else_clause, SelectInstruction) and
  295. not self.else_clause.condition.has_definition()):
  296. self.else_clause.generate_python_if(code_generator, True)
  297. if if_has_result:
  298. code_generator.increase_indentation()
  299. code_generator.append_definition(self, self.else_clause)
  300. code_generator.decrease_indentation()
  301. else:
  302. code_generator.append_line('else:')
  303. code_generator.increase_indentation()
  304. if if_has_result:
  305. code_generator.append_move_definition(self, self.else_clause)
  306. else:
  307. self.else_clause.generate_python_def(code_generator)
  308. code_generator.decrease_indentation()
  309. def generate_python_def(self, code_generator):
  310. """Generates Python code for this instruction."""
  311. return self.generate_python_if(code_generator)
  312. def __repr__(self):
  313. return "SelectInstruction(%r, %r, %r)" % (self.condition, self.if_clause, self.else_clause)
  314. class SwitchInstruction(VoidInstruction):
  315. """An instruction that evaluates an instruction based on which condition matches."""
  316. def __init__(self, conditions_and_clauses):
  317. VoidInstruction.__init__(self)
  318. self.conditions_and_clauses = conditions_and_clauses
  319. assert not any([cond.has_definition() for cond, _ in self.conditions_and_clauses])
  320. def simplify_node(self):
  321. """Applies basic simplification to this instruction only."""
  322. if len(self.conditions_and_clauses) == 0:
  323. return EmptyInstruction()
  324. elif len(self.conditions_and_clauses) == 1:
  325. cond, clause = next(iter(self.conditions_and_clauses))
  326. return SelectInstruction(cond, IgnoreInstruction(clause), EmptyInstruction())
  327. else:
  328. return self
  329. def get_children(self):
  330. """Gets this instruction's sequence of child instructions."""
  331. results = []
  332. for cond, body in self.conditions_and_clauses:
  333. results.append(cond)
  334. results.append(body)
  335. return results
  336. def create(self, new_children):
  337. """Creates a new instruction of this type from the given sequence of child instructions."""
  338. new_pairs = []
  339. for i in range(len(self.conditions_and_clauses)):
  340. new_pairs.append((new_children[2 * i], new_children[2 * i + 1]))
  341. return SwitchInstruction(new_pairs)
  342. def generate_python_def(self, code_generator):
  343. """Generates Python code for this instruction."""
  344. if_keyword = 'if '
  345. for condition, clause in self.conditions_and_clauses:
  346. code_generator.append_line(
  347. if_keyword + condition.generate_python_use(code_generator) + ':')
  348. code_generator.increase_indentation()
  349. clause.generate_python_def(code_generator)
  350. code_generator.decrease_indentation()
  351. if_keyword = 'elif '
  352. def __repr__(self):
  353. return "SwitchInstruction(%r)" % self.conditions_and_clauses
  354. class ReturnInstruction(VoidInstruction):
  355. """Represents a return-instruction."""
  356. def __init__(self, value):
  357. VoidInstruction.__init__(self)
  358. self.value = value
  359. def get_children(self):
  360. """Gets this instruction's sequence of child instructions."""
  361. return [self.value]
  362. def create(self, new_children):
  363. """Creates a new instruction of this type from the given sequence of child instructions."""
  364. value, = new_children
  365. return ReturnInstruction(value)
  366. def simplify_node(self):
  367. """Applies basic simplification to this instruction only."""
  368. # If we have a return whose value is a call, then we can rewrite
  369. # that as a tail call and save us a stack frame.
  370. def rewrite_call(instruction):
  371. """Rewrites the given instruction in tail-call form, or returns
  372. None."""
  373. if isinstance(instruction, RunGeneratorFunctionInstruction):
  374. return RunTailGeneratorFunctionInstruction(*instruction.get_children())
  375. elif isinstance(instruction, CompoundInstruction):
  376. snd_rewritten = rewrite_call(instruction.second)
  377. if snd_rewritten is not None:
  378. return CompoundInstruction(instruction.first, snd_rewritten)
  379. return None
  380. rewritten_value = rewrite_call(self.value)
  381. if rewritten_value is None:
  382. return self
  383. else:
  384. # We don't even need to create a return here, because tail calls terminate
  385. # the current stack frame anyway.
  386. return rewritten_value
  387. def generate_python_def(self, code_generator):
  388. """Generates Python code for this instruction."""
  389. if self.value.has_definition():
  390. self.value.generate_python_def(code_generator)
  391. if PROFILING:
  392. code_generator.append_line("print('%s : %s : %s' % (___profiling[0], time.time() - ___profiling[1], time.time() - ___profiling[1] - ___profiling[2]))")
  393. code_generator.append_line(
  394. 'raise PrimitiveFinished(' +
  395. self.value.generate_python_use(code_generator) +
  396. ')')
  397. def __repr__(self):
  398. return "ReturnInstruction(%r)" % self.value
  399. class RaiseInstruction(VoidInstruction):
  400. """An instruction that raises an error."""
  401. def __init__(self, value):
  402. VoidInstruction.__init__(self)
  403. self.value = value
  404. def get_children(self):
  405. """Gets this instruction's sequence of child instructions."""
  406. return [self.value]
  407. def create(self, new_children):
  408. """Creates a new instruction of this type from the given sequence of child instructions."""
  409. value, = new_children
  410. return RaiseInstruction(value)
  411. def generate_python_def(self, code_generator):
  412. """Generates Python code for this instruction."""
  413. self.value.generate_python_def(code_generator)
  414. code_generator.append_line(
  415. 'raise ' + self.value.generate_python_use(code_generator))
  416. def __repr__(self):
  417. return "RaiseInstruction(%r)" % self.value
  418. class CallInstruction(Instruction):
  419. """An instruction that performs a simple call."""
  420. def __init__(self, target, argument_list):
  421. Instruction.__init__(self)
  422. self.target = target
  423. self.argument_list = argument_list
  424. def get_children(self):
  425. """Gets this instruction's sequence of child instructions."""
  426. return [self.target] + self.argument_list
  427. def create(self, new_children):
  428. """Creates a new instruction of this type from the given sequence of child instructions."""
  429. return CallInstruction(new_children[0], new_children[1:])
  430. def generate_python_def(self, code_generator):
  431. """Generates Python code for this instruction."""
  432. if self.target.has_definition():
  433. self.target.generate_python_def(code_generator)
  434. for arg in self.argument_list:
  435. if arg.has_definition():
  436. arg.generate_python_def(code_generator)
  437. code_generator.append_line(
  438. '%s = %s(%s)' % (
  439. code_generator.get_result_name(self),
  440. self.target.generate_python_use(code_generator),
  441. ', '.join([arg.generate_python_use(code_generator) for arg in self.argument_list])))
  442. def __repr__(self):
  443. return "CallInstruction(%r, %r)" % (self.target, self.argument_list)
  444. class PrintInstruction(VoidInstruction):
  445. """An instruction that prints a value."""
  446. def __init__(self, argument):
  447. VoidInstruction.__init__(self)
  448. self.argument = argument
  449. assert isinstance(argument, Instruction)
  450. def get_children(self):
  451. """Gets this instruction's sequence of child instructions."""
  452. return [self.argument]
  453. def create(self, new_children):
  454. """Creates a new instruction of this type from the given sequence of child instructions."""
  455. arg, = new_children
  456. return PrintInstruction(arg)
  457. def generate_python_def(self, code_generator):
  458. """Generates Python code for this instruction."""
  459. if self.argument.has_definition():
  460. self.argument.generate_python_def(code_generator)
  461. code_generator.append_line(
  462. 'print(%s)' % (
  463. self.argument.generate_python_use(code_generator)))
  464. def __repr__(self):
  465. return "PrintInstruction(%r)" % self.argument
  466. class DebugInfoInstruction(Instruction):
  467. """An instruction that defines debug information for its child instruction."""
  468. def __init__(self, value, debug_info):
  469. Instruction.__init__(self)
  470. self.value = value
  471. self.debug_info = debug_info
  472. def has_definition_impl(self):
  473. """Tells if this instruction requires a definition."""
  474. return self.value.has_definition()
  475. def has_result_temporary(self):
  476. """Tells if this instruction stores its result in a temporary."""
  477. return self.value.has_result_temporary()
  478. def get_result_type_impl(self):
  479. """Gets this instruction's result type."""
  480. return self.value.get_result_type()
  481. def get_result_name_override(self, code_generator):
  482. """Gets a value that overrides the code generator's result name for this
  483. instruction if it is not None."""
  484. return self.value.get_result_name_override(code_generator)
  485. def get_children(self):
  486. """Gets this instruction's sequence of child instructions."""
  487. return [self.value]
  488. def create(self, new_children):
  489. """Creates a new instruction of this type from the given sequence of child instructions."""
  490. arg, = new_children
  491. return DebugInfoInstruction(arg, self.debug_info)
  492. def generate_python_def(self, code_generator):
  493. """Generates Python code for this instruction."""
  494. if self.has_definition():
  495. code_generator.source_map_builder.push_debug_info(self.debug_info)
  496. code_generator.append_move_definition(self, self.value)
  497. code_generator.source_map_builder.pop_debug_info()
  498. def generate_python_use(self, code_generator):
  499. """Generates a Python expression that retrieves this instruction's
  500. result. The expression is returned as a string."""
  501. return self.value.generate_python_use(code_generator)
  502. def __repr__(self):
  503. return "DebugInfoInstruction(%r, %r)" % (self.value, self.debug_info)
  504. class BinaryInstruction(Instruction):
  505. """An instruction that performs a binary operation."""
  506. def __init__(self, lhs, operator, rhs):
  507. Instruction.__init__(self)
  508. self.lhs = lhs
  509. self.operator = operator
  510. self.rhs = rhs
  511. def has_definition_impl(self):
  512. """Tells if this instruction requires a definition."""
  513. return self.lhs.has_definition() or self.rhs.has_definition()
  514. def get_children(self):
  515. """Gets this instruction's sequence of child instructions."""
  516. return [self.lhs, self.rhs]
  517. def create(self, new_children):
  518. """Creates a new instruction of this type from the given sequence of child instructions."""
  519. lhs, rhs, = new_children
  520. return BinaryInstruction(lhs, self.operator, rhs)
  521. def simplify_node(self):
  522. """Applies basic simplification to this instruction only."""
  523. if isinstance(self.lhs, LiteralInstruction) and isinstance(self.rhs, LiteralInstruction):
  524. # TODO: there's probably a better way to do this than with eval.
  525. return LiteralInstruction(
  526. eval('%s %s %s' % (repr(self.lhs.literal), self.operator, repr(self.rhs.literal))))
  527. else:
  528. return self
  529. def has_result_temporary(self):
  530. """Tells if this instruction stores its result in a temporary."""
  531. return False
  532. def generate_python_use(self, code_generator):
  533. """Generates a Python expression that retrieves this instruction's
  534. result. The expression is returned as a string."""
  535. return '(%s %s %s)' % (
  536. self.lhs.generate_python_use(code_generator),
  537. self.operator,
  538. self.rhs.generate_python_use(code_generator))
  539. def generate_python_def(self, code_generator):
  540. """Generates a Python statement that executes this instruction.
  541. The statement is appended immediately to the code generator."""
  542. lhs_has_def, rhs_has_def = self.lhs.has_definition(), self.rhs.has_definition()
  543. if lhs_has_def:
  544. self.lhs.generate_python_def(code_generator)
  545. if rhs_has_def:
  546. self.rhs.generate_python_def(code_generator)
  547. elif rhs_has_def:
  548. self.rhs.generate_python_def(code_generator)
  549. else:
  550. code_generator.append_line('pass')
  551. def __repr__(self):
  552. return "BinaryInstruction(%r, %r, %r)" % (self.lhs, self.operator, self.rhs)
  553. class UnaryInstruction(Instruction):
  554. """An instruction that performs a unary operation."""
  555. def __init__(self, operator, operand):
  556. Instruction.__init__(self)
  557. self.operator = operator
  558. self.operand = operand
  559. def has_definition_impl(self):
  560. """Tells if this instruction requires a definition."""
  561. return self.operand.has_definition()
  562. def get_children(self):
  563. """Gets this instruction's sequence of child instructions."""
  564. return [self.operand]
  565. def has_result_temporary(self):
  566. """Tells if this instruction stores its result in a temporary."""
  567. return False
  568. def create(self, new_children):
  569. """Creates a new instruction of this type from the given sequence of child instructions."""
  570. operand, = new_children
  571. return UnaryInstruction(self.operator, operand)
  572. def simplify_node(self):
  573. """Applies basic simplification to this instruction only."""
  574. if isinstance(self.operand, LiteralInstruction):
  575. # TODO: there's probably a better way to do this than with eval.
  576. return LiteralInstruction(
  577. eval('%s %s' % (self.operator, repr(self.operand.literal))))
  578. else:
  579. return self
  580. def generate_python_use(self, code_generator):
  581. """Generates a Python expression that retrieves this instruction's
  582. result. The expression is returned as a string."""
  583. return '(%s %s)' % (
  584. self.operator,
  585. self.operand.generate_python_use(code_generator))
  586. def generate_python_def(self, code_generator):
  587. """Generates a Python statement that executes this instruction.
  588. The statement is appended immediately to the code generator."""
  589. if self.operand.has_definition():
  590. self.operand.generate_python_def(code_generator)
  591. else:
  592. code_generator.append_line('pass')
  593. def __repr__(self):
  594. return "UnaryInstruction(%r, %r)" % (self.operator, self.operand)
  595. class LoopInstruction(VoidInstruction):
  596. """Represents a loop-instruction, which loops until broken."""
  597. def __init__(self, body):
  598. VoidInstruction.__init__(self)
  599. self.body = body
  600. def get_children(self):
  601. """Gets this instruction's sequence of child instructions."""
  602. return [self.body]
  603. def create(self, new_children):
  604. """Creates a new instruction of this type from the given sequence of child instructions."""
  605. body, = new_children
  606. return LoopInstruction(body)
  607. def generate_python_def(self, code_generator):
  608. """Generates Python code for this instruction."""
  609. code_generator.append_line('while 1:')
  610. code_generator.increase_indentation()
  611. self.body.generate_python_def(code_generator)
  612. code_generator.decrease_indentation()
  613. def __repr__(self):
  614. return "LoopInstruction(%r)" % self.body
  615. class BreakInstruction(VoidInstruction):
  616. """Represents a break-instruction."""
  617. def generate_python_def(self, code_generator):
  618. """Generates Python code for this instruction."""
  619. code_generator.append_line('break')
  620. def __repr__(self):
  621. return "BreakInstruction()"
  622. class ContinueInstruction(VoidInstruction):
  623. """Represents a continue-instruction."""
  624. def generate_python_def(self, code_generator):
  625. """Generates Python code for this instruction."""
  626. code_generator.append_line('continue')
  627. def __repr__(self):
  628. return "ContinueInstruction()"
  629. class IgnoreInstruction(VoidInstruction):
  630. """Represents an instruction that evaluates its operand, and then discards
  631. the result."""
  632. def __init__(self, value):
  633. VoidInstruction.__init__(self)
  634. self.value = value
  635. def has_definition_impl(self):
  636. """Tells if this instruction requires a definition."""
  637. return self.value.has_definition()
  638. def get_children(self):
  639. """Gets this instruction's sequence of child instructions."""
  640. return [self.value]
  641. def create(self, new_children):
  642. """Creates a new instruction of this type from the given sequence of child instructions."""
  643. value, = new_children
  644. return IgnoreInstruction(value)
  645. def simplify_node(self):
  646. """Applies basic simplification to this instruction and its children."""
  647. if not self.value.has_result():
  648. return self.value
  649. else:
  650. return self
  651. def generate_python_def(self, code_generator):
  652. """Generates Python code for this instruction."""
  653. self.value.generate_python_def(code_generator)
  654. def __repr__(self):
  655. return "IgnoreInstruction(%r)" % self.value
  656. class CompoundInstruction(Instruction):
  657. """Represents an instruction that evaluates two other instructions
  658. in order, and returns the second instruction's result."""
  659. def __init__(self, first, second):
  660. Instruction.__init__(self)
  661. self.first = first
  662. self.second = second
  663. def get_result_type_impl(self):
  664. """Gets this instruction's result type."""
  665. if self.second.has_result():
  666. return self.second.get_result_type()
  667. else:
  668. return self.first.get_result_type()
  669. def get_children(self):
  670. """Gets this instruction's sequence of child instructions."""
  671. return [self.first, self.second]
  672. def create(self, new_children):
  673. """Creates a new instruction of this type from the given sequence of child instructions."""
  674. first, second = new_children
  675. return CompoundInstruction(first, second)
  676. def simplify_node(self):
  677. """Applies basic simplification to this instruction and its children."""
  678. if not self.first.has_definition() and (
  679. not self.first.has_result() or self.second.has_result()):
  680. return self.second
  681. elif (not self.second.has_definition()) and (not self.second.has_result()):
  682. return self.first
  683. else:
  684. return self
  685. def generate_python_def(self, code_generator):
  686. """Generates Python code for this instruction."""
  687. if self.second.has_result():
  688. self.first.generate_python_def(code_generator)
  689. code_generator.append_move_definition(self, self.second)
  690. elif self.first.has_result():
  691. code_generator.append_move_definition(self, self.first)
  692. self.second.generate_python_def(code_generator)
  693. else:
  694. self.first.generate_python_def(code_generator)
  695. self.second.generate_python_def(code_generator)
  696. def __repr__(self):
  697. return "CompoundInstruction(%r, %r)" % (self.first, self.second)
  698. class LiteralInstruction(Instruction):
  699. """Represents an integer, floating-point, string or Boolean literal."""
  700. def __init__(self, literal):
  701. Instruction.__init__(self)
  702. self.literal = literal
  703. def has_definition_impl(self):
  704. """Tells if this instruction requires a definition."""
  705. return False
  706. def has_result_temporary(self):
  707. """Tells if this instruction stores its result in a temporary."""
  708. return False
  709. def get_children(self):
  710. """Gets this instruction's sequence of child instructions."""
  711. return []
  712. def create(self, new_children):
  713. """Creates a new instruction of this type from the given sequence of child instructions."""
  714. return self
  715. def generate_python_use(self, code_generator):
  716. """Generates a Python expression that retrieves this instruction's
  717. result. The expression is returned as a string."""
  718. return repr(self.literal)
  719. def __repr__(self):
  720. return "LiteralInstruction(%r)" % self.literal
  721. class DictionaryLiteralInstruction(Instruction):
  722. """Constructs a dictionary literal."""
  723. def __init__(self, key_value_pairs):
  724. Instruction.__init__(self)
  725. self.key_value_pairs = key_value_pairs
  726. def get_children(self):
  727. """Gets this instruction's sequence of child instructions."""
  728. results = []
  729. for key, val in self.key_value_pairs:
  730. results.append(key)
  731. results.append(val)
  732. return results
  733. def create(self, new_children):
  734. """Creates a new instruction of this type from the given sequence of child instructions."""
  735. new_kv_pairs = []
  736. for i in range(len(self.key_value_pairs)):
  737. new_kv_pairs.append((new_children[2 * i], new_children[2 * i + 1]))
  738. return DictionaryLiteralInstruction(new_kv_pairs)
  739. def has_definition_impl(self):
  740. """Tells if this instruction requires a definition."""
  741. return any(
  742. [key.has_definition() or val.has_definition()
  743. for key, val in self.key_value_pairs])
  744. def has_result_temporary(self):
  745. """Tells if this instruction stores its result in a temporary."""
  746. return False
  747. def simplify(self):
  748. """Applies basic simplification to this instruction and its children."""
  749. return DictionaryLiteralInstruction(
  750. [(key.simplify(), val.simplify()) for key, val in self.key_value_pairs])
  751. def generate_python_def(self, code_generator):
  752. """Generates a Python statement that executes this instruction.
  753. The statement is appended immediately to the code generator."""
  754. for key, val in self.key_value_pairs:
  755. if key.has_definition():
  756. key.generate_python_def(code_generator)
  757. if val.has_definition():
  758. val.generate_python_def(code_generator)
  759. def generate_python_use(self, code_generator):
  760. """Generates a Python expression that retrieves this instruction's
  761. result. The expression is returned as a string."""
  762. return '{%s}' % ', '.join(
  763. ['%s : %s' % (
  764. key.generate_python_use(code_generator),
  765. val.generate_python_use(code_generator))
  766. for key, val in self.key_value_pairs])
  767. def __repr__(self):
  768. return "DictionaryLiteralInstruction(%r)" % self.key_value_pairs
  769. class ListSliceInstruction(Instruction):
  770. """Slices a list."""
  771. def __init__(self, seq, start, end, step):
  772. Instruction.__init__(self)
  773. self.seq = seq
  774. self.start = start
  775. self.end = end
  776. self.step = step
  777. def get_children(self):
  778. """Gets this instruction's sequence of child instructions."""
  779. all_items = (self.seq, self.start, self.end, self.step)
  780. return [item for item in all_items if item is not None]
  781. def create(self, new_children):
  782. """Creates a new instruction of this type from the given sequence of child instructions."""
  783. # pylint: disable=I0011,E1120
  784. args = []
  785. i = 0
  786. for old_item in (self.seq, self.start, self.end, self.step):
  787. if old_item is None:
  788. args.append(None)
  789. else:
  790. args.append(new_children[i])
  791. i += 1
  792. assert len(new_children) == i
  793. assert len(args) == 4
  794. return ListSliceInstruction(*args)
  795. def has_definition_impl(self):
  796. """Tells if this instruction requires a definition."""
  797. return any([item.has_definition() for item in self.get_children()])
  798. def has_result_temporary(self):
  799. """Tells if this instruction stores its result in a temporary."""
  800. return False
  801. def generate_python_def(self, code_generator):
  802. """Generates a Python statement that executes this instruction.
  803. The statement is appended immediately to the code generator."""
  804. for item in self.get_children():
  805. if item.has_definition():
  806. item.generate_python_def(code_generator)
  807. def generate_python_use(self, code_generator):
  808. """Generates a Python expression that retrieves this instruction's
  809. result. The expression is returned as a string."""
  810. return '%s[%s:%s:%s]' % (
  811. self.seq.generate_python_use(code_generator),
  812. '' if self.start is None else self.start.generate_python_use(code_generator),
  813. '' if self.end is None else self.end.generate_python_use(code_generator),
  814. '' if self.step is None else self.step.generate_python_use(code_generator))
  815. def __repr__(self):
  816. return "ListSliceInstruction(%r, %r, %r, %r)" % (self.seq, self.start, self.end, self.step)
  817. class StateInstruction(Instruction):
  818. """An instruction that accesses the modelverse state."""
  819. def get_result_type_impl(self):
  820. """Gets the type of value produced by this instruction."""
  821. return NODE_RESULT_TYPE
  822. def get_opcode(self):
  823. """Gets the opcode for this state instruction."""
  824. raise NotImplementedError()
  825. def get_arguments(self):
  826. """Gets this state instruction's argument list."""
  827. raise NotImplementedError()
  828. def get_children(self):
  829. """Gets this instruction's sequence of child instructions."""
  830. return self.get_arguments()
  831. def create(self, new_children):
  832. """Creates a new instruction of this type from the given sequence of child instructions."""
  833. return type(self)(*new_children)
  834. def generate_python_def(self, code_generator):
  835. """Generates a Python statement that executes this instruction.
  836. The statement is appended immediately to the code generator."""
  837. args = self.get_arguments()
  838. for arg_i in args:
  839. if arg_i.has_definition():
  840. arg_i.generate_python_def(code_generator)
  841. if PROFILING and "CALL" in self.get_opcode():
  842. code_generator.append_line("___profiling_start = time.time()")
  843. code_generator.append_state_definition(self, self.get_opcode(), args)
  844. if PROFILING and "CALL" in self.get_opcode():
  845. code_generator.append_line("___profiling[2] += (time.time() - ___profiling_start)")
  846. def __repr__(self):
  847. return "StateInstruction(%s)" % ', '.join(map(repr, self.get_arguments()))
  848. class RunGeneratorFunctionInstruction(StateInstruction):
  849. """An instruction that runs a generator function."""
  850. def __init__(self, function, argument_dict, result_type=PRIMITIVE_RESULT_TYPE):
  851. StateInstruction.__init__(self)
  852. self.function = function
  853. self.argument_dict = argument_dict
  854. self.result_type_cache = result_type
  855. def get_opcode(self):
  856. """Gets the opcode for this state instruction."""
  857. return "CALL_KWARGS"
  858. def get_arguments(self):
  859. """Gets this state instruction's argument list."""
  860. return [self.function, self.argument_dict]
  861. def create(self, new_children):
  862. """Creates a new instruction of this type from the given sequence of child instructions."""
  863. func, arg_dict = new_children
  864. return RunGeneratorFunctionInstruction(func, arg_dict, self.get_result_type())
  865. class RunTailGeneratorFunctionInstruction(StateInstruction):
  866. """An instruction that runs a generator function."""
  867. def __init__(self, function, argument_dict, result_type=NO_RESULT_TYPE):
  868. StateInstruction.__init__(self)
  869. self.function = function
  870. self.argument_dict = argument_dict
  871. self.result_type_cache = result_type
  872. def get_opcode(self):
  873. """Gets the opcode for this state instruction."""
  874. return "TAIL_CALL_KWARGS"
  875. def get_arguments(self):
  876. """Gets this state instruction's argument list."""
  877. return [self.function, self.argument_dict]
  878. class RegisterDebugInfoInstruction(StateInstruction):
  879. """An instruction that sends a DEBUG_INFO request to the request handler."""
  880. def __init__(self, function_name, function_source_map, function_origin):
  881. StateInstruction.__init__(self)
  882. self.function_name = function_name
  883. self.function_source_map = function_source_map
  884. self.function_origin = function_origin
  885. def get_result_type_impl(self):
  886. """Gets the type of value produced by this instruction."""
  887. return NO_RESULT_TYPE
  888. def get_opcode(self):
  889. """Gets the opcode for this state instruction."""
  890. return "DEBUG_INFO"
  891. def get_arguments(self):
  892. """Gets this state instruction's argument list."""
  893. return [self.function_name, self.function_source_map, self.function_origin]
  894. class VariableName(object):
  895. """A data structure that unifies names across instructions that access the
  896. same variable."""
  897. def __init__(self, name):
  898. self.name = name
  899. def get_result_name_override(self, _):
  900. """Gets a value that overrides the code generator's result name for this
  901. instruction if it is not None."""
  902. return self.name
  903. def __str__(self):
  904. return self.name
  905. def __repr__(self):
  906. return 'VariableName(%r)' % self.name
  907. class VariableInstruction(Instruction):
  908. """A base class for instructions that access variables."""
  909. def __init__(self, name):
  910. Instruction.__init__(self)
  911. if sys.version_info[0] < 3:
  912. if isinstance(name, unicode) or isinstance(name, str) or name is None:
  913. self.name = VariableName(name)
  914. else:
  915. self.name = name
  916. else:
  917. if isinstance(name, str) or name is None:
  918. self.name = VariableName(name)
  919. else:
  920. self.name = name
  921. def get_children(self):
  922. """Gets this instruction's sequence of child instructions."""
  923. raise NotImplementedError()
  924. def create(self, new_children):
  925. """Creates a new instruction of this type from the given sequence of child instructions."""
  926. raise NotImplementedError()
  927. def get_result_name_override(self, code_generator):
  928. """Gets a value that overrides the code generator's result name for this
  929. instruction if it is not None."""
  930. return code_generator.get_result_name(self.name)
  931. class LocalInstruction(VariableInstruction):
  932. """A base class for instructions that access local variables."""
  933. def get_children(self):
  934. """Gets this instruction's sequence of child instructions."""
  935. raise NotImplementedError()
  936. def create(self, new_children):
  937. """Creates a new instruction of this type from the given sequence of child instructions."""
  938. raise NotImplementedError()
  939. def create_load(self):
  940. """Creates an instruction that loads the variable referenced by this instruction."""
  941. return LoadLocalInstruction(self.name)
  942. def create_store(self, value):
  943. """Creates an instruction that stores the given value in the variable referenced
  944. by this instruction."""
  945. return StoreLocalInstruction(self.name, value)
  946. class StoreLocalInstruction(LocalInstruction):
  947. """An instruction that stores a value in a local variable."""
  948. def __init__(self, name, value):
  949. LocalInstruction.__init__(self, name)
  950. self.value = value
  951. def get_children(self):
  952. """Gets this instruction's sequence of child instructions."""
  953. return [self.value]
  954. def create(self, new_children):
  955. """Creates a new instruction of this type from the given sequence of child instructions."""
  956. val, = new_children
  957. return StoreLocalInstruction(self.name, val)
  958. def generate_python_def(self, code_generator):
  959. """Generates a Python statement that executes this instruction.
  960. The statement is appended immediately to the code generator."""
  961. code_generator.append_move_definition(self, self.value)
  962. def __repr__(self):
  963. return 'StoreLocalInstruction(%r, %r)' % (self.name, self.value)
  964. class TupleStoreLocalInstruction(VoidInstruction):
  965. """Assigns a number of values to a number of variables."""
  966. def __init__(self, name_value_pairs):
  967. VoidInstruction.__init__(self)
  968. self.name_value_pairs = name_value_pairs
  969. def get_children(self):
  970. """Gets this instruction's sequence of child instructions."""
  971. return [val for _, val in self.name_value_pairs]
  972. def has_result_temporary(self):
  973. """Tells if this instruction stores its result in a temporary."""
  974. return False
  975. def create(self, new_children):
  976. """Creates a new instruction of this type from the given sequence of child instructions."""
  977. new_name_value_pairs = [
  978. (name, new_value) for (name, _), new_value in zip(self.name_value_pairs, new_children)]
  979. return TupleStoreLocalInstruction(new_name_value_pairs)
  980. def generate_python_def(self, code_generator):
  981. """Generates a Python statement that executes this instruction.
  982. The statement is appended immediately to the code generator."""
  983. tuple_lhs = []
  984. tuple_rhs = []
  985. for name, value in self.name_value_pairs:
  986. if sys.version_info[0] < 3:
  987. if isinstance(name, unicode) or isinstance(name, str) or name is None:
  988. variable = VariableName(name)
  989. else:
  990. variable = name
  991. else:
  992. if isinstance(name, str) or name is None:
  993. variable = VariableName(name)
  994. else:
  995. variable = name
  996. # Retrieve the result name for the variable.
  997. var_result_name = code_generator.get_result_name(variable)
  998. # Encourage the value to take on the same result name as the variable.
  999. value_result_name = code_generator.get_result_name(value, var_result_name)
  1000. if value.has_definition():
  1001. # Generate the value' definition.
  1002. value.generate_python_def(code_generator)
  1003. # Only perform an assignment if it's truly necessary.
  1004. if var_result_name != value_result_name or not value.has_result_temporary():
  1005. tuple_lhs.append(var_result_name)
  1006. tuple_rhs.append(value.generate_python_use(code_generator))
  1007. if len(tuple_lhs) > 0:
  1008. code_generator.append_line(
  1009. '%s = %s' % (', '.join(tuple_lhs), ', '.join(tuple_rhs)))
  1010. def __repr__(self):
  1011. return 'TupleStoreLocalInstruction(%r)' % (self.name_value_pairs)
  1012. class LoadLocalInstruction(LocalInstruction):
  1013. """An instruction that loads a value from a local variable."""
  1014. def has_definition_impl(self):
  1015. """Tells if this instruction requires a definition."""
  1016. return False
  1017. def get_children(self):
  1018. """Gets this instruction's sequence of child instructions."""
  1019. return []
  1020. def create(self, new_children):
  1021. """Creates a new instruction of this type from the given sequence of child instructions."""
  1022. return self
  1023. def __repr__(self):
  1024. return 'LoadLocalInstruction(%r)' % self.name
  1025. class DefineFunctionInstruction(VariableInstruction):
  1026. """An instruction that defines a function."""
  1027. def __init__(self, name, parameter_list, body):
  1028. VariableInstruction.__init__(self, name)
  1029. self.parameter_list = parameter_list
  1030. self.body = body
  1031. def get_children(self):
  1032. """Gets this instruction's sequence of child instructions."""
  1033. return [self.body]
  1034. def create(self, new_children):
  1035. """Creates a new instruction of this type from the given sequence of child instructions."""
  1036. body, = new_children
  1037. return DefineFunctionInstruction(self.name, self.parameter_list, body)
  1038. def generate_python_def(self, code_generator):
  1039. """Generates a Python statement that executes this instruction.
  1040. The statement is appended immediately to the code generator."""
  1041. code_generator.append_line('def %s(%s):' % (
  1042. code_generator.get_result_name(self), ', '.join(self.parameter_list)))
  1043. code_generator.increase_indentation()
  1044. if PROFILING:
  1045. code_generator.append_line("import time")
  1046. code_generator.append_line("___profiling = ['%s', time.time(), 0.0]" % self.name)
  1047. self.body.generate_python_def(code_generator)
  1048. code_generator.decrease_indentation()
  1049. def __repr__(self):
  1050. return 'DefineFunctionInstruction(%r, %r, %r)' % (self.name, self.parameter_list, self.body)
  1051. class LocalExistsInstruction(LocalInstruction):
  1052. """An instruction that checks if a local variable exists."""
  1053. def has_definition_impl(self):
  1054. """Tells if this instruction requires a definition."""
  1055. return False
  1056. def get_children(self):
  1057. """Gets this instruction's sequence of child instructions."""
  1058. return []
  1059. def create(self, new_children):
  1060. """Creates a new instruction of this type from the given sequence of child instructions."""
  1061. return self
  1062. def generate_python_use(self, code_generator):
  1063. """Generates a Python expression that retrieves this instruction's
  1064. result. The expression is returned as a string."""
  1065. return "'%s' in locals()" % self.get_result_name_override(code_generator)
  1066. def __repr__(self):
  1067. return 'LocalExistsInstruction(%r)' % self.name
  1068. class LoadGlobalInstruction(VariableInstruction):
  1069. """An instruction that loads a value from a global variable."""
  1070. def has_definition_impl(self):
  1071. """Tells if this instruction requires a definition."""
  1072. return False
  1073. def get_children(self):
  1074. """Gets this instruction's sequence of child instructions."""
  1075. return []
  1076. def create(self, new_children):
  1077. """Creates a new instruction of this type from the given sequence of child instructions."""
  1078. return self
  1079. def __repr__(self):
  1080. return 'LoadGlobalInstruction(%r)' % self.name
  1081. class StoreGlobalInstruction(VariableInstruction):
  1082. """An instruction that assigns a value to a global variable."""
  1083. def __init__(self, name, value):
  1084. VariableInstruction.__init__(self, name)
  1085. self.value = value
  1086. def get_children(self):
  1087. """Gets this instruction's sequence of child instructions."""
  1088. return [self.value]
  1089. def create(self, new_children):
  1090. """Creates a new instruction of this type from the given sequence of child instructions."""
  1091. val, = new_children
  1092. return StoreGlobalInstruction(self.name, val)
  1093. def generate_python_def(self, code_generator):
  1094. """Generates a Python statement that executes this instruction.
  1095. The statement is appended immediately to the code generator."""
  1096. code_generator.append_move_definition(self, self.value)
  1097. def __repr__(self):
  1098. return 'StoreGlobalInstruction(%r, %r)' % (self.name, self.value)
  1099. class DeclareGlobalInstruction(VariableInstruction):
  1100. """An instruction that declares a name as a global variable."""
  1101. def get_children(self):
  1102. """Gets this instruction's sequence of child instructions."""
  1103. return []
  1104. def get_result_type_impl(self):
  1105. """Gets the type of value produced by this instruction."""
  1106. return NO_RESULT_TYPE
  1107. def has_result_temporary(self):
  1108. """Tells if this instruction stores its result in a temporary."""
  1109. return False
  1110. def create(self, new_children):
  1111. """Creates a new instruction of this type from the given sequence of child instructions."""
  1112. return self
  1113. def generate_python_def(self, code_generator):
  1114. """Generates a Python statement that executes this instruction.
  1115. The statement is appended immediately to the code generator."""
  1116. code_generator.append_line('global %s' % self.name)
  1117. def __repr__(self):
  1118. return 'DeclareGlobalInstruction(%r)' % self.name
  1119. class LoadIndexInstruction(Instruction):
  1120. """An instruction that produces a value by indexing a specified expression with
  1121. a given key."""
  1122. def __init__(self, indexed, key):
  1123. Instruction.__init__(self)
  1124. self.indexed = indexed
  1125. self.key = key
  1126. def has_definition_impl(self):
  1127. """Tells if this instruction requires a definition."""
  1128. return self.indexed.has_definition() or self.key.has_definition()
  1129. def get_children(self):
  1130. """Gets this instruction's sequence of child instructions."""
  1131. return [self.indexed, self.key]
  1132. def has_result_temporary(self):
  1133. """Tells if this instruction stores its result in a temporary."""
  1134. return False
  1135. def create(self, new_children):
  1136. """Creates a new instruction of this type from the given sequence of child instructions."""
  1137. indexed, key = new_children
  1138. return LoadIndexInstruction(indexed, key)
  1139. def generate_python_use(self, code_generator):
  1140. """Generates a Python expression that retrieves this instruction's
  1141. result. The expression is returned as a string."""
  1142. return "%s[%s]" % (
  1143. self.indexed.generate_python_use(code_generator),
  1144. self.key.generate_python_use(code_generator))
  1145. def generate_python_def(self, code_generator):
  1146. """Generates a Python statement that executes this instruction.
  1147. The statement is appended immediately to the code generator."""
  1148. indexed_has_def, key_has_def = self.indexed.has_definition(), self.key.has_definition()
  1149. if indexed_has_def:
  1150. self.indexed.generate_python_def(code_generator)
  1151. if key_has_def:
  1152. self.key.generate_python_def(code_generator)
  1153. if not indexed_has_def and not key_has_def:
  1154. code_generator.append_line('pass')
  1155. def __repr__(self):
  1156. return 'LoadIndexInstruction(%r, %r)' % (self.indexed, self.key)
  1157. class LoadMemberInstruction(Instruction):
  1158. """An instruction that produces a value by loading a member from a container."""
  1159. def __init__(self, container, member_name):
  1160. Instruction.__init__(self)
  1161. self.container = container
  1162. self.member_name = member_name
  1163. def has_definition_impl(self):
  1164. """Tells if this instruction requires a definition."""
  1165. return self.container.has_definition()
  1166. def get_children(self):
  1167. """Gets this instruction's sequence of child instructions."""
  1168. return [self.container]
  1169. def has_result_temporary(self):
  1170. """Tells if this instruction stores its result in a temporary."""
  1171. return False
  1172. def create(self, new_children):
  1173. """Creates a new instruction of this type from the given sequence of child instructions."""
  1174. container, = new_children
  1175. return LoadMemberInstruction(container, self.member_name)
  1176. def generate_python_def(self, code_generator):
  1177. """Generates a Python statement that executes this instruction.
  1178. The statement is appended immediately to the code generator."""
  1179. self.container.generate_python_def(code_generator)
  1180. def generate_python_use(self, code_generator):
  1181. """Generates a Python expression that retrieves this instruction's
  1182. result. The expression is returned as a string."""
  1183. return "%s.%s" % (
  1184. self.container.generate_python_use(code_generator),
  1185. self.member_name)
  1186. def __repr__(self):
  1187. return 'LoadMemberInstruction(%r, %r)' % (self.container, self.member_name)
  1188. class StoreMemberInstruction(VoidInstruction):
  1189. """An instruction that stores a value in a container member."""
  1190. def __init__(self, container, member_name, value):
  1191. VoidInstruction.__init__(self)
  1192. self.container = container
  1193. self.member_name = member_name
  1194. self.value = value
  1195. def has_definition_impl(self):
  1196. """Tells if this instruction requires a definition."""
  1197. return True
  1198. def get_children(self):
  1199. """Gets this instruction's sequence of child instructions."""
  1200. return [self.container, self.value]
  1201. def create(self, new_children):
  1202. """Creates a new instruction of this type from the given sequence of child instructions."""
  1203. container, value = new_children
  1204. return StoreMemberInstruction(container, self.member_name, value)
  1205. def generate_python_def(self, code_generator):
  1206. """Generates a Python statement that executes this instruction.
  1207. The statement is appended immediately to the code generator."""
  1208. if self.container.has_definition():
  1209. self.container.generate_python_def(code_generator)
  1210. code_generator.append_line('%s.%s = %s' % (
  1211. self.container.generate_python_use(code_generator),
  1212. self.member_name,
  1213. self.value.generate_python_use(code_generator)))
  1214. def __repr__(self):
  1215. return 'StoreMemberInstruction(%r, %r, %r)' % (self.container, self.member_name, self.value)
  1216. class NopInstruction(VoidInstruction):
  1217. """A nop instruction, which allows for the kernel's thread of execution to be interrupted."""
  1218. def generate_python_def(self, code_generator):
  1219. """Generates a Python statement that executes this instruction.
  1220. The statement is appended immediately to the code generator."""
  1221. code_generator.append_line('yield %s' % repr(NOP_LITERAL))
  1222. def __repr__(self):
  1223. return 'NopInstruction()'
  1224. class ReadValueInstruction(StateInstruction):
  1225. """An instruction that reads a value from a node."""
  1226. def __init__(self, node_id):
  1227. StateInstruction.__init__(self)
  1228. self.node_id = node_id
  1229. def get_result_type_impl(self):
  1230. """Gets the type of value produced by this instruction."""
  1231. return PRIMITIVE_RESULT_TYPE
  1232. def simplify_node(self):
  1233. """Applies basic simplification to this instruction only."""
  1234. if isinstance(self.node_id, CreateNodeWithValueInstruction):
  1235. return self.node_id.value
  1236. else:
  1237. return self
  1238. def get_opcode(self):
  1239. """Gets the opcode for this state instruction."""
  1240. return "RV"
  1241. def get_arguments(self):
  1242. """Gets this state instruction's argument list."""
  1243. return [self.node_id]
  1244. class ReadDictionaryValueInstruction(StateInstruction):
  1245. """An instruction that reads a dictionary value."""
  1246. def __init__(self, node_id, key):
  1247. StateInstruction.__init__(self)
  1248. self.node_id = node_id
  1249. self.key = key
  1250. def get_opcode(self):
  1251. """Gets the opcode for this state instruction."""
  1252. return "RD"
  1253. def get_arguments(self):
  1254. """Gets this state instruction's argument list."""
  1255. return [self.node_id, self.key]
  1256. class ReadDictionaryNodeInstruction(StateInstruction):
  1257. """An instruction that reads a dictionary node."""
  1258. def __init__(self, node_id, key):
  1259. StateInstruction.__init__(self)
  1260. self.node_id = node_id
  1261. self.key = key
  1262. def get_opcode(self):
  1263. """Gets the opcode for this state instruction."""
  1264. return "RDN"
  1265. def get_arguments(self):
  1266. """Gets this state instruction's argument list."""
  1267. return [self.node_id, self.key]
  1268. class ReadDictionaryEdgeInstruction(StateInstruction):
  1269. """An instruction that reads a dictionary edge."""
  1270. def __init__(self, node_id, key):
  1271. StateInstruction.__init__(self)
  1272. self.node_id = node_id
  1273. self.key = key
  1274. def get_opcode(self):
  1275. """Gets the opcode for this state instruction."""
  1276. return "RDE"
  1277. def get_arguments(self):
  1278. """Gets this state instruction's argument list."""
  1279. return [self.node_id, self.key]
  1280. class ReadDictionaryKeysInstruction(StateInstruction):
  1281. """An instruction that reads all keys from a dictionary."""
  1282. def __init__(self, node_id):
  1283. StateInstruction.__init__(self)
  1284. self.node_id = node_id
  1285. def get_opcode(self):
  1286. """Gets the opcode for this state instruction."""
  1287. return "RDK"
  1288. def get_arguments(self):
  1289. """Gets this state instruction's argument list."""
  1290. return [self.node_id]
  1291. class ReadEdgeInstruction(StateInstruction):
  1292. """An instruction that reads an edge."""
  1293. def __init__(self, node_id):
  1294. StateInstruction.__init__(self)
  1295. self.node_id = node_id
  1296. def get_opcode(self):
  1297. """Gets the opcode for this state instruction."""
  1298. return "RE"
  1299. def get_arguments(self):
  1300. """Gets this state instruction's argument list."""
  1301. return [self.node_id]
  1302. class ReadOutgoingEdgesInstruction(StateInstruction):
  1303. """An instruction that reads all outgoing edges for a node."""
  1304. def __init__(self, node_id):
  1305. StateInstruction.__init__(self)
  1306. self.node_id = node_id
  1307. def get_result_type_impl(self):
  1308. """Gets the type of value produced by this instruction."""
  1309. return PRIMITIVE_RESULT_TYPE
  1310. def get_opcode(self):
  1311. """Gets the opcode for this state instruction."""
  1312. return "RO"
  1313. def get_arguments(self):
  1314. """Gets this state instruction's argument list."""
  1315. return [self.node_id]
  1316. class ReadIncomingEdgesInstruction(StateInstruction):
  1317. """An instruction that reads all incoming edges for a node."""
  1318. def __init__(self, node_id):
  1319. StateInstruction.__init__(self)
  1320. self.node_id = node_id
  1321. def get_result_type_impl(self):
  1322. """Gets the type of value produced by this instruction."""
  1323. return PRIMITIVE_RESULT_TYPE
  1324. def get_opcode(self):
  1325. """Gets the opcode for this state instruction."""
  1326. return "RI"
  1327. def get_arguments(self):
  1328. """Gets this state instruction's argument list."""
  1329. return [self.node_id]
  1330. class CreateNodeInstruction(StateInstruction):
  1331. """An instruction that creates an empty node."""
  1332. def get_opcode(self):
  1333. """Gets the opcode for this state instruction."""
  1334. return "CN"
  1335. def get_arguments(self):
  1336. """Gets this state instruction's argument list."""
  1337. return []
  1338. class CreateNodeWithValueInstruction(StateInstruction):
  1339. """An instruction that creates a node with a given value."""
  1340. def __init__(self, value):
  1341. StateInstruction.__init__(self)
  1342. self.value = value
  1343. def get_opcode(self):
  1344. """Gets the opcode for this state instruction."""
  1345. return "CNV"
  1346. def get_arguments(self):
  1347. """Gets this state instruction's argument list."""
  1348. return [self.value]
  1349. class CreateEdgeInstruction(StateInstruction):
  1350. """An instruction that creates an edge."""
  1351. def __init__(self, source_id, target_id):
  1352. StateInstruction.__init__(self)
  1353. self.source_id = source_id
  1354. self.target_id = target_id
  1355. def get_opcode(self):
  1356. """Gets the opcode for this state instruction."""
  1357. return "CE"
  1358. def get_arguments(self):
  1359. """Gets this state instruction's argument list."""
  1360. return [self.source_id, self.target_id]
  1361. class CreateDictionaryEdgeInstruction(StateInstruction):
  1362. """An instruction that creates a dictionary edge."""
  1363. def __init__(self, source_id, key, target_id):
  1364. StateInstruction.__init__(self)
  1365. self.source_id = source_id
  1366. self.key = key
  1367. self.target_id = target_id
  1368. def get_opcode(self):
  1369. """Gets the opcode for this state instruction."""
  1370. return "CD"
  1371. def get_arguments(self):
  1372. """Gets this state instruction's argument list."""
  1373. return [self.source_id, self.key, self.target_id]
  1374. class DeleteNodeInstruction(StateInstruction):
  1375. """An instruction that deletes a node."""
  1376. def __init__(self, node_id):
  1377. StateInstruction.__init__(self)
  1378. self.node_id = node_id
  1379. def get_result_type_impl(self):
  1380. """Gets the type of value produced by this instruction."""
  1381. return NO_RESULT_TYPE
  1382. def get_opcode(self):
  1383. """Gets the opcode for this state instruction."""
  1384. return "DN"
  1385. def get_arguments(self):
  1386. """Gets this state instruction's argument list."""
  1387. return [self.node_id]
  1388. class DeleteEdgeInstruction(StateInstruction):
  1389. """An instruction that deletes an edge."""
  1390. def __init__(self, edge_id):
  1391. StateInstruction.__init__(self)
  1392. self.edge_id = edge_id
  1393. def get_result_type_impl(self):
  1394. """Gets the type of value produced by this instruction."""
  1395. return NO_RESULT_TYPE
  1396. def get_opcode(self):
  1397. """Gets the opcode for this state instruction."""
  1398. return "DE"
  1399. def get_arguments(self):
  1400. """Gets this state instruction's argument list."""
  1401. return [self.edge_id]
  1402. def create_block(*statements):
  1403. """Creates a block-statement from the given list of statements."""
  1404. length = len(statements)
  1405. if length == 0:
  1406. return EmptyInstruction()
  1407. elif length == 1:
  1408. return statements[0]
  1409. else:
  1410. return CompoundInstruction(
  1411. statements[0],
  1412. create_block(*statements[1:]))
  1413. def create_jit_call(
  1414. target, named_arguments, kwargs,
  1415. create_run_generator=RunGeneratorFunctionInstruction):
  1416. """Creates a call that abides by the JIT's calling convention."""
  1417. # A JIT call looks like this:
  1418. #
  1419. # target = ...
  1420. # arg_dict = { ... }
  1421. # arg_dict.update(kwargs)
  1422. # result, = yield [("CALL_KWARGS", [target, arg_dict])]
  1423. results = []
  1424. if target.has_definition():
  1425. target_tmp = StoreLocalInstruction(None, target)
  1426. results.append(target_tmp)
  1427. target = target_tmp.create_load()
  1428. arg_dict = StoreLocalInstruction(
  1429. None,
  1430. DictionaryLiteralInstruction(
  1431. [(LiteralInstruction(key), val) for key, val in named_arguments]))
  1432. results.append(arg_dict)
  1433. results.append(
  1434. CallInstruction(
  1435. LoadMemberInstruction(arg_dict.create_load(), 'update'),
  1436. [kwargs]))
  1437. return CompoundInstruction(
  1438. create_block(*results),
  1439. create_run_generator(
  1440. target, arg_dict.create_load(), NODE_RESULT_TYPE))
  1441. def evaluate_and_load(value):
  1442. """Creates a statement that evaluates the given tree, and creates
  1443. an expression that loads the result. These instructions are returned
  1444. as a pair of trees."""
  1445. if isinstance(value, (LoadLocalInstruction, LiteralInstruction)):
  1446. return EmptyInstruction(), value
  1447. else:
  1448. store = StoreLocalInstruction(None, value)
  1449. return IgnoreInstruction(store), store.create_load()
  1450. def create_new_local_node(local_variable, connected_node, edge_variable=None):
  1451. """Creates a local node that is the backing storage for a local variable.
  1452. This node is connected to a given node to make sure it's not perceived
  1453. as dead by the GC. The newly created node is stored in the given
  1454. local variable. The edge's id can also optionally be stored in a variable."""
  1455. local_store = StoreLocalInstruction(local_variable, CreateNodeInstruction())
  1456. create_edge = CreateEdgeInstruction(connected_node, local_store.create_load())
  1457. if edge_variable is not None:
  1458. create_edge = StoreLocalInstruction(edge_variable, create_edge)
  1459. return create_block(IgnoreInstruction(local_store), IgnoreInstruction(create_edge))
  1460. def map_instruction_tree_top_down(function, instruction):
  1461. """Applies the given mapping function to every instruction in the tree
  1462. that has the given instruction as root. The map is applied in a top-down
  1463. fashion."""
  1464. mapped_instruction = function(instruction)
  1465. return mapped_instruction.create(
  1466. [map_instruction_tree_top_down(function, child)
  1467. for child in mapped_instruction.get_children()])
  1468. def map_and_simplify(function, instruction):
  1469. """Applies the given mapping function to every instruction in the tree
  1470. that has the given instruction as root, and simplifies it on-the-fly.
  1471. The map is applied in a bottom-up fashion.
  1472. This is at least as powerful as first mapping and then simplifying, as
  1473. maps and simplifications are interspersed."""
  1474. return function(
  1475. instruction.create(
  1476. [map_and_simplify(function, child)
  1477. for child in instruction.get_children()])).simplify_node()
  1478. def iterate_as_stack(instruction, stack_iterator):
  1479. """Iterates over the given instruction and its children in the order in which temporaries are
  1480. 'pushed' on and 'popped' from a virtual evaluation stack."""
  1481. if isinstance(instruction, SelectInstruction):
  1482. iterate_as_stack(instruction.condition, stack_iterator)
  1483. stack_iterator.pop()
  1484. if_iterator, else_iterator = stack_iterator.branch(), stack_iterator.branch()
  1485. iterate_as_stack(instruction.if_clause, if_iterator)
  1486. iterate_as_stack(instruction.else_clause, else_iterator)
  1487. stack_iterator.merge(if_iterator, else_iterator)
  1488. elif isinstance(instruction, CompoundInstruction):
  1489. iterate_as_stack(instruction.first, stack_iterator)
  1490. if instruction.second.has_result():
  1491. stack_iterator.pop()
  1492. iterate_as_stack(instruction.second, stack_iterator)
  1493. if not instruction.second.has_result():
  1494. stack_iterator.pop()
  1495. else:
  1496. children = instruction.get_children()
  1497. for child in children:
  1498. # Push all children onto the stack.
  1499. iterate_as_stack(child, stack_iterator)
  1500. stack_iterator.before_pop_args(instruction)
  1501. for child in children:
  1502. # Pop all children from the stack.
  1503. stack_iterator.pop()
  1504. # Push the instruction.
  1505. stack_iterator.push(instruction)
  1506. class StackIterator(object):
  1507. """A base class for stack iterators."""
  1508. def __init__(self, stack=None):
  1509. self.stack = [] if stack is None else stack
  1510. def before_pop_args(self, instruction):
  1511. """Performs an action before the given instruction's arguments are popped."""
  1512. pass
  1513. def pop(self):
  1514. """Pops an instruction from the stack."""
  1515. self.stack.pop()
  1516. def push(self, instruction):
  1517. """Pushes an instruction onto the stack."""
  1518. self.stack.append(set([instruction]))
  1519. def branch(self):
  1520. """Creates a copy of this stack iterator."""
  1521. return self.create(self.copy_stack())
  1522. def merge(self, *branches):
  1523. """Sets this stack iterator's stack to the union of the given branches."""
  1524. self.__init__(self.merge_stacks(*branches))
  1525. def copy_stack(self):
  1526. """Creates a copy of this stack iterator's stack."""
  1527. return [set(vals) for vals in self.stack]
  1528. def create(self, new_stack):
  1529. """Creates a stack iterator from the given stack"""
  1530. return type(self)(new_stack)
  1531. def merge_stacks(self, *branches):
  1532. """Computes the union of the stacks of the given branches."""
  1533. results = None
  1534. for branch in branches:
  1535. if results is None:
  1536. results = branch.copy_stack()
  1537. else:
  1538. assert len(branch.stack) == len(results)
  1539. results = [set.union(*t) for t in zip(branch.stack, results)]
  1540. return results
  1541. def protect_temporaries_from_gc(instruction, connected_node, fast_jit_compat=False):
  1542. """Protects temporaries from the garbage collector by connecting them to the given node."""
  1543. # # The reasoning behind this function
  1544. #
  1545. # A nop instruction (`yield None`) may trigger the garbage collector, which will delete
  1546. # unreachable ("dead") vertices and edges. Now take into account that a bare temporary node
  1547. # is actually unreachable from the root node. The consequence is that temporary nodes
  1548. # may be garbage-collected if a nop instruction is executed while they are on the evaluation
  1549. # "stack." This is _never_ what we want.
  1550. #
  1551. # To counter this, we can connect temporary nodes to a node that is reachable from the root.
  1552. # However, we only want to create edges between edges and a known reachable node if we really
  1553. # have to, because creating edges incurs some overhead.
  1554. #
  1555. # We will create an edge between a temporary and the known reachable node if and only if the
  1556. # temporary is on the "stack" when either a nop or a call instruction is executed.
  1557. class GCStackIterator(StackIterator):
  1558. """A stack iterator that detects which instructions might be at risk of getting garbage
  1559. collected."""
  1560. def __init__(self, stack=None, gc_temporaries=None):
  1561. StackIterator.__init__(self, stack)
  1562. self.gc_temporaries = set() if gc_temporaries is None else gc_temporaries
  1563. def before_pop_args(self, instruction):
  1564. """Performs an action before the given instruction's arguments are popped."""
  1565. if fast_jit_compat and isinstance(instruction, DictionaryLiteralInstruction):
  1566. for instruction_set in self.stack:
  1567. self.gc_temporaries.update(instruction_set)
  1568. def push(self, instruction):
  1569. """Pushes an instruction onto the stack."""
  1570. if isinstance(instruction, (
  1571. NopInstruction,
  1572. RunGeneratorFunctionInstruction,
  1573. RunTailGeneratorFunctionInstruction)):
  1574. # All values currently on the stack are at risk. Mark them as such.
  1575. for instruction_set in self.stack:
  1576. self.gc_temporaries.update(instruction_set)
  1577. # Proceed.
  1578. StackIterator.push(self, instruction)
  1579. def merge(self, *branches):
  1580. """Sets this stack iterator's stack to the union of the given branches."""
  1581. self.__init__(
  1582. self.merge_stacks(*branches),
  1583. set.union(*[br.gc_temporaries for br in branches]))
  1584. def create(self, new_stack):
  1585. """Creates a stack iterator from the given stack"""
  1586. return GCStackIterator(new_stack, self.gc_temporaries)
  1587. # Find out which instructions are at risk.
  1588. gc_iterator = GCStackIterator()
  1589. iterate_as_stack(instruction, gc_iterator)
  1590. # These temporaries need to be protected from the GC.
  1591. gc_temporaries = gc_iterator.gc_temporaries
  1592. def protect_result(instruction):
  1593. """Protects the given instruction's (temporary) result."""
  1594. if instruction in gc_temporaries and instruction.get_result_type() == NODE_RESULT_TYPE:
  1595. gc_temporaries.remove(instruction)
  1596. store_instr = StoreLocalInstruction(None, instruction)
  1597. return CompoundInstruction(
  1598. store_instr,
  1599. CompoundInstruction(
  1600. SelectInstruction(
  1601. BinaryInstruction(
  1602. store_instr.create_load(), 'is not', LiteralInstruction(None)),
  1603. CreateEdgeInstruction(connected_node, store_instr.create_load()),
  1604. EmptyInstruction()),
  1605. store_instr.create_load()))
  1606. else:
  1607. return instruction
  1608. return map_instruction_tree_top_down(protect_result, instruction)