Compiler-IR.st 26 KB

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