Use of ::= in the Compiler, eliminating almost all mutable state from its methods.
[cslatevm.git] / src / mobius / compiler.slate
blobff9a4ced05324cd68e86e1346a6698cdcf755b9d
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 do:
19     [| :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?"
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."
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
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."
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."
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
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."
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."
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
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
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."
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."
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 [| 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."
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
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
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
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
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'."
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.
680   result
683 gen@(VM SSACompiler traits) branchTableHash: key
685   key identityHash
688 gen@(VM SSACompiler traits) buildBranchTableMapping: keys
689 [| 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
727   (gen mayInlineCaseOf: msg)
728    ifFalse: [^ resend].
729   assocs ::= args second statements.
730   labels ::= assocs collect: [| :_ | gen newLabelIndex].
731   finalResult `defaultsTo: gen newRegister.
732   table ::=
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}
742     from: msg.
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:
750     [| :assoc :label |
751      gen emitLabel &labelIndex: label.
752      table
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
760     encode a Nil-push."
761   gen emitLabel &labelIndex: otherwiseLabel.
762   args size >= 3
763     ifTrue: [gen generateExecutionOf: {args third} from: msg result: finalResult]
764     ifFalse: [gen registerFor: Nil from: msg result: finalResult].
765   gen emitLabel &labelIndex: endLabel.
766   finalResult
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]
774     ifFalse: [resend]
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.
793   finalResult
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.
812   finalResult
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.
830   finalResult
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.
844   finalResult
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.
858   finalResult
861 gen@(VM SSACompiler traits) generate: _@#/\ on: args from: msg result: finalResult
862 "Optionally evaluates a block."
864   (args second isSameAs: nodes Block)
865     ifFalse: [^ resend].
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.
879   finalResult
882 gen@(VM SSACompiler traits) generate: _@#\/ on: args from: msg result: finalResult
883 "Optionally evaluates a block."
885   (args second isSameAs: nodes Block)
886     ifFalse: [^ resend].
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.
900   finalResult
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.
963   result
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.
970   value := args third.
971   (block isSameAs: nodes Block)
972     /\ [index isSameAs: nodes Literal]
973     /\ [block inputVariables acceptsKey: index value]
974     ifFalse: [^ resend].
975   (value isSameAs: nodes Literal)
976     ifFalse:
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.
983   block localVariables
984     replaceFrom: index
985     below: block localVariables indexLast
986     with: block localVariables
987     startingAt: index + 1.
988   block localVariables at: block localVariables indexLast put: var.
989   block statements :=
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)
998     ifTrue:
999       [gen
1000          generate: #fill:with:
1001          on: (args copyWith:
1002                 (nodes Literal for: args first inputVariables indexLast) at: 1)
1003          from: msg
1004          result: result]
1005     ifFalse: [resend]