2 m@(CompiledMethod traits) new
3 "Answer a new CompiledMethod with a fresh compilation state."
8 literals: m literals new.
9 selectors: m selectors new.
10 optionalKeywords: m optionalKeywords new.
12 debugMap: m debugMap new. ]
15 m@(CompiledMethod traits) sourceTreeOf: index
16 "Find the source tree corresponding to a bytecode's index."
19 do: [| :start :end :sourceTree |
20 (index between: start and: end)
21 ifTrue: [^ sourceTree]]
26 m@(CompiledMethod traits) definitionLocation
28 m sourceTree isNil \/ [(m sourceTree hasSlotNamed: #source) not] ifTrue: [^ 'Nil'].
29 (m sourceTree source hasSlotNamed: #resource)
30 ifTrue: [m sourceTree source resource locator
31 ifNil: ['stdin:' ; (m sourceTree lineNumber - 2) printString]
32 ifNotNil: [(m sourceTree source resource locator as: String) ; ':' ; m sourceTree lineNumber printString]]
33 ifFalse: [m sourceTree source
35 ifNotNil: [(m sourceTree source printString) ; ':' ; m sourceTree lineNumber printString]]
38 m@(CompiledMethod traits) recompile
39 "If the method has a sourceTree, replace the method with a re-compiled version
43 ifNil: [warn: 'The method has no source code to recompile.'. m]
44 ifNotNilDo: [| :src | m forwardTo: src compile]
47 lobby ensureNamespace: #VM.
48 VM ensureNamespace: #SSACode.
50 VM SSACode define: #Instruction &parents: {Cloneable} &slots: {
55 #offsettingArgIndices -> {}.
58 x@(Cloneable traits) instancesSetting: slotNames to: values
60 values collect: [| :columnValues newX |
62 slotNames with: columnValues do:
63 [| :slotName :slotValue | newX atSlotNamed: slotName put: slotValue].
67 VM SSACode Instruction traits define: #ByCode -> Dictionary new.
69 i@(VM SSACode Instruction traits) instancesSetting: slotNames to: values
71 arityNames: #('arity' 'size').
72 resend `>> [do: [| :each |
74 [| :argName | (arityNames includes: argName) ifTrue:
76 VM SSACode addImmutableSlot: each selector valued: each code.
77 i ByCode at: each code put: each].
81 VM SSACode Instruction instancesSetting: #(code selector name argNames offsettingArgIndices) to: {
82 {0. #directSendMessage. 'Direct Send'. {'register of result'. 'selector'. 'arity' ". args..."}. {2}}.
83 "{1. #indirectSendMessage. 'Indirect Send'. {'register of result'. 'selector'. 'arity'. args...}. {2}}."
84 "{2. #allocateRegisters. 'Allocate Registers'. 3. {}}."
85 {3. #loadLiteral. 'Load Literal'. {'register of result'. 'index of literal'}}.
86 "{4. #storeLiteral. 'Store Literal'. {'index of literal'. 'register of source'}}."
87 {5. #sendMessageWithOptionals. 'Send with Optionals'. {'register of result'. 'register of selector'. 'arity'. 'register of optionals array' ". args..."}. {2}}.
88 {7. #newClosure. 'New Closure'. {'register of result'. 'block'}}.
89 {8. #newArrayWith. 'New Array With'. {'register of result'. 'size' ". args..."}. {1}}.
90 {9. #resendMessage. 'Resend'. {'register of result'. 'lexical offset'}}.
91 {10. #returnFrom. 'Return From'. {'register of result'. 'lexical offset'}}.
92 {11. #loadEnvironment. 'Load Environment'. {'register of result'}}.
93 {12. #loadVariable. 'Load Variable'. {'register of result'}}.
94 {13. #storeVariable. 'Store Variable'. {'register of result'}}.
95 {14. #loadFreeVariable. 'Load Free Variable'. {'register of result'. 'lexical offset'. 'index of variable'}}.
96 {15. #storeFreeVariable. 'Store Free Variable'. {'lexical offset'. 'index of variable'. 'register of source'}}.
97 {16. #isIdenticalTo. 'Is Identical To'. {'register of result'. 'register of x'. 'register of y'}}.
98 {17. #branchKeyed. 'Branch Keyed'. {'register of key'. 'table'}}.
99 {18. #jumpTo. 'Jump To'. {'offset'}}.
100 "Used like SSA phi / branch merges:"
101 {19. #moveRegister. 'Move Register'. {'register of source'. 'register of result'}}.
102 {20. #branchIfTrue. 'Branch If True'. {'register of condition'. 'branch offset'}}.
103 {21. #branchIfFalse. 'Branch If False'. {'register of condition'. 'branch offset'}}.
104 "Marks the end of a block:"
105 {22. #returnRegister. 'Return Register'. {'register of value'}}.
106 "Marks the end of a block:"
107 {23. #returnValue. 'Return Value'. {'value to return'}}.
108 "I'm not sure what this does yet..used in bootstrap:"
109 {24. #resume. 'Resume'. {}}.
110 {25. #primitiveDo. 'Primitive Do'. {'number of primitive'. 'arity'. 'register of result' ". args..."}. {1}}.
111 {26. #directApplyTo. 'Direct Apply To'. {'method'. 'arity'. 'register of result' ". args..."}. {1}}.
112 {27. #isNilOp. 'Is Nil'. {'register of result'. 'register of x'}}.
113 "these check the arguments to see if their maps match the ones in the map array"
114 "if they match, we fall through to the next instruction which is the primitive (no code) or inlined function"
115 "it also needs to set up the input varibles"
116 {28. #inlinePrimitiveCheckJump. 'Inline Primitive Check Jump'. {'register of result'. 'map array'. 'prim number(in-opcode not a register)'. 'arity'. 'jump offset' ". args..."}. {3}}.
117 {29. #inlineMethodCheckJump. 'Inline Method Check Jump'. {'map array'. 'arity'. 'jump offset' ". args..."}. {1}}.
120 VM define: #SSACompiler &parents: {Cloneable}
121 &slots: {#contexts -> Stack new}.
123 VM SSACompiler traitsWindow addDelegate: VM SSACode.
125 g@(VM SSACompiler traits) new
126 [g clone `>> [contexts: g contexts new. ]].
128 VM SSACompiler traits define: #Context &parents: {Cloneable} &slots:
129 {#isClosure -> False "Whether the method being compiled is a closure.".
130 #method -> CompiledMethod new "The method the context targets.".
131 #codeWriter "The stream for writing bytecodes to the method.".
132 #debugMap -> ExtensibleArray new
133 "Gathers the method's debug map; must be indexable at all times.".
134 #registerValues -> ExtensibleArray new
135 "The current register values.".
136 #labels -> ExtensibleArray new
137 "label serials -> code index.".
138 #relocations -> Dictionary new
139 "code index -> label serials".
140 #currentRegister -> 0
141 "The last assigned register value.. or the count?"
144 c@(VM SSACompiler Context traits) newOn: method
145 "FIXME change method code to array instead of bytearray."
147 method code: Array new.
148 c clone `setting: #(method codeWriter debugMap registerValues relocations labels currentRegister)
149 to: {method. method code writer.
150 method debugMap as: c debugMap.
151 c registerValues new.
154 method inputVariables + method localVariables}
157 c@(VM SSACompiler Context traits) copy
159 resend `setting: (registerValues relocations labels currentRegister)
160 to: {c registerValues copy.
166 c@(VM SSACompiler Context traits) resolveLabel: label at: index
168 (c labels at: label) - index
171 c@(VM SSACompiler Context traits) resolveLabels
172 "This takes the labels Dictionary and uses it to replace the temporary ID's
173 placed in the jump fields with actual offsets."
176 c relocations keysAndValuesDo:
177 [| :index :label offset |
178 offset: (c resolveLabel: label at: index).
179 code at: index put: offset]
182 c@(VM SSACompiler Context traits) flush
184 c method code: c codeWriter contents.
185 c method debugMap: (c debugMap as: Array).
190 gen@(VM SSACompiler traits) currentContext
193 gen@(VM SSACompiler traits) newRegister
195 gen contexts top currentRegister: gen contexts top currentRegister + 1.
196 gen contexts top currentRegister
199 gen@(VM SSACompiler traits) registerFor: obj from: def result: result
201 "the whole problem with this function is that we could cache a literal that
202 is only loaded in a loop which may not always be executed. remove this code
203 until we have it figured out."
204 " gen contexts top registerValues do:
205 [| :val | val value = obj
207 [val key = result \/ [result isNil]
209 ifFalse: [result `defaultsTo: gen newRegister.
210 gen emitInstruction: gen moveRegister withParameters: {result. val key} from: def.
213 "we don't want result to be a local variable and have it overwritten later"
214 "result ifNil: [saveRegister: True] ifNotNil: [saveRegister: False]."
216 result `defaultsTo: gen newRegister.
217 gen emitInstruction: gen loadLiteral withParameters: {result. obj} from: def.
218 saveRegister ifTrue: [gen setRegister: result to: obj].
222 gen@(VM SSACompiler traits) setRegister: x to: y
224 gen contexts top registerValues add: x -> y ifPresent: [error: 'Compiler error: Register already set.'].
227 gen@(VM SSACompiler traits) currentMethod
228 [gen currentContext method].
230 gen@(VM SSACompiler traits) codeWriter
231 [gen currentContext codeWriter].
233 gen@(VM SSACompiler traits) newLabelIndex
235 gen currentContext labels `>> [addLast: Nil. indexLast]
238 gen@(VM SSACompiler traits) emitLabel &labelIndex: labelIndex
240 labelIndex `defaultsTo: gen newLabelIndex.
241 gen currentContext labels at: labelIndex put: gen codeWriter position.
245 gen@(VM SSACompiler traits) emitRelocationAgainst: label
247 gen currentContext relocations at: gen codeWriter position put: label
250 gen@(VM SSACompiler traits) emitObject: value from: node
252 "0 below: bytesPerWord do: [| :byte | gen emitByte: (value byteShift: 0 - byte) intoByte from: node]."
254 gen codeWriter nextPut: value
257 gen@(VM SSACompiler traits) emitBranchTo: label from: msg
259 gen emitRelocationAgainst: label.
260 gen emitObject: 0 from: msg "replaced later when flushed"
263 gen@(VM SSACompiler traits) mapTo: sourceTree
265 index: gen codeWriter position.
266 gen currentContext debugMap `cacheAs: #debugMap.
267 debugMap isEmpty not /\ [debugMap last == sourceTree]
268 ifTrue: [debugMap at: debugMap indexLast - 1 infect: [| :value | index max: value].
269 debugMap at: debugMap indexLast - 2 infect: [| :value | index min: value]]
270 ifFalse: [debugMap addAllLast: {index. index. sourceTree}]
273 gen@(VM SSACompiler traits) emitInstruction: code@(Integer traits) withParameters: values from: node
274 "this gets called before the real function"
276 "values do: [| :value | (value is: Syntax Node) ifTrue: [error: 'bad code']]." "commented out because we could actually load node literals in compiler code"
280 gen@(VM SSACompiler traits) emitInstruction: code withParameters: values from: node
282 "add the selector to the list so we know what this function calls... so it can be unoptimized if needed"
283 code = gen directSendMessage \/ [code = gen sendMessageWithOptionals] ifTrue: [gen currentContext method selectors: gen currentContext method selectors ; {values second}].
284 gen emitObject: code from: node.
285 values do: [| :value | gen emitObject: value from: node]
288 gen@(VM SSACompiler traits) emitInstruction: code from: node
289 "Emitting an instruction without an immediate value required just puts the
292 gen emitInstruction: code withParameters: #() from: node
296 =======================================================================
297 Generate methods. They all must return the register(s) with the results
298 =======================================================================
301 _@(VM SSACompiler traits) generate: _@(Syntax Node traits)
302 "Do nothing in the default case, for comments and annotations and such."
303 [error: 'do not call generate without a result'].
305 _@(VM SSACompiler traits) generate: _@(Syntax Node traits) result: result
306 "Do nothing in the default case, for comments and annotations and such."
309 gen@(VM SSACompiler traits) generate: ann@(Syntax Annotation traits) result: result
310 "Generate the annotation's value."
312 gen generate: ann value
315 gen@(VM SSACompiler traits) generate: block@(Syntax Block traits) result: result &topLevel: topLevel
316 "Encountering a new block, build a new CompiledMethod object and push it and
317 a new bytecode array writer onto the generator, then go through the underlying
318 code and generate that. When done, pop both, set up the block as a literal
319 and push it onto the stack."
320 [| newBlock isClosure statements |
321 topLevel `defaultsTo: False.
322 newBlock: CompiledMethod new.
323 newBlock environment: (gen contexts isEmpty
324 ifTrue: [block parentScope topLevel namespace]
325 ifFalse: [gen currentMethod environment]).
326 newBlock sourceTree: block.
327 gen contexts push: (gen Context newOn: newBlock).
328 "we macroexpand everything before we set the current register because macroexpansion can add localvariables etc"
329 statements: (block statements collect: [| :statement | statement macroExpand &environment: gen currentMethod sourceTree]).
330 gen currentContext currentRegister: block localVariables size. "input variables might not be needed"
331 statements allButLastDo: [| :node | gen generate: node result: Nil].
333 ifTrue: [gen emitInstruction: gen returnValue withParameters: {Nil} from: block]
334 ifFalse: [gen emitInstruction: gen returnRegister withParameters: {gen generate: statements last result: Nil} from: block].
336 "Set the variable information after generation, just in case it was modified."
338 [inputVariables: block inputVariables size.
339 localVariables: block localVariables size.
340 restVariable: block restVariable isNotNil.
341 registerCount: gen currentContext currentRegister + 1.
342 "reserved1: gen currentContext currentRegister + 1."
343 optionalKeywords: block optionalKeywords.].
344 isClosure: gen currentContext isClosure.
346 gen contexts pop flush.
347 "Forces the newBlock to record all the remaining stream input correctly."
349 gen contexts isEmpty \/ [topLevel]
351 [result `defaultsTo: gen newRegister. "asking for a register requires a context"
354 [gen emitInstruction: gen newClosure withParameters: {result. newBlock} from: block]
356 [gen emitInstruction: gen loadLiteral withParameters: {result. newBlock} from: block]].
358 gen contexts isEmpty \/ [topLevel] ifTrue: [newBlock] ifFalse: [result]
361 gen@(VM SSACompiler traits) generate: def@(Syntax MethodDefinition traits) result: resultRegister
362 "Translate method definitions to equivalent asMethod:on: invocations."
363 [| blockRegister roleRegisters arrayRegister resultRegister selectorRegister |
366 blockRegister: (#generate:result: sendTo: {gen. def. Nil} through: {gen. Syntax Block. Nil}).
367 arrayRegister: gen newRegister.
368 selectorRegister: (gen registerFor: def selector from: def result: Nil).
369 roleRegisters: (def roles collect: [| :role | gen generate: role result: Nil]).
370 resultRegister `defaultsTo: gen newRegister.
371 gen emitInstruction: gen newArrayWith withParameters: {arrayRegister. roleRegisters size} ; roleRegisters from: def.
372 gen emitInstruction: gen directSendMessage withParameters: {resultRegister. #asMethod:on:. 3. blockRegister. selectorRegister. arrayRegister} from: def.
376 gen@(VM SSACompiler traits) generate: r@(Syntax Resend traits) result: resultRegister
378 scope: gen currentMethod sourceTree.
379 lexOffset: gen contexts indexLast -
380 ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree isSameAs: Syntax MethodDefinition])
382 [error: 'resend must be used within a method definition.']).
385 [(gen contexts fromTop: lexOffset) method heapAllocate: True.
386 (gen contexts top: lexOffset) do: #isClosure: `er <-* True].
387 resultRegister `defaultsTo: gen newRegister.
388 gen emitInstruction: gen resendMessage withParameters: {resultRegister. lexOffset} from: r.
392 gen@(VM SSACompiler traits) generate: r@(Syntax Return traits) result: blah
395 gen@(VM SSACompiler traits) generate: r@(Syntax Return traits) by: lexOffset result: resultRegister
397 resultRegister `defaultsTo: gen newRegister.
400 [(gen contexts fromTop: lexOffset) method heapAllocate: True.
401 (gen contexts top: lexOffset) do: [| :x | x isClosure: True]].
402 gen generate: r value result: resultRegister.
403 gen emitInstruction: gen returnFrom withParameters: {resultRegister. lexOffset} from: r.
407 gen@(VM SSACompiler traits) generate: r@(Syntax ReturnClose traits) result: resultRegister
408 "Exits the first enclosing named method in the lexical scope."
410 lexOffset: gen contexts indexLast -
411 ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree isSameAs: Syntax MethodDefinition])
413 [error: '^ must be used within a method definition.']).
414 gen generate: r by: lexOffset result: resultRegister
417 gen@(VM SSACompiler traits) generate: r@(Syntax ReturnFar traits) result: result
418 "Exits the last enclosing named method in the lexical scope."
420 lexOffset: gen contexts indexLast -
421 ((gen contexts indexOfFirstSatisfying: [| :context | context method sourceTree isSameAs: Syntax MethodDefinition])
423 [error: '^^ must be used within a method definition.']).
424 gen generate: r by: lexOffset result: result
427 gen@(VM SSACompiler traits) generate: r@(Syntax ReturnLevel traits) result: result
428 "Exits the Nth enclosing lexical scope."
429 [gen generate: r by: r level result: result].
431 gen@(VM SSACompiler traits) generate: literal@(Syntax Literal traits) result: result
433 gen registerFor: literal value from: literal result: result
436 gen@(VM SSACompiler traits) generate: n@(Syntax CompoundStatement traits) result: result
437 "return the registers that the values were saved into"
441 ifFalse: [(n statements allButLast collect: [| :node | gen generate: node result: Nil])
442 ; {(gen generate: n statements last result: result)}]
445 gen@(VM SSACompiler traits) generate: n@(Syntax Parenthesis traits) result: result
446 "return the registers that the values were saved into"
450 ifFalse: [n statements allButLastDo: [| :node | gen generate: node result: Nil].
451 gen generate: n statements last result: result]
454 gen@(VM SSACompiler traits) generate: i@(Syntax ImplicitArgument traits) result: result
456 result `defaultsTo: gen newRegister.
457 gen emitInstruction: gen loadEnvironment withParameters: {result} from: i.
461 gen@(VM SSACompiler traits) generate: _@(Syntax Namespace traits) result: result
462 [shouldNotImplement].
464 gen@(VM SSACompiler traits) generate: load@(Syntax LoadVariable traits) result: result
465 [| lexOffset varIndex |
466 load variable scope `cacheAs: #scope.
467 varIndex: (scope localVariables indexOf: load variable).
468 lexOffset: gen contexts indexLast -
469 ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree == scope])
471 [error: 'Could not determine variable scope.']).
474 [result `defaultsTo: varIndex.
475 gen emitInstruction: gen loadVariable withParameters: {varIndex} from: load.
477 ifFalse: [gen emitInstruction: gen moveRegister withParameters: {result. varIndex} from: load]]
479 [result `defaultsTo: gen newRegister.
480 (gen contexts fromTop: lexOffset) method heapAllocate: True.
481 (gen contexts top: lexOffset) do: #isClosure: `er <-* True.
482 gen emitInstruction: gen loadFreeVariable withParameters: {result. lexOffset. varIndex} from: load].
486 gen@(VM SSACompiler traits) generate: store@(Syntax StoreVariable traits) result: result
487 [| lexOffset varIndex |
488 store variable scope `cacheAs: #scope.
489 varIndex: (scope localVariables indexOf: store variable).
490 lexOffset: gen contexts indexLast -
491 ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree == scope])
493 [error: 'Could not determine variable scope.']).
496 [result `defaultsTo: varIndex.
497 gen generate: store value result: varIndex.
498 gen emitInstruction: gen storeVariable withParameters: {varIndex} from: store.
500 ifFalse: [gen emitInstruction: gen moveRegister withParameters: {result. varIndex} from: store]]
502 [result `defaultsTo: gen newRegister.
503 gen generate: store value result: result.
504 (gen contexts fromTop: lexOffset) method heapAllocate: True.
505 (gen contexts top: lexOffset) do: #isClosure: `er <-* True.
506 gen emitInstruction: gen storeFreeVariable withParameters: {lexOffset. varIndex. result} from: store].
510 gen@(VM SSACompiler traits) generate: array@(Syntax Array traits) result: result
511 "Generate the code to push the element expression results on the stack,
512 then the appropriate literal-array constructor bytecode."
515 result `defaultsTo: gen newRegister.
516 gen emitInstruction: gen newArrayWith withParameters: {result. array size} ; registers from: array.
520 gen@(VM SSACompiler traits) generate: selector@(Symbol traits) on: args from: msg@(Syntax Message traits) result: result
521 "Generate the code to push the argument expression results on the stack, then
522 the push for the selector, and then the appropriate message send bytecode."
524 result `defaultsTo: gen newRegister.
525 argRegisters: (args collect: [| :arg | gen generate: arg result: Nil]).
526 gen emitInstruction: gen directSendMessage withParameters: {result. selector. args size} ; argRegisters from: msg.
530 gen@(VM SSACompiler traits) generate: msg@(Syntax Message traits) result: result &optionals: opts
532 gen generate: msg selector on: msg arguments from: (opts ifNil: [msg]) result: result
535 gen@(VM SSACompiler traits) generate: macro@(Syntax Macro traits) result: result &optionals: opts
537 "gen generate: (macro macroExpand &optionals: opts &environment: gen currentMethod sourceTree) result: result"
538 error: 'SSA Compiler cannot support macroexpansion at code generation time because of localVariable side-effects'.
541 gen@(VM SSACompiler traits) generate: def@(Syntax Deferred traits) result: result &optionals: opts
543 block: Syntax Block new `>> [parentScope: gen currentMethod sourceTree. ].
544 def arguments size timesRepeat: #addInputVariable `er <- block.
545 message: (Syntax Message sending: def selector to:
546 (block inputVariables collect: [| :var | Syntax LoadVariable from: var])).
550 ((Syntax OptionalArguments for: message)
551 `>> [arguments: (opts arguments deepCopy: block). ])].
552 block statements: {message}.
554 (Syntax KeywordMessage
555 sending: #whenFulfilled:
556 to: {def arguments as: Syntax Array. block})
560 gen@(VM SSACompiler traits) generate: selector@(Symbol traits) on: args from: opts@(Syntax OptionalKeywords traits) result: result
561 "Generate the code to push the argument expression results on the stack, then
562 the push for the selector, and then the appropriate message send bytecode."
563 [| argRegisters optsArray optsWriter optsArrayRegister |
564 result `defaultsTo: gen newRegister.
565 argRegisters: (args collect: [| :arg | gen generate: arg result: Nil]).
566 optsArrayRegister: gen newRegister.
567 optsArray: ExtensibleArray new.
568 optsWriter: optsArray writer.
569 opts keywords with: opts arguments do:
571 optsWriter nextPut: (gen registerFor: key from: opts result: Nil).
572 optsWriter nextPut: (gen generate: arg result: Nil)].
573 gen emitInstruction: gen newArrayWith withParameters:
574 {optsArrayRegister. optsArray size} ; optsArray from: opts.
575 gen emitInstruction: gen sendMessageWithOptionals withParameters:
576 {result. selector. args size. optsArrayRegister } ; argRegisters from: opts.
580 gen@(VM SSACompiler traits) generate: opts@(Syntax OptionalKeywords traits) result: result
582 gen generate: opts message result: result &optionals: opts
585 gen@(VM SSACompiler traits) generate: rest@(Syntax RestArguments traits) result: result
587 gen generate: rest message result: result
590 gen@(VM SSACompiler traits) generate: _@#True on: args from: msg result: result
592 (args first isSameAs: Syntax ImplicitArgument)
593 ifTrue: [gen registerFor: True from: msg result: result]
597 gen@(VM SSACompiler traits) generate: _@#False on: args from: msg result: result
599 (args first isSameAs: Syntax ImplicitArgument)
600 ifTrue: [gen registerFor: False from: msg result: result]
604 gen@(VM SSACompiler traits) generate: _@#Nil on: args from: msg result: result
606 (args first isSameAs: Syntax ImplicitArgument)
607 ifTrue: [gen registerFor: Nil from: msg result: result]
611 gen@(VM SSACompiler traits) generate: _@#== on: args from: msg result: result
613 result `defaultsTo: gen newRegister.
614 argRegs: (args collect: [| :arg | gen generate: arg result: Nil]).
615 gen emitInstruction: gen isIdenticalTo withParameters: {result. argRegs first. argRegs second} from: msg.
619 gen@(VM SSACompiler traits) generate: _@#do on: args from: msg result: result
620 "If the block is a literal with no variables, then inline it.
621 Otherwise, fall back to evaluating it via 'do'."
623 args first `cacheAs: #block.
624 (block isSameAs: Syntax Block)
625 /\ [block localVariables isEmpty]
627 result `defaultsTo: gen newRegister.
628 block statements isEmpty
629 ifTrue: [gen emitInstruction: gen loadLiteral withParameters: {result. Nil} from: msg.
631 ifFalse: [block statements allButLastDo: [| :node | gen generate: node result: Nil].
632 gen generate: block statements last result: result]
635 gen@(VM SSACompiler traits) generateExecutionOf: args from: msg result: result
636 [gen generate: #do on: args from: msg result: result].
638 gen@(VM SSACompiler traits) generate: _@#loop on: args from: msg result: result
639 "Repeatedly evaluates a block via 'do'."
641 label: gen emitLabel.
642 gen generateExecutionOf: args from: msg result: Nil.
643 gen emitInstruction: gen jumpTo withParameters: #()"see below" from: msg.
644 gen emitBranchTo: label from: msg.
645 gen registerFor: Nil from: msg result: result "return nil"
648 gen@(VM SSACompiler traits) generate: _@#isNil on: args from: msg result: result
650 result `defaultsTo: gen newRegister.
651 objReg: (gen generate: args first result: Nil).
652 gen emitInstruction: gen isNilOp withParameters: {result. objReg} from: msg.
656 gen@(VM SSACompiler traits) branchTableHash: key
661 gen@(VM SSACompiler traits) buildBranchTableMapping: keys
664 [tableSize < keys size]
666 [tableSize: tableSize * 2].
667 table: (Array newSize: tableSize * 2).
670 hash: ((gen branchTableHash: key) bitAnd: (tableSize - 1) * 2).
671 [(table at: hash) isNil]
673 [key = (table at: hash)
675 [error: 'Duplicate key ' ; key printString ; ' in caseOf:.'].
677 hash >= (tableSize * 2)
680 table at: hash put: key
685 gen@(VM SSACompiler traits) mayInlineCaseOf: msg
686 "Answer whether a safe inlining is possible for a caseOf: expression without
687 further analysis; currently this is the case where the second argument is a
688 literal array, and the appropriate Associations and their elements are laid
689 out with literal keys."
691 (msg arguments second isSameAs: Syntax Array) /\
692 [msg arguments second statements allSatisfy:
694 (assoc is: Syntax Message)
695 /\ [assoc selector = #->]
696 /\ [assoc arguments first is: Syntax Literal]
697 /\ [{Symbol. ASCIIString Character. SmallInteger} anySatisfy:
698 [| :proto | assoc arguments first value is: proto]]]]
701 gen@(VM SSACompiler traits) generate: _@#caseOf:otherwise: on: args from: msg result: finalResult
702 [| labels table indices branchOffset otherwiseLabel endLabel switchKeyRegister |
703 (gen mayInlineCaseOf: msg)
705 args second statements `cacheAs: #assocs.
706 labels: (assocs collect: [| :_ | gen newLabelIndex]).
707 finalResult `defaultsTo: gen newRegister.
710 buildBranchTableMapping:
711 (assocs collect: [| :assoc | assoc arguments first value])).
712 indices: IdentityDictionary new.
713 0 below: table size by: 2 do: [| :index |
714 (table at: index) ifNotNilDo: [| :val | indices at: val put: index]].
716 switchKeyRegister: (gen generate: args first result: Nil).
717 gen emitInstruction: gen branchKeyed withParameters: {switchKeyRegister. (gen registerFor: table from: msg result: Nil)} from: msg.
718 branchOffset: gen codeWriter position.
719 gen emitInstruction: gen jumpTo from: msg.
720 endLabel: gen newLabelIndex.
721 otherwiseLabel: gen newLabelIndex.
722 gen emitBranchTo: otherwiseLabel from: msg.
724 assocs with: labels do:
726 gen emitLabel &labelIndex: label.
728 at: (indices at: assoc arguments first value) + 1
729 put: (gen currentContext resolveLabel: label at: branchOffset).
730 gen generateExecutionOf: {assoc arguments second} from: msg result: finalResult.
731 gen emitInstruction: gen jumpTo from: msg.
732 gen emitBranchTo: endLabel from: msg].
734 "Handle the otherwise clause. If we didn't get a literal block for it, just
736 gen emitLabel &labelIndex: otherwiseLabel.
738 ifTrue: [gen generateExecutionOf: {args third} from: msg result: finalResult]
739 ifFalse: [gen registerFor: Nil from: msg result: finalResult].
740 gen emitLabel &labelIndex: endLabel.
744 gen@(VM SSACompiler traits) generate: _@#caseOf: on: args from: msg result: result
745 "Generates a caseOf:otherwise: with a default otherwise clause."
747 (gen mayInlineCaseOf: msg)
748 ifTrue: [gen generate: #caseOf:otherwise: on: args from: msg result: result]
752 gen@(VM SSACompiler traits) generate: _@#ifTrue:ifFalse: on: args from: msg result: finalResult
753 "Branches to one of two blocks and evaluates it."
754 [| falseLabel endLabel condReg |
755 falseLabel: gen newLabelIndex.
756 endLabel: gen newLabelIndex.
757 finalResult `defaultsTo: gen newRegister.
758 condReg: (gen generate: args first result: Nil).
759 condReg ifNil: [error: 'conditional is nil: ' ; args first printString].
760 gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
761 gen emitBranchTo: falseLabel from: msg.
762 gen generateExecutionOf: {args second} from: msg result: finalResult.
763 gen emitInstruction: gen jumpTo from: msg.
764 gen emitBranchTo: endLabel from: msg.
765 gen emitLabel &labelIndex: falseLabel.
766 gen generateExecutionOf: {args third} from: msg result: finalResult.
767 gen emitLabel &labelIndex: endLabel.
771 gen@(VM SSACompiler traits) generate: _@#ifTrue: on: args from: msg result: finalResult
772 "Optionally evaluates a block."
773 [| falseLabel endLabel condReg |
774 falseLabel: gen newLabelIndex.
775 endLabel: gen newLabelIndex.
776 finalResult `defaultsTo: gen newRegister.
777 condReg: (gen generate: args first result: Nil).
778 condReg ifNil: [error: 'conditional is nil: ' ; args first printString].
779 gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
780 gen emitBranchTo: falseLabel from: msg.
781 gen generateExecutionOf: {args second} from: msg result: finalResult.
782 gen emitInstruction: gen jumpTo from: msg.
783 gen emitBranchTo: endLabel from: msg.
784 gen emitLabel &labelIndex: falseLabel.
785 gen registerFor: Nil from: msg result: finalResult.
786 gen emitLabel &labelIndex: endLabel.
790 gen@(VM SSACompiler traits) generate: _@#ifFalse: on: args from: msg result: finalResult
791 [| falseLabel endLabel condResult |
792 falseLabel: gen newLabelIndex.
793 endLabel: gen newLabelIndex.
794 finalResult `defaultsTo: gen newRegister.
795 condResult: (gen generate: args first result: Nil).
796 condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
797 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
798 gen emitBranchTo: falseLabel from: msg.
799 gen generateExecutionOf: {args second} from: msg result: finalResult.
800 gen emitInstruction: gen jumpTo from: msg.
801 gen emitBranchTo: endLabel from: msg.
802 gen emitLabel &labelIndex: falseLabel.
803 gen registerFor: Nil from: msg result: finalResult.
804 gen emitLabel &labelIndex: endLabel.
809 gen@(VM SSACompiler traits) generate: _@#ifNil: on: args from: msg result: finalResult
810 [ | endLabel condReg lhsValueReg |
811 endLabel: gen newLabelIndex.
812 finalResult `defaultsTo: gen newRegister.
813 lhsValueReg: (gen generate: args first result: finalResult). "do not evaluate twice"
814 condReg: gen newRegister.
815 gen emitInstruction: gen isNilOp withParameters: {condReg. lhsValueReg} from: msg.
816 gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
817 gen emitBranchTo: endLabel from: msg.
818 gen generateExecutionOf: {args second} from: msg result: finalResult.
819 gen emitLabel &labelIndex: endLabel.
823 gen@(VM SSACompiler traits) generate: _@#ifNotNil: on: args from: msg result: finalResult
824 [ | endLabel condReg lhsValueReg |
825 endLabel: gen newLabelIndex.
826 finalResult `defaultsTo: gen newRegister.
827 lhsValueReg: (gen generate: args first result: finalResult). "do not evaluate twice"
828 condReg: gen newRegister.
829 gen emitInstruction: gen isNilOp withParameters: {condReg. lhsValueReg} from: msg.
830 gen emitInstruction: gen branchIfTrue withParameters: {condReg} from: msg.
831 gen emitBranchTo: endLabel from: msg.
832 gen generateExecutionOf: {args second} from: msg result: finalResult.
833 gen emitLabel &labelIndex: endLabel.
838 gen@(VM SSACompiler traits) generate: _@#/\ on: args from: msg result: finalResult
839 "Optionally evaluates a block."
840 [| falseLabel endLabel condResult |
841 (args second isSameAs: Syntax Block)
843 falseLabel: gen newLabelIndex.
844 endLabel: gen newLabelIndex.
845 finalResult `defaultsTo: gen newRegister.
846 condResult: (gen generate: args first result: Nil).
847 condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
848 gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
849 gen emitBranchTo: falseLabel from: msg.
850 gen generateExecutionOf: {args second} from: msg result: finalResult.
851 gen emitInstruction: gen jumpTo from: msg.
852 gen emitBranchTo: endLabel from: msg.
853 gen emitLabel &labelIndex: falseLabel.
854 gen registerFor: False from: msg result: finalResult.
855 gen emitLabel &labelIndex: endLabel.
859 gen@(VM SSACompiler traits) generate: _@#\/ on: args from: msg result: finalResult
860 "Optionally evaluates a block."
861 [| block falseLabel endLabel condResult |
862 (args second isSameAs: Syntax Block)
864 falseLabel: gen newLabelIndex.
865 endLabel: gen newLabelIndex.
866 finalResult `defaultsTo: gen newRegister.
867 condResult: (gen generate: args first result: Nil).
868 condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
869 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
870 gen emitBranchTo: falseLabel from: msg.
871 gen generateExecutionOf: {args second} from: msg result: finalResult.
872 gen emitInstruction: gen jumpTo from: msg.
873 gen emitBranchTo: endLabel from: msg.
874 gen emitLabel &labelIndex: falseLabel.
875 gen registerFor: True from: msg result: finalResult.
876 gen emitLabel &labelIndex: endLabel.
880 gen@(VM SSACompiler traits) generate: _@#whileTrue: on: args from: msg result: finalResult
881 "Repeatedly evaluates a block while it returns True."
882 [| label endLabel condResult |
883 endLabel: gen newLabelIndex.
884 label: gen emitLabel.
885 condResult: (gen generateExecutionOf: {args first} from: msg result: Nil).
886 condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
887 gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
888 gen emitBranchTo: endLabel from: msg.
889 gen generateExecutionOf: {args second} from: msg result: Nil.
890 gen emitInstruction: gen jumpTo from: msg.
891 gen emitBranchTo: label from: msg.
892 gen emitLabel &labelIndex: endLabel.
893 gen registerFor: Nil from: msg result: finalResult
896 gen@(VM SSACompiler traits) generate: _@#whileFalse: on: args from: msg result: finalResult
897 "Repeatedly evaluates a block while it returns False."
898 [| label endLabel condResult |
899 endLabel: gen newLabelIndex.
900 label: gen emitLabel.
901 condResult: (gen generateExecutionOf: {args first} from: msg result: Nil).
902 condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
903 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
904 gen emitBranchTo: endLabel from: msg.
905 gen generateExecutionOf: {args second} from: msg result: Nil.
906 gen emitInstruction: gen jumpTo from: msg.
907 gen emitBranchTo: label from: msg.
908 gen emitLabel &labelIndex: endLabel.
909 gen registerFor: Nil from: msg result: finalResult
912 gen@(VM SSACompiler traits) generate: _@#whileTrue on: args from: msg result: result
913 "Repeatedly evaluates a block while it returns True."
914 [| label condResult |
915 label: gen emitLabel.
916 condResult: (gen generateExecutionOf: args from: msg result: Nil).
917 condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
918 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
919 gen emitBranchTo: label from: msg.
920 gen registerFor: Nil from: msg result: result
923 gen@(VM SSACompiler traits) generate: _@#whileFalse on: args from: msg result: result
924 "Repeatedly evaluates a block while it returns False."
925 [| label condResult |
926 label: gen emitLabel.
927 condResult: (gen generateExecutionOf: args from: msg result: Nil).
928 condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
929 gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
930 gen emitBranchTo: label from: msg.
931 gen registerFor: Nil from: msg result: result
935 gen@(VM SSACompiler traits) generate: _@#primitiveDo: on: args from: msg result: result
936 [| indexReg argRegs |
937 result `defaultsTo: gen newRegister.
938 indexReg: (gen generate: args first result: Nil).
939 argRegs: (args second statements collect: [|:item| (gen generate: item result: Nil)]).
940 gen emitInstruction: gen primitiveDo withParameters: {indexReg. argRegs size. result} ; argRegs from: msg.
944 gen@(VM SSACompiler traits) generate: _@#applyTo: on: args from: msg result: result
945 [| methodReg argRegs |
946 (args second isSameAs: Syntax Array) ifFalse: [^ resend].
947 result `defaultsTo: gen newRegister.
948 methodReg: (gen generate: args first result: Nil).
949 argRegs: (args second statements collect: [|:item| (gen generate: item result: Nil)]).
950 gen emitInstruction: gen directApplyTo withParameters: {methodReg. argRegs size. result} ; argRegs from: msg.
955 gen@(VM SSACompiler traits) generate: _@#fill:with: on: args from: msg result: result
956 [| block index var value |
960 (block isSameAs: Syntax Block) /\
961 [index isSameAs: Syntax Literal] /\
962 [block inputVariables acceptsKey: index value]
964 (value isSameAs: Syntax Literal)
967 tmp: gen currentMethod sourceTree addVariable.
968 gen generate: (Syntax StoreVariable of: value into: tmp) result: Nil. "fixme"
969 value: (Syntax LoadVariable from: tmp)].
971 var: (block inputVariables at: index).
972 block inputVariables: (block inputVariables copyWithoutAt: index).
975 below: block localVariables indexLast
976 with: block localVariables
977 startingAt: index + 1.
978 block localVariables at: block localVariables indexLast put: var.
980 {(Syntax StoreVariable of: value into: var)} ; block statements.
981 gen generate: block result: result
984 gen@(VM SSACompiler traits) generate: _@#<- on: args from: msg result: result
985 "Optimizes currying calls on literal blocks using #fill:with:."
986 [gen generate: #fill:with: on: (args copyWith: (Syntax Literal for: 0) at: 1) from: msg result: result].
988 gen@(VM SSACompiler traits) generate: _@#<-1 on: args from: msg result: result
989 "Optimizes currying calls on literal blocks using #fill:with:."
990 [gen generate: #fill:with: on: (args copyWith: (Syntax Literal for: 0) at: 1) from: msg result: result].
992 gen@(VM SSACompiler traits) generate: _@#<-2 on: args from: msg result: result
993 "Optimizes currying calls on literal blocks using #fill:with:."
994 [gen generate: #fill:with: on: (args copyWith: (Syntax Literal for: 1) at: 1) from: msg result: result].
996 gen@(VM SSACompiler traits) generate: _@#<-3 on: args from: msg result: result
997 "Optimizes currying calls on literal blocks using #fill:with:."
998 [gen generate: #fill:with: on: (args copyWith: (Syntax Literal for: 2) at: 1) from: msg result: result].
1000 gen@(VM SSACompiler traits) generate: _@#<-4 on: args from: msg result: result
1001 "Optimizes currying calls on literal blocks using #fill:with:."
1002 [gen generate: #fill:with: on: (args copyWith: (Syntax Literal for: 3) at: 1) from: msg result: result].
1004 gen@(VM SSACompiler traits) generate: _@#<-5 on: args from: msg result: result
1005 "Optimizes currying calls on literal blocks using #fill:with:."
1006 [gen generate: #fill:with: on: (args copyWith: (Syntax Literal for: 4) at: 1) from: msg result: result].
1008 gen@(VM SSACompiler traits) generate: _@#<-* on: args from: msg result: result
1009 "Optimizes currying calls on literal blocks using #fill:with:."
1011 (args first isSameAs: Syntax Block)
1013 [gen generate: #fill:with:
1015 (Syntax Literal for: args first inputVariables indexLast) at: 1)