Compiler-IR.st 26 KB

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