1
0

Compiler-IR.st 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280
  1. Smalltalk current createPackage: 'Compiler-IR'!
  2. NodeVisitor subclass: #IRASTTranslator
  3. instanceVariableNames: 'source theClass method sequence nextAlias'
  4. package: 'Compiler-IR'!
  5. !IRASTTranslator commentStamp!
  6. I am the AST (abstract syntax tree) visitor responsible for building the intermediate representation graph.!
  7. !IRASTTranslator methodsFor: 'accessing'!
  8. method
  9. ^ method
  10. !
  11. method: anIRMethod
  12. method := anIRMethod
  13. !
  14. nextAlias
  15. nextAlias ifNil: [ nextAlias := 0 ].
  16. nextAlias := nextAlias + 1.
  17. ^ nextAlias asString
  18. !
  19. sequence
  20. ^ sequence
  21. !
  22. sequence: anIRSequence
  23. sequence := anIRSequence
  24. !
  25. source
  26. ^ source
  27. !
  28. source: aString
  29. source := aString
  30. !
  31. theClass
  32. ^ theClass
  33. !
  34. theClass: aClass
  35. theClass := aClass
  36. !
  37. withSequence: aSequence do: aBlock
  38. | outerSequence |
  39. outerSequence := self sequence.
  40. self sequence: aSequence.
  41. aBlock value.
  42. self sequence: outerSequence.
  43. ^ aSequence
  44. ! !
  45. !IRASTTranslator methodsFor: 'visiting'!
  46. alias: aNode
  47. | variable |
  48. aNode isImmutable ifTrue: [ ^ self visit: aNode ].
  49. variable := IRVariable new
  50. variable: (AliasVar new name: '$', self nextAlias);
  51. yourself.
  52. self sequence add: (IRAssignment new
  53. add: variable;
  54. add: (self visit: aNode);
  55. yourself).
  56. self method internalVariables add: variable.
  57. ^ variable
  58. !
  59. aliasTemporally: aCollection
  60. "https://github.com/NicolasPetton/amber/issues/296
  61. If a node is aliased, all preceding ones are aliased as well.
  62. The tree is iterated twice. First we get the aliasing dependency,
  63. then the aliasing itself is done"
  64. | threshold result |
  65. threshold := 0.
  66. aCollection withIndexDo: [ :each :i |
  67. each subtreeNeedsAliasing
  68. ifTrue: [ threshold := i ]].
  69. result := OrderedCollection new.
  70. aCollection withIndexDo: [ :each :i |
  71. result add: (i <= threshold
  72. ifTrue: [ self alias: each ]
  73. ifFalse: [ self visit: each ])].
  74. ^result
  75. !
  76. visitAssignmentNode: aNode
  77. | left right assignment |
  78. right := self visit: aNode right.
  79. left := self visit: aNode left.
  80. self sequence add: (IRAssignment new
  81. add: left;
  82. add: right;
  83. yourself).
  84. ^ left
  85. !
  86. visitBlockNode: aNode
  87. | closure |
  88. closure := IRClosure new
  89. arguments: aNode parameters;
  90. scope: aNode scope;
  91. yourself.
  92. aNode scope temps do: [ :each |
  93. closure add: (IRTempDeclaration new
  94. name: each name;
  95. scope: aNode scope;
  96. yourself) ].
  97. aNode nodes do: [ :each | closure add: (self visit: each) ].
  98. ^ closure
  99. !
  100. visitBlockSequenceNode: aNode
  101. ^ self
  102. withSequence: IRBlockSequence new
  103. do: [
  104. aNode nodes ifNotEmpty: [
  105. aNode nodes allButLast do: [ :each |
  106. self sequence add: (self visit: each) ].
  107. aNode nodes last isReturnNode
  108. ifFalse: [ self sequence add: (IRBlockReturn new add: (self visit: aNode nodes last); yourself) ]
  109. ifTrue: [ self sequence add: (self visit: aNode nodes last) ]]]
  110. !
  111. visitCascadeNode: aNode
  112. | alias |
  113. aNode receiver isImmutable ifFalse: [
  114. alias := self alias: aNode receiver.
  115. aNode nodes do: [ :each |
  116. each receiver: (VariableNode new binding: alias variable) ]].
  117. aNode nodes allButLast do: [ :each |
  118. self sequence add: (self visit: each) ].
  119. ^ self alias: aNode nodes last
  120. !
  121. visitDynamicArrayNode: aNode
  122. | array |
  123. array := IRDynamicArray new.
  124. (self aliasTemporally: aNode nodes) do: [:each | array add: each].
  125. ^ array
  126. !
  127. visitDynamicDictionaryNode: aNode
  128. | dictionary |
  129. dictionary := IRDynamicDictionary new.
  130. (self aliasTemporally: aNode nodes) do: [:each | dictionary add: each].
  131. ^ dictionary
  132. !
  133. visitJSStatementNode: aNode
  134. ^ IRVerbatim new
  135. source: aNode source crlfSanitized;
  136. yourself
  137. !
  138. visitMethodNode: aNode
  139. self method: (IRMethod new
  140. source: self source crlfSanitized;
  141. theClass: self theClass;
  142. arguments: aNode arguments;
  143. selector: aNode selector;
  144. sendIndexes: aNode sendIndexes;
  145. superSends: aNode superSends;
  146. classReferences: aNode classReferences;
  147. scope: aNode scope;
  148. yourself).
  149. aNode scope temps do: [ :each |
  150. self method add: (IRTempDeclaration new
  151. name: each name;
  152. scope: aNode scope;
  153. yourself) ].
  154. aNode nodes do: [ :each | self method add: (self visit: each) ].
  155. aNode scope hasLocalReturn ifFalse: [
  156. (self method add: IRReturn new) add: (IRVariable new
  157. variable: (aNode scope pseudoVars at: 'self');
  158. yourself) ].
  159. ^ self method
  160. !
  161. visitReturnNode: aNode
  162. | return |
  163. return := aNode nonLocalReturn
  164. ifTrue: [ IRNonLocalReturn new ]
  165. ifFalse: [ IRReturn new ].
  166. return scope: aNode scope.
  167. aNode nodes do: [ :each |
  168. return add: (self alias: each) ].
  169. ^ return
  170. !
  171. visitSendNode: aNode
  172. | send all receiver arguments |
  173. send := IRSend new.
  174. send
  175. selector: aNode selector;
  176. index: aNode index.
  177. aNode superSend ifTrue: [ send classSend: self theClass superclass ].
  178. all := self aliasTemporally: { aNode receiver }, aNode arguments.
  179. receiver := all first.
  180. arguments := all allButFirst.
  181. send add: receiver.
  182. arguments do: [ :each | send add: each ].
  183. ^ send
  184. !
  185. visitSequenceNode: aNode
  186. ^ self
  187. withSequence: IRSequence new
  188. do: [
  189. aNode nodes do: [ :each | | instruction |
  190. instruction := each shouldBeAliased
  191. ifTrue: [ self alias: each ]
  192. ifFalse: [ self visit: each ].
  193. instruction isVariable ifFalse: [
  194. self sequence add: instruction ]]]
  195. !
  196. visitValueNode: aNode
  197. ^ IRValue new
  198. value: aNode value;
  199. yourself
  200. !
  201. visitVariableNode: aNode
  202. ^ IRVariable new
  203. variable: aNode binding;
  204. yourself
  205. ! !
  206. Object subclass: #IRInstruction
  207. instanceVariableNames: 'parent instructions'
  208. package: 'Compiler-IR'!
  209. !IRInstruction commentStamp!
  210. I am the abstract root class of the IR (intermediate representation) instructions class hierarchy.
  211. The IR graph is used to emit JavaScript code using a JSStream.!
  212. !IRInstruction methodsFor: 'accessing'!
  213. instructions
  214. ^ instructions ifNil: [ instructions := OrderedCollection new ]
  215. !
  216. method
  217. ^ self parent method
  218. !
  219. parent
  220. ^ parent
  221. !
  222. parent: anIRInstruction
  223. parent := anIRInstruction
  224. !
  225. scope
  226. ^ self parent ifNotNil: [ :node |
  227. node scope ]
  228. ! !
  229. !IRInstruction methodsFor: 'building'!
  230. add: anObject
  231. anObject parent: self.
  232. ^ self instructions add: anObject
  233. !
  234. remove
  235. self parent remove: self
  236. !
  237. remove: anIRInstruction
  238. self instructions remove: anIRInstruction
  239. !
  240. replace: anIRInstruction with: anotherIRInstruction
  241. anotherIRInstruction parent: self.
  242. self instructions
  243. at: (self instructions indexOf: anIRInstruction)
  244. put: anotherIRInstruction
  245. !
  246. replaceWith: anIRInstruction
  247. self parent replace: self with: anIRInstruction
  248. ! !
  249. !IRInstruction methodsFor: 'testing'!
  250. canBeAssigned
  251. ^ true
  252. !
  253. isClosure
  254. ^ false
  255. !
  256. isInlined
  257. ^ false
  258. !
  259. isLocalReturn
  260. ^ false
  261. !
  262. isMethod
  263. ^ false
  264. !
  265. isReturn
  266. ^ false
  267. !
  268. isSend
  269. ^ false
  270. !
  271. isSequence
  272. ^ false
  273. !
  274. isTempDeclaration
  275. ^ false
  276. !
  277. isVariable
  278. ^ false
  279. !
  280. needsBoxingAsReceiver
  281. ^ true
  282. ! !
  283. !IRInstruction methodsFor: 'visiting'!
  284. accept: aVisitor
  285. ^ aVisitor visitIRInstruction: self
  286. ! !
  287. !IRInstruction class methodsFor: 'instance creation'!
  288. on: aBuilder
  289. ^ self new
  290. builder: aBuilder;
  291. yourself
  292. ! !
  293. IRInstruction subclass: #IRAssignment
  294. instanceVariableNames: ''
  295. package: 'Compiler-IR'!
  296. !IRAssignment methodsFor: 'visiting'!
  297. accept: aVisitor
  298. ^ aVisitor visitIRAssignment: self
  299. ! !
  300. IRInstruction subclass: #IRDynamicArray
  301. instanceVariableNames: ''
  302. package: 'Compiler-IR'!
  303. !IRDynamicArray methodsFor: 'visiting'!
  304. accept: aVisitor
  305. ^ aVisitor visitIRDynamicArray: self
  306. ! !
  307. IRInstruction subclass: #IRDynamicDictionary
  308. instanceVariableNames: ''
  309. package: 'Compiler-IR'!
  310. !IRDynamicDictionary methodsFor: 'visiting'!
  311. accept: aVisitor
  312. ^ aVisitor visitIRDynamicDictionary: self
  313. ! !
  314. IRInstruction subclass: #IRScopedInstruction
  315. instanceVariableNames: 'scope'
  316. package: 'Compiler-IR'!
  317. !IRScopedInstruction methodsFor: 'accessing'!
  318. scope
  319. ^ scope
  320. !
  321. scope: aScope
  322. scope := aScope
  323. ! !
  324. IRScopedInstruction subclass: #IRClosureInstruction
  325. instanceVariableNames: 'arguments'
  326. package: 'Compiler-IR'!
  327. !IRClosureInstruction methodsFor: 'accessing'!
  328. arguments
  329. ^ arguments ifNil: [ #() ]
  330. !
  331. arguments: aCollection
  332. arguments := aCollection
  333. !
  334. locals
  335. ^ self arguments copy
  336. addAll: (self tempDeclarations collect: [ :each | each name ]);
  337. yourself
  338. !
  339. scope: aScope
  340. super scope: aScope.
  341. aScope instruction: self
  342. !
  343. tempDeclarations
  344. ^ self instructions select: [ :each |
  345. each isTempDeclaration ]
  346. ! !
  347. IRClosureInstruction subclass: #IRClosure
  348. instanceVariableNames: ''
  349. package: 'Compiler-IR'!
  350. !IRClosure methodsFor: 'accessing'!
  351. sequence
  352. ^ self instructions last
  353. ! !
  354. !IRClosure methodsFor: 'testing'!
  355. isClosure
  356. ^ true
  357. ! !
  358. !IRClosure methodsFor: 'visiting'!
  359. accept: aVisitor
  360. ^ aVisitor visitIRClosure: self
  361. ! !
  362. IRClosureInstruction subclass: #IRMethod
  363. instanceVariableNames: 'theClass source selector classReferences sendIndexes superSends internalVariables'
  364. package: 'Compiler-IR'!
  365. !IRMethod commentStamp!
  366. I am a method instruction!
  367. !IRMethod methodsFor: 'accessing'!
  368. classReferences
  369. ^ classReferences
  370. !
  371. classReferences: aCollection
  372. classReferences := aCollection
  373. !
  374. internalVariables
  375. ^ internalVariables ifNil: [ internalVariables := Set new ]
  376. !
  377. isMethod
  378. ^ true
  379. !
  380. messageSends
  381. ^ self sendIndexes keys
  382. !
  383. method
  384. ^ self
  385. !
  386. selector
  387. ^ selector
  388. !
  389. selector: aString
  390. selector := aString
  391. !
  392. sendIndexes
  393. ^ sendIndexes
  394. !
  395. sendIndexes: aDictionary
  396. sendIndexes := aDictionary
  397. !
  398. source
  399. ^ source
  400. !
  401. source: aString
  402. source := aString
  403. !
  404. superSends
  405. ^ superSends
  406. !
  407. superSends: aCollection
  408. superSends := aCollection
  409. !
  410. theClass
  411. ^ theClass
  412. !
  413. theClass: aClass
  414. theClass := aClass
  415. ! !
  416. !IRMethod methodsFor: 'visiting'!
  417. accept: aVisitor
  418. ^ aVisitor visitIRMethod: self
  419. ! !
  420. IRScopedInstruction subclass: #IRReturn
  421. instanceVariableNames: ''
  422. package: 'Compiler-IR'!
  423. !IRReturn commentStamp!
  424. I am a local return instruction.!
  425. !IRReturn methodsFor: 'accessing'!
  426. scope
  427. ^ scope ifNil: [ self parent scope ]
  428. ! !
  429. !IRReturn methodsFor: 'testing'!
  430. canBeAssigned
  431. ^ false
  432. !
  433. isBlockReturn
  434. ^ false
  435. !
  436. isLocalReturn
  437. ^ true
  438. !
  439. isNonLocalReturn
  440. ^ self isLocalReturn not
  441. !
  442. isReturn
  443. ^ true
  444. ! !
  445. !IRReturn methodsFor: 'visiting'!
  446. accept: aVisitor
  447. ^ aVisitor visitIRReturn: self
  448. ! !
  449. IRReturn subclass: #IRBlockReturn
  450. instanceVariableNames: ''
  451. package: 'Compiler-IR'!
  452. !IRBlockReturn commentStamp!
  453. Smalltalk blocks return their last statement. I am a implicit block return instruction.!
  454. !IRBlockReturn methodsFor: 'testing'!
  455. isBlockReturn
  456. ^ true
  457. ! !
  458. !IRBlockReturn methodsFor: 'visiting'!
  459. accept: aVisitor
  460. ^ aVisitor visitIRBlockReturn: self
  461. ! !
  462. IRReturn subclass: #IRNonLocalReturn
  463. instanceVariableNames: ''
  464. package: 'Compiler-IR'!
  465. !IRNonLocalReturn commentStamp!
  466. I am a non local return instruction.
  467. Non local returns are handled using a try/catch JavaScript statement.
  468. See `IRNonLocalReturnHandling` class.!
  469. !IRNonLocalReturn methodsFor: 'testing'!
  470. isLocalReturn
  471. ^ false
  472. ! !
  473. !IRNonLocalReturn methodsFor: 'visiting'!
  474. accept: aVisitor
  475. ^ aVisitor visitIRNonLocalReturn: self
  476. ! !
  477. IRScopedInstruction subclass: #IRTempDeclaration
  478. instanceVariableNames: 'name'
  479. package: 'Compiler-IR'!
  480. !IRTempDeclaration methodsFor: 'accessing'!
  481. name
  482. ^ name
  483. !
  484. name: aString
  485. name := aString
  486. ! !
  487. !IRTempDeclaration methodsFor: 'testing'!
  488. isTempDeclaration
  489. ^ true
  490. ! !
  491. !IRTempDeclaration methodsFor: 'visiting'!
  492. accept: aVisitor
  493. ^ aVisitor visitIRTempDeclaration: self
  494. ! !
  495. IRInstruction subclass: #IRSend
  496. instanceVariableNames: 'selector classSend index'
  497. package: 'Compiler-IR'!
  498. !IRSend commentStamp!
  499. I am a message send instruction.!
  500. !IRSend methodsFor: 'accessing'!
  501. classSend
  502. ^ classSend
  503. !
  504. classSend: aClass
  505. classSend := aClass
  506. !
  507. index
  508. ^ index
  509. !
  510. index: anInteger
  511. index := anInteger
  512. !
  513. selector
  514. ^ selector
  515. !
  516. selector: aString
  517. selector := aString
  518. ! !
  519. !IRSend methodsFor: 'testing'!
  520. isSend
  521. ^ true
  522. ! !
  523. !IRSend methodsFor: 'visiting'!
  524. accept: aVisitor
  525. ^ aVisitor visitIRSend: self
  526. ! !
  527. IRInstruction subclass: #IRSequence
  528. instanceVariableNames: ''
  529. package: 'Compiler-IR'!
  530. !IRSequence methodsFor: 'testing'!
  531. isSequence
  532. ^ true
  533. ! !
  534. !IRSequence methodsFor: 'visiting'!
  535. accept: aVisitor
  536. ^ aVisitor visitIRSequence: self
  537. ! !
  538. IRSequence subclass: #IRBlockSequence
  539. instanceVariableNames: ''
  540. package: 'Compiler-IR'!
  541. !IRBlockSequence methodsFor: 'visiting'!
  542. accept: aVisitor
  543. ^ aVisitor visitIRBlockSequence: self
  544. ! !
  545. IRInstruction subclass: #IRValue
  546. instanceVariableNames: 'value'
  547. package: 'Compiler-IR'!
  548. !IRValue commentStamp!
  549. I am the simplest possible instruction. I represent a value.!
  550. !IRValue methodsFor: 'accessing'!
  551. value
  552. ^value
  553. !
  554. value: aString
  555. value := aString
  556. ! !
  557. !IRValue methodsFor: 'testing'!
  558. needsBoxingAsReceiver
  559. ^ false
  560. ! !
  561. !IRValue methodsFor: 'visiting'!
  562. accept: aVisitor
  563. ^ aVisitor visitIRValue: self
  564. ! !
  565. IRInstruction subclass: #IRVariable
  566. instanceVariableNames: 'variable'
  567. package: 'Compiler-IR'!
  568. !IRVariable commentStamp!
  569. I am a variable instruction.!
  570. !IRVariable methodsFor: 'accessing'!
  571. variable
  572. ^ variable
  573. !
  574. variable: aScopeVariable
  575. variable := aScopeVariable
  576. ! !
  577. !IRVariable methodsFor: 'testing'!
  578. isVariable
  579. ^ true
  580. !
  581. needsBoxingAsReceiver
  582. ^ self variable isPseudoVar not
  583. ! !
  584. !IRVariable methodsFor: 'visiting'!
  585. accept: aVisitor
  586. ^ aVisitor visitIRVariable: self
  587. ! !
  588. IRInstruction subclass: #IRVerbatim
  589. instanceVariableNames: 'source'
  590. package: 'Compiler-IR'!
  591. !IRVerbatim methodsFor: 'accessing'!
  592. source
  593. ^ source
  594. !
  595. source: aString
  596. source := aString
  597. ! !
  598. !IRVerbatim methodsFor: 'visiting'!
  599. accept: aVisitor
  600. ^ aVisitor visitIRVerbatim: self
  601. ! !
  602. Object subclass: #IRVisitor
  603. instanceVariableNames: ''
  604. package: 'Compiler-IR'!
  605. !IRVisitor methodsFor: 'visiting'!
  606. visit: anIRInstruction
  607. ^ anIRInstruction accept: self
  608. !
  609. visitIRAssignment: anIRAssignment
  610. ^ self visitIRInstruction: anIRAssignment
  611. !
  612. visitIRBlockReturn: anIRBlockReturn
  613. ^ self visitIRReturn: anIRBlockReturn
  614. !
  615. visitIRBlockSequence: anIRBlockSequence
  616. ^ self visitIRSequence: anIRBlockSequence
  617. !
  618. visitIRClosure: anIRClosure
  619. ^ self visitIRInstruction: anIRClosure
  620. !
  621. visitIRDynamicArray: anIRDynamicArray
  622. ^ self visitIRInstruction: anIRDynamicArray
  623. !
  624. visitIRDynamicDictionary: anIRDynamicDictionary
  625. ^ self visitIRInstruction: anIRDynamicDictionary
  626. !
  627. visitIRInlinedClosure: anIRInlinedClosure
  628. ^ self visitIRClosure: anIRInlinedClosure
  629. !
  630. visitIRInlinedSequence: anIRInlinedSequence
  631. ^ self visitIRSequence: anIRInlinedSequence
  632. !
  633. visitIRInstruction: anIRInstruction
  634. anIRInstruction instructions do: [ :each | self visit: each ].
  635. ^ anIRInstruction
  636. !
  637. visitIRMethod: anIRMethod
  638. ^ self visitIRInstruction: anIRMethod
  639. !
  640. visitIRNonLocalReturn: anIRNonLocalReturn
  641. ^ self visitIRInstruction: anIRNonLocalReturn
  642. !
  643. visitIRNonLocalReturnHandling: anIRNonLocalReturnHandling
  644. ^ self visitIRInstruction: anIRNonLocalReturnHandling
  645. !
  646. visitIRReturn: anIRReturn
  647. ^ self visitIRInstruction: anIRReturn
  648. !
  649. visitIRSend: anIRSend
  650. ^ self visitIRInstruction: anIRSend
  651. !
  652. visitIRSequence: anIRSequence
  653. ^ self visitIRInstruction: anIRSequence
  654. !
  655. visitIRTempDeclaration: anIRTempDeclaration
  656. ^ self visitIRInstruction: anIRTempDeclaration
  657. !
  658. visitIRValue: anIRValue
  659. ^ self visitIRInstruction: anIRValue
  660. !
  661. visitIRVariable: anIRVariable
  662. ^ self visitIRInstruction: anIRVariable
  663. !
  664. visitIRVerbatim: anIRVerbatim
  665. ^ self visitIRInstruction: anIRVerbatim
  666. ! !
  667. IRVisitor subclass: #IRJSTranslator
  668. instanceVariableNames: 'stream currentClass'
  669. package: 'Compiler-IR'!
  670. !IRJSTranslator methodsFor: 'accessing'!
  671. contents
  672. ^ self stream contents
  673. !
  674. currentClass
  675. ^ currentClass
  676. !
  677. currentClass: aClass
  678. currentClass := aClass
  679. !
  680. stream
  681. ^ stream
  682. !
  683. stream: aStream
  684. stream := aStream
  685. ! !
  686. !IRJSTranslator methodsFor: 'initialization'!
  687. initialize
  688. super initialize.
  689. stream := JSStream new.
  690. ! !
  691. !IRJSTranslator methodsFor: 'visiting'!
  692. visitIRAssignment: anIRAssignment
  693. self visit: anIRAssignment instructions first.
  694. self stream nextPutAssignment.
  695. self visit: anIRAssignment instructions last.
  696. !
  697. visitIRClosure: anIRClosure
  698. self stream
  699. nextPutClosureWith: [
  700. self stream nextPutVars: (anIRClosure tempDeclarations collect: [ :each |
  701. each name asVariableName ]).
  702. self stream
  703. nextPutBlockContextFor: anIRClosure
  704. during: [ super visitIRClosure: anIRClosure ] ]
  705. arguments: anIRClosure arguments
  706. !
  707. visitIRDynamicArray: anIRDynamicArray
  708. self stream nextPutAll: '['.
  709. anIRDynamicArray instructions
  710. do: [ :each | self visit: each ]
  711. separatedBy: [ self stream nextPutAll: ',' ].
  712. stream nextPutAll: ']'
  713. !
  714. visitIRDynamicDictionary: anIRDynamicDictionary
  715. self stream nextPutAll: 'smalltalk.HashedCollection._from_(['.
  716. anIRDynamicDictionary instructions
  717. do: [ :each | self visit: each ]
  718. separatedBy: [self stream nextPutAll: ',' ].
  719. self stream nextPutAll: '])'
  720. !
  721. visitIRMethod: anIRMethod
  722. self stream
  723. nextPutMethodDeclaration: anIRMethod
  724. with: [ self stream
  725. nextPutFunctionWith: [
  726. self stream nextPutVars: (anIRMethod tempDeclarations collect: [ :each |
  727. each name asVariableName ]).
  728. anIRMethod classReferences do: [ :each | self stream nextPutClassRefFunction: each ].
  729. self stream nextPutContextFor: anIRMethod during: [
  730. anIRMethod internalVariables notEmpty ifTrue: [
  731. self stream nextPutVars: (anIRMethod internalVariables asArray collect: [ :each |
  732. each variable alias ]) ].
  733. anIRMethod scope hasNonLocalReturn
  734. ifTrue: [
  735. self stream nextPutNonLocalReturnHandlingWith: [
  736. super visitIRMethod: anIRMethod ]]
  737. ifFalse: [ super visitIRMethod: anIRMethod ]]]
  738. arguments: anIRMethod arguments ]
  739. !
  740. visitIRNonLocalReturn: anIRNonLocalReturn
  741. self stream nextPutNonLocalReturnWith: [
  742. super visitIRNonLocalReturn: anIRNonLocalReturn ]
  743. !
  744. visitIRReturn: anIRReturn
  745. self stream nextPutReturnWith: [
  746. super visitIRReturn: anIRReturn ]
  747. !
  748. visitIRSend: anIRSend
  749. anIRSend classSend
  750. ifNil: [ self visitSend: anIRSend ]
  751. ifNotNil: [ self visitSuperSend: anIRSend ].
  752. " (anIRSend method sendIndexes at: anIRSend selector) size > 1
  753. ifTrue: [ self stream nextPutSendIndexFor: anIRSend ]"
  754. !
  755. visitIRSequence: anIRSequence
  756. self stream nextPutSequenceWith: [
  757. anIRSequence instructions do: [ :each |
  758. self stream nextPutStatementWith: (self visit: each) ]]
  759. !
  760. visitIRTempDeclaration: anIRTempDeclaration
  761. "self stream
  762. nextPutAll: 'var ', anIRTempDeclaration name asVariableName, ';';
  763. lf"
  764. !
  765. visitIRValue: anIRValue
  766. self stream nextPutAll: anIRValue value asJavascript
  767. !
  768. visitIRVariable: anIRVariable
  769. anIRVariable variable name = 'thisContext'
  770. ifTrue: [ self stream nextPutAll: 'smalltalk.getThisContext()' ]
  771. ifFalse: [ self stream nextPutAll: anIRVariable variable alias ]
  772. !
  773. visitIRVerbatim: anIRVerbatim
  774. self stream nextPutStatementWith: [
  775. self stream nextPutAll: anIRVerbatim source ]
  776. !
  777. visitReceiver: anIRInstruction
  778. anIRInstruction needsBoxingAsReceiver ifFalse: [ ^ self visit: anIRInstruction ].
  779. self stream nextPutAll: '_st('.
  780. self visit: anIRInstruction.
  781. self stream nextPutAll: ')'
  782. !
  783. visitSend: anIRSend
  784. self visitReceiver: anIRSend instructions first.
  785. self stream nextPutAll: '.', anIRSend selector asSelector, '('.
  786. anIRSend instructions allButFirst
  787. do: [ :each | self visit: each ]
  788. separatedBy: [ self stream nextPutAll: ',' ].
  789. self stream nextPutAll: ')'
  790. !
  791. visitSuperSend: anIRSend
  792. self stream
  793. nextPutAll: self currentClass asJavascript;
  794. nextPutAll: '.superclass.fn.prototype.';
  795. nextPutAll: anIRSend selector asSelector, '.apply(';
  796. nextPutAll: '_st('.
  797. self visit: anIRSend instructions first.
  798. self stream nextPutAll: '), ['.
  799. anIRSend instructions allButFirst
  800. do: [ :each | self visit: each ]
  801. separatedBy: [ self stream nextPutAll: ',' ].
  802. self stream nextPutAll: '])'
  803. ! !
  804. Object subclass: #JSStream
  805. instanceVariableNames: 'stream'
  806. package: 'Compiler-IR'!
  807. !JSStream methodsFor: 'accessing'!
  808. contents
  809. ^ stream contents
  810. ! !
  811. !JSStream methodsFor: 'initialization'!
  812. initialize
  813. super initialize.
  814. stream := '' writeStream.
  815. ! !
  816. !JSStream methodsFor: 'streaming'!
  817. lf
  818. stream lf
  819. !
  820. nextPut: aString
  821. stream nextPut: aString
  822. !
  823. nextPutAll: aString
  824. stream nextPutAll: aString
  825. !
  826. nextPutAssignment
  827. stream nextPutAll: '='
  828. !
  829. nextPutBlockContextFor: anIRClosure during: aBlock
  830. self
  831. nextPutAll: 'return smalltalk.withContext(function(', anIRClosure scope alias, ') {'; lf.
  832. aBlock value.
  833. self
  834. nextPutAll: '}, function(', anIRClosure scope alias, ') {';
  835. nextPutAll: anIRClosure scope alias, '.fillBlock({'.
  836. anIRClosure locals
  837. do: [ :each |
  838. self
  839. nextPutAll: each asVariableName;
  840. nextPutAll: ':';
  841. nextPutAll: each asVariableName]
  842. separatedBy: [ self nextPutAll: ',' ].
  843. self
  844. nextPutAll: '},';
  845. nextPutAll: anIRClosure scope outerScope alias, ',', anIRClosure scope blockIndex asString, ')})'
  846. !
  847. nextPutClassRefFunction: aString
  848. "Creates an inner function $aString into method and called as `$Foo()`whenever the global is accessed.
  849. This ensures that undefined global access will answer `nil`"
  850. stream
  851. nextPutAll: 'function $';
  852. nextPutAll: aString;
  853. nextPutAll: '(){return smalltalk.';
  854. nextPutAll: aString;
  855. nextPutAll: '||(typeof ';
  856. nextPutAll: aString;
  857. nextPutAll: '=="undefined"?nil:';
  858. nextPutAll: aString;
  859. nextPutAll: ')}';
  860. lf
  861. !
  862. nextPutClosureWith: aBlock arguments: anArray
  863. stream nextPutAll: '(function('.
  864. anArray
  865. do: [ :each | stream nextPutAll: each asVariableName ]
  866. separatedBy: [ stream nextPut: ',' ].
  867. stream nextPutAll: '){'; lf.
  868. aBlock value.
  869. stream nextPutAll: '})'
  870. !
  871. nextPutContextFor: aMethod during: aBlock
  872. self
  873. nextPutAll: 'return smalltalk.withContext(function(', aMethod scope alias, ') { '; lf.
  874. aBlock value.
  875. self
  876. nextPutAll: '}, function(', aMethod scope alias, ') {', aMethod scope alias;
  877. nextPutAll: '.fill(self,', aMethod selector asJavascript, ',{'.
  878. aMethod locals
  879. do: [ :each |
  880. self
  881. nextPutAll: each asVariableName;
  882. nextPutAll: ':';
  883. nextPutAll: each asVariableName]
  884. separatedBy: [ self nextPutAll: ',' ].
  885. self
  886. nextPutAll: '},';
  887. nextPutAll: aMethod theClass asJavascript;
  888. nextPutAll: ')})'
  889. !
  890. nextPutFunctionWith: aBlock arguments: anArray
  891. stream nextPutAll: 'fn: function('.
  892. anArray
  893. do: [ :each | stream nextPutAll: each asVariableName ]
  894. separatedBy: [ stream nextPut: ',' ].
  895. stream nextPutAll: '){'; lf.
  896. stream nextPutAll: 'var self=this;'; lf.
  897. aBlock value.
  898. stream nextPutAll: '}'
  899. !
  900. nextPutIf: aBlock with: anotherBlock
  901. stream nextPutAll: 'if('.
  902. aBlock value.
  903. stream nextPutAll: '){'; lf.
  904. anotherBlock value.
  905. stream nextPutAll: '}'
  906. !
  907. nextPutIfElse: aBlock with: ifBlock with: elseBlock
  908. stream nextPutAll: 'if('.
  909. aBlock value.
  910. stream nextPutAll: '){'; lf.
  911. ifBlock value.
  912. stream nextPutAll: '} else {'; lf.
  913. elseBlock value.
  914. stream nextPutAll: '}'
  915. !
  916. nextPutMethodDeclaration: aMethod with: aBlock
  917. stream
  918. nextPutAll: 'smalltalk.method({'; lf;
  919. nextPutAll: 'selector: ', aMethod selector asJavascript, ','; lf;
  920. nextPutAll: 'source: ', aMethod source asJavascript, ',';lf.
  921. aBlock value.
  922. stream
  923. nextPutAll: ',', String lf, 'messageSends: ';
  924. nextPutAll: aMethod messageSends asArray asJavascript, ','; lf;
  925. nextPutAll: 'args: ', (aMethod arguments collect: [ :each | each value ]) asArray asJavascript, ','; lf;
  926. nextPutAll: 'referencedClasses: ['.
  927. aMethod classReferences
  928. do: [:each | stream nextPutAll: each asJavascript]
  929. separatedBy: [stream nextPutAll: ','].
  930. stream
  931. nextPutAll: ']';
  932. nextPutAll: '})'
  933. !
  934. nextPutNonLocalReturnHandlingWith: aBlock
  935. stream
  936. nextPutAll: 'var $early={};'; lf;
  937. nextPutAll: 'try {'; lf.
  938. aBlock value.
  939. stream
  940. nextPutAll: '}'; lf;
  941. nextPutAll: 'catch(e) {if(e===$early)return e[0]; throw e}'; lf
  942. !
  943. nextPutNonLocalReturnWith: aBlock
  944. stream nextPutAll: 'throw $early=['.
  945. aBlock value.
  946. stream nextPutAll: ']'
  947. !
  948. nextPutReturn
  949. stream nextPutAll: 'return '
  950. !
  951. nextPutReturnWith: aBlock
  952. self nextPutReturn.
  953. aBlock value
  954. !
  955. nextPutSendIndexFor: anIRSend
  956. self
  957. nextPutAll: ';'; lf;
  958. nextPutAll: anIRSend scope alias;
  959. nextPutAll: '.sendIdx["';
  960. nextPutAll: anIRSend selector;
  961. nextPutAll: '"]=';
  962. nextPutAll: anIRSend index asString
  963. !
  964. nextPutSequenceWith: aBlock
  965. "stream
  966. nextPutAll: 'switch(smalltalk.thisContext.pc){'; lf."
  967. aBlock value.
  968. "stream
  969. nextPutAll: '};'; lf"
  970. !
  971. nextPutStatementWith: aBlock
  972. aBlock value.
  973. stream nextPutAll: ';'; lf
  974. !
  975. nextPutVars: aCollection
  976. aCollection ifEmpty: [ ^self ].
  977. stream nextPutAll: 'var '.
  978. aCollection
  979. do: [ :each | stream nextPutAll: each ]
  980. separatedBy: [ stream nextPutAll: ',' ].
  981. stream nextPutAll: ';'; lf
  982. ! !
  983. !BlockClosure methodsFor: '*Compiler-IR'!
  984. appendToInstruction: anIRInstruction
  985. anIRInstruction appendBlock: self
  986. ! !
  987. !String methodsFor: '*Compiler-IR'!
  988. asVariableName
  989. ^ (Smalltalk current reservedWords includes: self)
  990. ifTrue: [ self, '_' ]
  991. ifFalse: [ self ]
  992. ! !