Compiler-Inlining.st 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. Smalltalk current createPackage: 'Compiler-Inlining' properties: #{}!
  2. IRAssignment subclass: #IRInlinedAssignment
  3. instanceVariableNames: ''
  4. package: 'Compiler-Inlining'!
  5. !IRInlinedAssignment methodsFor: 'testing'!
  6. isInlined
  7. ^ true
  8. ! !
  9. !IRInlinedAssignment methodsFor: 'visiting'!
  10. accept: aVisitor
  11. ^ aVisitor visitIRInlinedAssignment: self
  12. ! !
  13. IRClosure subclass: #IRInlinedClosure
  14. instanceVariableNames: 'assignTo'
  15. package: 'Compiler-Inlining'!
  16. !IRInlinedClosure methodsFor: 'accessing'!
  17. assignTo
  18. ^ assignTo
  19. !
  20. assignTo: aScopeVar
  21. assignTo := aScopeVar
  22. ! !
  23. !IRInlinedClosure methodsFor: 'testing'!
  24. isInlined
  25. ^ true
  26. ! !
  27. !IRInlinedClosure methodsFor: 'visiting'!
  28. accept: aVisitor
  29. aVisitor visitIRInlinedClosure: self
  30. ! !
  31. IRReturn subclass: #IRInlinedNonLocalReturn
  32. instanceVariableNames: ''
  33. package: 'Compiler-Inlining'!
  34. !IRInlinedNonLocalReturn methodsFor: 'testing'!
  35. isInlined
  36. ^ true
  37. ! !
  38. !IRInlinedNonLocalReturn methodsFor: 'visiting'!
  39. accept: aVisitor
  40. ^ aVisitor visitIRInlinedNonLocalReturn: self
  41. ! !
  42. IRSend subclass: #IRInlinedSend
  43. instanceVariableNames: ''
  44. package: 'Compiler-Inlining'!
  45. !IRInlinedSend methodsFor: 'testing'!
  46. isInlined
  47. ^ true
  48. ! !
  49. !IRInlinedSend methodsFor: 'visiting'!
  50. accept: aVisitor
  51. aVisitor visitInlinedSend: self
  52. ! !
  53. IRInlinedSend subclass: #IRInlinedIfFalse
  54. instanceVariableNames: ''
  55. package: 'Compiler-Inlining'!
  56. !IRInlinedIfFalse methodsFor: 'visiting'!
  57. accept: aVisitor
  58. aVisitor visitIRInlinedIfFalse: self
  59. ! !
  60. IRInlinedSend subclass: #IRInlinedIfTrue
  61. instanceVariableNames: ''
  62. package: 'Compiler-Inlining'!
  63. !IRInlinedIfTrue methodsFor: 'visiting'!
  64. accept: aVisitor
  65. aVisitor visitIRInlinedIfTrue: self
  66. ! !
  67. IRVisitor subclass: #IRInliner
  68. instanceVariableNames: ''
  69. package: 'Compiler-Inlining'!
  70. !IRInliner methodsFor: 'testing'!
  71. shouldInlineAssignment: anIRAssignment
  72. ^ anIRAssignment isInlined not and: [
  73. anIRAssignment instructions last isSend and: [
  74. self shouldInlineSend: (anIRAssignment instructions last) ]]
  75. !
  76. shouldInlineSend: anIRSend
  77. ^ anIRSend isInlined not and: [
  78. IRSendInliner inlinedSelectors includes: anIRSend selector ]
  79. ! !
  80. !IRInliner methodsFor: 'visiting'!
  81. assignmentInliner
  82. ^ IRAssignmentInliner new
  83. translator: self;
  84. yourself
  85. !
  86. sendInliner
  87. ^ IRSendInliner new
  88. translator: self;
  89. yourself
  90. !
  91. visitIRAssignment: anIRAssignment
  92. (self shouldInlineAssignment: anIRAssignment)
  93. ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]
  94. ifFalse: [ super visitIRAssignment: anIRAssignment ]
  95. !
  96. visitIRNonLocalReturn: anIRNonLocalReturn
  97. | localReturn |
  98. anIRNonLocalReturn scope canInlineNonLocalReturns ifTrue: [
  99. anIRNonLocalReturn scope methodScope removeNonLocalReturn: anIRNonLocalReturn scope.
  100. localReturn := IRInlinedNonLocalReturn new
  101. scope: anIRNonLocalReturn scope;
  102. yourself.
  103. anIRNonLocalReturn instructions do: [ :each |
  104. localReturn add: each ].
  105. anIRNonLocalReturn replaceWith: localReturn ].
  106. super visitIRNonLocalReturn: anIRNonLocalReturn
  107. !
  108. visitIRSend: anIRSend
  109. (self shouldInlineSend: anIRSend)
  110. ifTrue: [ self sendInliner inlineSend: anIRSend ]
  111. ifFalse: [ super visitIRSend: anIRSend ]
  112. ! !
  113. IRJSTranslator subclass: #IRInliningJSTranslator
  114. instanceVariableNames: ''
  115. package: 'Compiler-Inlining'!
  116. !IRInliningJSTranslator methodsFor: 'visiting'!
  117. visitIRInlinedAssignment: anIRInlinedAssignment
  118. self visit: anIRInlinedAssignment instructions last
  119. !
  120. visitIRInlinedClosure: anIRInlinedClosure
  121. anIRInlinedClosure instructions allButLast do: [ :each | self visit: each ].
  122. (anIRInlinedClosure assignTo notNil and: [
  123. anIRInlinedClosure instructions last canBeAssigned ]) ifTrue: [
  124. self stream nextPutAll: anIRInlinedClosure assignTo variable alias.
  125. self stream nextPutAssignment ].
  126. self visit: anIRInlinedClosure instructions last
  127. !
  128. visitIRInlinedIfFalse: anIRInlinedIfFalse
  129. self stream
  130. nextPutIf: [
  131. self stream nextPutAll: '!!'.
  132. self visit: anIRInlinedIfFalse instructions first ]
  133. with: [ self visit: anIRInlinedIfFalse instructions last ]
  134. !
  135. visitIRInlinedIfTrue: anIRInlinedIfTrue
  136. self stream
  137. nextPutIf: [ self visit: anIRInlinedIfTrue instructions first ]
  138. with: [ self visit: anIRInlinedIfTrue instructions last ]
  139. ! !
  140. Object subclass: #IRSendInliner
  141. instanceVariableNames: 'send translator'
  142. package: 'Compiler-Inlining'!
  143. !IRSendInliner commentStamp!
  144. I inline some message sends and block closure arguments. I heavily rely on #perform: to dispatch inlining methods.!
  145. !IRSendInliner methodsFor: 'accessing'!
  146. inlinedClosure
  147. ^ IRInlinedClosure new
  148. !
  149. send
  150. ^ send
  151. !
  152. send: anIRSend
  153. send := anIRSend
  154. !
  155. translator
  156. ^ translator
  157. !
  158. translator: anASTTranslator
  159. translator := anASTTranslator
  160. ! !
  161. !IRSendInliner methodsFor: 'error handling'!
  162. inliningError: aString
  163. InliningError signal: aString
  164. ! !
  165. !IRSendInliner methodsFor: 'inlining'!
  166. ifFalse: anIRInstruction
  167. | inlinedSend inlinedClosure |
  168. anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
  169. anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].
  170. inlinedClosure := self inlineClosure: anIRInstruction.
  171. inlinedSend := IRInlinedIfFalse new.
  172. inlinedSend
  173. add: self send instructions first;
  174. add: inlinedClosure.
  175. self send replaceWith: inlinedSend.
  176. ^ inlinedSend
  177. !
  178. ifTrue: anIRInstruction
  179. | inlinedSend inlinedClosure |
  180. anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
  181. anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].
  182. inlinedClosure := self inlineClosure: anIRInstruction.
  183. inlinedSend := IRInlinedIfTrue new.
  184. inlinedSend
  185. add: self send instructions first;
  186. add: inlinedClosure.
  187. self send replaceWith: inlinedSend.
  188. ^ inlinedSend
  189. !
  190. inlineClosure: anIRClosure
  191. | inlinedClosure |
  192. inlinedClosure := self inlinedClosure.
  193. inlinedClosure scope: anIRClosure scope.
  194. anIRClosure instructions first instructions do: [ :each |
  195. inlinedClosure add: (self translator visit: each) ].
  196. ^ inlinedClosure
  197. !
  198. inlineSend: anIRSend
  199. self send: anIRSend.
  200. self perform: self send selector withArguments: self send instructions allButFirst
  201. ! !
  202. !IRSendInliner class methodsFor: 'accessing'!
  203. inlinedSelectors
  204. ^ #('ifTrue:' 'ifFalse:')
  205. ! !
  206. IRSendInliner subclass: #IRAssignmentInliner
  207. instanceVariableNames: 'assignment'
  208. package: 'Compiler-Inlining'!
  209. !IRAssignmentInliner methodsFor: 'accessing'!
  210. assignment
  211. ^ assignment
  212. !
  213. assignment: aNode
  214. assignment := aNode
  215. !
  216. inlinedClosure
  217. ^ super inlinedClosure
  218. assignTo: self assignment instructions first;
  219. yourself
  220. ! !
  221. !IRAssignmentInliner methodsFor: 'inlining'!
  222. inlineAssignment: anIRAssignment
  223. | inlinedAssignment |
  224. self assignment: anIRAssignment.
  225. inlinedAssignment := IRInlinedAssignment new.
  226. anIRAssignment instructions do: [ :each |
  227. inlinedAssignment add: each ].
  228. anIRAssignment replaceWith: inlinedAssignment.
  229. self inlineSend: inlinedAssignment instructions last.
  230. ^ inlinedAssignment
  231. ! !
  232. CodeGenerator subclass: #InliningCodeGenerator
  233. instanceVariableNames: ''
  234. package: 'Compiler-Inlining'!
  235. !InliningCodeGenerator methodsFor: 'compiling'!
  236. compileNode: aNode
  237. | ir stream |
  238. self semanticAnalyzer visit: aNode.
  239. ir := self translator visit: aNode.
  240. self inliner visit: ir.
  241. ^ self irTranslator
  242. visit: ir;
  243. contents
  244. !
  245. inliner
  246. ^ IRInliner new
  247. !
  248. irTranslator
  249. ^ IRInliningJSTranslator new
  250. ! !