Removed instructionInfo entirely, replacing the remaining usage with instancesSetting...
[cslatevm.git] / src / mobius / compiler.slate
blob30206367a88db5ea137d38ee0ab653069c2a540b
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 isNil \/ [(m sourceTree hasSlotNamed: #source) not] ifTrue: [^ 'Nil'].
29   (m sourceTree source hasSlotNamed: #resource)
30    ifTrue: [m sourceTree source resource locator
31               ifNil: ['stdin:' ; (m sourceTree lineNumber - 2) printString]
32               ifNotNil: [(m sourceTree source resource locator as: String) ; ':' ; m sourceTree lineNumber printString]]
33    ifFalse: [m sourceTree source
34                ifNil: ['Nil']
35                ifNotNil: [(m sourceTree source printString) ; ':' ; m sourceTree lineNumber printString]]
38 m@(CompiledMethod traits) recompile
39 "If the method has a sourceTree, replace the method with a re-compiled version
40 of it."
42   m sourceTree
43     ifNil: [warn: 'The method has no source code to recompile.'. m]
44     ifNotNilDo: [| :src | m forwardTo: src compile]
47 lobby ensureNamespace: #VM.
48 VM ensureNamespace: #SSACode.
50 VM SSACode define: #Instruction &parents: {Cloneable} &slots: {
51   #code.
52   #selector.
53   #name.
54   #argNames -> {}.
55   #offsettingArgIndices -> {}.
58 x@(Cloneable traits) instancesSetting: slotNames to: values
60   values collect: [| :columnValues newX |
61     newX: x new.
62     slotNames with: columnValues do:
63       [| :slotName :slotValue | newX atSlotNamed: slotName put: slotValue].
64     newX]
67 VM SSACode Instruction traits define: #ByCode -> Dictionary new.
69 i@(VM SSACode Instruction traits) instancesSetting: slotNames to: values
70 [| arityNames |
71   arityNames: #('arity' 'size').
72   resend `>> [do: [| :each |
73     each argNames do:
74       [| :argName | (arityNames includes: argName) ifTrue:
75         [""]].
76     VM SSACode addImmutableSlot: each selector valued: each code.
77     i ByCode at: each code put: each].
78   ]
81 VM SSACode Instruction instancesSetting: #(code selector name argNames offsettingArgIndices) to: {
82   {0. #directSendMessage. 'Direct Send'. {'register of result'. 'selector'. 'arity' ". args..."}. {2}}.
83   "{1. #indirectSendMessage. 'Indirect Send'. {'register of result'. 'selector'. 'arity'. args...}. {2}}."
84   "{2. #allocateRegisters. 'Allocate Registers'. 3. {}}."
85   {3. #loadLiteral. 'Load Literal'. {'register of result'. 'index of literal'}}.
86   "{4. #storeLiteral. 'Store Literal'. {'index of literal'. 'register of source'}}."
87   {5. #sendMessageWithOptionals. 'Send with Optionals'. {'register of result'. 'register of selector'. 'arity'. 'register of optionals array' ". args..."}. {2}}.
88   {7. #newClosure. 'New Closure'. {'register of result'. 'block'}}.
89   {8. #newArrayWith. 'New Array With'. {'register of result'. 'size' ". args..."}. {1}}.
90   {9. #resendMessage. 'Resend'. {'register of result'. 'lexical offset'}}.
91   {10. #returnFrom. 'Return From'. {'register of result'. 'lexical offset'}}.
92   {11. #loadEnvironment. 'Load Environment'. {'register of result'}}.
93   {12. #loadVariable. 'Load Variable'. {'register of result'}}.
94   {13. #storeVariable. 'Store Variable'. {'register of result'}}.
95   {14. #loadFreeVariable. 'Load Free Variable'. {'register of result'. 'lexical offset'. 'index of variable'}}.
96   {15. #storeFreeVariable. 'Store Free Variable'. {'lexical offset'. 'index of variable'. 'register of source'}}.
97   {16. #isIdenticalTo. 'Is Identical To'. {'register of result'. 'register of x'. 'register of y'}}.
98   {17. #branchKeyed. 'Branch Keyed'. {'register of key'. 'table'}}.
99   {18. #jumpTo. 'Jump To'. {'offset'}}.
100   "Used like SSA phi / branch merges:"
101   {19. #moveRegister. 'Move Register'. {'register of source'. 'register of result'}}.
102   {20. #branchIfTrue. 'Branch If True'. {'register of condition'. 'branch offset'}}.
103   {21. #branchIfFalse. 'Branch If False'. {'register of condition'. 'branch offset'}}.
104   "Marks the end of a block:"
105   {22. #returnRegister. 'Return Register'. {'register of value'}}.
106   "Marks the end of a block:"
107   {23. #returnValue. 'Return Value'. {'value to return'}}.
108   "I'm not sure what this does yet..used in bootstrap:"
109   {24. #resume. 'Resume'. {}}.
110   {25. #primitiveDo. 'Primitive Do'. {'number of primitive'. 'arity'. 'register of result' ". args..."}. {1}}.
111   {26. #directApplyTo. 'Direct Apply To'. {'method'. 'arity'. 'register of result' ". args..."}. {1}}.
112   {27. #isNilOp. 'Is Nil'. {'register of result'. 'register of x'}}.
113   "these check the arguments to see if their maps match the ones in the map array"
114   "if they match, we fall through to the next instruction which is the primitive (no code) or inlined function"
115   "it also needs to set up the input varibles"
116   {28. #inlinePrimitiveCheckJump. 'Inline Primitive Check Jump'. {'register of result'. 'map array'. 'prim number(in-opcode not a register)'. 'arity'. 'jump offset' ". args..."}. {3}}.
117   {29. #inlineMethodCheckJump. 'Inline Method Check Jump'. {'map array'. 'arity'. 'jump offset' ". args..."}. {1}}.
120 VM define: #SSACompiler &parents: {Cloneable}
121   &slots: {#contexts -> Stack new}.
123 VM SSACompiler traitsWindow addDelegate: VM SSACode.
125 g@(VM SSACompiler traits) new
126 [g clone `>> [contexts: g contexts new. ]].
128 VM SSACompiler traits define: #Context &parents: {Cloneable} &slots:
129   {#isClosure -> False "Whether the method being compiled is a closure.".
130    #method -> CompiledMethod new "The method the context targets.".
131    #codeWriter "The stream for writing bytecodes to the method.".
132    #debugMap -> ExtensibleArray new
133    "Gathers the method's debug map; must be indexable at all times.".
134    #registerValues -> ExtensibleArray new
135    "The current register values.".
136    #labels -> ExtensibleArray new
137    "label serials -> code index.".
138    #relocations -> Dictionary new
139    "code index -> label serials".
140    #currentRegister -> 0
141    "The last assigned register value.. or the count?"
142    }.
144 c@(VM SSACompiler Context traits) newOn: method
145 "FIXME change method code to array instead of bytearray."
147   method code: Array new.
148   c clone `setting: #(method codeWriter debugMap registerValues relocations labels currentRegister)
149    to: {method. method code writer.
150         method debugMap as: c debugMap.
151         c registerValues new.
152         c relocations new.
153         c labels new.
154         method inputVariables + method localVariables}
157 c@(VM SSACompiler Context traits) copy
159   resend `setting: (registerValues relocations labels currentRegister)
160          to: {c registerValues copy.
161               c relocations copy.
162               c labels copy.
163               c currentRegister}
166 c@(VM SSACompiler Context traits) resolveLabel: label at: index
168   (c labels at: label) - index
171 c@(VM SSACompiler Context traits) resolveLabels
172 "This takes the labels Dictionary and uses it to replace the temporary ID's
173 placed in the jump fields with actual offsets."
174 [| code |
175   code: c method code.
176   c relocations keysAndValuesDo:
177     [| :index :label offset |
178      offset: (c resolveLabel: label at: index).
179      code at: index put: offset]
182 c@(VM SSACompiler Context traits) flush
184   c method code: c codeWriter contents.
185   c method debugMap: (c debugMap as: Array).
186   c resolveLabels.
187   c
190 gen@(VM SSACompiler traits) currentContext
191 [gen contexts top].
193 gen@(VM SSACompiler traits) newRegister
195  gen contexts top currentRegister: gen contexts top currentRegister + 1.
196  gen contexts top currentRegister
199 gen@(VM SSACompiler traits) registerFor: obj from: def result: result
200 [| saveRegister |
201    "the whole problem with this function is that we could cache a literal that
202  is only loaded in a loop which may not always be executed. remove this code
203 until we have it figured out."
204 "  gen contexts top registerValues do:
205     [| :val | val value = obj
206                  ifTrue:
207                    [val key = result \/ [result isNil]
208                         ifTrue: [^ val key]
209                         ifFalse: [result `defaultsTo: gen newRegister.
210                                    gen emitInstruction: gen moveRegister withParameters: {result. val key} from: def.
211                                   ^ result]]].
213   "we don't want result to be a local variable and have it overwritten later"
214   "result ifNil: [saveRegister: True] ifNotNil: [saveRegister: False]."
215    saveRegister: False.
216   result `defaultsTo: gen newRegister.
217   gen emitInstruction: gen loadLiteral withParameters: {result. obj} from: def.
218   saveRegister ifTrue: [gen setRegister: result to: obj].
219   result
222 gen@(VM SSACompiler traits) setRegister: x to: y
224   gen contexts top registerValues add: x -> y ifPresent: [error: 'Compiler error: Register already set.'].
227 gen@(VM SSACompiler traits) currentMethod
228 [gen currentContext method].
230 gen@(VM SSACompiler traits) codeWriter
231 [gen currentContext codeWriter].
233 gen@(VM SSACompiler traits) newLabelIndex
235   gen currentContext labels `>> [addLast: Nil. indexLast]
238 gen@(VM SSACompiler traits) emitLabel &labelIndex: labelIndex
240   labelIndex `defaultsTo: gen newLabelIndex.
241   gen currentContext labels at: labelIndex put: gen codeWriter position.
242   labelIndex
245 gen@(VM SSACompiler traits) emitRelocationAgainst: label
247   gen currentContext relocations at: gen codeWriter position put: label
250 gen@(VM SSACompiler traits) emitObject: value from: node
252   "0 below: bytesPerWord do: [| :byte | gen emitByte: (value byteShift: 0 - byte) intoByte from: node]."
253   gen mapTo: node.
254   gen codeWriter nextPut: value
257 gen@(VM SSACompiler traits) emitBranchTo: label from: msg
259   gen emitRelocationAgainst: label.
260   gen emitObject: 0 from: msg "replaced later when flushed"
263 gen@(VM SSACompiler traits) mapTo: sourceTree
264 [| index |
265   index: gen codeWriter position.
266   gen currentContext debugMap `cacheAs: #debugMap.
267   debugMap isEmpty not /\ [debugMap last == sourceTree]
268     ifTrue: [debugMap at: debugMap indexLast - 1 infect: [| :value | index max: value].
269              debugMap at: debugMap indexLast - 2 infect: [| :value | index min: value]]
270     ifFalse: [debugMap addAllLast: {index. index. sourceTree}]
273 gen@(VM SSACompiler traits) emitInstruction: code@(Integer traits) withParameters: values from: node
274 "this gets called before the real function"
276   "values do: [| :value | (value is: Syntax Node) ifTrue: [error: 'bad code']]." "commented out because we could actually load node literals in compiler code"
277   resend
280 gen@(VM SSACompiler traits) emitInstruction: code withParameters: values from: node
282   "add the selector to the list so we know what this function calls... so it can be unoptimized if needed"
283   code = gen directSendMessage \/ [code = gen sendMessageWithOptionals] ifTrue: [gen currentContext method selectors: gen currentContext method selectors ; {values second}].
284   gen emitObject: code from: node.
285   values do: [| :value | gen emitObject: value from: node]
288 gen@(VM SSACompiler traits) emitInstruction: code from: node
289 "Emitting an instruction without an immediate value required just puts the
290 byte onto the end."
292   gen emitInstruction: code withParameters: #() from: node
296 =======================================================================
297 Generate methods. They all must return the register(s) with the results
298 =======================================================================
301 _@(VM SSACompiler traits) generate: _@(Syntax Node traits)
302 "Do nothing in the default case, for comments and annotations and such."
303 [error: 'do not call generate without a result'].
305 _@(VM SSACompiler traits) generate: _@(Syntax Node traits) result: result
306 "Do nothing in the default case, for comments and annotations and such."
309 gen@(VM SSACompiler traits) generate: ann@(Syntax Annotation traits) result: result
310 "Generate the annotation's value."
312   gen generate: ann value
315 gen@(VM SSACompiler traits) generate: block@(Syntax Block traits) result: result &topLevel: topLevel
316 "Encountering a new block, build a new CompiledMethod object and push it and
317 a new bytecode array writer onto the generator, then go through the underlying
318 code and generate that. When done, pop both, set up the block as a literal
319 and push it onto the stack."
320 [| newBlock isClosure statements |
321   topLevel `defaultsTo: False.
322   newBlock: CompiledMethod new.
323   newBlock environment: (gen contexts isEmpty
324     ifTrue: [block parentScope topLevel namespace]
325     ifFalse: [gen currentMethod environment]).
326   newBlock sourceTree: block.
327   gen contexts push: (gen Context newOn: newBlock).
328   "we macroexpand everything before we set the current register because macroexpansion can add localvariables etc"
329   statements: (block statements collect: [| :statement | statement macroExpand &environment: gen currentMethod sourceTree]).
330   gen currentContext currentRegister: block localVariables size. "input variables might not be needed"
331   statements allButLastDo: [| :node | gen generate: node result: Nil].
332   statements isEmpty
333     ifTrue: [gen emitInstruction: gen returnValue withParameters: {Nil} from: block]
334     ifFalse: [gen emitInstruction: gen returnRegister withParameters: {gen generate: statements last result: Nil} from: block].
336   "Set the variable information after generation, just in case it was modified."
337   newBlock `>>
338    [inputVariables: block inputVariables size.
339     localVariables: block localVariables size.
340     restVariable: block restVariable isNotNil.
341     registerCount: gen currentContext currentRegister + 1.
342     "reserved1: gen currentContext currentRegister + 1."
343     optionalKeywords: block optionalKeywords.].
344   isClosure: gen currentContext isClosure.
346   gen contexts pop flush.
347   "Forces the newBlock to record all the remaining stream input correctly."
349   gen contexts isEmpty \/ [topLevel]
350     ifFalse:
351       [result `defaultsTo: gen newRegister. "asking for a register requires a context"
352        isClosure
353         ifTrue:
354           [gen emitInstruction: gen newClosure withParameters: {result. newBlock} from: block]
355         ifFalse:
356           [gen emitInstruction: gen loadLiteral withParameters: {result. newBlock} from: block]].
358   gen contexts isEmpty \/ [topLevel] ifTrue: [newBlock] ifFalse: [result]
361 gen@(VM SSACompiler traits) generate: def@(Syntax MethodDefinition traits) result: resultRegister
362 "Translate method definitions to equivalent asMethod:on: invocations."
363 [| blockRegister roleRegisters arrayRegister resultRegister selectorRegister |
364   gen contexts isEmpty
365     ifTrue: [^ resend].
366   blockRegister: (#generate:result: sendTo: {gen. def. Nil} through: {gen. Syntax Block. Nil}).
367   arrayRegister: gen newRegister.
368   selectorRegister: (gen registerFor: def selector from: def result: Nil).
369   roleRegisters: (def roles collect: [| :role | gen generate: role result: Nil]).
370   resultRegister `defaultsTo: gen newRegister.
371   gen emitInstruction: gen newArrayWith withParameters: {arrayRegister. roleRegisters size} ; roleRegisters from: def.
372   gen emitInstruction: gen directSendMessage withParameters: {resultRegister. #asMethod:on:. 3. blockRegister. selectorRegister. arrayRegister} from: def.
373   resultRegister
376 gen@(VM SSACompiler traits) generate: r@(Syntax Resend traits) result: resultRegister
377 [| lexOffset scope |
378   scope: gen currentMethod sourceTree.
379   lexOffset: gen contexts indexLast -
380     ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree isSameAs: Syntax MethodDefinition])
381       ifNil:
382         [error: 'resend must be used within a method definition.']).
383   lexOffset isPositive
384     ifTrue:
385       [(gen contexts fromTop: lexOffset) method heapAllocate: True.
386         (gen contexts top: lexOffset) do: #isClosure: `er <-* True].
387   resultRegister `defaultsTo: gen newRegister.
388   gen emitInstruction: gen resendMessage withParameters: {resultRegister. lexOffset} from: r.
389   resultRegister
392 gen@(VM SSACompiler traits) generate: r@(Syntax Return traits) result: blah
393 [overrideThis].
395 gen@(VM SSACompiler traits) generate: r@(Syntax Return traits) by: lexOffset result: resultRegister
397   resultRegister `defaultsTo: gen newRegister.
398   lexOffset isPositive
399     ifTrue:
400       [(gen contexts fromTop: lexOffset) method heapAllocate: True.
401        (gen contexts top: lexOffset) do: [| :x | x isClosure: True]].
402   gen generate: r value result: resultRegister.
403   gen emitInstruction: gen returnFrom withParameters: {resultRegister. lexOffset} from: r.
404   resultRegister.
407 gen@(VM SSACompiler traits) generate: r@(Syntax ReturnClose traits) result: resultRegister
408 "Exits the first enclosing named method in the lexical scope."
409 [| lexOffset |
410   lexOffset: gen contexts indexLast -
411     ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree isSameAs: Syntax MethodDefinition])
412       ifNil:
413         [error: '^ must be used within a method definition.']).
414   gen generate: r by: lexOffset result: resultRegister
417 gen@(VM SSACompiler traits) generate: r@(Syntax ReturnFar traits) result: result
418 "Exits the last enclosing named method in the lexical scope."
419 [| lexOffset |
420   lexOffset: gen contexts indexLast -
421     ((gen contexts indexOfFirstSatisfying: [| :context | context method sourceTree isSameAs: Syntax MethodDefinition])
422       ifNil:
423         [error: '^^ must be used within a method definition.']).
424   gen generate: r by: lexOffset result: result
427 gen@(VM SSACompiler traits) generate: r@(Syntax ReturnLevel traits) result: result
428 "Exits the Nth enclosing lexical scope."
429 [gen generate: r by: r level result: result].
431 gen@(VM SSACompiler traits) generate: literal@(Syntax Literal traits) result: result
433   gen registerFor: literal value from: literal result: result
436 gen@(VM SSACompiler traits) generate: n@(Syntax CompoundStatement traits) result: result
437 "return the registers that the values were saved into"
439   n statements isEmpty
440     ifTrue: [{}]
441     ifFalse: [(n statements allButLast collect: [| :node | gen generate: node result: Nil])
442                 ; {(gen generate: n statements last result: result)}]
445 gen@(VM SSACompiler traits) generate: n@(Syntax Parenthesis traits) result: result
446 "return the registers that the values were saved into"
448   n statements isEmpty
449    ifTrue: [{}]
450    ifFalse: [n statements allButLastDo: [| :node | gen generate: node result: Nil].
451              gen generate: n statements last result: result]
454 gen@(VM SSACompiler traits) generate: i@(Syntax ImplicitArgument traits) result: result
456   result `defaultsTo: gen newRegister.
457   gen emitInstruction: gen loadEnvironment withParameters: {result} from: i.
458   result
461 gen@(VM SSACompiler traits) generate: _@(Syntax Namespace traits) result: result
462 [shouldNotImplement].
464 gen@(VM SSACompiler traits) generate: load@(Syntax LoadVariable traits) result: result
465 [| lexOffset varIndex |
466   load variable scope `cacheAs: #scope.
467   varIndex: (scope localVariables indexOf: load variable).
468   lexOffset: gen contexts indexLast -
469     ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree == scope])
470       ifNil:
471         [error: 'Could not determine variable scope.']).
472   lexOffset isZero
473     ifTrue:
474       [result `defaultsTo: varIndex.
475        gen emitInstruction: gen loadVariable withParameters: {varIndex} from: load.
476        result = varIndex
477               ifFalse: [gen emitInstruction: gen moveRegister withParameters: {result. varIndex} from: load]]
478     ifFalse:
479       [result `defaultsTo: gen newRegister.
480        (gen contexts fromTop: lexOffset) method heapAllocate: True.
481        (gen contexts top: lexOffset) do: #isClosure: `er <-* True.
482        gen emitInstruction: gen loadFreeVariable withParameters: {result. lexOffset. varIndex} from: load].
483   result
486 gen@(VM SSACompiler traits) generate: store@(Syntax StoreVariable traits) result: result
487 [| lexOffset varIndex |
488   store variable scope `cacheAs: #scope.
489   varIndex: (scope localVariables indexOf: store variable).
490   lexOffset: gen contexts indexLast -
491     ((gen contexts indexOfLastSatisfying: [| :context | context method sourceTree == scope])
492       ifNil:
493         [error: 'Could not determine variable scope.']).
494   lexOffset isZero
495     ifTrue:
496       [result `defaultsTo: varIndex.
497        gen generate: store value result: varIndex.
498        gen emitInstruction: gen storeVariable withParameters: {varIndex} from: store.
499        result = varIndex
500               ifFalse: [gen emitInstruction: gen moveRegister withParameters: {result. varIndex} from: store]]
501     ifFalse:
502       [result `defaultsTo: gen newRegister.
503        gen generate: store value result: result.
504        (gen contexts fromTop: lexOffset) method heapAllocate: True.
505        (gen contexts top: lexOffset) do: #isClosure: `er <-* True.
506         gen emitInstruction: gen storeFreeVariable withParameters: {lexOffset. varIndex. result} from: store].
507   result
510 gen@(VM SSACompiler traits) generate: array@(Syntax Array traits) result: result
511 "Generate the code to push the element expression results on the stack,
512 then the appropriate literal-array constructor bytecode."
513 [| registers |
514   registers: resend.
515   result `defaultsTo: gen newRegister.
516   gen emitInstruction: gen newArrayWith withParameters: {result. array size} ; registers from: array.
517   result
520 gen@(VM SSACompiler traits) generate: selector@(Symbol traits) on: args from: msg@(Syntax Message traits) result: result
521 "Generate the code to push the argument expression results on the stack, then
522 the push for the selector, and then the appropriate message send bytecode."
523 [| argRegisters |
524   result `defaultsTo: gen newRegister.
525   argRegisters: (args collect: [| :arg | gen generate: arg result: Nil]).
526   gen emitInstruction: gen directSendMessage withParameters: {result. selector. args size} ; argRegisters from: msg.
527   result
530 gen@(VM SSACompiler traits) generate: msg@(Syntax Message traits) result: result &optionals: opts
532   gen generate: msg selector on: msg arguments from: (opts ifNil: [msg]) result: result
535 gen@(VM SSACompiler traits) generate: macro@(Syntax Macro traits) result: result &optionals: opts
537   "gen generate: (macro macroExpand &optionals: opts &environment: gen currentMethod sourceTree) result: result"
538   error: 'SSA Compiler cannot support macroexpansion at code generation time because of localVariable side-effects'.
541 gen@(VM SSACompiler traits) generate: def@(Syntax Deferred traits) result: result &optionals: opts
542 [| block message |
543   block: Syntax Block new `>> [parentScope: gen currentMethod sourceTree. ].
544   def arguments size timesRepeat: #addInputVariable `er <- block.
545   message: (Syntax Message sending: def selector to:
546     (block inputVariables collect: [| :var | Syntax LoadVariable from: var])).
547   opts
548     ifNotNil:
549       [message:
550         ((Syntax OptionalArguments for: message)
551           `>> [arguments: (opts arguments deepCopy: block). ])].
552   block statements: {message}.
553   gen generate:
554     (Syntax KeywordMessage
555       sending: #whenFulfilled:
556       to: {def arguments as: Syntax Array. block})
557     result: result
560 gen@(VM SSACompiler traits) generate: selector@(Symbol traits) on: args from: opts@(Syntax OptionalKeywords traits) result: result
561 "Generate the code to push the argument expression results on the stack, then
562 the push for the selector, and then the appropriate message send bytecode."
563 [| argRegisters optsArray optsWriter optsArrayRegister |
564   result `defaultsTo: gen newRegister.
565   argRegisters: (args collect: [| :arg | gen generate: arg result: Nil]).
566   optsArrayRegister: gen newRegister.
567   optsArray: ExtensibleArray new.
568   optsWriter: optsArray writer.
569   opts keywords with: opts arguments do:
570     [| :key :arg |
571      optsWriter nextPut: (gen registerFor: key from: opts result: Nil).
572      optsWriter nextPut: (gen generate: arg result: Nil)].
573   gen emitInstruction: gen newArrayWith withParameters:
574     {optsArrayRegister. optsArray size} ; optsArray from: opts.
575   gen emitInstruction: gen sendMessageWithOptionals withParameters:
576     {result. selector. args size. optsArrayRegister } ; argRegisters from: opts.
577   result
580 gen@(VM SSACompiler traits) generate: opts@(Syntax OptionalKeywords traits) result: result
582   gen generate: opts message result: result &optionals: opts
585 gen@(VM SSACompiler traits) generate: rest@(Syntax RestArguments traits) result: result
587   gen generate: rest message result: result
590 gen@(VM SSACompiler traits) generate: _@#True on: args from: msg result: result
592   (args first isSameAs: Syntax ImplicitArgument)
593     ifTrue: [gen registerFor: True from: msg result: result]
594     ifFalse: [resend]
597 gen@(VM SSACompiler traits) generate: _@#False on: args from: msg result: result
599   (args first isSameAs: Syntax ImplicitArgument)
600     ifTrue: [gen registerFor: False from: msg result: result]
601     ifFalse: [resend]
604 gen@(VM SSACompiler traits) generate: _@#Nil on: args from: msg result: result
606   (args first isSameAs: Syntax ImplicitArgument)
607     ifTrue: [gen registerFor: Nil from: msg result: result]
608     ifFalse: [resend]
611 gen@(VM SSACompiler traits) generate: _@#== on: args from: msg result: result
612 [| argRegs |
613   result `defaultsTo: gen newRegister.
614   argRegs: (args collect: [| :arg | gen generate: arg result: Nil]).
615   gen emitInstruction: gen isIdenticalTo withParameters: {result. argRegs first. argRegs second} from: msg.
616   result
619 gen@(VM SSACompiler traits) generate: _@#do on: args from: msg result: result
620 "If the block is a literal with no variables, then inline it.
621 Otherwise, fall back to evaluating it via 'do'."
623   args first `cacheAs: #block.
624   (block isSameAs: Syntax Block)
625     /\ [block localVariables isEmpty]
626     ifFalse: [^ resend].
627   result `defaultsTo: gen newRegister.
628   block statements isEmpty
629     ifTrue: [gen emitInstruction: gen loadLiteral withParameters: {result. Nil} from: msg.
630              result]
631     ifFalse: [block statements allButLastDo: [| :node | gen generate: node result: Nil].
632               gen generate: block statements last result: result]
635 gen@(VM SSACompiler traits) generateExecutionOf: args from: msg result: result
636 [gen generate: #do on: args from: msg result: result].
638 gen@(VM SSACompiler traits) generate: _@#loop on: args from: msg result: result
639 "Repeatedly evaluates a block via 'do'."
640 [| label |
641   label: gen emitLabel.
642   gen generateExecutionOf: args from: msg result: Nil.
643   gen emitInstruction: gen jumpTo withParameters: #()"see below" from: msg.
644   gen emitBranchTo: label from: msg.
645   gen registerFor: Nil from: msg result: result "return nil"
648 gen@(VM SSACompiler traits) generate: _@#isNil on: args from: msg result: result
649 [ | objReg |
650   result `defaultsTo: gen newRegister.
651   objReg: (gen generate: args first result: Nil).
652   gen emitInstruction: gen isNilOp withParameters: {result. objReg} from: msg.
653   result
656 gen@(VM SSACompiler traits) branchTableHash: key
658   key identityHash
661 gen@(VM SSACompiler traits) buildBranchTableMapping: keys
662 [| table tableSize |
663   tableSize: 1.
664   [tableSize < keys size]
665     whileTrue:
666       [tableSize: tableSize * 2].
667   table: (Array newSize: tableSize * 2).
668   keys do:
669     [| :key hash |
670       hash: ((gen branchTableHash: key) bitAnd: (tableSize - 1) * 2).
671       [(table at: hash) isNil]
672         whileFalse:
673           [key = (table at: hash)
674             ifTrue:
675               [error: 'Duplicate key ' ; key printString ; ' in caseOf:.'].
676             hash: hash + 2.
677             hash >= (tableSize * 2)
678               ifTrue:
679                 [hash: 0]].
680       table at: hash put: key
681     ].
682   table
685 gen@(VM SSACompiler traits) mayInlineCaseOf: msg
686 "Answer whether a safe inlining is possible for a caseOf: expression without
687 further analysis; currently this is the case where the second argument is a
688 literal array, and the appropriate Associations and their elements are laid
689 out with literal keys."
691   (msg arguments second isSameAs: Syntax Array) /\
692    [msg arguments second statements allSatisfy:
693      [| :assoc |
694       (assoc is: Syntax Message)
695         /\ [assoc selector = #->]
696         /\ [assoc arguments first is: Syntax Literal]
697         /\ [{Symbol. ASCIIString Character. SmallInteger} anySatisfy:
698           [| :proto | assoc arguments first value is: proto]]]]
701 gen@(VM SSACompiler traits) generate: _@#caseOf:otherwise: on: args from: msg result: finalResult
702 [| labels table indices branchOffset otherwiseLabel endLabel switchKeyRegister |
703   (gen mayInlineCaseOf: msg)
704     ifFalse: [^ resend].
705   args second statements `cacheAs: #assocs.
706   labels: (assocs collect: [| :_ | gen newLabelIndex]).
707   finalResult `defaultsTo: gen newRegister.
708   table:
709     (gen
710       buildBranchTableMapping:
711         (assocs collect: [| :assoc | assoc arguments first value])).
712   indices: IdentityDictionary new.
713   0 below: table size by: 2 do: [| :index |
714     (table at: index) ifNotNilDo: [| :val | indices at: val put: index]].
716   switchKeyRegister: (gen generate: args first result: Nil).
717   gen emitInstruction: gen branchKeyed withParameters: {switchKeyRegister. (gen registerFor: table from: msg result: Nil)} from: msg.
718   branchOffset: gen codeWriter position.
719   gen emitInstruction: gen jumpTo from: msg.
720   endLabel: gen newLabelIndex.
721   otherwiseLabel: gen newLabelIndex.
722   gen emitBranchTo: otherwiseLabel from: msg.
724   assocs with: labels do:
725     [| :assoc :label |
726       gen emitLabel &labelIndex: label.
727       table
728         at: (indices at: assoc arguments first value) + 1
729         put: (gen currentContext resolveLabel: label at: branchOffset).
730       gen generateExecutionOf: {assoc arguments second} from: msg result: finalResult.
731       gen emitInstruction: gen jumpTo from: msg.
732       gen emitBranchTo: endLabel from: msg].
734   "Handle the otherwise clause. If we didn't get a literal block for it, just
735   encode a Nil-push."
736   gen emitLabel &labelIndex: otherwiseLabel.
737   args size >= 3
738     ifTrue: [gen generateExecutionOf: {args third} from: msg result: finalResult]
739     ifFalse: [gen registerFor: Nil from: msg result: finalResult].
740   gen emitLabel &labelIndex: endLabel.
741   finalResult
744 gen@(VM SSACompiler traits) generate: _@#caseOf: on: args from: msg result: result
745 "Generates a caseOf:otherwise: with a default otherwise clause."
747   (gen mayInlineCaseOf: msg)
748     ifTrue: [gen generate: #caseOf:otherwise: on: args from: msg result: result]
749     ifFalse: [resend]
752 gen@(VM SSACompiler traits) generate: _@#ifTrue:ifFalse: on: args from: msg result: finalResult
753 "Branches to one of two blocks and evaluates it."
754 [| falseLabel endLabel condReg |
755   falseLabel: gen newLabelIndex.
756   endLabel: gen newLabelIndex.
757   finalResult `defaultsTo: gen newRegister.
758   condReg: (gen generate: args first result: Nil).
759   condReg ifNil: [error: 'conditional is nil: ' ; args first printString].
760   gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
761   gen emitBranchTo: falseLabel from: msg.
762   gen generateExecutionOf: {args second} from: msg result: finalResult.
763   gen emitInstruction: gen jumpTo from: msg.
764   gen emitBranchTo: endLabel from: msg.
765   gen emitLabel &labelIndex: falseLabel.
766   gen generateExecutionOf: {args third} from: msg result: finalResult.
767   gen emitLabel &labelIndex: endLabel.
768   finalResult
771 gen@(VM SSACompiler traits) generate: _@#ifTrue: on: args from: msg result: finalResult
772 "Optionally evaluates a block."
773 [| falseLabel endLabel condReg |
774   falseLabel: gen newLabelIndex.
775   endLabel: gen newLabelIndex.
776   finalResult `defaultsTo: gen newRegister.
777   condReg: (gen generate: args first result: Nil).
778   condReg ifNil: [error: 'conditional is nil: ' ; args first printString].
779   gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
780   gen emitBranchTo: falseLabel from: msg.
781   gen generateExecutionOf: {args second} from: msg result: finalResult.
782   gen emitInstruction: gen jumpTo from: msg.
783   gen emitBranchTo: endLabel from: msg.
784   gen emitLabel &labelIndex: falseLabel.
785   gen registerFor: Nil from: msg result: finalResult.
786   gen emitLabel &labelIndex: endLabel.
787   finalResult
790 gen@(VM SSACompiler traits) generate: _@#ifFalse: on: args from: msg result: finalResult
791 [| falseLabel endLabel condResult |
792   falseLabel: gen newLabelIndex.
793   endLabel: gen newLabelIndex.
794   finalResult `defaultsTo: gen newRegister.
795   condResult: (gen generate: args first result: Nil).
796   condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
797   gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
798   gen emitBranchTo: falseLabel from: msg.
799   gen generateExecutionOf: {args second} from: msg result: finalResult.
800   gen emitInstruction: gen jumpTo from: msg.
801   gen emitBranchTo: endLabel from: msg.
802   gen emitLabel &labelIndex: falseLabel.
803   gen registerFor: Nil from: msg result: finalResult.
804   gen emitLabel &labelIndex: endLabel.
805   finalResult
809 gen@(VM SSACompiler traits) generate: _@#ifNil: on: args from: msg result: finalResult
810 [ | endLabel condReg lhsValueReg |
811   endLabel: gen newLabelIndex.
812   finalResult `defaultsTo: gen newRegister.
813   lhsValueReg: (gen generate: args first result: finalResult). "do not evaluate twice"
814   condReg: gen newRegister.
815   gen emitInstruction: gen isNilOp withParameters: {condReg. lhsValueReg} from: msg.
816   gen emitInstruction: gen branchIfFalse withParameters: {condReg} from: msg.
817   gen emitBranchTo: endLabel from: msg.
818   gen generateExecutionOf: {args second} from: msg result: finalResult.
819   gen emitLabel &labelIndex: endLabel.
820   finalResult
823 gen@(VM SSACompiler traits) generate: _@#ifNotNil: on: args from: msg result: finalResult
824 [ | endLabel condReg lhsValueReg |
825   endLabel: gen newLabelIndex.
826   finalResult `defaultsTo: gen newRegister.
827   lhsValueReg: (gen generate: args first result: finalResult). "do not evaluate twice"
828   condReg: gen newRegister.
829   gen emitInstruction: gen isNilOp withParameters: {condReg. lhsValueReg} from: msg.
830   gen emitInstruction: gen branchIfTrue withParameters: {condReg} from: msg.
831   gen emitBranchTo: endLabel from: msg.
832   gen generateExecutionOf: {args second} from: msg result: finalResult.
833   gen emitLabel &labelIndex: endLabel.
834   finalResult
838 gen@(VM SSACompiler traits) generate: _@#/\ on: args from: msg result: finalResult
839 "Optionally evaluates a block."
840 [| falseLabel endLabel condResult |
841   (args second isSameAs: Syntax Block)
842     ifFalse: [^ resend].
843   falseLabel: gen newLabelIndex.
844   endLabel: gen newLabelIndex.
845   finalResult `defaultsTo: gen newRegister.
846   condResult: (gen generate: args first result: Nil).
847   condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
848   gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
849   gen emitBranchTo: falseLabel from: msg.
850   gen generateExecutionOf: {args second} from: msg result: finalResult.
851   gen emitInstruction: gen jumpTo from: msg.
852   gen emitBranchTo: endLabel from: msg.
853   gen emitLabel &labelIndex: falseLabel.
854   gen registerFor: False from: msg result: finalResult.
855   gen emitLabel &labelIndex: endLabel.
856   finalResult
859 gen@(VM SSACompiler traits) generate: _@#\/ on: args from: msg result: finalResult
860 "Optionally evaluates a block."
861 [| block falseLabel endLabel condResult |
862   (args second isSameAs: Syntax Block)
863     ifFalse: [^ resend].
864   falseLabel: gen newLabelIndex.
865   endLabel: gen newLabelIndex.
866   finalResult `defaultsTo: gen newRegister.
867   condResult: (gen generate: args first result: Nil).
868   condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
869   gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
870   gen emitBranchTo: falseLabel from: msg.
871   gen generateExecutionOf: {args second} from: msg result: finalResult.
872   gen emitInstruction: gen jumpTo from: msg.
873   gen emitBranchTo: endLabel from: msg.
874   gen emitLabel &labelIndex: falseLabel.
875   gen registerFor: True from: msg result: finalResult.
876   gen emitLabel &labelIndex: endLabel.
877   finalResult
880 gen@(VM SSACompiler traits) generate: _@#whileTrue: on: args from: msg result: finalResult
881 "Repeatedly evaluates a block while it returns True."
882 [| label endLabel condResult |
883   endLabel: gen newLabelIndex.
884   label: gen emitLabel.
885   condResult: (gen generateExecutionOf: {args first} from: msg result: Nil).
886   condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
887   gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
888   gen emitBranchTo: endLabel from: msg.
889   gen generateExecutionOf: {args second} from: msg result: Nil.
890   gen emitInstruction: gen jumpTo from: msg.
891   gen emitBranchTo: label from: msg.
892   gen emitLabel &labelIndex: endLabel.
893   gen registerFor: Nil from: msg result: finalResult
896 gen@(VM SSACompiler traits) generate: _@#whileFalse: on: args from: msg result: finalResult
897 "Repeatedly evaluates a block while it returns False."
898 [| label endLabel condResult |
899   endLabel: gen newLabelIndex.
900   label: gen emitLabel.
901   condResult: (gen generateExecutionOf: {args first} from: msg result: Nil).
902   condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
903   gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
904   gen emitBranchTo: endLabel from: msg.
905   gen generateExecutionOf: {args second} from: msg result: Nil.
906   gen emitInstruction: gen jumpTo from: msg.
907   gen emitBranchTo: label from: msg.
908   gen emitLabel &labelIndex: endLabel.
909   gen registerFor: Nil from: msg result: finalResult
912 gen@(VM SSACompiler traits) generate: _@#whileTrue on: args from: msg result: result
913 "Repeatedly evaluates a block while it returns True."
914 [| label condResult |
915   label: gen emitLabel.
916   condResult: (gen generateExecutionOf: args from: msg result: Nil).
917   condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
918   gen emitInstruction: gen branchIfTrue withParameters: {condResult} from: msg.
919   gen emitBranchTo: label from: msg.
920   gen registerFor: Nil from: msg result: result
923 gen@(VM SSACompiler traits) generate: _@#whileFalse on: args from: msg result: result
924 "Repeatedly evaluates a block while it returns False."
925 [| label condResult |
926   label: gen emitLabel.
927   condResult: (gen generateExecutionOf: args from: msg result: Nil).
928   condResult ifNil: [error: 'conditional is nil: ' ; args first printString].
929   gen emitInstruction: gen branchIfFalse withParameters: {condResult} from: msg.
930   gen emitBranchTo: label from: msg.
931   gen registerFor: Nil from: msg result: result
935 gen@(VM SSACompiler traits) generate: _@#primitiveDo: on: args from: msg result: result
936 [| indexReg argRegs |
937   result `defaultsTo: gen newRegister.
938   indexReg: (gen generate: args first result: Nil).
939   argRegs: (args second statements collect: [|:item| (gen generate: item result: Nil)]).
940   gen emitInstruction: gen primitiveDo withParameters: {indexReg. argRegs size. result} ; argRegs from: msg.
941   result
944 gen@(VM SSACompiler traits) generate: _@#applyTo: on: args from: msg result: result
945 [| methodReg argRegs |
946   (args second isSameAs: Syntax Array) ifFalse: [^ resend].
947   result `defaultsTo: gen newRegister.
948   methodReg: (gen generate: args first result: Nil).
949   argRegs: (args second statements collect: [|:item| (gen generate: item result: Nil)]).
950   gen emitInstruction: gen directApplyTo withParameters: {methodReg. argRegs size. result} ; argRegs from: msg.
951   result
955 gen@(VM SSACompiler traits) generate: _@#fill:with: on: args from: msg result: result
956 [| block index var value |
957   block: args first.
958   index: args second.
959   value: args third.
960   (block isSameAs: Syntax Block) /\
961     [index isSameAs: Syntax Literal] /\
962     [block inputVariables acceptsKey: index value]
963     ifFalse: [^ resend].
964   (value isSameAs: Syntax Literal)
965     ifFalse:
966       [| tmp |
967         tmp: gen currentMethod sourceTree addVariable.
968         gen generate: (Syntax StoreVariable of: value into: tmp) result: Nil. "fixme"
969         value: (Syntax LoadVariable from: tmp)].
970   index: index value.
971   var: (block inputVariables at: index).
972   block inputVariables: (block inputVariables copyWithoutAt: index).
973   block localVariables
974     replaceFrom: index
975     below: block localVariables indexLast
976     with: block localVariables
977     startingAt: index + 1.
978   block localVariables at: block localVariables indexLast put: var.
979   block statements:
980     {(Syntax StoreVariable of: value into: var)} ; block statements.
981   gen generate: block result: result
984 gen@(VM SSACompiler traits) generate: _@#<- on: args from: msg result: result
985 "Optimizes currying calls on literal blocks using #fill:with:."
986 [gen generate: #fill:with: on: (args copyWith: (Syntax Literal for: 0) at: 1) from: msg result: result].
988 gen@(VM SSACompiler traits) generate: _@#<-1 on: args from: msg result: result
989 "Optimizes currying calls on literal blocks using #fill:with:."
990 [gen generate: #fill:with: on: (args copyWith: (Syntax Literal for: 0) at: 1) from: msg result: result].
992 gen@(VM SSACompiler traits) generate: _@#<-2 on: args from: msg result: result
993 "Optimizes currying calls on literal blocks using #fill:with:."
994 [gen generate: #fill:with: on: (args copyWith: (Syntax Literal for: 1) at: 1) from: msg result: result].
996 gen@(VM SSACompiler traits) generate: _@#<-3 on: args from: msg result: result
997 "Optimizes currying calls on literal blocks using #fill:with:."
998 [gen generate: #fill:with: on: (args copyWith: (Syntax Literal for: 2) at: 1) from: msg result: result].
1000 gen@(VM SSACompiler traits) generate: _@#<-4 on: args from: msg result: result
1001 "Optimizes currying calls on literal blocks using #fill:with:."
1002 [gen generate: #fill:with: on: (args copyWith: (Syntax Literal for: 3) at: 1) from: msg result: result].
1004 gen@(VM SSACompiler traits) generate: _@#<-5 on: args from: msg result: result
1005 "Optimizes currying calls on literal blocks using #fill:with:."
1006 [gen generate: #fill:with: on: (args copyWith: (Syntax Literal for: 4) at: 1) from: msg result: result].
1008 gen@(VM SSACompiler traits) generate: _@#<-* on: args from: msg result: result
1009 "Optimizes currying calls on literal blocks using #fill:with:."
1011   (args first isSameAs: Syntax Block)
1012     ifTrue:
1013       [gen generate: #fill:with:
1014            on: (args copyWith:
1015              (Syntax Literal for: args first inputVariables indexLast) at: 1)
1016            from: msg
1017            result: result]
1018     ifFalse: [resend]