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 [| :start :end :sourceTree |
20 (index between: start and: end)
21 ifTrue: [^ sourceTree]]
26 m@(CompiledMethod traits) definitionLocation
28 m sourceTree isNotNil /\ [m sourceTree hasSlotNamed: #source]
29 ifTrue: [m sourceTree definitionLocation]
33 m@(CompiledMethod traits) recompile
34 "If the method has a sourceTree, replace the method with a re-compiled version
38 ifNil: [warn: 'The method has no source code to recompile.'. m]
39 ifNotNilDo: [| :src | m forwardTo: src compile]
42 lobby ensureNamespace: #VM.
43 VM ensureNamespace: #SSACode.
45 VM SSACode define: #Instruction &parents: {Cloneable} &slots: {
50 #offsettingArgIndices -> {}.
53 VM SSACode Instruction traits define: #ByCode -> Dictionary new.
55 i@(VM SSACode Instruction traits) instancesSetting: slotNames to: values
57 resend `>> [do: [| :each |
59 [| :argName | (#{'arity'. 'size'} includes: argName) ifTrue:
61 VM SSACode addImmutableSlot: each selector valued: each code.
62 i ByCode at: each code put: each].
66 VM SSACode Instruction instancesSetting: #{#code. #selector. #name. #argNames. #offsettingArgIndices} to: #{
67 {0. #directSendMessage. 'Direct Send'. {'register of result'. 'selector'. 'arity' ". args..."}. {2}}.
68 "{1. #indirectSendMessage. 'Indirect Send'. {'register of result'. 'selector'. 'arity'. args...}. {2}}."
69 "{2. #allocateRegisters. 'Allocate Registers'. 3. {}}."
70 {3. #loadLiteral. 'Load Literal'. {'register of result'. 'index of literal'}}.
71 "{4. #storeLiteral. 'Store Literal'. {'index of literal'. 'register of source'}}."
72 {5. #sendMessageWithOptionals. 'Send with Optionals'. {'register of result'. 'selector'. 'arity'. 'register of optionals array' ". args..."}. {2}}.
73 {7. #newClosure. 'New Closure'. {'register of result'. 'block'}}.
74 {8. #newArrayWith. 'New Array With'. {'register of result'. 'size' ". args..."}. {1}}.
75 {9. #resendMessage. 'Resend'. {'register of result'. 'lexical offset'}}.
76 {10. #returnFrom. 'Return From'. {'register of result'. 'lexical offset'}}.
77 {11. #loadEnvironment. 'Load Environment'. {'register of result'}}.
78 {12. #loadVariable. 'Load Variable'. {'register of result'}}.
79 {13. #storeVariable. 'Store Variable'. {'register of result'}}.
80 {14. #loadFreeVariable. 'Load Free Variable'. {'register of result'. 'lexical offset'. 'index of variable'}}.
81 {15. #storeFreeVariable. 'Store Free Variable'. {'lexical offset'. 'index of variable'. 'register of source'}}.
82 {16. #isIdenticalTo. 'Is Identical To'. {'register of result'. 'register of x'. 'register of y'}}.
83 {17. #branchKeyed. 'Branch Keyed'. {'register of key'. 'table'}}.
84 {18. #jumpTo. 'Jump To'. {'offset'}}.
85 "Used like SSA phi / branch merges:"
86 {19. #moveRegister. 'Move Register'. {'register of source'. 'register of result'}}.
87 {20. #branchIfTrue. 'Branch If True'. {'register of condition'. 'branch offset'}}.
88 {21. #branchIfFalse. 'Branch If False'. {'register of condition'. 'branch offset'}}.
89 "Marks the end of a block:"
90 {22. #returnRegister. 'Return Register'. {'register of value'}}.
91 "Marks the end of a block:"
92 {23. #returnValue. 'Return Value'. {'value to return'}}.
93 "I'm not sure what this does yet..used in bootstrap:"
94 {24. #resume. 'Resume'. {}}.
95 {25. #primitiveDo. 'Primitive Do'. {'number of primitive'. 'arity'. 'register of result' ". args..."}. {1}}.
96 {26. #directApplyTo. 'Direct Apply To'. {'method'. 'arity'. 'register of result' ". args..."}. {1}}.
97 {27. #isNilOp. 'Is Nil'. {'register of result'. 'register of x'}}.
98 "these check the arguments to see if their maps match the ones in the map array"
99 "if they match, we fall through to the next instruction which is the primitive (no code) or inlined function"
100 "it also needs to set up the input varibles"
101 {28. #inlinePrimitiveCheckJump. 'Inline Primitive Check Jump'. {'register of result'. 'map array'. 'prim number(in-opcode not a register)'. 'arity'. 'jump offset' ". args..."}. {3}}.
102 {29. #inlineMethodCheckJump. 'Inline Method Check Jump'. {'map array'. 'arity'. 'jump offset' ". args..."}. {1}}.
103 {30. #sendMessageWithOptionalsInline. 'Send with Optionals Inline'. {'register of result'. 'selector'. 'arity'. 'optional count'. ". args...optionals..."}. {2. 3}}.
107 VM define: #SSACompiler &parents: {Cloneable}
108 &slots: {#contexts -> Stack new}.
110 VM SSACompiler traitsWindow addDelegate: VM SSACode.
112 g@(VM SSACompiler traits) new
113 [g clone `>> [contexts := g contexts new. ]].
115 VM SSACompiler traits define: #Context &parents: {Cloneable} &slots: {
116 #isClosure -> False "Whether the method being compiled is a closure.".
117 #method -> CompiledMethod new "The method the context targets.".
118 #codeWriter "The stream for writing bytecodes to the method.".
119 #debugMap -> ExtensibleArray new
120 "Gathers the method's debug map; must be indexable at all times.".
121 #registerValues -> ExtensibleArray new
122 "The current register values.".
123 #labels -> ExtensibleArray new
124 "label serials -> code index.".
125 #relocations -> Dictionary new
126 "code index -> label serials".
127 #currentRegister -> 0
128 "The last assigned register value.. or the count?"
131 c@(VM SSACompiler Context traits) newOn: method
132 "FIXME change method code to array instead of bytearray."
134 method code := Array new.
135 c clone `setting: #{#method. #codeWriter. #debugMap. #registerValues. #relocations. #labels. #currentRegister}
138 method debugMap as: c debugMap.
139 c registerValues new.
142 method inputVariables + method localVariables}
145 c@(VM SSACompiler Context traits) copy
147 resend `setting: (registerValues relocations labels currentRegister)
148 to: {c registerValues copy.
154 c@(VM SSACompiler Context traits) resolveLabel: label at: index
156 (c labels at: label) - index
159 c@(VM SSACompiler Context traits) resolveLabels
160 "This takes the labels Dictionary and uses it to replace the temporary ID's
161 placed in the jump fields with actual offsets."
163 code ::= c method code.
164 c relocations keysAndValuesDo:
165 [| :index :label offset |
166 offset := c resolveLabel: label at: index.
167 code at: index put: offset]
170 c@(VM SSACompiler Context traits) flush
172 c method code := c codeWriter contents.
173 c method debugMap := c debugMap as: Array.
178 c@(VM SSACompiler Context traits) beClosure [c isClosure := True].
180 gen@(VM SSACompiler traits) currentContext
183 gen@(VM SSACompiler traits) newRegister
185 gen contexts top currentRegister += 1
188 gen@(VM SSACompiler traits) registerFor: obj from: def result: result
190 "the whole problem with this function is that we could cache a literal that
191 is only loaded in a loop which may not always be executed. remove this code
192 until we have it figured out."
193 " gen contexts top registerValues do:
194 [| :val | val value = obj
196 [val key = result \/ [result isNil]
198 ifFalse: [result `defaultsTo: gen newRegister.
199 gen emitInstruction: gen moveRegister withParameters: {result. val key} from: def.
202 "we don't want result to be a local variable and have it overwritten later"
203 "saveRegister := result isNil."
204 saveRegister := False.
205 result `defaultsTo: gen newRegister.
206 gen emitInstruction: gen loadLiteral withParameters: {result. obj} from: def.
207 saveRegister ifTrue: [gen setRegister: result to: obj].
211 gen@(VM SSACompiler traits) setRegister: x to: y
213 gen contexts top registerValues add: x -> y ifPresent:
214 [error: 'Compiler error: Register already set.'].
217 gen@(VM SSACompiler traits) currentMethod
218 [gen currentContext method].
220 gen@(VM SSACompiler traits) codeWriter
221 [gen currentContext codeWriter].
223 gen@(VM SSACompiler traits) newLabelIndex
225 gen currentContext labels `>> [addLast: Nil. indexLast]
228 gen@(VM SSACompiler traits) emitLabel &labelIndex: labelIndex
230 labelIndex `defaultsTo: gen newLabelIndex.
231 gen currentContext labels at: labelIndex put: gen codeWriter position.
235 gen@(VM SSACompiler traits) emitRelocationAgainst: label
237 gen currentContext relocations at: gen codeWriter position put: label
240 gen@(VM SSACompiler traits) emitObject: value from: node
242 "0 below: bytesPerWord do: [| :byte | gen emitByte: (value byteShift: 0 - byte) intoByte from: node]."
244 gen codeWriter nextPut: value
247 gen@(VM SSACompiler traits) emitBranchTo: label from: msg
249 gen emitRelocationAgainst: label.
250 gen emitObject: 0 from: msg "replaced later when flushed"
253 gen@(VM SSACompiler traits) mapTo: sourceTree
255 index ::= gen codeWriter position.
256 gen currentContext debugMap `cacheAs: #debugMap.
257 debugMap isEmpty not /\ [debugMap last == sourceTree]
258 ifTrue: [debugMap at: debugMap indexLast - 1 infect: [| :value | index max: value].
259 debugMap at: debugMap indexLast - 2 infect: [| :value | index min: value]]
260 ifFalse: [debugMap addAllLast: {index. index. sourceTree}]
263 gen@(VM SSACompiler traits) emitInstruction: code@(Integer traits) withParameters: values from: node
264 "this gets called before the real function"
266 "values do: [| :value | (value is: nodes Node) ifTrue: [error: 'bad code']]." "commented out because we could actually load node literals in compiler code"
270 gen@(VM SSACompiler traits) emitInstruction: code withParameters: values from: node
272 "add the selector to the list so we know what this function calls... so it can be unoptimized if needed"
273 code = gen directSendMessage
274 \/ [code = gen sendMessageWithOptionals]
275 \/ [code = gen sendMessageWithOptionalsInline]
276 ifTrue: [gen currentContext method selectors := gen currentContext method selectors ; {values second}].
277 gen emitObject: code from: node.
278 values do: [| :value | gen emitObject: value from: node]
281 gen@(VM SSACompiler traits) emitInstruction: code from: node
282 "Emitting an instruction without an immediate value required just puts the
285 gen emitInstruction: code withParameters: #{} from: node
289 =======================================================================
290 Generate methods. They all must return the register(s) with the results
291 =======================================================================
294 _@(VM SSACompiler traits) generate: _@(nodes Node traits)
295 "Do nothing in the default case, for comments and annotations and such."
296 [error: 'do not call generate without a result'].
298 _@(VM SSACompiler traits) generate: _@(nodes Node traits) result: result
299 "Do nothing in the default case, for comments and annotations and such."
302 gen@(VM SSACompiler traits) generate: ann@(nodes Annotation traits) result: result
303 "Generate the annotation's value."
305 gen generate: ann value
308 gen@(VM SSACompiler traits) generate: block@(nodes Block traits) result: result &topLevel: topLevel
309 "Encountering a new block, build a new CompiledMethod object and push it and
310 a new bytecode array writer onto the generator, then go through the underlying
311 code and generate that. When done, pop both, set up the block as a literal
312 and push it onto the stack."
314 topLevel `defaultsTo: False.
315 newBlock ::= CompiledMethod new `>>
316 [environment := gen contexts isEmpty
317 ifTrue: [block parentScope topLevel namespace]
318 ifFalse: [gen currentMethod environment].
319 sourceTree := block. ].
320 gen contexts push: (gen Context newOn: newBlock).
321 "we macroexpand everything before we set the current register because macroexpansion can add localvariables etc"
322 statements ::= block statements collect:
323 [| :statement | statement macroExpand &environment: gen currentMethod sourceTree].
324 gen currentContext currentRegister := block localVariables size. "input variables might not be needed"
325 statements allButLastDo: [| :node | gen generate: node result: Nil].
327 ifTrue: [gen emitInstruction: gen returnValue withParameters: {Nil} from: block]
328 ifFalse: [gen emitInstruction: gen returnRegister withParameters: {gen generate: statements last result: Nil} from: block].
330 "Set the variable information after generation, just in case it was modified."
332 [inputVariables := block inputVariables size.
333 localVariables := block localVariables size.
334 restVariable := block restVariable isNotNil.
335 registerCount := gen currentContext currentRegister + 1.
336 "reserved1 := gen currentContext currentRegister + 1."
337 optionalKeywords := block optionalKeywords. ].
338 isClosure ::= gen currentContext isClosure.
340 gen contexts pop flush.
341 "Forces the newBlock to record all the remaining stream input correctly."
343 gen contexts isEmpty \/ [topLevel]
345 [result `defaultsTo: gen newRegister. "asking for a register requires a context"
346 gen emitInstruction: (isClosure ifTrue: [gen newClosure] ifFalse: [gen loadLiteral])
347 withParameters: {result. newBlock} from: block].
349 gen contexts isEmpty \/ [topLevel] ifTrue: [newBlock] ifFalse: [result]
352 gen@(VM SSACompiler traits) generate: sig@(nodes Signature traits) result: resultRegister
357 gen@(VM SSACompiler traits) generate: def@(nodes MethodDefinition traits) result: resultRegister
358 "Translate method definitions to equivalent asMethod:on: invocations."
362 blockRegister ::= #generate:result: sendTo: {gen. def. Nil} through: {gen. nodes Block. Nil}.
363 arrayRegister ::= gen newRegister.
364 selectorRegister ::= gen registerFor: def selector from: def result: Nil.
365 roleRegisters ::= def roles collect: #(gen generate: _ result: Nil) `er.
366 resultRegister `defaultsTo: gen newRegister.
367 gen emitInstruction: gen newArrayWith withParameters: {arrayRegister. roleRegisters size} ; roleRegisters from: def.
368 gen emitInstruction: gen directSendMessage withParameters: {resultRegister. #asMethod:on:. 3. blockRegister. selectorRegister. arrayRegister} from: def.
372 gen@(VM SSACompiler traits) generate: r@(nodes Resend traits) result: resultRegister
374 scope ::= gen currentMethod sourceTree.
375 lexOffset ::= gen contexts indexLast -
376 ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree isSameAs: nodes MethodDefinition])
378 [error: 'resend must be used within a method definition.']).
381 [(gen contexts fromTop: lexOffset) method heapAllocate := True.
382 (gen contexts top: lexOffset) do: #beClosure `er].
383 resultRegister `defaultsTo: gen newRegister.
384 gen emitInstruction: gen resendMessage withParameters: {resultRegister. lexOffset} from: r.
388 gen@(VM SSACompiler traits) generate: r@(nodes Return traits) result: blah
391 gen@(VM SSACompiler traits) generate: r@(nodes Return traits) by: lexOffset result: resultRegister
393 resultRegister `defaultsTo: gen newRegister.
396 [(gen contexts fromTop: lexOffset) method heapAllocate := True.
397 (gen contexts top: lexOffset) do: #beClosure `er].
398 gen generate: r value result: resultRegister.
399 gen emitInstruction: gen returnFrom withParameters: {resultRegister. lexOffset} from: r.
403 gen@(VM SSACompiler traits) generate: r@(nodes ReturnClose traits) result: resultRegister
404 "Exits the first enclosing named method in the lexical scope."
406 lexOffset ::= gen contexts indexLast -
407 ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree isSameAs: nodes MethodDefinition])
409 [error: '^ must be used within a method definition.']).
410 gen generate: r by: lexOffset result: resultRegister
413 gen@(VM SSACompiler traits) generate: r@(nodes ReturnFar traits) result: result
414 "Exits the last enclosing named method in the lexical scope."
416 lexOffset ::= gen contexts indexLast -
417 ((gen contexts indexOfFirstSatisfying: [| :context | context method sourceTree isSameAs: nodes MethodDefinition])
419 [error: '^^ must be used within a method definition.']).
420 gen generate: r by: lexOffset result: result
423 gen@(VM SSACompiler traits) generate: r@(nodes ReturnLevel traits) result: result
424 "Exits the Nth enclosing lexical scope."
425 [gen generate: r by: r level result: result].
427 gen@(VM SSACompiler traits) generate: literal@(nodes Literal traits) result: result
429 gen registerFor: literal value from: literal result: result
432 gen@(VM SSACompiler traits) generate: n@(nodes CompoundStatement traits) result: result
433 "return the registers that the values were saved into"
437 ifFalse: [(n statements allButLast collect: [| :node | gen generate: node result: Nil])
438 ; {(gen generate: n statements last result: result)}]
441 gen@(VM SSACompiler traits) generate: n@(nodes Parenthesis traits) result: result
442 "return the registers that the values were saved into"
446 ifFalse: [n statements allButLastDo: [| :node | gen generate: node result: Nil].
447 gen generate: n statements last result: result]
450 gen@(VM SSACompiler traits) generate: i@(nodes ImplicitArgument traits) result: result
452 result `defaultsTo: gen newRegister.
453 gen emitInstruction: gen loadEnvironment withParameters: {result} from: i.
457 gen@(VM SSACompiler traits) generate: _@(nodes Namespace traits) result: result
458 [shouldNotImplement].
460 gen@(VM SSACompiler traits) generate: load@(nodes LoadVariable traits) result: result
462 load variable scope `cacheAs: #scope.
463 varIndex ::= scope localVariables indexOf: load variable.
464 lexOffset ::= gen contexts indexLast -
465 ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree == scope])
467 [error: 'Could not determine variable scope.']).
470 [result `defaultsTo: varIndex.
471 gen emitInstruction: gen loadVariable withParameters: {varIndex} from: load.
473 ifFalse: [gen emitInstruction: gen moveRegister withParameters: {result. varIndex} from: load]]
475 [result `defaultsTo: gen newRegister.
476 (gen contexts fromTop: lexOffset) method heapAllocate := True.
477 (gen contexts top: lexOffset) do: #beClosure `er.
478 gen emitInstruction: gen loadFreeVariable withParameters: {result. lexOffset. varIndex} from: load].
482 gen@(VM SSACompiler traits) generate: store@(nodes StoreVariable traits) result: result
484 store variable scope `cacheAs: #scope.
485 varIndex ::= scope localVariables indexOf: store variable.
486 lexOffset ::= gen contexts indexLast -
487 ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree == scope])
489 [error: 'Could not determine variable scope.']).
492 [result `defaultsTo: varIndex.
493 gen generate: store value result: varIndex.
494 gen emitInstruction: gen storeVariable withParameters: {varIndex} from: store.
496 ifFalse: [gen emitInstruction: gen moveRegister withParameters: {result. varIndex} from: store]]
498 [result `defaultsTo: gen newRegister.
499 gen generate: store value result: result.
500 (gen contexts fromTop: lexOffset) method heapAllocate := True.
501 (gen contexts top: lexOffset) do: #beClosure `er.
502 gen emitInstruction: gen storeFreeVariable withParameters: {lexOffset. varIndex. result} from: store].
506 gen@(VM SSACompiler traits) generate: array@(nodes Array traits) result: result
507 "Generate the code to push the element expression results on the stack,
508 then the appropriate literal-array constructor bytecode."
510 registers ::= resend.
511 result `defaultsTo: gen newRegister.
512 gen emitInstruction: gen newArrayWith withParameters: {result. array size} ; registers from: array.
516 gen@(VM SSACompiler traits) generate: selector@(Symbol traits) on: args from: msg@(nodes Message traits) result: result
517 "Generate the code to push the argument expression results on the stack, then
518 the push for the selector, and then the appropriate message send bytecode."
520 result `defaultsTo: gen newRegister.
521 argRegisters ::= args collect: #(gen generate: _ result: Nil) `er.
522 gen emitInstruction: gen directSendMessage withParameters: {result. selector. args size} ; argRegisters from: msg.
526 gen@(VM SSACompiler traits) generate: msg@(nodes Message traits) result: result &optionals: opts
528 gen generate: msg selector on: msg arguments from: (opts ifNil: [msg]) result: result
531 gen@(VM SSACompiler traits) generate: macro@(nodes Macro traits) result: result &optionals: opts
533 "gen generate: (macro macroExpand &optionals: opts &environment: gen currentMethod sourceTree) result: result"
534 error: 'SSA Compiler cannot support macroexpansion at code generation time because of localVariable side-effects'.
537 gen@(VM SSACompiler traits) generate: def@(nodes Deferred traits) result: result &optionals: opts
539 block ::= nodes Block new `>> [parentScope := gen currentMethod sourceTree. ].
540 def arguments size timesRepeat: [block addInputVariable].
541 message := nodes Message sending: def selector to:
542 (block inputVariables collect: #(nodes LoadVariable from: _) `er).
546 ((nodes OptionalArguments for: message)
547 `>> [arguments := opts arguments deepCopy: block. ])].
548 block statements := {message}.
550 (nodes KeywordMessage
551 sending: #whenFulfilled:
552 to: {def arguments as: nodes Array. block})
556 gen@(VM SSACompiler traits) generate: selector@(Symbol traits) on: args from: opts@(nodes OptionalKeywords traits) result: result
557 "Generate the code to push the argument expression results on the stack, then
558 the push for the selector, and then the appropriate message send bytecode."
560 result `defaultsTo: gen newRegister.
561 argRegisters ::= args collect: #(gen generate: _ result: Nil) `er.
562 optsArray ::= ExtensibleArray new.
563 optsWriter ::= optsArray writer.
564 opts keywords with: opts arguments do:
566 optsWriter nextPut: (gen registerFor: key from: opts result: Nil).
567 optsWriter nextPut: (gen generate: arg result: Nil)].
568 gen emitInstruction: gen sendMessageWithOptionalsInline withParameters:
569 {result. selector. args size. optsArray size} ; argRegisters ; optsArray from: opts.
573 gen@(VM SSACompiler traits) generate: opts@(nodes OptionalKeywords traits) result: result
575 gen generate: opts message result: result &optionals: opts
578 gen@(VM SSACompiler traits) generate: rest@(nodes RestArguments traits) result: result
580 gen generate: rest message selector on: rest message arguments ; rest arguments from: rest message result: result
583 gen@(VM SSACompiler traits) generate: _@#apply* on: args from: msg result: result
585 result `defaultsTo: gen newRegister.
586 methodReg ::= gen generate: args first result: Nil.
587 argRegs ::= args allButFirst collect: [| :item | gen generate: item result: Nil].
588 gen emitInstruction: gen directApplyTo withParameters: {methodReg. argRegs size. result} ; argRegs from: msg.
592 gen@(VM SSACompiler traits) generate: _@#applyTo: on: args from: msg result: result
594 (args second isSameAs: nodes Array)
596 [result `defaultsTo: gen newRegister.
597 methodReg ::= gen generate: args first result: Nil.
598 argRegs ::= args second statements collect:
599 [| :item | gen generate: item result: Nil].
600 gen emitInstruction: gen directApplyTo
601 withParameters: {methodReg. argRegs size. result} ; argRegs
607 gen@(VM SSACompiler traits) generate: _@#primitiveApply* on: args from: msg result: result
609 result `defaultsTo: gen newRegister.
610 indexReg ::= gen generate: args first result: Nil.
611 argRegs ::= args second statements collect: [| :item | gen generate: item result: Nil].
612 gen emitInstruction: gen primitiveDo withParameters: {indexReg. argRegs size. result} ; argRegs from: msg.
616 gen@(VM SSACompiler traits) generate: _@#True on: args from: msg result: result
618 (args first isSameAs: nodes ImplicitArgument)
619 ifTrue: [gen registerFor: True from: msg result: result]
623 gen@(VM SSACompiler traits) generate: _@#False on: args from: msg result: result
625 (args first isSameAs: nodes ImplicitArgument)
626 ifTrue: [gen registerFor: False from: msg result: result]
630 gen@(VM SSACompiler traits) generate: _@#Nil on: args from: msg result: result
632 (args first isSameAs: nodes ImplicitArgument)
633 ifTrue: [gen registerFor: Nil from: msg result: result]
637 gen@(VM SSACompiler traits) generate: _@#== on: args from: msg result: result
639 result `defaultsTo: gen newRegister.
640 argRegs ::= args collect: [| :arg | gen generate: arg result: Nil].
641 gen emitInstruction: gen isIdenticalTo withParameters: {result. argRegs first. argRegs second} from: msg.
645 gen@(VM SSACompiler traits) generate: _@#do on: args from: msg result: result
646 "If the block is a literal with no variables, then inline it.
647 Otherwise, fall back to evaluating it via 'do'."
649 args first `cacheAs: #block.
650 (block isSameAs: nodes Block)
651 /\ [block localVariables isEmpty]
653 [result `defaultsTo: gen newRegister.
654 block statements isEmpty
655 ifTrue: [gen emitInstruction: gen loadLiteral withParameters: {result. Nil} from: msg.
657 ifFalse: [block statements allButLastDo: [| :node | gen generate: node result: Nil].
658 gen generate: block statements last result: result]]
662 gen@(VM SSACompiler traits) generateExecutionOf: args from: msg result: result
663 [gen generate: #do on: args from: msg result: result].
665 gen@(VM SSACompiler traits) generate: _@#loop on: args from: msg result: result
666 "Repeatedly evaluates a block via 'do'."
668 label ::= gen emitLabel.
669 gen generateExecutionOf: args from: msg result: Nil.
670 gen emitInstruction: gen jumpTo withParameters: #{}"see below" from: msg.
671 gen emitBranchTo: label from: msg.
672 gen registerFor: Nil from: msg result: result "return nil"
675 gen@(VM SSACompiler traits) generate: _@#isNil on: args from: msg result: result
677 result `defaultsTo: gen newRegister.
678 objReg ::= gen generate: args first result: Nil.
679 gen emitInstruction: gen isNilOp withParameters: {result. objReg} from: msg.
683 gen@(VM SSACompiler traits) branchTableHash: key
688 gen@(VM SSACompiler traits) buildBranchTableMapping: keys
691 [tableSize < keys size]
694 table ::= Array newSize: tableSize * 2.
697 hash := (gen branchTableHash: key) bitAnd: (tableSize - 1) * 2.
698 [(table at: hash) isNil]
700 [key = (table at: hash)
702 [error: 'Duplicate key ' ; key printString ; ' in caseOf:.'].
703 (hash += 2) >= (tableSize * 2) ifTrue:
705 table at: hash put: key].
709 gen@(VM SSACompiler traits) mayInlineCaseOf: msg
710 "Answer whether a safe inlining is possible for a caseOf: expression without
711 further analysis; currently this is the case where the second argument is a
712 literal array, and the appropriate Associations and their elements are laid
713 out with literal keys."
715 (msg arguments second isSameAs: nodes Array) /\
716 [msg arguments second statements allSatisfy:
718 (assoc is: nodes Message)
719 /\ [assoc selector = #->]
720 /\ [assoc arguments first is: nodes Literal]
721 /\ [{Symbol. ASCIIString Character. SmallInteger} anySatisfy:
722 [| :proto | assoc arguments first value is: proto]]]]
725 gen@(VM SSACompiler traits) generate: _@#caseOf:otherwise: on: args from: msg result: finalResult
727 (gen mayInlineCaseOf: msg)
729 assocs ::= args second statements.
730 labels ::= assocs collect: [| :_ | gen newLabelIndex].
731 finalResult `defaultsTo: gen newRegister.
733 gen buildBranchTableMapping:
734 (assocs collect: [| :assoc | assoc arguments first value]).
735 indices ::= IdentityDictionary new.
736 0 below: table size by: 2 do:
737 [| :index | (table at: index) ifNotNilDo: [| :val | indices at: val put: index]].
739 switchKeyRegister ::= gen generate: args first result: Nil.
740 gen emitInstruction: gen branchKeyed
741 withParameters: {switchKeyRegister. gen registerFor: table from: msg result: Nil}
743 branchOffset ::= gen codeWriter position.
744 gen emitInstruction: gen jumpTo from: msg.
745 endLabel ::= gen newLabelIndex.
746 otherwiseLabel ::= gen newLabelIndex.
747 gen emitBranchTo: otherwiseLabel from: msg.
749 assocs with: labels do:
751 gen emitLabel &labelIndex: label.
753 at: (indices at: assoc arguments first value) + 1
754 put: (gen currentContext resolveLabel: label at: branchOffset).
755 gen generateExecutionOf: {assoc arguments second} from: msg result: finalResult.
756 gen emitInstruction: gen jumpTo from: msg.
757 gen emitBranchTo: endLabel from: msg].
759 "Handle the otherwise clause. If we didn't get a literal block for it, just
761 gen emitLabel &labelIndex: otherwiseLabel.
763 ifTrue: [gen generateExecutionOf: {args third} from: msg result: finalResult]
764 ifFalse: [gen registerFor: Nil from: msg result: finalResult].
765 gen emitLabel &labelIndex: endLabel.
769 gen@(VM SSACompiler traits) generate: _@#caseOf: on: args from: msg result: result
770 "Generates a caseOf:otherwise: with a default otherwise clause."
772 (gen mayInlineCaseOf: msg)
773 ifTrue: [gen generate: #caseOf:otherwise: on: args from: msg result: result]
777 gen@(VM SSACompiler traits) generate: _@#ifTrue:ifFalse: on: args from: msg result: finalResult
778 "Branches to one of two blocks and evaluates it."
780 falseLabel ::= gen newLabelIndex.
781 endLabel ::= gen newLabelIndex.
782 finalResult `defaultsTo: gen newRegister.
783 (condReg ::= gen generate: args first result: Nil)
784 ifNil: [error: 'conditional is nil: ' ; args first printString].
785 gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
786 gen emitBranchTo: falseLabel from: msg.
787 gen generateExecutionOf: {args second} from: msg result: finalResult.
788 gen emitInstruction: gen jumpTo from: msg.
789 gen emitBranchTo: endLabel from: msg.
790 gen emitLabel &labelIndex: falseLabel.
791 gen generateExecutionOf: {args third} from: msg result: finalResult.
792 gen emitLabel &labelIndex: endLabel.
796 gen@(VM SSACompiler traits) generate: _@#ifTrue: on: args from: msg result: finalResult
797 "Optionally evaluates a block."
799 falseLabel ::= gen newLabelIndex.
800 endLabel ::= gen newLabelIndex.
801 finalResult `defaultsTo: gen newRegister.
802 (condReg ::= gen generate: args first result: Nil)
803 ifNil: [error: 'conditional is nil: ' ; args first printString].
804 gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
805 gen emitBranchTo: falseLabel from: msg.
806 gen generateExecutionOf: {args second} from: msg result: finalResult.
807 gen emitInstruction: gen jumpTo from: msg.
808 gen emitBranchTo: endLabel from: msg.
809 gen emitLabel &labelIndex: falseLabel.
810 gen registerFor: Nil from: msg result: finalResult.
811 gen emitLabel &labelIndex: endLabel.
815 gen@(VM SSACompiler traits) generate: _@#ifFalse: on: args from: msg result: finalResult
817 falseLabel ::= gen newLabelIndex.
818 endLabel ::= gen newLabelIndex.
819 finalResult `defaultsTo: gen newRegister.
820 (condResult ::= gen generate: args first result: Nil)
821 ifNil: [error: 'conditional is nil: ' ; args first printString].
822 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
823 gen emitBranchTo: falseLabel from: msg.
824 gen generateExecutionOf: {args second} from: msg result: finalResult.
825 gen emitInstruction: gen jumpTo from: msg.
826 gen emitBranchTo: endLabel from: msg.
827 gen emitLabel &labelIndex: falseLabel.
828 gen registerFor: Nil from: msg result: finalResult.
829 gen emitLabel &labelIndex: endLabel.
833 gen@(VM SSACompiler traits) generate: _@#ifNil: on: args from: msg result: finalResult
835 endLabel ::= gen newLabelIndex.
836 finalResult `defaultsTo: gen newRegister.
837 lhsValueReg ::= gen generate: args first result: finalResult. "do not evaluate twice"
838 condReg ::= gen newRegister.
839 gen emitInstruction: gen isNilOp withParameters: {condReg. lhsValueReg} from: msg.
840 gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
841 gen emitBranchTo: endLabel from: msg.
842 gen generateExecutionOf: {args second} from: msg result: finalResult.
843 gen emitLabel &labelIndex: endLabel.
847 gen@(VM SSACompiler traits) generate: _@#ifNotNil: on: args from: msg result: finalResult
849 endLabel ::= gen newLabelIndex.
850 finalResult `defaultsTo: gen newRegister.
851 lhsValueReg ::= gen generate: args first result: finalResult. "do not evaluate twice"
852 condReg ::= gen newRegister.
853 gen emitInstruction: gen isNilOp withParameters: {condReg. lhsValueReg} from: msg.
854 gen emitInstruction: gen branchIfTrue withParameters: {condReg} from: msg.
855 gen emitBranchTo: endLabel from: msg.
856 gen generateExecutionOf: {args second} from: msg result: finalResult.
857 gen emitLabel &labelIndex: endLabel.
861 gen@(VM SSACompiler traits) generate: _@#/\ on: args from: msg result: finalResult
862 "Optionally evaluates a block."
864 (args second isSameAs: nodes Block)
866 falseLabel ::= gen newLabelIndex.
867 endLabel ::= gen newLabelIndex.
868 finalResult `defaultsTo: gen newRegister.
869 (condResult ::= gen generate: args first result: Nil)
870 ifNil: [error: 'conditional is nil: ' ; args first printString].
871 gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
872 gen emitBranchTo: falseLabel from: msg.
873 gen generateExecutionOf: {args second} from: msg result: finalResult.
874 gen emitInstruction: gen jumpTo from: msg.
875 gen emitBranchTo: endLabel from: msg.
876 gen emitLabel &labelIndex: falseLabel.
877 gen registerFor: False from: msg result: finalResult.
878 gen emitLabel &labelIndex: endLabel.
882 gen@(VM SSACompiler traits) generate: _@#\/ on: args from: msg result: finalResult
883 "Optionally evaluates a block."
885 (args second isSameAs: nodes Block)
887 falseLabel ::= gen newLabelIndex.
888 endLabel ::= gen newLabelIndex.
889 finalResult `defaultsTo: gen newRegister.
890 (condResult ::= gen generate: args first result: Nil)
891 ifNil: [error: 'conditional is nil: ' ; args first printString].
892 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
893 gen emitBranchTo: falseLabel from: msg.
894 gen generateExecutionOf: {args second} from: msg result: finalResult.
895 gen emitInstruction: gen jumpTo from: msg.
896 gen emitBranchTo: endLabel from: msg.
897 gen emitLabel &labelIndex: falseLabel.
898 gen registerFor: True from: msg result: finalResult.
899 gen emitLabel &labelIndex: endLabel.
903 gen@(VM SSACompiler traits) generate: _@#whileTrue: on: args from: msg result: finalResult
904 "Repeatedly evaluates a block while it returns True."
906 endLabel ::= gen newLabelIndex.
907 label ::= gen emitLabel.
908 (condResult ::= gen generateExecutionOf: {args first} from: msg result: Nil)
909 ifNil: [error: 'conditional is nil: ' ; args first printString].
910 gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
911 gen emitBranchTo: endLabel from: msg.
912 gen generateExecutionOf: {args second} from: msg result: Nil.
913 gen emitInstruction: gen jumpTo from: msg.
914 gen emitBranchTo: label from: msg.
915 gen emitLabel &labelIndex: endLabel.
916 gen registerFor: Nil from: msg result: finalResult
919 gen@(VM SSACompiler traits) generate: _@#whileFalse: on: args from: msg result: finalResult
920 "Repeatedly evaluates a block while it returns False."
922 endLabel ::= gen newLabelIndex.
923 label ::= gen emitLabel.
924 (condResult ::= gen generateExecutionOf: {args first} from: msg result: Nil)
925 ifNil: [error: 'conditional is nil: ' ; args first printString].
926 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
927 gen emitBranchTo: endLabel from: msg.
928 gen generateExecutionOf: {args second} from: msg result: Nil.
929 gen emitInstruction: gen jumpTo from: msg.
930 gen emitBranchTo: label from: msg.
931 gen emitLabel &labelIndex: endLabel.
932 gen registerFor: Nil from: msg result: finalResult
935 gen@(VM SSACompiler traits) generate: _@#whileTrue on: args from: msg result: result
936 "Repeatedly evaluates a block while it returns True."
938 label ::= gen emitLabel.
939 (condResult ::= gen generateExecutionOf: args from: msg result: Nil)
940 ifNil: [error: 'conditional is nil: ' ; args first printString].
941 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
942 gen emitBranchTo: label from: msg.
943 gen registerFor: Nil from: msg result: result
946 gen@(VM SSACompiler traits) generate: _@#whileFalse on: args from: msg result: result
947 "Repeatedly evaluates a block while it returns False."
949 label ::= gen emitLabel.
950 (condResult ::= gen generateExecutionOf: args from: msg result: Nil)
951 ifNil: [error: 'conditional is nil: ' ; args first printString].
952 gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
953 gen emitBranchTo: label from: msg.
954 gen registerFor: Nil from: msg result: result
957 gen@(VM SSACompiler traits) generate: _@#primitiveDo: on: args from: msg result: result
959 result `defaultsTo: gen newRegister.
960 indexReg ::= gen generate: args first result: Nil.
961 argRegs ::= args second statements collect: [| :item | gen generate: item result: Nil].
962 gen emitInstruction: gen primitiveDo withParameters: {indexReg. argRegs size. result} ; argRegs from: msg.
966 gen@(VM SSACompiler traits) generate: _@#fill:with: on: args from: msg result: result
967 [| index value tempVar |
968 block ::= args first.
969 index := args second.
971 (block isSameAs: nodes Block)
972 /\ [index isSameAs: nodes Literal]
973 /\ [block inputVariables acceptsKey: index value]
975 (value isSameAs: nodes Literal)
977 [tempVar := gen currentMethod sourceTree addVariable.
978 gen generate: (nodes StoreVariable of: value into: tempVar) result: Nil. "fixme"
979 value := nodes LoadVariable from: tempVar].
980 index := index value.
981 var ::= block inputVariables at: index.
982 block inputVariables := block inputVariables copyWithoutAt: index.
985 below: block localVariables indexLast
986 with: block localVariables
987 startingAt: index + 1.
988 block localVariables at: block localVariables indexLast put: var.
990 {nodes StoreVariable of: value into: var} ; block statements.
991 gen generate: block result: result
994 gen@(VM SSACompiler traits) generate: _@#<-* on: args from: msg result: result
995 "Optimizes currying calls on literal blocks using #fill:with:."
997 (args first isSameAs: nodes Block)
1000 generate: #fill:with:
1002 (nodes Literal for: args first inputVariables indexLast) at: 1)