Compiler-Visitors.st 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. Smalltalk current createPackage: 'Compiler-Visitors' properties: #{}!
  2. AbstractCodeGenerator subclass: #ImpCodeGenerator
  3. instanceVariableNames: 'stream nestedBlocks earlyReturn currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced argVariables mutables target lazyVars realVarNames'
  4. package: 'Compiler-Visitors'!
  5. !ImpCodeGenerator methodsFor: 'accessing'!
  6. argVariables
  7. ^argVariables copy
  8. !
  9. knownVariables
  10. ^self pseudoVariables
  11. addAll: self tempVariables;
  12. addAll: self argVariables;
  13. yourself
  14. !
  15. tempVariables
  16. ^tempVariables copy
  17. !
  18. unknownVariables
  19. ^unknownVariables copy
  20. ! !
  21. !ImpCodeGenerator methodsFor: 'compilation DSL'!
  22. aboutToModifyState
  23. | list old |
  24. list := mutables.
  25. mutables := Set new.
  26. old := self switchTarget: nil.
  27. list do: [ :each | | value |
  28. self switchTarget: each.
  29. self realAssign: (lazyVars at: each)
  30. ].
  31. self switchTarget: old
  32. !
  33. ifValueWanted: aBlock
  34. target ifNotNil: aBlock
  35. !
  36. isolated: node
  37. ^ self visit: node targetBeing: self nextLazyvarName
  38. !
  39. isolatedUse: node
  40. | old |
  41. old := self switchTarget: self nextLazyvarName.
  42. self visit: node.
  43. ^self useValueNamed: (self switchTarget: old)
  44. !
  45. lazyAssign: aString dependsOnState: aBoolean
  46. (lazyVars includesKey: target)
  47. ifTrue: [ lazyVars at: target put: aString. aBoolean ifTrue: [ mutables add: target ] ]
  48. ifFalse: [ self realAssign: aString ]
  49. !
  50. lazyAssignExpression: aString
  51. self lazyAssign: aString dependsOnState: true
  52. !
  53. lazyAssignValue: aString
  54. self lazyAssign: aString dependsOnState: false
  55. !
  56. makeTargetRealVariable
  57. (lazyVars includesKey: target) ifTrue: [
  58. lazyVars removeKey: target.
  59. lazyVars at: 'assigned ',target put: nil. "<-- only to retain size, it is used in nextLazyvarName"
  60. realVarNames add: target ].
  61. !
  62. nextLazyvarName
  63. | name |
  64. name := '$', lazyVars size asString.
  65. lazyVars at: name put: name.
  66. ^name
  67. !
  68. nilIfValueWanted
  69. target ifNotNil: [ self lazyAssignValue: 'nil' ]
  70. !
  71. realAssign: aString
  72. | closer |
  73. aString ifNotEmpty: [
  74. self aboutToModifyState.
  75. closer := ''.
  76. self ifValueWanted: [ stream nextPutAll:
  77. (target = '^' ifTrue: ['return '] ifFalse: [
  78. target = '!!' ifTrue: [ closer := ']'. 'throw $early=['] ifFalse: [
  79. target, '=']]) ].
  80. self makeTargetRealVariable.
  81. stream nextPutAll: aString, closer, ';', self mylf ]
  82. !
  83. switchTarget: aString
  84. | old |
  85. old := target.
  86. target := aString.
  87. ^old
  88. !
  89. useValueNamed: key
  90. | val |
  91. (realVarNames includes: key) ifTrue: [ ^key ].
  92. mutables remove: key.
  93. ^lazyVars at: key
  94. !
  95. visit: aNode targetBeing: aString
  96. | old |
  97. old := self switchTarget: aString.
  98. self visit: aNode.
  99. ^ self switchTarget: old.
  100. ! !
  101. !ImpCodeGenerator methodsFor: 'compiling'!
  102. compileNode: aNode
  103. stream := '' writeStream.
  104. self visit: aNode.
  105. ^stream contents
  106. ! !
  107. !ImpCodeGenerator methodsFor: 'initialization'!
  108. initialize
  109. super initialize.
  110. stream := '' writeStream.
  111. unknownVariables := #().
  112. tempVariables := #().
  113. argVariables := #().
  114. messageSends := #().
  115. classReferenced := #().
  116. mutables := Set new.
  117. realVarNames := Set new.
  118. lazyVars := HashedCollection new.
  119. target := nil
  120. ! !
  121. !ImpCodeGenerator methodsFor: 'optimizations'!
  122. checkClass: aClassName for: receiver
  123. self prvCheckClass: aClassName for: receiver.
  124. stream nextPutAll: '{'
  125. !
  126. checkClass: aClassName for: receiver includeIf: aBoolean
  127. self prvCheckClass: aClassName for: receiver.
  128. stream nextPutAll: (aBoolean ifTrue: ['if(('] ifFalse: ['if(!!(']), (self useValueNamed: receiver), ')) {'
  129. !
  130. inline: aSelector receiver: receiver argumentNodes: aCollection
  131. "-- Booleans --"
  132. (aSelector = 'ifFalse:') ifTrue: [
  133. aCollection first isBlockNode ifTrue: [
  134. self checkClass: 'Boolean' for: receiver includeIf: false.
  135. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  136. self prvPutAndElse: [ self nilIfValueWanted ].
  137. ^true]].
  138. (aSelector = 'ifTrue:') ifTrue: [
  139. aCollection first isBlockNode ifTrue: [
  140. self checkClass: 'Boolean' for: receiver includeIf: true.
  141. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  142. self prvPutAndElse: [ self nilIfValueWanted ].
  143. ^true]].
  144. (aSelector = 'ifTrue:ifFalse:') ifTrue: [
  145. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  146. self checkClass: 'Boolean' for: receiver includeIf: true.
  147. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  148. self prvPutAndElse: [ self visit: aCollection second nodes first ].
  149. ^true]].
  150. (aSelector = 'ifFalse:ifTrue:') ifTrue: [
  151. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  152. self checkClass: 'Boolean' for: receiver includeIf: false.
  153. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  154. self prvPutAndElse: [ self visit: aCollection second nodes first ].
  155. ^true]].
  156. "-- Numbers --"
  157. (aSelector = '<') ifTrue: [ | operand |
  158. operand := self isolatedUse: aCollection first.
  159. self checkClass: 'Number' for: receiver.
  160. self prvPutAndElse: [
  161. self lazyAssignExpression: '(', (self useValueNamed: receiver), '<', operand, ')' ].
  162. ^{ VerbatimNode new value: operand }].
  163. (aSelector = '<=') ifTrue: [ | operand |
  164. operand := self isolatedUse: aCollection first.
  165. self checkClass: 'Number' for: receiver.
  166. self prvPutAndElse: [
  167. self lazyAssignExpression: '(', (self useValueNamed: receiver), '<=', operand, ')' ].
  168. ^{ VerbatimNode new value: operand }].
  169. (aSelector = '>') ifTrue: [ | operand |
  170. operand := self isolatedUse: aCollection first.
  171. self checkClass: 'Number' for: receiver.
  172. self prvPutAndElse: [
  173. self lazyAssignExpression: '(', (self useValueNamed: receiver), '>', operand, ')' ].
  174. ^{ VerbatimNode new value: operand }].
  175. (aSelector = '>=') ifTrue: [ | operand |
  176. operand := self isolatedUse: aCollection first.
  177. self checkClass: 'Number' for: receiver.
  178. self prvPutAndElse: [
  179. self lazyAssignExpression: '(', (self useValueNamed: receiver), '>=', operand, ')' ].
  180. ^{ VerbatimNode new value: operand }].
  181. (aSelector = '+') ifTrue: [ | operand |
  182. operand := self isolatedUse: aCollection first.
  183. self checkClass: 'Number' for: receiver.
  184. self prvPutAndElse: [
  185. self lazyAssignExpression: '(', (self useValueNamed: receiver), '+', operand, ')' ].
  186. ^{ VerbatimNode new value: operand }].
  187. (aSelector = '-') ifTrue: [ | operand |
  188. operand := self isolatedUse: aCollection first.
  189. self checkClass: 'Number' for: receiver.
  190. self prvPutAndElse: [
  191. self lazyAssignExpression: '(', (self useValueNamed: receiver), '-', operand, ')' ].
  192. ^{ VerbatimNode new value: operand }].
  193. (aSelector = '*') ifTrue: [ | operand |
  194. operand := self isolatedUse: aCollection first.
  195. self checkClass: 'Number' for: receiver.
  196. self prvPutAndElse: [
  197. self lazyAssignExpression: '(', (self useValueNamed: receiver), '*', operand, ')' ].
  198. ^{ VerbatimNode new value: operand }].
  199. (aSelector = '/') ifTrue: [ | operand |
  200. operand := self isolatedUse: aCollection first.
  201. self checkClass: 'Number' for: receiver.
  202. self prvPutAndElse: [
  203. self lazyAssignExpression: '(', (self useValueNamed: receiver), '/', operand, ')' ].
  204. ^{ VerbatimNode new value: operand }].
  205. ^nil
  206. !
  207. inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
  208. | inlined |
  209. inlined := false.
  210. "-- BlockClosures --"
  211. (aSelector = 'whileTrue:') ifTrue: [
  212. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [ | old |
  213. self prvWhileConditionStatement: 'for(;;){' pre: 'if (!!(' condition: anObject post: ')) {'.
  214. stream nextPutAll: 'break}', self mylf.
  215. self prvPutAndClose: [ self visit: aCollection first nodes first targetBeing: nil ].
  216. inlined := true]].
  217. (aSelector = 'whileFalse:') ifTrue: [
  218. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [ | old |
  219. self prvWhileConditionStatement: 'for(;;){' pre: 'if ((' condition: anObject post: ')) {'.
  220. stream nextPutAll: 'break}', self mylf.
  221. self prvPutAndClose: [ self visit: aCollection first nodes first targetBeing: nil ].
  222. inlined := true]].
  223. (aSelector = 'whileTrue') ifTrue: [
  224. anObject isBlockNode ifTrue: [
  225. self prvWhileConditionStatement: 'do{' pre: '}while((' condition: anObject post: '));', self mylf.
  226. inlined := true]].
  227. (aSelector = 'whileFalse') ifTrue: [
  228. anObject isBlockNode ifTrue: [
  229. self prvWhileConditionStatement: 'do{' pre: '}while(!!(' condition: anObject post: '));', self mylf.
  230. inlined := true]].
  231. "-- Numbers --"
  232. (#('+' '-' '*' '/' '<' '<=' '>=' '>') includes: aSelector) ifTrue: [
  233. (self prvInlineNumberOperator: aSelector on: anObject and: aCollection first) ifTrue: [
  234. inlined := true]].
  235. "-- UndefinedObject --"
  236. (aSelector = 'ifNil:') ifTrue: [
  237. aCollection first isBlockNode ifTrue: [ | rcv |
  238. self aboutToModifyState.
  239. rcv := self isolatedUse: anObject.
  240. rcv = 'super' ifTrue: [ rcv := 'self' ].
  241. self makeTargetRealVariable.
  242. stream nextPutAll: 'if((', rcv, ') === nil || (', rcv, ') == null) {'.
  243. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  244. self prvPutAndClose: [ self lazyAssignValue: rcv ].
  245. inlined := true]].
  246. (aSelector = 'ifNotNil:') ifTrue: [
  247. aCollection first isBlockNode ifTrue: [ | rcv |
  248. self aboutToModifyState.
  249. rcv := self isolatedUse: anObject.
  250. rcv = 'super' ifTrue: [ rcv := 'self' ].
  251. self makeTargetRealVariable.
  252. stream nextPutAll: 'if((', rcv, ') !!== nil && (', rcv, ') !!= null) {'.
  253. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  254. self prvPutAndClose: [ self lazyAssignValue: rcv ].
  255. inlined := true]].
  256. (aSelector = 'ifNil:ifNotNil:') ifTrue: [
  257. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [ | rcv |
  258. self aboutToModifyState.
  259. rcv := self isolatedUse: anObject.
  260. rcv = 'super' ifTrue: [ rcv := 'self' ].
  261. self makeTargetRealVariable.
  262. stream nextPutAll: 'if((', rcv, ') === nil || (', rcv, ') == null) {'.
  263. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  264. self prvPutAndClose: [ self visit: aCollection second nodes first ].
  265. inlined := true]].
  266. (aSelector = 'ifNotNil:ifNil:') ifTrue: [
  267. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [ | rcv |
  268. self aboutToModifyState.
  269. rcv := self isolatedUse: anObject.
  270. rcv = 'super' ifTrue: [ rcv := 'self' ].
  271. self makeTargetRealVariable.
  272. stream nextPutAll: 'if((', rcv, ') !!== nil && (', rcv, ') !!= null) {'.
  273. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  274. self prvPutAndClose: [ self visit: aCollection second nodes first ].
  275. inlined := true]].
  276. (aSelector = 'isNil') ifTrue: [ | rcv |
  277. rcv := self isolatedUse: anObject.
  278. rcv = 'super' ifTrue: [ rcv := 'self' ].
  279. self lazyAssignValue: '((', rcv, ') === nil || (', rcv, ') == null)'.
  280. inlined := true].
  281. (aSelector = 'notNil') ifTrue: [ | rcv |
  282. rcv := self isolatedUse: anObject.
  283. rcv = 'super' ifTrue: [ rcv := 'self' ].
  284. self lazyAssignValue: '((', rcv, ') !!== nil && (', rcv, ') !!= null)'.
  285. inlined := true].
  286. ^inlined
  287. !
  288. isNode: aNode ofClass: aClass
  289. ^aNode isValueNode and: [
  290. aNode value class = aClass or: [
  291. aNode value = 'self' and: [self currentClass = aClass]]]
  292. !
  293. prvCheckClass: aClassName for: receiver
  294. self makeTargetRealVariable.
  295. self aboutToModifyState.
  296. stream nextPutAll: 'if((', (self useValueNamed: receiver), ').klass === smalltalk.', aClassName, ') '
  297. !
  298. prvInlineNumberOperator: aSelector on: receiverNode and: operandNode
  299. (aSelector = aSelector) ifTrue: [
  300. (self isNode: receiverNode ofClass: Number) ifTrue: [
  301. | rcv operand |
  302. rcv := self isolated: receiverNode.
  303. operand := self isolated: operandNode.
  304. self lazyAssignValue: ((self useValueNamed: rcv), aSelector, (self useValueNamed: operand)).
  305. ^true]].
  306. ^false
  307. !
  308. prvWhileConditionStatement: stmtString pre: preString condition: anObject post: postString
  309. | x |
  310. stream nextPutAll: stmtString.
  311. x := self isolatedUse: anObject nodes first.
  312. x ifEmpty: [ x := '"should not reach - receiver includes ^"' ].
  313. stream nextPutAll: preString, x, postString.
  314. self nilIfValueWanted
  315. ! !
  316. !ImpCodeGenerator methodsFor: 'output'!
  317. mylf
  318. ^String lf, ((Array new: nestedBlocks+2) join: String tab)
  319. !
  320. prvPutAndClose: aBlock
  321. aBlock value.
  322. stream nextPutAll: '}', self mylf
  323. !
  324. prvPutAndElse: aBlock
  325. aBlock value.
  326. stream nextPutAll: '} else {'
  327. !
  328. putTemps: temps
  329. temps ifNotEmpty: [
  330. stream nextPutAll: 'var '.
  331. temps do: [:each | | temp |
  332. temp := self safeVariableNameFor: each.
  333. tempVariables add: temp.
  334. stream nextPutAll: temp, '=nil'] separatedBy: [ stream nextPutAll: ',' ].
  335. stream nextPutAll: ';', self mylf
  336. ]
  337. ! !
  338. !ImpCodeGenerator methodsFor: 'testing'!
  339. assert: aBoolean
  340. aBoolean ifFalse: [ self error: 'assertion failed' ]
  341. !
  342. performOptimizations
  343. ^self class performOptimizations
  344. ! !
  345. !ImpCodeGenerator methodsFor: 'visiting'!
  346. send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
  347. | args |
  348. args := self isolated: (DynamicArrayNode new nodes: aCollection; yourself).
  349. self lazyAssignExpression: (String streamContents: [ :str |
  350. str nextPutAll: 'smalltalk.send('.
  351. str nextPutAll: (self useValueNamed: aReceiver).
  352. str nextPutAll: ', "', aSelector asSelector, '", '.
  353. str nextPutAll: (self useValueNamed: args).
  354. aBoolean ifTrue: [
  355. str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass superclass)].
  356. str nextPutAll: ')'
  357. ])
  358. !
  359. sequenceOfNodes: nodes temps: temps
  360. nodes isEmpty
  361. ifFalse: [ | old index |
  362. self putTemps: temps.
  363. old :=self switchTarget: nil.
  364. index := 0.
  365. nodes do: [:each |
  366. index := index + 1.
  367. index = nodes size ifTrue: [ self switchTarget: old ].
  368. self visit: each ]]
  369. ifTrue: [ self nilIfValueWanted ]
  370. !
  371. visit: aNode
  372. aNode accept: self
  373. !
  374. visitAssignmentNode: aNode
  375. | olds oldt |
  376. olds := stream.
  377. stream := '' writeStream.
  378. oldt := self switchTarget: self nextLazyvarName.
  379. self visit: aNode left.
  380. self assert: (lazyVars at: target) ~= target.
  381. self switchTarget: (self useValueNamed: (self switchTarget: nil)).
  382. self assert: (lazyVars includesKey: target) not.
  383. stream := olds.
  384. self visit: aNode right.
  385. olds := self switchTarget: oldt.
  386. self ifValueWanted: [ self lazyAssignExpression: olds ]
  387. !
  388. visitBlockNode: aNode
  389. | oldt olds oldm |
  390. self assert: aNode nodes size = 1.
  391. oldt := self switchTarget: '^'.
  392. olds := stream.
  393. stream := '' writeStream.
  394. stream nextPutAll: '(function('.
  395. aNode parameters
  396. do: [:each |
  397. tempVariables add: each.
  398. stream nextPutAll: each]
  399. separatedBy: [stream nextPutAll: ', '].
  400. stream nextPutAll: '){'.
  401. nestedBlocks := nestedBlocks + 1.
  402. oldm := mutables.
  403. mutables := Set new.
  404. self visit: aNode nodes first.
  405. self assert: mutables isEmpty.
  406. mutables := oldm.
  407. nestedBlocks := nestedBlocks - 1.
  408. stream nextPutAll: '})'.
  409. self switchTarget: oldt.
  410. oldt := stream contents.
  411. stream := olds.
  412. self lazyAssignExpression: oldt
  413. !
  414. visitBlockSequenceNode: aNode
  415. self sequenceOfNodes: aNode nodes temps: aNode temps
  416. !
  417. visitCascadeNode: aNode
  418. | rcv |
  419. rcv := self isolated: aNode receiver.
  420. self aboutToModifyState.
  421. rcv := self useValueNamed: rcv.
  422. aNode nodes do: [:each |
  423. each receiver: (VerbatimNode new value: rcv) ].
  424. self sequenceOfNodes: aNode nodes temps: #()
  425. !
  426. visitClassReferenceNode: aNode
  427. (referencedClasses includes: aNode value) ifFalse: [
  428. referencedClasses add: aNode value].
  429. self lazyAssignExpression: '(smalltalk.', aNode value, ' || ', aNode value, ')'
  430. !
  431. visitDynamicArrayNode: aNode
  432. | args |
  433. args :=aNode nodes collect: [ :node | self isolated: node ].
  434. self lazyAssignValue: (String streamContents: [ :str |
  435. str nextPutAll: '['.
  436. args
  437. do: [:each | str nextPutAll: (self useValueNamed: each) ]
  438. separatedBy: [str nextPutAll: ', '].
  439. str nextPutAll: ']'
  440. ])
  441. !
  442. visitDynamicDictionaryNode: aNode
  443. | elements |
  444. elements := self isolated: (DynamicArrayNode new nodes: aNode nodes; yourself).
  445. self lazyAssignValue: 'smalltalk.HashedCollection._fromPairs_(', (self useValueNamed: elements), ')'
  446. !
  447. visitFailure: aFailure
  448. self error: aFailure asString
  449. !
  450. visitJSStatementNode: aNode
  451. self aboutToModifyState.
  452. stream nextPutAll: ';', (aNode source replace: '>>' with: '>'), ';', self mylf
  453. !
  454. visitMethodNode: aNode
  455. | str currentSelector |
  456. currentSelector := aNode selector asSelector.
  457. nestedBlocks := 0.
  458. earlyReturn := false.
  459. messageSends := #().
  460. referencedClasses := #().
  461. unknownVariables := #().
  462. tempVariables := #().
  463. argVariables := #().
  464. lazyVars := HashedCollection new.
  465. mutables := Set new.
  466. realVarNames := Set new.
  467. stream
  468. nextPutAll: 'smalltalk.method({'; lf;
  469. nextPutAll: 'selector: "', aNode selector, '",'; lf.
  470. stream nextPutAll: 'source: ', self source asJavascript, ',';lf.
  471. stream nextPutAll: 'fn: function('.
  472. aNode arguments
  473. do: [:each |
  474. argVariables add: each.
  475. stream nextPutAll: each]
  476. separatedBy: [stream nextPutAll: ', '].
  477. stream
  478. nextPutAll: '){var self=this;', self mylf.
  479. str := stream.
  480. stream := '' writeStream.
  481. self switchTarget: nil.
  482. self assert: aNode nodes size = 1.
  483. self visit: aNode nodes first.
  484. realVarNames ifNotEmpty: [ str nextPutAll: 'var ', (realVarNames asArray join: ','), ';', self mylf ].
  485. earlyReturn ifTrue: [
  486. str nextPutAll: 'var $early={}; try{', self mylf].
  487. str nextPutAll: stream contents.
  488. stream := str.
  489. (aNode nodes first nodes notEmpty and: [ |checker|
  490. checker := ReturnNodeChecker new.
  491. checker visit: aNode nodes first nodes last.
  492. checker wasReturnNode]) ifFalse: [ self switchTarget: '^'. self lazyAssignValue: 'self'. self switchTarget: nil ].
  493. earlyReturn ifTrue: [
  494. stream nextPutAll: '} catch(e) {if(e===$early) return e[0]; throw e}'].
  495. stream nextPutAll: '}'.
  496. stream
  497. nextPutAll: ',', String lf, 'messageSends: ';
  498. nextPutAll: messageSends asJavascript, ','; lf;
  499. nextPutAll: 'args: ', argVariables asJavascript, ','; lf;
  500. nextPutAll: 'referencedClasses: ['.
  501. referencedClasses
  502. do: [:each | stream nextPutAll: each printString]
  503. separatedBy: [stream nextPutAll: ','].
  504. stream nextPutAll: ']'.
  505. stream nextPutAll: '})'.
  506. self assert: mutables isEmpty
  507. !
  508. visitReturnNode: aNode
  509. self assert: aNode nodes size = 1.
  510. nestedBlocks > 0 ifTrue: [
  511. earlyReturn := true].
  512. self
  513. visit: aNode nodes first
  514. targetBeing: (nestedBlocks > 0 ifTrue: ['!!'] ifFalse: ['^']).
  515. self lazyAssignValue: ''
  516. !
  517. visitSendNode: aNode
  518. | receiver superSend rcv |
  519. (messageSends includes: aNode selector) ifFalse: [
  520. messageSends add: aNode selector].
  521. self performOptimizations
  522. ifTrue: [
  523. (self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifTrue: [ ^self ].
  524. ].
  525. rcv := self isolated: aNode receiver.
  526. superSend := (lazyVars at: rcv ifAbsent: []) = 'super'.
  527. superSend ifTrue: [ mutables remove: rcv. lazyVars at: rcv put: 'self' ].
  528. self performOptimizations
  529. ifTrue: [ | inline |
  530. inline := self inline: aNode selector receiver: rcv argumentNodes: aNode arguments.
  531. inline ifNotNil: [ | args |
  532. args := inline = true ifTrue: [ aNode arguments ] ifFalse: [ inline ].
  533. self prvPutAndClose: [ self send: aNode selector to: rcv arguments: args superSend: superSend ].
  534. ^self ]].
  535. self send: aNode selector to: rcv arguments: aNode arguments superSend: superSend
  536. !
  537. visitSequenceNode: aNode
  538. aNode nodes isEmpty ifFalse: [
  539. self sequenceOfNodes: aNode nodes temps: aNode temps ]
  540. !
  541. visitValueNode: aNode
  542. self lazyAssignValue: aNode value asJavascript
  543. !
  544. visitVariableNode: aNode
  545. | varName |
  546. (self currentClass allInstanceVariableNames includes: aNode value)
  547. ifTrue: [self lazyAssignExpression: 'self[''@', aNode value, ''']']
  548. ifFalse: [
  549. varName := self safeVariableNameFor: aNode value.
  550. (self knownVariables includes: varName)
  551. ifFalse: [
  552. unknownVariables add: aNode value.
  553. aNode assigned
  554. ifTrue: [self lazyAssignExpression: varName]
  555. ifFalse: [self lazyAssignExpression: '(typeof ', varName, ' == ''undefined'' ? nil : ', varName, ')']]
  556. ifTrue: [
  557. aNode value = 'thisContext'
  558. ifTrue: [self lazyAssignExpression: '(smalltalk.getThisContext())']
  559. ifFalse: [(self pseudoVariables includes: varName)
  560. ifTrue: [ self lazyAssignValue: varName ]
  561. ifFalse: [ self lazyAssignExpression: varName]]]]
  562. !
  563. visitVerbatimNode: aNode
  564. self lazyAssignValue: aNode value
  565. ! !
  566. ImpCodeGenerator class instanceVariableNames: 'performOptimizations'!
  567. !ImpCodeGenerator class methodsFor: 'accessing'!
  568. performOptimizations
  569. ^performOptimizations ifNil: [true]
  570. !
  571. performOptimizations: aBoolean
  572. performOptimizations := aBoolean
  573. ! !
  574. NodeVisitor subclass: #ReturnNodeChecker
  575. instanceVariableNames: 'wasReturnNode'
  576. package: 'Compiler-Visitors'!
  577. !ReturnNodeChecker methodsFor: 'accessing'!
  578. wasReturnNode
  579. ^wasReturnNode
  580. ! !
  581. !ReturnNodeChecker methodsFor: 'initializing'!
  582. initialize
  583. wasReturnNode := false
  584. ! !
  585. !ReturnNodeChecker methodsFor: 'visiting'!
  586. visitReturnNode: aNode
  587. wasReturnNode := true
  588. ! !