1
0

Compiler-Inlining.st 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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 ifNotEmpty: [
  122. anIRInlinedClosure instructions allButLast do: [ :each | self visit: each ].
  123. (anIRInlinedClosure assignTo notNil and: [
  124. anIRInlinedClosure instructions last canBeAssigned ]) ifTrue: [
  125. self stream nextPutAll: anIRInlinedClosure assignTo variable alias.
  126. self stream nextPutAssignment ].
  127. self visit: anIRInlinedClosure instructions last ]
  128. !
  129. visitIRInlinedIfFalse: anIRInlinedIfFalse
  130. self stream
  131. nextPutIf: [
  132. self stream nextPutAll: '!! smalltalk.assert('.
  133. self visit: anIRInlinedIfFalse instructions first.
  134. self stream nextPutAll: ')' ]
  135. with: [ self visit: anIRInlinedIfFalse instructions last ]
  136. !
  137. visitIRInlinedIfTrue: anIRInlinedIfTrue
  138. self stream
  139. nextPutIf: [
  140. self stream nextPutAll: 'smalltalk.assert('.
  141. self visit: anIRInlinedIfTrue instructions first.
  142. self stream nextPutAll: ')' ]
  143. with: [ self visit: anIRInlinedIfTrue instructions last ]
  144. ! !
  145. Object subclass: #IRSendInliner
  146. instanceVariableNames: 'send translator'
  147. package: 'Compiler-Inlining'!
  148. !IRSendInliner commentStamp!
  149. I inline some message sends and block closure arguments. I heavily rely on #perform: to dispatch inlining methods.!
  150. !IRSendInliner methodsFor: 'accessing'!
  151. inlinedClosure
  152. ^ IRInlinedClosure new
  153. !
  154. send
  155. ^ send
  156. !
  157. send: anIRSend
  158. send := anIRSend
  159. !
  160. translator
  161. ^ translator
  162. !
  163. translator: anASTTranslator
  164. translator := anASTTranslator
  165. ! !
  166. !IRSendInliner methodsFor: 'error handling'!
  167. inliningError: aString
  168. InliningError signal: aString
  169. ! !
  170. !IRSendInliner methodsFor: 'inlining'!
  171. ifFalse: anIRInstruction
  172. | inlinedSend inlinedClosure |
  173. anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
  174. anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].
  175. inlinedClosure := self inlineClosure: anIRInstruction.
  176. inlinedSend := IRInlinedIfFalse new.
  177. inlinedSend
  178. add: self send instructions first;
  179. add: inlinedClosure.
  180. self send replaceWith: inlinedSend.
  181. ^ inlinedSend
  182. !
  183. ifTrue: anIRInstruction
  184. | inlinedSend inlinedClosure |
  185. anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
  186. anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].
  187. inlinedClosure := self inlineClosure: anIRInstruction.
  188. inlinedSend := IRInlinedIfTrue new.
  189. inlinedSend
  190. add: self send instructions first;
  191. add: inlinedClosure.
  192. self send replaceWith: inlinedSend.
  193. ^ inlinedSend
  194. !
  195. inlineClosure: anIRClosure
  196. | inlinedClosure |
  197. inlinedClosure := self inlinedClosure.
  198. inlinedClosure scope: anIRClosure scope.
  199. anIRClosure instructions first instructions do: [ :each |
  200. inlinedClosure add: (self translator visit: each) ].
  201. ^ inlinedClosure
  202. !
  203. inlineSend: anIRSend
  204. self send: anIRSend.
  205. self perform: self send selector withArguments: self send instructions allButFirst
  206. ! !
  207. !IRSendInliner class methodsFor: 'accessing'!
  208. inlinedSelectors
  209. ^ #('ifTrue:' 'ifFalse:')
  210. ! !
  211. IRSendInliner subclass: #IRAssignmentInliner
  212. instanceVariableNames: 'assignment'
  213. package: 'Compiler-Inlining'!
  214. !IRAssignmentInliner methodsFor: 'accessing'!
  215. assignment
  216. ^ assignment
  217. !
  218. assignment: aNode
  219. assignment := aNode
  220. !
  221. inlinedClosure
  222. ^ super inlinedClosure
  223. assignTo: self assignment instructions first;
  224. yourself
  225. ! !
  226. !IRAssignmentInliner methodsFor: 'inlining'!
  227. inlineAssignment: anIRAssignment
  228. | inlinedAssignment |
  229. self assignment: anIRAssignment.
  230. inlinedAssignment := IRInlinedAssignment new.
  231. anIRAssignment instructions do: [ :each |
  232. inlinedAssignment add: each ].
  233. anIRAssignment replaceWith: inlinedAssignment.
  234. self inlineSend: inlinedAssignment instructions last.
  235. ^ inlinedAssignment
  236. ! !
  237. CodeGenerator subclass: #InliningCodeGenerator
  238. instanceVariableNames: ''
  239. package: 'Compiler-Inlining'!
  240. !InliningCodeGenerator methodsFor: 'compiling'!
  241. compileNode: aNode
  242. | ir stream |
  243. self semanticAnalyzer visit: aNode.
  244. ir := self translator visit: aNode.
  245. self inliner visit: ir.
  246. ^ self irTranslator
  247. visit: ir;
  248. contents
  249. !
  250. inliner
  251. ^ IRInliner new
  252. !
  253. irTranslator
  254. ^ IRInliningJSTranslator new
  255. ! !