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 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."
313 [| newBlock isClosure statements |
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."
359 [| blockRegister roleRegisters arrayRegister resultRegister selectorRegister |
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
461 [| lexOffset varIndex |
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
483 [| lexOffset varIndex |
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."
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."
559 [| argRegisters optsArray optsWriter |
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
584 [| methodReg argRegs |
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
593 [| methodReg argRegs |
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
608 [| indexReg argRegs |
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
726 [| labels table indices branchOffset otherwiseLabel endLabel switchKeyRegister |
727 (gen mayInlineCaseOf: msg)
729 args second statements `cacheAs: #assocs.
730 labels := assocs collect: [| :_ | gen newLabelIndex].
731 finalResult `defaultsTo: gen newRegister.
734 buildBranchTableMapping:
735 (assocs collect: [| :assoc | assoc arguments first value])).
736 indices := IdentityDictionary new.
737 0 below: table size by: 2 do: [| :index |
738 (table at: index) ifNotNilDo: [| :val | indices at: val put: index]].
740 switchKeyRegister := gen generate: args first result: Nil.
741 gen emitInstruction: gen branchKeyed
742 withParameters: {switchKeyRegister. (gen registerFor: table from: msg result: Nil)}
744 branchOffset := gen codeWriter position.
745 gen emitInstruction: gen jumpTo from: msg.
746 endLabel := gen newLabelIndex.
747 otherwiseLabel := gen newLabelIndex.
748 gen emitBranchTo: otherwiseLabel from: msg.
750 assocs with: labels do:
752 gen emitLabel &labelIndex: label.
754 at: (indices at: assoc arguments first value) + 1
755 put: (gen currentContext resolveLabel: label at: branchOffset).
756 gen generateExecutionOf: {assoc arguments second} from: msg result: finalResult.
757 gen emitInstruction: gen jumpTo from: msg.
758 gen emitBranchTo: endLabel from: msg].
760 "Handle the otherwise clause. If we didn't get a literal block for it, just
762 gen emitLabel &labelIndex: otherwiseLabel.
764 ifTrue: [gen generateExecutionOf: {args third} from: msg result: finalResult]
765 ifFalse: [gen registerFor: Nil from: msg result: finalResult].
766 gen emitLabel &labelIndex: endLabel.
770 gen@(VM SSACompiler traits) generate: _@#caseOf: on: args from: msg result: result
771 "Generates a caseOf:otherwise: with a default otherwise clause."
773 (gen mayInlineCaseOf: msg)
774 ifTrue: [gen generate: #caseOf:otherwise: on: args from: msg result: result]
778 gen@(VM SSACompiler traits) generate: _@#ifTrue:ifFalse: on: args from: msg result: finalResult
779 "Branches to one of two blocks and evaluates it."
780 [| falseLabel endLabel condReg |
781 falseLabel := gen newLabelIndex.
782 endLabel := gen newLabelIndex.
783 finalResult `defaultsTo: gen newRegister.
784 (condReg := gen generate: args first result: Nil)
785 ifNil: [error: 'conditional is nil: ' ; args first printString].
786 gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
787 gen emitBranchTo: falseLabel from: msg.
788 gen generateExecutionOf: {args second} from: msg result: finalResult.
789 gen emitInstruction: gen jumpTo from: msg.
790 gen emitBranchTo: endLabel from: msg.
791 gen emitLabel &labelIndex: falseLabel.
792 gen generateExecutionOf: {args third} from: msg result: finalResult.
793 gen emitLabel &labelIndex: endLabel.
797 gen@(VM SSACompiler traits) generate: _@#ifTrue: on: args from: msg result: finalResult
798 "Optionally evaluates a block."
799 [| falseLabel endLabel condReg |
800 falseLabel := gen newLabelIndex.
801 endLabel := gen newLabelIndex.
802 finalResult `defaultsTo: gen newRegister.
803 (condReg := gen generate: args first result: Nil)
804 ifNil: [error: 'conditional is nil: ' ; args first printString].
805 gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
806 gen emitBranchTo: falseLabel from: msg.
807 gen generateExecutionOf: {args second} from: msg result: finalResult.
808 gen emitInstruction: gen jumpTo from: msg.
809 gen emitBranchTo: endLabel from: msg.
810 gen emitLabel &labelIndex: falseLabel.
811 gen registerFor: Nil from: msg result: finalResult.
812 gen emitLabel &labelIndex: endLabel.
816 gen@(VM SSACompiler traits) generate: _@#ifFalse: on: args from: msg result: finalResult
817 [| falseLabel endLabel condResult |
818 falseLabel := gen newLabelIndex.
819 endLabel := gen newLabelIndex.
820 finalResult `defaultsTo: gen newRegister.
821 (condResult := gen generate: args first result: Nil)
822 ifNil: [error: 'conditional is nil: ' ; args first printString].
823 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
824 gen emitBranchTo: falseLabel from: msg.
825 gen generateExecutionOf: {args second} from: msg result: finalResult.
826 gen emitInstruction: gen jumpTo from: msg.
827 gen emitBranchTo: endLabel from: msg.
828 gen emitLabel &labelIndex: falseLabel.
829 gen registerFor: Nil from: msg result: finalResult.
830 gen emitLabel &labelIndex: endLabel.
834 gen@(VM SSACompiler traits) generate: _@#ifNil: on: args from: msg result: finalResult
835 [ | endLabel condReg lhsValueReg |
836 endLabel := gen newLabelIndex.
837 finalResult `defaultsTo: gen newRegister.
838 lhsValueReg := gen generate: args first result: finalResult. "do not evaluate twice"
839 condReg := gen newRegister.
840 gen emitInstruction: gen isNilOp withParameters: {condReg. lhsValueReg} from: msg.
841 gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
842 gen emitBranchTo: endLabel from: msg.
843 gen generateExecutionOf: {args second} from: msg result: finalResult.
844 gen emitLabel &labelIndex: endLabel.
848 gen@(VM SSACompiler traits) generate: _@#ifNotNil: on: args from: msg result: finalResult
849 [ | endLabel condReg lhsValueReg |
850 endLabel := gen newLabelIndex.
851 finalResult `defaultsTo: gen newRegister.
852 lhsValueReg := gen generate: args first result: finalResult. "do not evaluate twice"
853 condReg := gen newRegister.
854 gen emitInstruction: gen isNilOp withParameters: {condReg. lhsValueReg} from: msg.
855 gen emitInstruction: gen branchIfTrue withParameters: {condReg} from: msg.
856 gen emitBranchTo: endLabel from: msg.
857 gen generateExecutionOf: {args second} from: msg result: finalResult.
858 gen emitLabel &labelIndex: endLabel.
862 gen@(VM SSACompiler traits) generate: _@#/\ on: args from: msg result: finalResult
863 "Optionally evaluates a block."
864 [| falseLabel endLabel condResult |
865 (args second isSameAs: nodes Block)
867 falseLabel := gen newLabelIndex.
868 endLabel := gen newLabelIndex.
869 finalResult `defaultsTo: gen newRegister.
870 (condResult := gen generate: args first result: Nil)
871 ifNil: [error: 'conditional is nil: ' ; args first printString].
872 gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
873 gen emitBranchTo: falseLabel from: msg.
874 gen generateExecutionOf: {args second} from: msg result: finalResult.
875 gen emitInstruction: gen jumpTo from: msg.
876 gen emitBranchTo: endLabel from: msg.
877 gen emitLabel &labelIndex: falseLabel.
878 gen registerFor: False from: msg result: finalResult.
879 gen emitLabel &labelIndex: endLabel.
883 gen@(VM SSACompiler traits) generate: _@#\/ on: args from: msg result: finalResult
884 "Optionally evaluates a block."
885 [| block falseLabel endLabel condResult |
886 (args second isSameAs: nodes Block)
888 falseLabel := gen newLabelIndex.
889 endLabel := gen newLabelIndex.
890 finalResult `defaultsTo: gen newRegister.
891 (condResult := gen generate: args first result: Nil)
892 ifNil: [error: 'conditional is nil: ' ; args first printString].
893 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
894 gen emitBranchTo: falseLabel from: msg.
895 gen generateExecutionOf: {args second} from: msg result: finalResult.
896 gen emitInstruction: gen jumpTo from: msg.
897 gen emitBranchTo: endLabel from: msg.
898 gen emitLabel &labelIndex: falseLabel.
899 gen registerFor: True from: msg result: finalResult.
900 gen emitLabel &labelIndex: endLabel.
904 gen@(VM SSACompiler traits) generate: _@#whileTrue: on: args from: msg result: finalResult
905 "Repeatedly evaluates a block while it returns True."
906 [| label endLabel condResult |
907 endLabel := gen newLabelIndex.
908 label := gen emitLabel.
909 (condResult := gen generateExecutionOf: {args first} from: msg result: Nil)
910 ifNil: [error: 'conditional is nil: ' ; args first printString].
911 gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
912 gen emitBranchTo: endLabel from: msg.
913 gen generateExecutionOf: {args second} from: msg result: Nil.
914 gen emitInstruction: gen jumpTo from: msg.
915 gen emitBranchTo: label from: msg.
916 gen emitLabel &labelIndex: endLabel.
917 gen registerFor: Nil from: msg result: finalResult
920 gen@(VM SSACompiler traits) generate: _@#whileFalse: on: args from: msg result: finalResult
921 "Repeatedly evaluates a block while it returns False."
922 [| label endLabel condResult |
923 endLabel := gen newLabelIndex.
924 label := gen emitLabel.
925 condResult := gen generateExecutionOf: {args first} from: msg result: Nil.
926 condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
927 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
928 gen emitBranchTo: endLabel from: msg.
929 gen generateExecutionOf: {args second} from: msg result: Nil.
930 gen emitInstruction: gen jumpTo from: msg.
931 gen emitBranchTo: label from: msg.
932 gen emitLabel &labelIndex: endLabel.
933 gen registerFor: Nil from: msg result: finalResult
936 gen@(VM SSACompiler traits) generate: _@#whileTrue on: args from: msg result: result
937 "Repeatedly evaluates a block while it returns True."
938 [| label condResult |
939 label := gen emitLabel.
940 condResult := gen generateExecutionOf: args from: msg result: Nil.
941 condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
942 gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
943 gen emitBranchTo: label from: msg.
944 gen registerFor: Nil from: msg result: result
947 gen@(VM SSACompiler traits) generate: _@#whileFalse on: args from: msg result: result
948 "Repeatedly evaluates a block while it returns False."
949 [| label condResult |
950 label := gen emitLabel.
951 condResult := gen generateExecutionOf: args from: msg result: Nil.
952 condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
953 gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
954 gen emitBranchTo: label from: msg.
955 gen registerFor: Nil from: msg result: result
958 gen@(VM SSACompiler traits) generate: _@#primitiveDo: on: args from: msg result: result
959 [| indexReg argRegs |
960 result `defaultsTo: gen newRegister.
961 indexReg := gen generate: args first result: Nil.
962 argRegs := args second statements collect: [| :item | gen generate: item result: Nil].
963 gen emitInstruction: gen primitiveDo withParameters: {indexReg. argRegs size. result} ; argRegs from: msg.
967 gen@(VM SSACompiler traits) generate: _@#fill:with: on: args from: msg result: result
968 [| block index var value |
970 index := args second.
972 (block isSameAs: nodes Block)
973 /\ [index isSameAs: nodes Literal]
974 /\ [block inputVariables acceptsKey: index value]
976 (value isSameAs: nodes Literal)
979 tmp := gen currentMethod sourceTree addVariable.
980 gen generate: (nodes StoreVariable of: value into: tmp) result: Nil. "fixme"
981 value := nodes LoadVariable from: tmp].
982 index := index value.
983 var := block inputVariables at: index.
984 block inputVariables := block inputVariables copyWithoutAt: index.
987 below: block localVariables indexLast
988 with: block localVariables
989 startingAt: index + 1.
990 block localVariables at: block localVariables indexLast put: var.
992 {(nodes StoreVariable of: value into: var)} ; block statements.
993 gen generate: block result: result
996 gen@(VM SSACompiler traits) generate: _@#<-* on: args from: msg result: result
997 "Optimizes currying calls on literal blocks using #fill:with:."
999 (args first isSameAs: nodes Block)
1002 generate: #fill:with:
1004 (nodes Literal for: args first inputVariables indexLast) at: 1)