Compiler-IR.st 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459
  1. Smalltalk createPackage: 'Compiler-IR'!
  2. NodeVisitor subclass: #IRASTTranslator
  3. slots: {#source. #theClass. #method. #sequence}
  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. sequence
  15. ^ sequence
  16. !
  17. sequence: anIRSequence
  18. sequence := anIRSequence
  19. !
  20. source
  21. ^ source
  22. !
  23. source: aString
  24. source := aString
  25. !
  26. theClass
  27. ^ theClass
  28. !
  29. theClass: aClass
  30. theClass := aClass
  31. !
  32. withSequence: aSequence do: aBlock
  33. | outerSequence |
  34. outerSequence := self sequence.
  35. self sequence: aSequence.
  36. aBlock value.
  37. self sequence: outerSequence.
  38. ^ aSequence
  39. ! !
  40. !IRASTTranslator methodsFor: 'visiting'!
  41. addToSequence: anInstruction
  42. anInstruction ifNotNil: [
  43. anInstruction isVariable ifFalse: [
  44. self sequence add: anInstruction ] ].
  45. ^ anInstruction
  46. !
  47. alias: anExpressionNode
  48. | assignment |
  49. anExpressionNode isIdempotent ifTrue: [ ^ self visit: anExpressionNode ].
  50. assignment := self method newAliasingOf: (self visit: anExpressionNode).
  51. self addToSequence: assignment.
  52. ^ assignment left
  53. !
  54. aliasTemporally: aCollection
  55. "https://lolg.it/amber/amber/issues/296
  56. If a node is aliased, all preceding ones are aliased as well.
  57. The tree is iterated twice. First we get the aliasing dependency,
  58. then the aliasing itself is done"
  59. | threshold shouldAlias |
  60. shouldAlias := false.
  61. threshold := aCollection reversed
  62. detect: [ :each |
  63. shouldAlias or: [
  64. each shouldBeAliased or: [
  65. (each hasOpeningStatements or: [ each subtreeNeedsAliasing ]) ifTrue: [ shouldAlias := true ].
  66. false ] ] ]
  67. ifNone: [ nil ].
  68. threshold ifNil: [ ^ self visitAll: aCollection ].
  69. shouldAlias := true.
  70. ^ aCollection collect: [ :each |
  71. shouldAlias
  72. ifTrue: [ each == threshold ifTrue: [ shouldAlias := false ]. self alias: each ]
  73. ifFalse: [ self visit: each ] ]
  74. !
  75. visitAssignmentNode: aNode
  76. | left right assignment |
  77. right := self visit: aNode right.
  78. left := self visit: aNode left.
  79. self addToSequence: (IRAssignment new
  80. add: left;
  81. add: right;
  82. yourself).
  83. ^ left
  84. !
  85. visitBlockNode: aNode
  86. | closure |
  87. closure := IRClosure new
  88. arguments: aNode parameters;
  89. requiresSmalltalkContext: aNode requiresSmalltalkContext;
  90. scope: aNode scope;
  91. yourself.
  92. aNode scope temps do: [ :each |
  93. closure add: (IRTempDeclaration new
  94. name: each name;
  95. scope: aNode scope;
  96. yourself) ].
  97. closure add: (self visit: aNode sequenceNode).
  98. ^ closure
  99. !
  100. visitBlockSequenceNode: aNode
  101. ^ self
  102. withSequence: IRBlockSequence new
  103. do: [
  104. aNode dagChildren ifNotEmpty: [
  105. aNode dagChildren allButLast do: [ :each |
  106. self addToSequence: (self visit: each) ].
  107. aNode dagChildren last isReturnNode
  108. ifFalse: [ self addToSequence: (IRBlockReturn new add: (self visit: aNode dagChildren last); yourself) ]
  109. ifTrue: [ self addToSequence: (self visit: aNode dagChildren last) ] ]]
  110. !
  111. visitCascadeNode: aNode
  112. | receiver |
  113. receiver := aNode receiver.
  114. receiver isIdempotent ifFalse: [
  115. | alias |
  116. alias := self alias: receiver.
  117. receiver := VariableNode new binding: alias variable ].
  118. aNode dagChildren do: [ :each | each receiver: receiver ].
  119. aNode dagChildren allButLast do: [ :each |
  120. self addToSequence: (self visit: each) ].
  121. ^ self visit: aNode dagChildren last
  122. !
  123. visitDynamicArrayNode: aNode
  124. | array |
  125. array := IRDynamicArray new.
  126. (self aliasTemporally: aNode dagChildren) do: [ :each | array add: each ].
  127. ^ array
  128. !
  129. visitDynamicDictionaryNode: aNode
  130. | dictionary |
  131. dictionary := IRDynamicDictionary new.
  132. (self aliasTemporally: aNode dagChildren) do: [ :each | dictionary add: each ].
  133. ^ dictionary
  134. !
  135. visitJSStatementNode: aNode
  136. ^ IRVerbatim new
  137. source: aNode source crlfSanitized;
  138. yourself
  139. !
  140. visitMethodNode: aNode
  141. | irSequence |
  142. self method: (IRMethod new
  143. source: self source;
  144. pragmas: (aNode pragmas collect: [ :each |
  145. Message
  146. selector: each selector
  147. arguments: (each arguments collect: [ :eachArg |
  148. eachArg isString ifTrue: [ eachArg crlfSanitized ] ifFalse: [ eachArg ]])]);
  149. theClass: self theClass;
  150. arguments: aNode arguments;
  151. selector: aNode selector;
  152. sendIndexes: aNode sendIndexes;
  153. requiresSmalltalkContext: aNode requiresSmalltalkContext;
  154. classReferences: aNode classReferences;
  155. scope: aNode scope;
  156. yourself).
  157. aNode scope temps do: [ :each |
  158. self method add: (IRTempDeclaration new
  159. name: each name;
  160. scope: aNode scope;
  161. yourself) ].
  162. self method add: (irSequence := self visit: aNode sequenceNode).
  163. aNode scope hasLocalReturn ifFalse: [ irSequence
  164. add: (IRReturn new
  165. add: (IRVariable new
  166. variable: (aNode scope pseudoVars at: 'self');
  167. yourself);
  168. yourself) ].
  169. ^ self method
  170. !
  171. visitReturnNode: aNode
  172. ^ (aNode nonLocalReturn
  173. ifTrue: [ IRNonLocalReturn new ]
  174. ifFalse: [ IRReturn new ])
  175. scope: aNode scope;
  176. add: (self visit: aNode expression);
  177. yourself
  178. !
  179. visitSendNode: aNode
  180. | send |
  181. send := IRSend new.
  182. send
  183. selector: aNode selector;
  184. javaScriptSelector: aNode javaScriptSelector;
  185. argumentSwitcher: aNode argumentSwitcher;
  186. index: aNode index.
  187. (self aliasTemporally: aNode dagChildren) do: [ :each | send add: each ].
  188. ^ send
  189. !
  190. visitSequenceNode: aNode
  191. ^ self
  192. withSequence: IRSequence new
  193. do: [ aNode dagChildren do: [ :each |
  194. self addToSequence: (self visit: each) ] ]
  195. !
  196. visitValueNode: aNode
  197. ^ IRValue new
  198. value: aNode value;
  199. yourself
  200. !
  201. visitVariableNode: aNode
  202. ^ IRVariable new
  203. variable: aNode binding;
  204. yourself
  205. ! !
  206. Object subclass: #IRAliasFactory
  207. slots: {#counter}
  208. package: 'Compiler-IR'!
  209. !IRAliasFactory methodsFor: 'accessing'!
  210. next
  211. counter := counter + 1.
  212. ^ AliasVar new
  213. name: '$', counter asString;
  214. yourself
  215. ! !
  216. !IRAliasFactory methodsFor: 'initialization'!
  217. initialize
  218. super initialize.
  219. counter := 0
  220. ! !
  221. DagParentNode subclass: #IRInstruction
  222. slots: {#parent}
  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. method
  229. ^ self parent method
  230. !
  231. parent
  232. ^ parent
  233. !
  234. parent: anIRInstruction
  235. parent := anIRInstruction
  236. !
  237. scope
  238. ^ self parent ifNotNil: [ :node |
  239. node scope ]
  240. ! !
  241. !IRInstruction methodsFor: 'building'!
  242. add: anObject
  243. ^ self addDagChild: anObject
  244. !
  245. remove: anIRInstruction
  246. self dagChildren remove: anIRInstruction
  247. !
  248. replace: anIRInstruction with: anotherIRInstruction
  249. anotherIRInstruction parent: self.
  250. self dagChildren
  251. at: (self dagChildren indexOf: anIRInstruction)
  252. put: anotherIRInstruction
  253. !
  254. replaceWith: anIRInstruction
  255. self parent replace: self with: anIRInstruction
  256. ! !
  257. !IRInstruction methodsFor: 'converting'!
  258. asReceiver
  259. "Return customized form to act as receiver.
  260. Return self to use standard $recv(...) boxing."
  261. ^ nil
  262. ! !
  263. !IRInstruction methodsFor: 'testing'!
  264. isClosure
  265. ^ false
  266. !
  267. isInlined
  268. ^ false
  269. !
  270. isMethod
  271. ^ false
  272. !
  273. isSend
  274. ^ false
  275. !
  276. isSequence
  277. ^ false
  278. !
  279. isSuper
  280. ^ false
  281. !
  282. isTempDeclaration
  283. ^ false
  284. !
  285. isVariable
  286. ^ false
  287. !
  288. needsBoxingAsReceiver
  289. self deprecatedAPI: 'Use asReceiver isNil instead.'.
  290. ^ self asReceiver isNil
  291. !
  292. yieldsValue
  293. ^ true
  294. ! !
  295. !IRInstruction class methodsFor: 'instance creation'!
  296. on: aBuilder
  297. ^ self new
  298. builder: aBuilder;
  299. yourself
  300. ! !
  301. IRInstruction subclass: #IRAssignment
  302. slots: {}
  303. package: 'Compiler-IR'!
  304. !IRAssignment methodsFor: 'accessing'!
  305. left
  306. ^ self dagChildren first
  307. !
  308. right
  309. ^ self dagChildren last
  310. ! !
  311. !IRAssignment methodsFor: 'visiting'!
  312. acceptDagVisitor: aVisitor
  313. ^ aVisitor visitIRAssignment: self
  314. ! !
  315. IRInstruction subclass: #IRDynamicArray
  316. slots: {}
  317. package: 'Compiler-IR'!
  318. !IRDynamicArray methodsFor: 'visiting'!
  319. acceptDagVisitor: aVisitor
  320. ^ aVisitor visitIRDynamicArray: self
  321. ! !
  322. IRInstruction subclass: #IRDynamicDictionary
  323. slots: {}
  324. package: 'Compiler-IR'!
  325. !IRDynamicDictionary methodsFor: 'visiting'!
  326. acceptDagVisitor: aVisitor
  327. ^ aVisitor visitIRDynamicDictionary: self
  328. ! !
  329. IRInstruction subclass: #IRScopedInstruction
  330. slots: {#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. slots: {#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, (self tempDeclarations collect: [ :each | each name ])
  351. !
  352. requiresSmalltalkContext
  353. ^ requiresSmalltalkContext ifNil: [ false ]
  354. !
  355. requiresSmalltalkContext: anObject
  356. requiresSmalltalkContext := anObject
  357. !
  358. scope: aScope
  359. super scope: aScope.
  360. aScope instruction: self
  361. !
  362. tempDeclarations
  363. ^ self dagChildren select: [ :each |
  364. each isTempDeclaration ]
  365. ! !
  366. IRClosureInstruction subclass: #IRClosure
  367. slots: {}
  368. package: 'Compiler-IR'!
  369. !IRClosure methodsFor: 'accessing'!
  370. sequence
  371. ^ self dagChildren last
  372. ! !
  373. !IRClosure methodsFor: 'testing'!
  374. isClosure
  375. ^ true
  376. ! !
  377. !IRClosure methodsFor: 'visiting'!
  378. acceptDagVisitor: aVisitor
  379. ^ aVisitor visitIRClosure: self
  380. ! !
  381. IRClosureInstruction subclass: #IRMethod
  382. slots: {#theClass. #source. #compiledSource. #attachments. #selector. #pragmas. #classReferences. #sendIndexes. #internalVariables. #aliasFactory}
  383. package: 'Compiler-IR'!
  384. !IRMethod commentStamp!
  385. I am a method instruction!
  386. !IRMethod methodsFor: 'accessing'!
  387. aliasFactory
  388. ^ aliasFactory ifNil: [ aliasFactory := IRAliasFactory new ]
  389. !
  390. attachments
  391. ^ attachments ifNil: [ attachments := #{} ]
  392. !
  393. classReferences
  394. ^ classReferences
  395. !
  396. classReferences: aCollection
  397. classReferences := aCollection
  398. !
  399. compiledSource
  400. ^ compiledSource
  401. !
  402. compiledSource: anObject
  403. compiledSource := anObject
  404. !
  405. internalVariables
  406. ^ internalVariables ifNil: [ internalVariables := Set new ]
  407. !
  408. messageSends
  409. ^ self sendIndexes keys
  410. !
  411. method
  412. ^ self
  413. !
  414. newAliasingOf: anIRInstruction
  415. | variable |
  416. variable := IRVariable new
  417. variable: self aliasFactory next;
  418. yourself.
  419. self internalVariables add: variable.
  420. ^ IRAssignment new
  421. add: variable;
  422. add: anIRInstruction;
  423. yourself
  424. !
  425. pragmas
  426. ^ pragmas
  427. !
  428. pragmas: aCollection
  429. pragmas := aCollection
  430. !
  431. selector
  432. ^ selector
  433. !
  434. selector: aString
  435. selector := aString
  436. !
  437. sendIndexes
  438. ^ sendIndexes
  439. !
  440. sendIndexes: aDictionary
  441. sendIndexes := aDictionary
  442. !
  443. source
  444. ^ source
  445. !
  446. source: aString
  447. source := aString
  448. !
  449. theClass
  450. ^ theClass
  451. !
  452. theClass: aClass
  453. theClass := aClass
  454. ! !
  455. !IRMethod methodsFor: 'testing'!
  456. isMethod
  457. ^ true
  458. ! !
  459. !IRMethod methodsFor: 'visiting'!
  460. acceptDagVisitor: aVisitor
  461. ^ aVisitor visitIRMethod: self
  462. ! !
  463. IRScopedInstruction subclass: #IRReturn
  464. slots: {}
  465. package: 'Compiler-IR'!
  466. !IRReturn commentStamp!
  467. I am a local return instruction.!
  468. !IRReturn methodsFor: 'accessing'!
  469. expression
  470. ^ self dagChildren single
  471. !
  472. scope
  473. ^ scope ifNil: [ self parent scope ]
  474. ! !
  475. !IRReturn methodsFor: 'testing'!
  476. yieldsValue
  477. ^ false
  478. ! !
  479. !IRReturn methodsFor: 'visiting'!
  480. acceptDagVisitor: aVisitor
  481. ^ aVisitor visitIRReturn: self
  482. ! !
  483. IRReturn subclass: #IRBlockReturn
  484. slots: {}
  485. package: 'Compiler-IR'!
  486. !IRBlockReturn commentStamp!
  487. Smalltalk blocks return their last statement. I am a implicit block return instruction.!
  488. !IRBlockReturn methodsFor: 'visiting'!
  489. acceptDagVisitor: aVisitor
  490. ^ aVisitor visitIRBlockReturn: self
  491. ! !
  492. IRReturn subclass: #IRNonLocalReturn
  493. slots: {}
  494. package: 'Compiler-IR'!
  495. !IRNonLocalReturn commentStamp!
  496. I am a non local return instruction.
  497. Non local returns are handled using a try/catch JavaScript statement.
  498. See `IRNonLocalReturnHandling` class.!
  499. !IRNonLocalReturn methodsFor: 'visiting'!
  500. acceptDagVisitor: aVisitor
  501. ^ aVisitor visitIRNonLocalReturn: self
  502. ! !
  503. IRScopedInstruction subclass: #IRTempDeclaration
  504. slots: {#name}
  505. package: 'Compiler-IR'!
  506. !IRTempDeclaration methodsFor: 'accessing'!
  507. name
  508. ^ name
  509. !
  510. name: aString
  511. name := aString
  512. ! !
  513. !IRTempDeclaration methodsFor: 'testing'!
  514. isTempDeclaration
  515. ^ true
  516. ! !
  517. !IRTempDeclaration methodsFor: 'visiting'!
  518. acceptDagVisitor: aVisitor
  519. ^ aVisitor visitIRTempDeclaration: self
  520. ! !
  521. IRInstruction subclass: #IRSend
  522. slots: {#selector. #javaScriptSelector. #argumentSwitcher. #index}
  523. package: 'Compiler-IR'!
  524. !IRSend commentStamp!
  525. I am a message send instruction.!
  526. !IRSend methodsFor: 'accessing'!
  527. argumentSwitcher
  528. ^ argumentSwitcher
  529. !
  530. argumentSwitcher: aJSFunction
  531. argumentSwitcher := aJSFunction
  532. !
  533. arguments
  534. ^ self dagChildren allButFirst
  535. !
  536. index
  537. ^ index
  538. !
  539. index: anInteger
  540. index := anInteger
  541. !
  542. javaScriptSelector
  543. ^ javaScriptSelector ifNil: [ javaScriptSelector := self selector asJavaScriptMethodName ]
  544. !
  545. javaScriptSelector: aString
  546. javaScriptSelector := aString
  547. !
  548. receiver
  549. ^ self dagChildren first
  550. !
  551. selector
  552. ^ selector
  553. !
  554. selector: aString
  555. selector := aString
  556. ! !
  557. !IRSend methodsFor: 'testing'!
  558. isSend
  559. ^ true
  560. ! !
  561. !IRSend methodsFor: 'visiting'!
  562. acceptDagVisitor: aVisitor
  563. ^ aVisitor visitIRSend: self
  564. ! !
  565. IRInstruction subclass: #IRSequence
  566. slots: {}
  567. package: 'Compiler-IR'!
  568. !IRSequence methodsFor: 'testing'!
  569. isSequence
  570. ^ true
  571. ! !
  572. !IRSequence methodsFor: 'visiting'!
  573. acceptDagVisitor: aVisitor
  574. ^ aVisitor visitIRSequence: self
  575. ! !
  576. IRSequence subclass: #IRBlockSequence
  577. slots: {}
  578. package: 'Compiler-IR'!
  579. !IRBlockSequence methodsFor: 'visiting'!
  580. acceptDagVisitor: aVisitor
  581. ^ aVisitor visitIRBlockSequence: self
  582. ! !
  583. IRInstruction subclass: #IRValue
  584. slots: {#value}
  585. package: 'Compiler-IR'!
  586. !IRValue commentStamp!
  587. I am the simplest possible instruction. I represent a value.!
  588. !IRValue methodsFor: 'accessing'!
  589. value
  590. ^ value
  591. !
  592. value: aString
  593. value := aString
  594. ! !
  595. !IRValue methodsFor: 'converting'!
  596. asReceiver
  597. ^ self
  598. ! !
  599. !IRValue methodsFor: 'visiting'!
  600. acceptDagVisitor: aVisitor
  601. ^ aVisitor visitIRValue: self
  602. ! !
  603. IRInstruction subclass: #IRVariable
  604. slots: {#variable}
  605. package: 'Compiler-IR'!
  606. !IRVariable commentStamp!
  607. I am a variable instruction.!
  608. !IRVariable methodsFor: 'accessing'!
  609. variable
  610. ^ variable
  611. !
  612. variable: aScopeVariable
  613. variable := aScopeVariable
  614. ! !
  615. !IRVariable methodsFor: 'converting'!
  616. asReceiver
  617. self variable asReceiver
  618. ifNil: [ ^ super asReceiver ]
  619. ifNotNil: [ :receiverVar |
  620. self variable == receiverVar ifTrue: [ ^ self ].
  621. ^ self copy variable: receiverVar; yourself ]
  622. ! !
  623. !IRVariable methodsFor: 'testing'!
  624. isSuper
  625. ^ self variable isSuper
  626. !
  627. isVariable
  628. ^ true
  629. ! !
  630. !IRVariable methodsFor: 'visiting'!
  631. acceptDagVisitor: aVisitor
  632. ^ aVisitor visitIRVariable: self
  633. ! !
  634. IRInstruction subclass: #IRVerbatim
  635. slots: {#source}
  636. package: 'Compiler-IR'!
  637. !IRVerbatim methodsFor: 'accessing'!
  638. source
  639. ^ source
  640. !
  641. source: aString
  642. source := aString
  643. ! !
  644. !IRVerbatim methodsFor: 'visiting'!
  645. acceptDagVisitor: aVisitor
  646. ^ aVisitor visitIRVerbatim: self
  647. ! !
  648. Object subclass: #IRPragmator
  649. slots: {#irMethod}
  650. package: 'Compiler-IR'!
  651. !IRPragmator methodsFor: 'accessing'!
  652. irMethod
  653. ^ irMethod
  654. !
  655. irMethod: anObject
  656. irMethod := anObject
  657. ! !
  658. !IRPragmator methodsFor: 'visiting'!
  659. value: anIRMethod
  660. self irMethod: anIRMethod.
  661. self processPragmas: anIRMethod pragmas.
  662. ^ anIRMethod
  663. ! !
  664. IRPragmator subclass: #IRLatePragmator
  665. slots: {}
  666. package: 'Compiler-IR'!
  667. !IRLatePragmator methodsFor: 'pragmas'!
  668. jsOverride: aString
  669. self irMethod arguments ifNotEmpty: [
  670. CompilerError signal: 'Must use <jsOverride:> in unary method.' ].
  671. self irMethod attachments
  672. at: aString
  673. put: (NativeFunction
  674. constructorNamed: #Function
  675. value: 'return this.', irMethod selector asJavaScriptMethodName, '()')
  676. !
  677. jsOverride: aString args: aCollection
  678. | myArgs |
  679. myArgs := self irMethod arguments.
  680. myArgs size = aCollection size ifFalse: [
  681. CompilerError signal: 'Should have ', self irMethod arguments size asString, ' args in <jsOverride:args:>.' ].
  682. myArgs asSet = aCollection asSet ifFalse: [
  683. CompilerError signal: 'Argument mismatch in <jsOverride:args:>.' ].
  684. self irMethod attachments
  685. at: aString
  686. put: (NativeFunction
  687. constructorNamed: #Function
  688. value: (',' join: aCollection)
  689. value: 'return this.', irMethod selector asJavaScriptMethodName, '(', (',' join: myArgs), ')')
  690. ! !
  691. ParentFakingPathDagVisitor subclass: #IRVisitor
  692. slots: {}
  693. package: 'Compiler-IR'!
  694. !IRVisitor methodsFor: 'visiting'!
  695. visitDagNode: aNode
  696. ^ self visitDagNodeVariantSimple: aNode
  697. !
  698. visitIRAssignment: anIRAssignment
  699. ^ self visitDagNode: anIRAssignment
  700. !
  701. visitIRBlockReturn: anIRBlockReturn
  702. ^ self visitIRReturn: anIRBlockReturn
  703. !
  704. visitIRBlockSequence: anIRBlockSequence
  705. ^ self visitIRSequence: anIRBlockSequence
  706. !
  707. visitIRClosure: anIRClosure
  708. ^ self visitDagNode: anIRClosure
  709. !
  710. visitIRDynamicArray: anIRDynamicArray
  711. ^ self visitDagNode: anIRDynamicArray
  712. !
  713. visitIRDynamicDictionary: anIRDynamicDictionary
  714. ^ self visitDagNode: anIRDynamicDictionary
  715. !
  716. visitIRMethod: anIRMethod
  717. ^ self visitDagNode: anIRMethod
  718. !
  719. visitIRNonLocalReturn: anIRNonLocalReturn
  720. ^ self visitDagNode: anIRNonLocalReturn
  721. !
  722. visitIRNonLocalReturnHandling: anIRNonLocalReturnHandling
  723. ^ self visitDagNode: anIRNonLocalReturnHandling
  724. !
  725. visitIRReturn: anIRReturn
  726. ^ self visitDagNode: anIRReturn
  727. !
  728. visitIRSend: anIRSend
  729. ^ self visitDagNode: anIRSend
  730. !
  731. visitIRSequence: anIRSequence
  732. ^ self visitDagNode: anIRSequence
  733. !
  734. visitIRTempDeclaration: anIRTempDeclaration
  735. ^ self visitDagNode: anIRTempDeclaration
  736. !
  737. visitIRValue: anIRValue
  738. ^ self visitDagNode: anIRValue
  739. !
  740. visitIRVariable: anIRVariable
  741. ^ self visitDagNode: anIRVariable
  742. !
  743. visitIRVerbatim: anIRVerbatim
  744. ^ self visitDagNode: anIRVerbatim
  745. ! !
  746. IRVisitor subclass: #IRJSTranslator
  747. slots: {#stream. #currentClass}
  748. package: 'Compiler-IR'!
  749. !IRJSTranslator methodsFor: 'accessing'!
  750. contents
  751. ^ self stream contents
  752. !
  753. currentClass
  754. ^ currentClass
  755. !
  756. currentClass: aClass
  757. currentClass := aClass
  758. !
  759. stream
  760. ^ stream
  761. !
  762. stream: aStream
  763. stream := aStream
  764. ! !
  765. !IRJSTranslator methodsFor: 'initialization'!
  766. initialize
  767. super initialize.
  768. stream := JSStream new.
  769. ! !
  770. !IRJSTranslator methodsFor: 'visiting'!
  771. visitIRAssignment: anIRAssignment
  772. self stream
  773. nextPutAssignLhs: [self visit: anIRAssignment left]
  774. rhs: [self visit: anIRAssignment right].
  775. !
  776. visitIRClosure: anIRClosure
  777. self stream
  778. nextPutClosureWith: [
  779. self stream nextPutVars: (anIRClosure tempDeclarations collect: [ :each |
  780. each name asVariableName ]).
  781. self stream
  782. nextPutBlockContextFor: anIRClosure
  783. during: [ super visitIRClosure: anIRClosure ] ]
  784. arguments: anIRClosure arguments
  785. !
  786. visitIRDynamicArray: anIRDynamicArray
  787. self
  788. visitInstructionList: anIRDynamicArray dagChildren
  789. enclosedBetween: '[' and: ']'
  790. !
  791. visitIRDynamicDictionary: anIRDynamicDictionary
  792. self
  793. visitInstructionList: anIRDynamicDictionary dagChildren
  794. enclosedBetween: '$globals.HashedCollection._newFromPairs_([' and: '])'
  795. !
  796. visitIRMethod: anIRMethod
  797. self stream
  798. nextPutFunctionWith: [
  799. self stream nextPutVars: (anIRMethod tempDeclarations collect: [ :each |
  800. each name asVariableName ]).
  801. self stream nextPutContextFor: anIRMethod during: [
  802. anIRMethod internalVariables ifNotEmpty: [ :internalVars |
  803. self stream nextPutVars:
  804. (internalVars collect: [ :each | each variable alias ]) asSet ].
  805. anIRMethod scope hasNonLocalReturn
  806. ifTrue: [
  807. self stream nextPutNonLocalReturnHandlingWith: [
  808. super visitIRMethod: anIRMethod ] ]
  809. ifFalse: [ super visitIRMethod: anIRMethod ] ]]
  810. arguments: anIRMethod arguments.
  811. ^ anIRMethod compiledSource: self contents; yourself
  812. !
  813. visitIRNonLocalReturn: anIRNonLocalReturn
  814. self stream nextPutNonLocalReturnWith: [
  815. super visitIRNonLocalReturn: anIRNonLocalReturn ]
  816. !
  817. visitIRReturn: anIRReturn
  818. self stream nextPutReturnWith: [
  819. super visitIRReturn: anIRReturn ]
  820. !
  821. visitIRSend: anIRSend
  822. | prefixes suffixes workBlock |
  823. prefixes := #().
  824. suffixes := #().
  825. workBlock := [ self visitSend: anIRSend ].
  826. anIRSend index < (anIRSend method sendIndexes at: anIRSend selector) size ifTrue: [
  827. suffixes add:
  828. anIRSend scope alias,
  829. '.sendIdx[',
  830. anIRSend selector asJavaScriptSource,
  831. ']=',
  832. anIRSend index asString ].
  833. anIRSend receiver isSuper ifTrue: [
  834. prefixes add: anIRSend scope alias, '.supercall = true'.
  835. suffixes add: anIRSend scope alias, '.supercall = false'.
  836. workBlock := [ self visitSuperSend: anIRSend ] ].
  837. self stream nextPutBefore: prefixes after: suffixes with: workBlock
  838. !
  839. visitIRSequence: anIRSequence
  840. anIRSequence dagChildren do: [ :each |
  841. self stream nextPutStatementWith: [ self visit: each ] ]
  842. !
  843. visitIRTempDeclaration: anIRTempDeclaration
  844. "self stream
  845. nextPutAll: 'var ', anIRTempDeclaration name asVariableName, ';';
  846. lf"
  847. !
  848. visitIRValue: anIRValue
  849. self stream nextPutAll: anIRValue value asJavaScriptSource
  850. !
  851. visitIRVariable: anIRVariable
  852. self stream nextPutAll: anIRVariable variable alias
  853. !
  854. visitIRVerbatim: anIRVerbatim
  855. self stream nextPutAll: anIRVerbatim source
  856. !
  857. visitInstructionList: anArray enclosedBetween: aString and: anotherString
  858. self stream nextPutAll: aString.
  859. anArray
  860. do: [ :each | self visit: each ]
  861. separatedBy: [ self stream nextPutAll: ',' ].
  862. stream nextPutAll: anotherString
  863. !
  864. visitReceiver: anIRInstruction
  865. anIRInstruction asReceiver
  866. ifNotNil: [ :instr | self visit: instr ]
  867. ifNil: [
  868. self stream nextPutAll: '$recv('.
  869. self visit: anIRInstruction.
  870. self stream nextPutAll: ')' ]
  871. !
  872. visitSend: anIRSend
  873. self visitReceiver: anIRSend receiver.
  874. self stream nextPutAll: '.', anIRSend javaScriptSelector.
  875. self
  876. visitInstructionList: anIRSend arguments
  877. enclosedBetween: '(' and: ')'
  878. !
  879. visitSuperSend: anIRSend
  880. self stream
  881. nextPutAll: anIRSend receiver variable lookupAsJavaScriptSource, '.';
  882. nextPutAll: anIRSend javaScriptSelector.
  883. anIRSend arguments
  884. ifEmpty: [
  885. self stream nextPutAll: '.call('.
  886. self visitReceiver: anIRSend receiver.
  887. self stream nextPutAll: ')' ]
  888. ifNotEmpty: [
  889. anIRSend argumentSwitcher
  890. ifNil: [
  891. self stream nextPutAll: '.call('.
  892. self visitReceiver: anIRSend receiver.
  893. self
  894. visitInstructionList: anIRSend arguments
  895. enclosedBetween: ',' and: ')' ]
  896. ifNotNil: [ :switcher |
  897. self stream nextPutAll: '.apply('.
  898. self visitReceiver: anIRSend receiver.
  899. self
  900. visitInstructionList: anIRSend arguments
  901. enclosedBetween: ',(', switcher asJavaScriptSource, ')('
  902. and: '))' ] ]
  903. ! !
  904. Object subclass: #JSStream
  905. slots: {#stream. #omitSemicolon}
  906. package: 'Compiler-IR'!
  907. !JSStream methodsFor: 'accessing'!
  908. contents
  909. ^ stream contents
  910. !
  911. omitSemicolon
  912. ^ omitSemicolon
  913. !
  914. omitSemicolon: aBoolean
  915. omitSemicolon := aBoolean
  916. ! !
  917. !JSStream methodsFor: 'initialization'!
  918. initialize
  919. super initialize.
  920. stream := '' writeStream.
  921. ! !
  922. !JSStream methodsFor: 'streaming'!
  923. lf
  924. stream lf
  925. !
  926. nextPut: aString
  927. stream nextPut: aString
  928. !
  929. nextPutAll: aString
  930. stream nextPutAll: aString
  931. !
  932. nextPutAssignLhs: aBlock rhs: anotherBlock
  933. aBlock value.
  934. stream nextPutAll: '='.
  935. anotherBlock value
  936. !
  937. nextPutBefore: prefixCollection after: suffixCollection with: aBlock
  938. suffixCollection isEmpty
  939. ifTrue: [ self nextPutBefore: prefixCollection with: aBlock ]
  940. ifFalse: [
  941. self
  942. nextPutAll: '['; nextPutBefore: prefixCollection with: aBlock; lf;
  943. nextPutAll: '//>>excludeStart("ctx", pragmas.excludeDebugContexts);'; lf.
  944. suffixCollection do: [ :each | self nextPutAll: ','; nextPutAll: each ].
  945. self
  946. lf;
  947. nextPutAll: '//>>excludeEnd("ctx");'; lf;
  948. nextPutAll: '][0]' ]
  949. !
  950. nextPutBefore: aCollection with: aBlock
  951. aCollection isEmpty ifTrue: [ aBlock value ] ifFalse: [
  952. self nextPutAll: '('; lf; nextPutAll: '//>>excludeStart("ctx", pragmas.excludeDebugContexts);'; lf.
  953. aCollection do: [ :each | self nextPutAll: each; nextPutAll: ',' ].
  954. self lf; nextPutAll: '//>>excludeEnd("ctx");'; lf.
  955. aBlock value.
  956. self nextPutAll: ')' ]
  957. !
  958. nextPutBlockContextFor: anIRClosure during: aBlock
  959. anIRClosure requiresSmalltalkContext ifFalse: [ ^ aBlock value ].
  960. self
  961. nextPutAll: '//>>excludeStart("ctx", pragmas.excludeDebugContexts);';
  962. lf;
  963. nextPutAll: 'return $core.withContext(function(', anIRClosure scope alias, ') {';
  964. lf;
  965. nextPutAll: '//>>excludeEnd("ctx");';
  966. lf.
  967. aBlock value.
  968. self
  969. nextPutAll: '//>>excludeStart("ctx", pragmas.excludeDebugContexts);';
  970. lf;
  971. nextPutAll: '}, function(', anIRClosure scope alias, ') {';
  972. nextPutAll: anIRClosure scope alias, '.fillBlock({'.
  973. anIRClosure locals
  974. do: [ :each |
  975. self
  976. nextPutAll: each asVariableName;
  977. nextPutAll: ':';
  978. nextPutAll: each asVariableName ]
  979. separatedBy: [ self nextPutAll: ',' ].
  980. self
  981. nextPutAll: '},';
  982. nextPutAll: anIRClosure scope outerScope alias, ',', anIRClosure scope blockIndex asString, ')});';
  983. lf;
  984. nextPutAll: '//>>excludeEnd("ctx");'
  985. !
  986. nextPutClosureWith: aBlock arguments: anArray
  987. stream nextPutAll: '(function('.
  988. anArray
  989. do: [ :each | stream nextPutAll: each asVariableName ]
  990. separatedBy: [ stream nextPut: ',' ].
  991. stream nextPutAll: '){'; lf.
  992. aBlock value.
  993. stream lf; nextPutAll: '})'
  994. !
  995. nextPutContextFor: aMethod during: aBlock
  996. aMethod requiresSmalltalkContext ifFalse: [ ^ aBlock value ].
  997. self
  998. nextPutAll: '//>>excludeStart("ctx", pragmas.excludeDebugContexts);';
  999. lf;
  1000. nextPutAll: 'return $core.withContext(function(', aMethod scope alias, ') {';
  1001. lf;
  1002. nextPutAll: '//>>excludeEnd("ctx");';
  1003. lf.
  1004. aBlock value.
  1005. self
  1006. nextPutAll: '//>>excludeStart("ctx", pragmas.excludeDebugContexts);';
  1007. lf;
  1008. nextPutAll: '}, function(', aMethod scope alias, ') {', aMethod scope alias;
  1009. nextPutAll: '.fill(self,', aMethod selector asJavaScriptSource, ',{'.
  1010. aMethod locals
  1011. do: [ :each |
  1012. self
  1013. nextPutAll: each asVariableName;
  1014. nextPutAll: ':';
  1015. nextPutAll: each asVariableName ]
  1016. separatedBy: [ self nextPutAll: ',' ].
  1017. self
  1018. nextPutAll: '})});';
  1019. lf;
  1020. nextPutAll: '//>>excludeEnd("ctx");'
  1021. !
  1022. nextPutFunctionWith: aBlock arguments: anArray
  1023. stream nextPutAll: 'function ('.
  1024. anArray
  1025. do: [ :each | stream nextPutAll: each asVariableName ]
  1026. separatedBy: [ stream nextPut: ',' ].
  1027. stream nextPutAll: '){'; lf.
  1028. stream nextPutAll: 'var self=this,$self=this;'; lf.
  1029. aBlock value.
  1030. stream lf; nextPutAll: '}'
  1031. !
  1032. nextPutIf: aBlock then: anotherBlock
  1033. stream nextPutAll: 'if('.
  1034. aBlock value.
  1035. stream nextPutAll: '){'; lf.
  1036. anotherBlock value.
  1037. stream nextPutAll: '}'.
  1038. self omitSemicolon: true
  1039. !
  1040. nextPutIf: aBlock then: ifBlock else: elseBlock
  1041. stream nextPutAll: 'if('.
  1042. aBlock value.
  1043. stream nextPutAll: '){'; lf.
  1044. ifBlock value.
  1045. stream nextPutAll: '} else {'; lf.
  1046. elseBlock value.
  1047. stream nextPutAll: '}'.
  1048. self omitSemicolon: true
  1049. !
  1050. nextPutNonLocalReturnHandlingWith: aBlock
  1051. stream
  1052. nextPutAll: 'var $early={};'; lf;
  1053. nextPutAll: 'try {'; lf.
  1054. aBlock value.
  1055. stream
  1056. nextPutAll: '}'; lf;
  1057. nextPutAll: 'catch(e) {if(e===$early)return e[0]; throw e}'; lf
  1058. !
  1059. nextPutNonLocalReturnWith: aBlock
  1060. stream nextPutAll: 'throw $early=['.
  1061. aBlock value.
  1062. stream nextPutAll: ']'
  1063. !
  1064. nextPutReturnWith: aBlock
  1065. stream nextPutAll: 'return '.
  1066. aBlock value
  1067. !
  1068. nextPutStatementWith: aBlock
  1069. self omitSemicolon: false.
  1070. aBlock value.
  1071. self omitSemicolon ifFalse: [ stream nextPutAll: ';' ].
  1072. self omitSemicolon: false.
  1073. stream lf
  1074. !
  1075. nextPutVars: aCollection
  1076. aCollection ifNotEmpty: [
  1077. stream nextPutAll: 'var '.
  1078. aCollection
  1079. do: [ :each | stream nextPutAll: each ]
  1080. separatedBy: [ stream nextPutAll: ',' ].
  1081. stream nextPutAll: ';'; lf ]
  1082. ! !
  1083. IRPragmator setTraitComposition: {TPragmator} asTraitComposition!
  1084. ! !
  1085. !ASTNode methodsFor: '*Compiler-IR'!
  1086. requiresSmalltalkContext
  1087. "Answer true if the receiver requires a smalltalk context.
  1088. Only send nodes require a context.
  1089. If no node requires a context, the method will be compiled without one.
  1090. See `IRJSTranslator` and `JSStream` for context creation"
  1091. ^ self dagChildren anySatisfy: [ :each | each requiresSmalltalkContext ]
  1092. ! !
  1093. !AssignmentNode methodsFor: '*Compiler-IR'!
  1094. hasOpeningStatements
  1095. ^ true
  1096. ! !
  1097. !BlockNode methodsFor: '*Compiler-IR'!
  1098. subtreeNeedsAliasing
  1099. ^ false
  1100. ! !
  1101. !CascadeNode methodsFor: '*Compiler-IR'!
  1102. hasOpeningStatements
  1103. ^ true
  1104. ! !
  1105. !ExpressionNode methodsFor: '*Compiler-IR'!
  1106. hasOpeningStatements
  1107. ^ false
  1108. !
  1109. subtreeNeedsAliasing
  1110. ^ self dagChildren anySatisfy: [ :each |
  1111. each shouldBeAliased or: [
  1112. each hasOpeningStatements or: [
  1113. each subtreeNeedsAliasing ] ] ]
  1114. ! !
  1115. !JSStatementNode methodsFor: '*Compiler-IR'!
  1116. requiresSmalltalkContext
  1117. ^ true
  1118. ! !
  1119. !PseudoVar methodsFor: '*Compiler-IR'!
  1120. asReceiver
  1121. ^ self class receiverNames
  1122. at: self name
  1123. ifPresent: [ :newName | self copy name: newName; yourself ]
  1124. ifAbsent: [ self ]
  1125. ! !
  1126. !ScopeVar methodsFor: '*Compiler-IR'!
  1127. asReceiver
  1128. "Return customized copy to use as receiver,
  1129. or self if suffices."
  1130. ^ nil
  1131. ! !
  1132. !SendNode methodsFor: '*Compiler-IR'!
  1133. requiresSmalltalkContext
  1134. ^ true
  1135. ! !