Revert "Use of ::= in the Compiler, eliminating almost all mutable state from its...
[cslatevm.git] / src / mobius / compiler.slate
blob3d3d825f1c0ffb0823293833ad7c9576e2d7a532
2 m@(CompiledMethod traits) new
3 "Answer a new CompiledMethod with a fresh compilation state."
5   m clone `>>
6     [| :newM |
7       method := newM.
8       literals := m literals new.
9       selectors := m selectors new.
10       optionalKeywords := m optionalKeywords new.
11       code := m code new.
12       debugMap := m debugMap new. ]
15 m@(CompiledMethod traits) sourceTreeOf: index
16 "Find the source tree corresponding to a bytecode's index."
18   m debugMap
19     do: [| :start :end :sourceTree |
20          (index between: start and: end)
21            ifTrue: [^ sourceTree]]
22     inGroupsOf: 3.
23   Nil
26 m@(CompiledMethod traits) definitionLocation
28   m sourceTree isNotNil /\ [m sourceTree hasSlotNamed: #source]
29     ifTrue: [m sourceTree definitionLocation]
30     ifFalse: ['Nil']
33 m@(CompiledMethod traits) recompile
34 "If the method has a sourceTree, replace the method with a re-compiled version
35 of it."
37   m sourceTree
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: {
46   #code.
47   #selector.
48   #name.
49   #argNames -> {}.
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 |
58     each argNames do:
59       [| :argName | (#{'arity'. 'size'} includes: argName) ifTrue:
60         [""]].
61     VM SSACode addImmutableSlot: each selector valued: each code.
62     i ByCode at: each code put: each].
63   ]
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?"
129    }.
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}
136    to: {method.
137         method code writer.
138         method debugMap as: c debugMap.
139         c registerValues new.
140         c relocations new.
141         c labels 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.
149               c relocations copy.
150               c labels copy.
151               c currentRegister}
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."
162 [| code |
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.
174   c resolveLabels.
175   c
178 c@(VM SSACompiler Context traits) beClosure [c isClosure := True].
180 gen@(VM SSACompiler traits) currentContext
181 [gen contexts top].
183 gen@(VM SSACompiler traits) newRegister
185   gen contexts top currentRegister += 1
188 gen@(VM SSACompiler traits) registerFor: obj from: def result: result
189 [| saveRegister |
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
195                  ifTrue:
196                    [val key = result \/ [result isNil]
197                         ifTrue: [^ val key]
198                         ifFalse: [result `defaultsTo: gen newRegister.
199                                    gen emitInstruction: gen moveRegister withParameters: {result. val key} from: def.
200                                   ^ result]]].
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].
208   result
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.
232   labelIndex
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]."
243   gen mapTo: 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
254 [| index |
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"
267   resend
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
283 byte onto the end."
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].
326   statements isEmpty
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."
331   newBlock `>>
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]
344     ifFalse:
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
354   shouldNotImplement
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 |
360   gen contexts isEmpty
361     ifTrue: [^ resend].
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.
369   resultRegister
372 gen@(VM SSACompiler traits) generate: r@(nodes Resend traits) result: resultRegister
373 [| lexOffset scope |
374   scope := gen currentMethod sourceTree.
375   lexOffset := gen contexts indexLast -
376     ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree isSameAs: nodes MethodDefinition])
377       ifNil:
378         [error: 'resend must be used within a method definition.']).
379   lexOffset isPositive
380     ifTrue:
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.
385   resultRegister
388 gen@(VM SSACompiler traits) generate: r@(nodes Return traits) result: blah
389 [overrideThis].
391 gen@(VM SSACompiler traits) generate: r@(nodes Return traits) by: lexOffset result: resultRegister
393   resultRegister `defaultsTo: gen newRegister.
394   lexOffset isPositive
395     ifTrue:
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.
400   resultRegister.
403 gen@(VM SSACompiler traits) generate: r@(nodes ReturnClose traits) result: resultRegister
404 "Exits the first enclosing named method in the lexical scope."
405 [| lexOffset |
406   lexOffset := gen contexts indexLast -
407     ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree isSameAs: nodes MethodDefinition])
408       ifNil:
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."
415 [| lexOffset |
416   lexOffset := gen contexts indexLast -
417     ((gen contexts indexOfFirstSatisfying: [| :context | context method sourceTree isSameAs: nodes MethodDefinition])
418       ifNil:
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"
435   n statements isEmpty
436     ifTrue: [#{}]
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"
444   n statements isEmpty
445    ifTrue: [#{}]
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.
454   result
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])
466       ifNil:
467         [error: 'Could not determine variable scope.']).
468   lexOffset isZero
469     ifTrue:
470       [result `defaultsTo: varIndex.
471        gen emitInstruction: gen loadVariable withParameters: {varIndex} from: load.
472        result = varIndex
473               ifFalse: [gen emitInstruction: gen moveRegister withParameters: {result. varIndex} from: load]]
474     ifFalse:
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].
479   result
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])
488       ifNil:
489         [error: 'Could not determine variable scope.']).
490   lexOffset isZero
491     ifTrue:
492       [result `defaultsTo: varIndex.
493        gen generate: store value result: varIndex.
494        gen emitInstruction: gen storeVariable withParameters: {varIndex} from: store.
495        result = varIndex
496               ifFalse: [gen emitInstruction: gen moveRegister withParameters: {result. varIndex} from: store]]
497     ifFalse:
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].
503   result
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."
509 [| registers |
510   registers := resend.
511   result `defaultsTo: gen newRegister.
512   gen emitInstruction: gen newArrayWith withParameters: {result. array size} ; registers from: array.
513   result
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."
519 [| argRegisters |
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.
523   result
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
538 [| block message |
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).
543   opts
544     ifNotNil:
545       [message :=
546         ((nodes OptionalArguments for: message)
547           `>> [arguments := opts arguments deepCopy: block. ])].
548   block statements := {message}.
549   gen generate:
550     (nodes KeywordMessage
551       sending: #whenFulfilled:
552       to: {def arguments as: nodes Array. block})
553     result: result
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:
565     [| :key :arg |
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.
570   result
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.
589   result
592 gen@(VM SSACompiler traits) generate: _@#applyTo: on: args from: msg result: result
593 [| methodReg argRegs |
594   (args second isSameAs: nodes Array)
595     ifTrue:
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
602          from: msg.
603        result]
604     ifFalse: [resend]
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.
613   result
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]
620     ifFalse: [resend]
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]
627     ifFalse: [resend]
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]
634     ifFalse: [resend]
637 gen@(VM SSACompiler traits) generate: _@#== on: args from: msg result: result
638 [| argRegs |
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.
642   result
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]
652     ifTrue:
653       [result `defaultsTo: gen newRegister.
654        block statements isEmpty
655          ifTrue: [gen emitInstruction: gen loadLiteral withParameters: {result. Nil} from: msg.
656                   result]
657          ifFalse: [block statements allButLastDo: [| :node | gen generate: node result: Nil].
658                    gen generate: block statements last result: result]]
659     ifFalse: [resend]
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'."
667 [| label |
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
676 [ | objReg |
677   result `defaultsTo: gen newRegister.
678   objReg := gen generate: args first result: Nil.
679   gen emitInstruction: gen isNilOp withParameters: {result. objReg} from: msg.
680   result
683 gen@(VM SSACompiler traits) branchTableHash: key
685   key identityHash
688 gen@(VM SSACompiler traits) buildBranchTableMapping: keys
689 [| table tableSize |
690   tableSize := 1.
691   [tableSize < keys size]
692     whileTrue:
693       [tableSize *= 2].
694   table := Array newSize: tableSize * 2.
695   keys do:
696     [| :key hash |
697       hash := (gen branchTableHash: key) bitAnd: (tableSize - 1) * 2.
698       [(table at: hash) isNil]
699         whileFalse:
700           [key = (table at: hash)
701             ifTrue:
702               [error: 'Duplicate key ' ; key printString ; ' in caseOf:.'].
703             (hash += 2) >= (tableSize * 2) ifTrue:
704               [hash := 0]].
705       table at: hash put: key].
706   table
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:
717      [| :assoc |
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)
728     ifFalse: [^ resend].
729   args second statements `cacheAs: #assocs.
730   labels := assocs collect: [| :_ | gen newLabelIndex].
731   finalResult `defaultsTo: gen newRegister.
732   table :=
733     (gen
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)}
743       from: msg.
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:
751     [| :assoc :label |
752       gen emitLabel &labelIndex: label.
753       table
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
761   encode a Nil-push."
762   gen emitLabel &labelIndex: otherwiseLabel.
763   args size >= 3
764     ifTrue: [gen generateExecutionOf: {args third} from: msg result: finalResult]
765     ifFalse: [gen registerFor: Nil from: msg result: finalResult].
766   gen emitLabel &labelIndex: endLabel.
767   finalResult
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]
775     ifFalse: [resend]
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.
794   finalResult
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.
813   finalResult
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.
831   finalResult
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.
845   finalResult
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.
859   finalResult
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)
866     ifFalse: [^ resend].
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.
880   finalResult
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)
887     ifFalse: [^ resend].
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.
901   finalResult
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.
964   result
967 gen@(VM SSACompiler traits) generate: _@#fill:with: on: args from: msg result: result
968 [| block index var value |
969   block := args first.
970   index := args second.
971   value := args third.
972   (block isSameAs: nodes Block)
973     /\ [index isSameAs: nodes Literal]
974     /\ [block inputVariables acceptsKey: index value]
975     ifFalse: [^ resend].
976   (value isSameAs: nodes Literal)
977     ifFalse:
978       [| tmp |
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.
985   block localVariables
986     replaceFrom: index
987     below: block localVariables indexLast
988     with: block localVariables
989     startingAt: index + 1.
990   block localVariables at: block localVariables indexLast put: var.
991   block statements:
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)
1000     ifTrue:
1001       [gen
1002          generate: #fill:with:
1003          on: (args copyWith:
1004                 (nodes Literal for: args first inputVariables indexLast) at: 1)
1005          from: msg
1006          result: result]
1007     ifFalse: [resend]