2 m@(CompiledMethod traits) new
3 "Answer a new CompiledMethod with a fresh compilation state."
9 optionalKeywords := m optionalKeywords new.
10 restVariable := False.
14 literals := m literals new.
15 selectors := m selectors new.
17 debugMap := m debugMap new.
21 m@(CompiledMethod traits) sourceTreeOf: index
22 "Find the source tree corresponding to a bytecode's index."
25 [| :start :end :sourceTree |
26 (index between: start and: end)
27 ifTrue: [^ sourceTree]]
32 m@(CompiledMethod traits) definitionLocation
34 m sourceTree isNotNil /\ [m sourceTree hasSlotNamed: #source]
35 ifTrue: [m sourceTree definitionLocation]
39 m@(CompiledMethod traits) recompile
40 "If the method has a sourceTree, replace the method with a re-compiled version
44 ifNil: [warn: 'The method has no source code to recompile.'. m]
45 ifNotNilDo: [| :src | m forwardTo: src compile]
48 lobby ensureNamespace: #VM.
49 VM ensureNamespace: #SSACode.
51 VM SSACode define: #Instruction &parents: {Cloneable} &slots: {
56 #offsettingArgIndices -> {}.
59 VM SSACode Instruction traits define: #ByCode -> Dictionary new.
61 i@(VM SSACode Instruction traits) instancesSetting: slotNames to: values
63 resend `>> [do: [| :each |
65 [| :argName | (#{'arity'. 'size'} includes: argName) ifTrue:
67 VM SSACode addImmutableSlot: each selector valued: each code.
68 i ByCode at: each code put: each].
72 VM SSACode Instruction instancesSetting: #{#code. #selector. #name. #argNames. #offsettingArgIndices} to: #{
73 {0. #directSendMessage. 'Direct Send'. {'register of result'. 'selector'. 'arity' ". args..."}. {2}}.
74 "{1. #indirectSendMessage. 'Indirect Send'. {'register of result'. 'selector'. 'arity'. args...}. {2}}."
75 "{2. #allocateRegisters. 'Allocate Registers'. 3. {}}."
76 {3. #loadLiteral. 'Load Literal'. {'register of result'. 'index of literal'}}.
77 "{4. #storeLiteral. 'Store Literal'. {'index of literal'. 'register of source'}}."
78 {5. #sendMessageWithOptionals. 'Send with Optionals'. {'register of result'. 'selector'. 'arity'. 'register of optionals array' ". args..."}. {2}}.
79 {7. #newClosure. 'New Closure'. {'register of result'. 'block'}}.
80 {8. #newArrayWith. 'New Array With'. {'register of result'. 'size' ". args..."}. {1}}.
81 {9. #resendMessage. 'Resend'. {'register of result'. 'lexical offset'}}.
82 {10. #returnFrom. 'Return From'. {'register of result'. 'lexical offset'}}.
83 {11. #loadEnvironment. 'Load Environment'. {'register of result'}}.
84 {12. #loadVariable. 'Load Variable'. {'register of result'}}.
85 {13. #storeVariable. 'Store Variable'. {'register of result'}}.
86 {14. #loadFreeVariable. 'Load Free Variable'. {'register of result'. 'lexical offset'. 'index of variable'}}.
87 {15. #storeFreeVariable. 'Store Free Variable'. {'lexical offset'. 'index of variable'. 'register of source'}}.
88 {16. #isIdenticalTo. 'Is Identical To'. {'register of result'. 'register of x'. 'register of y'}}.
89 {17. #branchKeyed. 'Branch Keyed'. {'register of key'. 'table'}}.
90 {18. #jumpTo. 'Jump To'. {'offset'}}.
91 "Used like SSA phi / branch merges:"
92 {19. #moveRegister. 'Move Register'. {'register of source'. 'register of result'}}.
93 {20. #branchIfTrue. 'Branch If True'. {'register of condition'. 'branch offset'}}.
94 {21. #branchIfFalse. 'Branch If False'. {'register of condition'. 'branch offset'}}.
95 "Marks the end of a block:"
96 {22. #returnRegister. 'Return Register'. {'register of value'}}.
97 "Marks the end of a block:"
98 {23. #returnValue. 'Return Value'. {'value to return'}}.
99 "I'm not sure what this does yet..used in bootstrap:"
100 {24. #resume. 'Resume'. {}}.
101 {25. #primitiveDo. 'Primitive Do'. {'number of primitive'. 'arity'. 'register of result' ". args..."}. {1}}.
102 {26. #directApplyTo. 'Direct Apply To'. {'method'. 'arity'. 'register of result' ". args..."}. {1}}.
103 {27. #isNilOp. 'Is Nil'. {'register of result'. 'register of x'}}.
104 "these check the arguments to see if their maps match the ones in the map array"
105 "if they match, we fall through to the next instruction which is the primitive (no code) or inlined function"
106 "it also needs to set up the input varibles"
107 {28. #inlinePrimitiveCheckJump. 'Inline Primitive Check Jump'. {'register of result'. 'map array'. 'prim number(in-opcode not a register)'. 'arity'. 'jump offset' ". args..."}. {3}}.
108 {29. #inlineMethodCheckJump. 'Inline Method Check Jump'. {'map array'. 'arity'. 'jump offset' ". args..."}. {1}}.
109 {30. #sendMessageWithOptionalsInline. 'Send with Optionals Inline'. {'register of result'. 'selector'. 'arity'. 'optional count'. ". args...optionals..."}. {2. 3}}.
113 VM define: #SSACompiler &parents: {Cloneable}
114 &slots: {#contexts -> Stack new}.
116 VM SSACompiler traitsWindow addDelegate: VM SSACode.
118 g@(VM SSACompiler traits) new
119 [g clone `>> [contexts := g contexts new. ]].
121 VM SSACompiler traits define: #Context &parents: {Cloneable} &slots: {
122 #isClosure -> False "Whether the method being compiled is a closure.".
123 #method -> CompiledMethod new "The method the context targets.".
124 #codeWriter "The stream for writing bytecodes to the method.".
125 #debugMap -> ExtensibleArray new
126 "Gathers the method's debug map; must be indexable at all times.".
127 #registerValues -> ExtensibleArray new
128 "The current register values.".
129 #labels -> ExtensibleArray new
130 "label serials -> code index.".
131 #relocations -> Dictionary new
132 "code index -> label serials".
133 #currentRegister -> 0
134 "The last assigned register value.. or the count?"
137 c@(VM SSACompiler Context traits) newOn: method
139 method code := Array new.
140 c clone `setting: #{#method. #codeWriter. #debugMap. #registerValues. #relocations. #labels. #currentRegister}
143 method debugMap as: c debugMap.
144 c registerValues new.
147 method inputVariables + method localVariables}
150 c@(VM SSACompiler Context traits) copy
152 resend `setting: (registerValues relocations labels currentRegister)
153 to: {c registerValues copy.
159 c@(VM SSACompiler Context traits) resolveLabel: label at: index
161 (c labels at: label) - index
164 c@(VM SSACompiler Context traits) resolveLabels
165 "This takes the labels Dictionary and uses it to replace the temporary ID's
166 placed in the jump fields with actual offsets."
168 code ::= c method code.
169 c relocations keysAndValuesDo:
170 [| :index :label offset |
171 offset := c resolveLabel: label at: index.
172 code at: index put: offset]
175 c@(VM SSACompiler Context traits) flush
177 c method code := c codeWriter contents.
178 c method debugMap := c debugMap as: Array.
183 c@(VM SSACompiler Context traits) beClosure [c isClosure := True].
185 gen@(VM SSACompiler traits) currentContext
188 gen@(VM SSACompiler traits) newRegister
190 gen contexts top currentRegister += 1
193 gen@(VM SSACompiler traits) registerFor: obj from: def result: result
195 "the whole problem with this function is that we could cache a literal that
196 is only loaded in a loop which may not always be executed. remove this code
197 until we have it figured out."
198 " gen contexts top registerValues do:
199 [| :val | val value = obj
201 [val key = result \/ [result isNil]
203 ifFalse: [result `defaultsTo: gen newRegister.
204 gen emitInstruction: gen moveRegister withParameters: {result. val key} from: def.
207 "we don't want result to be a local variable and have it overwritten later"
208 "saveRegister ::= result isNil."
209 saveRegister ::= False.
210 result `defaultsTo: gen newRegister.
211 gen emitInstruction: gen loadLiteral withParameters: {result. obj} from: def.
212 saveRegister ifTrue: [gen setRegister: result to: obj].
216 gen@(VM SSACompiler traits) setRegister: x to: y
218 gen contexts top registerValues add: x -> y ifPresent:
219 [error: 'Compiler error: Register already set.'].
222 gen@(VM SSACompiler traits) currentMethod
223 [gen currentContext method].
225 gen@(VM SSACompiler traits) codeWriter
226 [gen currentContext codeWriter].
228 gen@(VM SSACompiler traits) newLabelIndex
230 gen currentContext labels `>> [addLast: Nil. indexLast]
233 gen@(VM SSACompiler traits) emitLabel &labelIndex: labelIndex
235 labelIndex `defaultsTo: gen newLabelIndex.
236 gen currentContext labels at: labelIndex put: gen codeWriter position.
240 gen@(VM SSACompiler traits) emitRelocationAgainst: label
242 gen currentContext relocations at: gen codeWriter position put: label
245 gen@(VM SSACompiler traits) emitObject: value from: node
247 "0 below: bytesPerWord do: [| :byte | gen emitByte: (value byteShift: 0 - byte) intoByte from: node]."
249 gen codeWriter nextPut: value
252 gen@(VM SSACompiler traits) emitBranchTo: label from: msg
254 gen emitRelocationAgainst: label.
255 gen emitObject: 0 from: msg "replaced later when flushed"
258 gen@(VM SSACompiler traits) mapTo: sourceTree
260 index ::= gen codeWriter position.
261 (debugMap ::= gen currentContext debugMap) isEmpty not /\ [debugMap last == sourceTree]
262 ifTrue: [debugMap at: debugMap indexLast - 1 infect: [| :value | index max: value].
263 debugMap at: debugMap indexLast - 2 infect: [| :value | index min: value]]
264 ifFalse: [debugMap addAllLast: {index. index. sourceTree}]
267 gen@(VM SSACompiler traits) emitInstruction: code@(Integer traits) withParameters: values from: node
268 "this gets called before the real function"
270 "values do: [| :value | (value is: nodes Node) ifTrue: [error: 'bad code']]." "commented out because we could actually load node literals in compiler code"
274 gen@(VM SSACompiler traits) emitInstruction: code withParameters: values from: node
276 "add the selector to the list so we know what this function calls... so it can be unoptimized if needed"
277 code = gen directSendMessage
278 \/ [code = gen sendMessageWithOptionals]
279 \/ [code = gen sendMessageWithOptionalsInline]
280 ifTrue: [gen currentContext method selectors := gen currentContext method selectors ; {values second}].
281 gen emitObject: code from: node.
282 values do: [| :value | gen emitObject: value from: node]
285 gen@(VM SSACompiler traits) emitInstruction: code from: node
286 "Emitting an instruction without an immediate value required just puts the
289 gen emitInstruction: code withParameters: #{} from: node
293 =======================================================================
294 Generate methods. They all must return the register(s) with the results
295 =======================================================================
298 _@(VM SSACompiler traits) generate: _@(nodes Node traits)
299 "Do nothing in the default case, for comments and annotations and such."
300 [error: 'do not call generate without a result'].
302 _@(VM SSACompiler traits) generate: _@(nodes Node traits) result: result
303 "Do nothing in the default case, for comments and annotations and such."
306 gen@(VM SSACompiler traits) generate: ann@(nodes Annotation traits) result: result
307 "Generate the annotation's value."
309 gen generate: ann value
312 gen@(VM SSACompiler traits) generate: block@(nodes Block traits) result: result &topLevel: topLevel
313 "Encountering a new block, build a new CompiledMethod object and push it and
314 a new bytecode array writer onto the generator, then go through the underlying
315 code and generate that. When done, pop both, set up the block as a literal
316 and push it onto the stack."
318 topLevel `defaultsTo: False.
319 newBlock ::= CompiledMethod new `>>
320 [environment := block bodyIncludesImplicitSends ifTrue:
321 [gen contexts isEmpty
322 ifTrue: [block topLevel namespace]
323 ifFalse: [gen currentMethod environment]].
324 sourceTree := block. ].
325 gen contexts push: (gen Context newOn: newBlock).
326 "we macroexpand everything before we set the current register because macroexpansion can add localvariables etc"
327 statements ::= block statements collect:
328 [| :statement | statement macroExpand &environment: gen currentMethod sourceTree].
329 gen currentContext currentRegister := block localVariables size. "input variables might not be needed"
331 ifTrue: [gen emitInstruction: gen returnValue withParameters: {Nil} from: block]
333 [statements allButLastDo: [| :node | gen generate: node result: Nil].
334 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"
352 gen emitInstruction: (isClosure ifTrue: [gen newClosure] ifFalse: [gen loadLiteral])
353 withParameters: {result. newBlock} from: block].
355 gen contexts isEmpty \/ [topLevel] ifTrue: [newBlock] ifFalse: [result]
358 gen@(VM SSACompiler traits) generate: sig@(nodes Signature traits) result: resultRegister
363 gen@(VM SSACompiler traits) generate: def@(nodes MethodDefinition traits) result: resultRegister
364 "Translate method definitions to equivalent asMethod:on: invocations."
368 blockRegister ::= #generate:result: sendTo: {gen. def. Nil} through: {gen. nodes Block. Nil}.
369 arrayRegister ::= gen newRegister.
370 selectorRegister ::= gen registerFor: def selector from: def result: Nil.
371 roleRegisters ::= def roles collect: #(gen generate: _ result: Nil) `er.
372 resultRegister `defaultsTo: gen newRegister.
373 gen emitInstruction: gen newArrayWith withParameters: {arrayRegister. roleRegisters size} ; roleRegisters from: def.
374 gen emitInstruction: gen directSendMessage withParameters: {resultRegister. #asMethod:on:. 3. blockRegister. selectorRegister. arrayRegister} from: def.
378 gen@(VM SSACompiler traits) generate: r@(nodes Resend traits) result: resultRegister
380 scope ::= gen currentMethod sourceTree.
381 lexOffset ::= gen contexts indexLast -
382 ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree isSameAs: nodes MethodDefinition])
384 [error: 'resend must be used within a method definition.']).
387 [(gen contexts fromTop: lexOffset) method heapAllocate := True.
388 (gen contexts top: lexOffset) do: #beClosure `er].
389 resultRegister `defaultsTo: gen newRegister.
390 gen emitInstruction: gen resendMessage withParameters: {resultRegister. lexOffset} from: r.
394 gen@(VM SSACompiler traits) generate: r@(nodes Return traits) result: blah
397 gen@(VM SSACompiler traits) generate: r@(nodes Return traits) by: lexOffset result: resultRegister
399 resultRegister `defaultsTo: gen newRegister.
402 [(gen contexts fromTop: lexOffset) method heapAllocate := True.
403 (gen contexts top: lexOffset) do: #beClosure `er].
404 gen generate: r value result: resultRegister.
405 gen emitInstruction: gen returnFrom withParameters: {resultRegister. lexOffset} from: r.
409 gen@(VM SSACompiler traits) generate: r@(nodes ReturnClose traits) result: resultRegister
410 "Exits the first enclosing named method in the lexical scope."
412 lexOffset ::= gen contexts indexLast -
413 ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree isSameAs: nodes MethodDefinition])
415 [error: '^ must be used within a method definition.']).
416 gen generate: r by: lexOffset result: resultRegister
419 gen@(VM SSACompiler traits) generate: r@(nodes ReturnFar traits) result: result
420 "Exits the last enclosing named method in the lexical scope."
422 lexOffset ::= gen contexts indexLast -
423 ((gen contexts indexOfFirstSatisfying: [| :context | context method sourceTree isSameAs: nodes MethodDefinition])
425 [error: '^^ must be used within a method definition.']).
426 gen generate: r by: lexOffset result: result
429 gen@(VM SSACompiler traits) generate: r@(nodes ReturnLevel traits) result: result
430 "Exits the Nth enclosing lexical scope."
431 [gen generate: r by: r level result: result].
433 gen@(VM SSACompiler traits) generate: literal@(nodes Literal traits) result: result
435 gen registerFor: literal value from: literal result: result
438 gen@(VM SSACompiler traits) generate: n@(nodes CompoundStatement traits) result: result
439 "return the registers that the values were saved into"
443 ifFalse: [(n statements allButLast collect: [| :node | gen generate: node result: Nil])
444 ; {(gen generate: n statements last result: result)}]
447 gen@(VM SSACompiler traits) generate: n@(nodes Parenthesis traits) result: result
448 "return the registers that the values were saved into"
452 ifFalse: [n statements allButLastDo: [| :node | gen generate: node result: Nil].
453 gen generate: n statements last result: result]
456 gen@(VM SSACompiler traits) generate: i@(nodes ImplicitArgument traits) result: result
458 result `defaultsTo: gen newRegister.
459 gen emitInstruction: gen loadEnvironment withParameters: {result} from: i.
463 gen@(VM SSACompiler traits) generate: _@(nodes Namespace traits) result: result
464 [shouldNotImplement].
466 gen@(VM SSACompiler traits) generate: load@(nodes LoadVariable traits) result: result
468 scope ::= load variable scope.
469 varIndex ::= scope localVariables indexOf: load variable.
470 lexOffset ::= gen contexts indexLast -
471 ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree == scope])
473 [error: 'Could not determine variable scope.']).
476 [result `defaultsTo: varIndex.
477 gen emitInstruction: gen loadVariable withParameters: {varIndex} from: load.
479 ifFalse: [gen emitInstruction: gen moveRegister withParameters: {result. varIndex} from: load]]
481 [result `defaultsTo: gen newRegister.
482 (gen contexts fromTop: lexOffset) method heapAllocate := True.
483 (gen contexts top: lexOffset) do: #beClosure `er.
484 gen emitInstruction: gen loadFreeVariable withParameters: {result. lexOffset. varIndex} from: load].
488 gen@(VM SSACompiler traits) generate: store@(nodes StoreVariable traits) result: result
490 scope ::= store variable scope.
491 varIndex ::= scope localVariables indexOf: store variable.
492 lexOffset ::= gen contexts indexLast -
493 ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree == scope])
495 [error: 'Could not determine variable scope.']).
498 [result `defaultsTo: varIndex.
499 gen generate: store value result: varIndex.
500 gen emitInstruction: gen storeVariable withParameters: {varIndex} from: store.
502 ifFalse: [gen emitInstruction: gen moveRegister withParameters: {result. varIndex} from: store]]
504 [result `defaultsTo: gen newRegister.
505 gen generate: store value result: result.
506 (gen contexts fromTop: lexOffset) method heapAllocate := True.
507 (gen contexts top: lexOffset) do: #beClosure `er.
508 gen emitInstruction: gen storeFreeVariable withParameters: {lexOffset. varIndex. result} from: store].
512 gen@(VM SSACompiler traits) generate: array@(nodes Array traits) result: result
513 "Generate the code to push the element expression results on the stack,
514 then the appropriate literal-array constructor bytecode."
516 registers ::= resend.
517 result `defaultsTo: gen newRegister.
518 gen emitInstruction: gen newArrayWith withParameters: {result. array size} ; registers from: array.
522 gen@(VM SSACompiler traits) generate: selector@(Symbol traits) on: args from: msg@(nodes Message traits) result: result
523 "Generate the code to push the argument expression results on the stack, then
524 the push for the selector, and then the appropriate message send bytecode."
526 result `defaultsTo: gen newRegister.
527 argRegisters ::= args collect: #(gen generate: _ result: Nil) `er.
528 gen emitInstruction: gen directSendMessage withParameters: {result. selector. args size} ; argRegisters from: msg.
532 gen@(VM SSACompiler traits) generate: msg@(nodes Message traits) result: result &optionals: opts
534 gen generate: msg selector on: msg arguments from: (opts `defaultsTo: msg) result: result
537 gen@(VM SSACompiler traits) generate: macro@(nodes Macro traits) result: result &optionals: opts
539 "gen generate: (macro macroExpand &optionals: opts &environment: gen currentMethod sourceTree) result: result"
540 error: 'SSA Compiler cannot support macroexpansion at code generation time because of localVariable side-effects'.
543 gen@(VM SSACompiler traits) generate: def@(nodes Deferred traits) result: result &optionals: opts
545 block ::= nodes Block new `>> [parentScope := gen currentMethod sourceTree. ].
546 def arguments size timesRepeat: [block addInputVariable].
547 message := nodes Message sending: def selector to:
548 (block inputVariables collect: #(nodes LoadVariable from: _) `er).
552 ((nodes OptionalArguments for: message)
553 `>> [arguments := opts arguments deepCopy: block. ])].
554 block statements := {message}.
556 (nodes KeywordMessage
557 sending: #whenFulfilled:
558 to: {def arguments as: nodes Array. block})
562 gen@(VM SSACompiler traits) generate: selector@(Symbol traits) on: args from: opts@(nodes OptionalKeywords traits) result: result
563 "Generate the code to push the argument expression results on the stack, then
564 the push for the selector, and then the appropriate message send bytecode."
566 result `defaultsTo: gen newRegister.
567 argRegisters ::= args collect: #(gen generate: _ result: Nil) `er.
568 optsArray ::= ExtensibleArray new.
569 optsWriter ::= optsArray writer.
570 opts keywords with: opts arguments do:
572 optsWriter nextPut: (gen registerFor: key from: opts result: Nil).
573 optsWriter nextPut: (gen generate: arg result: Nil)].
574 gen emitInstruction: gen sendMessageWithOptionalsInline withParameters:
575 {result. selector. args size. optsArray size} ; argRegisters ; optsArray from: opts.
579 gen@(VM SSACompiler traits) generate: opts@(nodes OptionalKeywords traits) result: result
581 gen generate: opts message result: result &optionals: opts
584 gen@(VM SSACompiler traits) generate: rest@(nodes RestArguments traits) result: result
586 gen generate: rest message selector on: rest message arguments ; rest arguments from: rest message result: result
589 gen@(VM SSACompiler traits) generate: _@#apply* on: args from: msg result: result
591 result `defaultsTo: gen newRegister.
592 methodReg ::= gen generate: args first result: Nil.
593 argRegs ::= args allButFirst collect: [| :item | gen generate: item result: Nil].
594 gen emitInstruction: gen directApplyTo withParameters: {methodReg. argRegs size. result} ; argRegs from: msg.
598 gen@(VM SSACompiler traits) generate: _@#applyTo: on: args from: msg result: result
600 (args second isSameAs: nodes Array)
602 [result `defaultsTo: gen newRegister.
603 methodReg ::= gen generate: args first result: Nil.
604 argRegs ::= args second statements collect:
605 [| :item | gen generate: item result: Nil].
606 gen emitInstruction: gen directApplyTo
607 withParameters: {methodReg. argRegs size. result} ; argRegs
613 gen@(VM SSACompiler traits) generate: _@#primitiveApply* on: args from: msg result: result
615 result `defaultsTo: gen newRegister.
616 indexReg ::= gen generate: args first result: Nil.
617 argRegs ::= args second statements collect: [| :item | gen generate: item result: Nil].
618 gen emitInstruction: gen primitiveDo withParameters: {indexReg. argRegs size. result} ; argRegs from: msg.
622 gen@(VM SSACompiler traits) generate: _@#True on: args from: msg result: result
624 (args first isSameAs: nodes ImplicitArgument)
625 ifTrue: [gen registerFor: True from: msg result: result]
629 gen@(VM SSACompiler traits) generate: _@#False on: args from: msg result: result
631 (args first isSameAs: nodes ImplicitArgument)
632 ifTrue: [gen registerFor: False from: msg result: result]
636 gen@(VM SSACompiler traits) generate: _@#Nil on: args from: msg result: result
638 (args first isSameAs: nodes ImplicitArgument)
639 ifTrue: [gen registerFor: Nil from: msg result: result]
643 gen@(VM SSACompiler traits) generate: _@#== on: args from: msg result: result
645 result `defaultsTo: gen newRegister.
646 argRegs ::= args collect: [| :arg | gen generate: arg result: Nil].
647 gen emitInstruction: gen isIdenticalTo withParameters: {result. argRegs first. argRegs second} from: msg.
651 gen@(VM SSACompiler traits) generate: _@#do on: args from: msg result: result
652 "If the block is a literal with no variables, then inline it.
653 Otherwise, fall back to evaluating it via 'do'."
655 ((block ::= args first) isSameAs: nodes Block)
656 /\ [block localVariables isEmpty]
658 [result `defaultsTo: gen newRegister.
659 block statements isEmpty
660 ifTrue: [gen emitInstruction: gen loadLiteral withParameters: {result. Nil} from: msg.
662 ifFalse: [block statements allButLastDo: [| :node | gen generate: node result: Nil].
663 gen generate: block statements last result: result]]
667 gen@(VM SSACompiler traits) generateExecutionOf: args from: msg result: result
668 [gen generate: #do on: args from: msg result: result].
670 gen@(VM SSACompiler traits) generate: _@#loop on: args from: msg result: result
671 "Repeatedly evaluates a block via 'do'."
673 label ::= gen emitLabel.
674 gen generateExecutionOf: args from: msg result: Nil.
675 gen emitInstruction: gen jumpTo withParameters: #{}"see below" from: msg.
676 gen emitBranchTo: label from: msg.
677 gen registerFor: Nil from: msg result: result "return nil"
680 gen@(VM SSACompiler traits) generate: _@#isNil on: args from: msg result: result
682 result `defaultsTo: gen newRegister.
683 objReg ::= gen generate: args first result: Nil.
684 gen emitInstruction: gen isNilOp withParameters: {result. objReg} from: msg.
688 gen@(VM SSACompiler traits) branchTableHash: key
693 gen@(VM SSACompiler traits) buildBranchTableMapping: keys
696 [tableSize < keys size]
699 table ::= Array newSize: tableSize * 2.
702 hash := (gen branchTableHash: key) bitAnd: (tableSize - 1) * 2.
703 [(table at: hash) isNil]
705 [key = (table at: hash)
707 [error: 'Duplicate key ' ; key printString ; ' in caseOf:.'].
708 (hash += 2) >= (tableSize * 2) ifTrue:
710 table at: hash put: key].
714 gen@(VM SSACompiler traits) mayInlineCaseOf: msg
715 "Answer whether a safe inlining is possible for a caseOf: expression without
716 further analysis; currently this is the case where the second argument is a
717 literal array, and the appropriate Associations and their elements are laid
718 out with literal keys."
720 (msg arguments second isSameAs: nodes Array) /\
721 [msg arguments second statements allSatisfy:
723 (assoc is: nodes Message)
724 /\ [assoc selector = #->]
725 /\ [assoc arguments first is: nodes Literal]
726 /\ [{Symbol. ASCIIString Character. SmallInteger} anySatisfy:
727 [| :proto | assoc arguments first value is: proto]]]]
730 gen@(VM SSACompiler traits) generate: _@#caseOf:otherwise: on: args from: msg result: finalResult
732 (gen mayInlineCaseOf: msg)
734 assocs ::= args second statements.
735 labels ::= assocs collect: [| :_ | gen newLabelIndex].
736 finalResult `defaultsTo: gen newRegister.
738 gen buildBranchTableMapping:
739 (assocs collect: [| :assoc | assoc arguments first value]).
740 indices ::= IdentityDictionary new.
741 0 below: table size by: 2 do:
742 [| :index | (table at: index) ifNotNilDo: [| :val | indices at: val put: index]].
744 switchKeyRegister ::= gen generate: args first result: Nil.
745 gen emitInstruction: gen branchKeyed
746 withParameters: {switchKeyRegister. gen registerFor: table from: msg result: Nil}
748 branchOffset ::= gen codeWriter position.
749 gen emitInstruction: gen jumpTo from: msg.
750 endLabel ::= gen newLabelIndex.
751 otherwiseLabel ::= gen newLabelIndex.
752 gen emitBranchTo: otherwiseLabel from: msg.
754 assocs with: labels do:
756 gen emitLabel &labelIndex: label.
758 at: (indices at: assoc arguments first value) + 1
759 put: (gen currentContext resolveLabel: label at: branchOffset).
760 gen generateExecutionOf: {assoc arguments second} from: msg result: finalResult.
761 gen emitInstruction: gen jumpTo from: msg.
762 gen emitBranchTo: endLabel from: msg].
764 "Handle the otherwise clause. If we didn't get a literal block for it, just
766 gen emitLabel &labelIndex: otherwiseLabel.
768 ifTrue: [gen generateExecutionOf: {args third} from: msg result: finalResult]
769 ifFalse: [gen registerFor: Nil from: msg result: finalResult].
770 gen emitLabel &labelIndex: endLabel.
774 gen@(VM SSACompiler traits) generate: _@#caseOf: on: args from: msg result: result
775 "Generates a caseOf:otherwise: with a default otherwise clause."
777 (gen mayInlineCaseOf: msg)
778 ifTrue: [gen generate: #caseOf:otherwise: on: args from: msg result: result]
782 gen@(VM SSACompiler traits) generate: _@#ifTrue:ifFalse: on: args from: msg result: finalResult
783 "Branches to one of two blocks and evaluates it."
785 falseLabel ::= gen newLabelIndex.
786 endLabel ::= gen newLabelIndex.
787 finalResult `defaultsTo: gen newRegister.
788 (condReg ::= gen generate: args first result: Nil)
789 ifNil: [error: 'conditional is nil: ' ; args first printString].
790 gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
791 gen emitBranchTo: falseLabel from: msg.
792 gen generateExecutionOf: {args second} from: msg result: finalResult.
793 gen emitInstruction: gen jumpTo from: msg.
794 gen emitBranchTo: endLabel from: msg.
795 gen emitLabel &labelIndex: falseLabel.
796 gen generateExecutionOf: {args third} from: msg result: finalResult.
797 gen emitLabel &labelIndex: endLabel.
801 gen@(VM SSACompiler traits) generate: _@#ifTrue: on: args from: msg result: finalResult
802 "Optionally evaluates a block."
804 falseLabel ::= gen newLabelIndex.
805 endLabel ::= gen newLabelIndex.
806 finalResult `defaultsTo: gen newRegister.
807 (condReg ::= gen generate: args first result: Nil)
808 ifNil: [error: 'conditional is nil: ' ; args first printString].
809 gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
810 gen emitBranchTo: falseLabel from: msg.
811 gen generateExecutionOf: {args second} from: msg result: finalResult.
812 gen emitInstruction: gen jumpTo from: msg.
813 gen emitBranchTo: endLabel from: msg.
814 gen emitLabel &labelIndex: falseLabel.
815 gen registerFor: Nil from: msg result: finalResult.
816 gen emitLabel &labelIndex: endLabel.
820 gen@(VM SSACompiler traits) generate: _@#ifFalse: on: args from: msg result: finalResult
822 falseLabel ::= gen newLabelIndex.
823 endLabel ::= gen newLabelIndex.
824 finalResult `defaultsTo: gen newRegister.
825 (condResult ::= gen generate: args first result: Nil)
826 ifNil: [error: 'conditional is nil: ' ; args first printString].
827 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
828 gen emitBranchTo: falseLabel from: msg.
829 gen generateExecutionOf: {args second} from: msg result: finalResult.
830 gen emitInstruction: gen jumpTo from: msg.
831 gen emitBranchTo: endLabel from: msg.
832 gen emitLabel &labelIndex: falseLabel.
833 gen registerFor: Nil from: msg result: finalResult.
834 gen emitLabel &labelIndex: endLabel.
838 gen@(VM SSACompiler traits) generate: _@#ifNil: on: args from: msg result: finalResult
840 endLabel ::= gen newLabelIndex.
841 finalResult `defaultsTo: gen newRegister.
842 lhsValueReg ::= gen generate: args first result: finalResult. "do not evaluate twice"
843 condReg ::= gen newRegister.
844 gen emitInstruction: gen isNilOp withParameters: {condReg. lhsValueReg} from: msg.
845 gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
846 gen emitBranchTo: endLabel from: msg.
847 gen generateExecutionOf: {args second} from: msg result: finalResult.
848 gen emitLabel &labelIndex: endLabel.
852 gen@(VM SSACompiler traits) generate: _@#ifNotNil: on: args from: msg result: finalResult
854 endLabel ::= gen newLabelIndex.
855 finalResult `defaultsTo: gen newRegister.
856 lhsValueReg ::= gen generate: args first result: finalResult. "do not evaluate twice"
857 condReg ::= gen newRegister.
858 gen emitInstruction: gen isNilOp withParameters: {condReg. lhsValueReg} from: msg.
859 gen emitInstruction: gen branchIfTrue withParameters: {condReg} from: msg.
860 gen emitBranchTo: endLabel from: msg.
861 gen generateExecutionOf: {args second} from: msg result: finalResult.
862 gen emitLabel &labelIndex: endLabel.
866 gen@(VM SSACompiler traits) generate: _@#/\ on: args from: msg result: finalResult
867 "Optionally evaluates a block."
869 (args second isSameAs: nodes Block)
871 falseLabel ::= gen newLabelIndex.
872 endLabel ::= gen newLabelIndex.
873 finalResult `defaultsTo: gen newRegister.
874 (condResult ::= gen generate: args first result: Nil)
875 ifNil: [error: 'conditional is nil: ' ; args first printString].
876 gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
877 gen emitBranchTo: falseLabel from: msg.
878 gen generateExecutionOf: {args second} from: msg result: finalResult.
879 gen emitInstruction: gen jumpTo from: msg.
880 gen emitBranchTo: endLabel from: msg.
881 gen emitLabel &labelIndex: falseLabel.
882 gen registerFor: False from: msg result: finalResult.
883 gen emitLabel &labelIndex: endLabel.
887 gen@(VM SSACompiler traits) generate: _@#\/ on: args from: msg result: finalResult
888 "Optionally evaluates a block."
890 (args second isSameAs: nodes Block)
892 falseLabel ::= gen newLabelIndex.
893 endLabel ::= gen newLabelIndex.
894 finalResult `defaultsTo: gen newRegister.
895 (condResult ::= gen generate: args first result: Nil)
896 ifNil: [error: 'conditional is nil: ' ; args first printString].
897 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
898 gen emitBranchTo: falseLabel from: msg.
899 gen generateExecutionOf: {args second} from: msg result: finalResult.
900 gen emitInstruction: gen jumpTo from: msg.
901 gen emitBranchTo: endLabel from: msg.
902 gen emitLabel &labelIndex: falseLabel.
903 gen registerFor: True from: msg result: finalResult.
904 gen emitLabel &labelIndex: endLabel.
908 gen@(VM SSACompiler traits) generate: _@#whileTrue: on: args from: msg result: finalResult
909 "Repeatedly evaluates a block while it returns True."
911 endLabel ::= gen newLabelIndex.
912 label ::= gen emitLabel.
913 (condResult ::= gen generateExecutionOf: {args first} from: msg result: Nil)
914 ifNil: [error: 'conditional is nil: ' ; args first printString].
915 gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
916 gen emitBranchTo: endLabel from: msg.
917 gen generateExecutionOf: {args second} from: msg result: Nil.
918 gen emitInstruction: gen jumpTo from: msg.
919 gen emitBranchTo: label from: msg.
920 gen emitLabel &labelIndex: endLabel.
921 gen registerFor: Nil from: msg result: finalResult
924 gen@(VM SSACompiler traits) generate: _@#whileFalse: on: args from: msg result: finalResult
925 "Repeatedly evaluates a block while it returns False."
927 endLabel ::= gen newLabelIndex.
928 label ::= gen emitLabel.
929 (condResult ::= gen generateExecutionOf: {args first} from: msg result: Nil)
930 ifNil: [error: 'conditional is nil: ' ; args first printString].
931 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
932 gen emitBranchTo: endLabel from: msg.
933 gen generateExecutionOf: {args second} from: msg result: Nil.
934 gen emitInstruction: gen jumpTo from: msg.
935 gen emitBranchTo: label from: msg.
936 gen emitLabel &labelIndex: endLabel.
937 gen registerFor: Nil from: msg result: finalResult
940 gen@(VM SSACompiler traits) generate: _@#whileTrue on: args from: msg result: result
941 "Repeatedly evaluates a block while it returns True."
943 label ::= gen emitLabel.
944 (condResult ::= gen generateExecutionOf: args from: msg result: Nil)
945 ifNil: [error: 'conditional is nil: ' ; args first printString].
946 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
947 gen emitBranchTo: label from: msg.
948 gen registerFor: Nil from: msg result: result
951 gen@(VM SSACompiler traits) generate: _@#whileFalse on: args from: msg result: result
952 "Repeatedly evaluates a block while it returns False."
954 label ::= gen emitLabel.
955 (condResult ::= gen generateExecutionOf: args from: msg result: Nil)
956 ifNil: [error: 'conditional is nil: ' ; args first printString].
957 gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
958 gen emitBranchTo: label from: msg.
959 gen registerFor: Nil from: msg result: result
962 gen@(VM SSACompiler traits) generate: _@#primitiveDo: on: args from: msg result: result
964 result `defaultsTo: gen newRegister.
965 indexReg ::= gen generate: args first result: Nil.
966 argRegs ::= args second statements collect: [| :item | gen generate: item result: Nil].
967 gen emitInstruction: gen primitiveDo withParameters: {indexReg. argRegs size. result} ; argRegs from: msg.
971 gen@(VM SSACompiler traits) generate: _@#fill:with: on: args from: msg result: result
972 [| index value tempVar |
973 block ::= args first.
974 index := args second.
976 (block isSameAs: nodes Block)
977 /\ [index isSameAs: nodes Literal]
978 /\ [block inputVariables acceptsKey: index value]
980 (value isSameAs: nodes Literal)
982 [tempVar := gen currentMethod sourceTree addVariable.
983 gen generate: (nodes StoreVariable of: value into: tempVar) result: Nil. "fixme"
984 value := nodes LoadVariable from: tempVar].
985 index := index value.
986 var ::= block inputVariables at: index.
987 block inputVariables := block inputVariables copyWithoutAt: index.
990 below: block localVariables indexLast
991 with: block localVariables
992 startingAt: index + 1.
993 block localVariables at: block localVariables indexLast put: var.
995 {nodes StoreVariable of: value into: var} ; block statements.
996 gen generate: block result: result
999 gen@(VM SSACompiler traits) generate: _@#<-* on: args from: msg result: result
1000 "Optimizes currying calls on literal blocks using #fill:with:."
1002 (args first isSameAs: nodes Block)
1005 generate: #fill:with:
1007 (nodes Literal for: args first inputVariables indexLast) at: 1)