Compiler-IR.st 26 KB

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