sig writes: > Consider following example: > > you write the code: > ------ > PrimitiveSmallIntegers>>add: a with: b > | result | > self pragma: #inline. "tell the parser to not generate prologue/epilogue" > > " adding pair of smallintegers (assuming a and b is smallintegers!!) " > > ^ ( result := a + b ) ifNotOverflow: [ result - 1 ] else: [ self call: > #coerceToBigIntsAndAdd:with: with: a with: b ] > ------- > and then in > > IntermediateGenerator>>generate:add: > ^ self parsedMethod: #add:with: "return inlined form for adding two > operands" > > It provides an easy way for extending Exupery with all basic numerics > functionality (like big integers/floats), without jungles of hardly to > write and hardly to manage mid-level code.
Generating intermediate is not hard, and has good support for unit testing. For use in Exupery primitives must be implemented in the mid level code because that exists to allow for easy optimization of waste across bytecodes (or primitives). For instance "a < b ifTrue: [...]" Will remove the conversion to then from a boolean object for the SmallInteger case. Only if a floating point < primitive was inlined into medium level intermediate could this optimisation be done. Which is similar to removing the temporary float created in "1.0 + 2.0 + 3.0". There are several different kinds of primitive: * Small frequently called ones. e.g. #at: and #at:put: * Larger important clean primitives (possibly large integer stuff) * Larger or infrequent unclean primitives * Interfacing to C * Performance optimizations. The small frequently called primitives are compiled into code customized for each receiver class. There's only a handful of them and most of them are inlined into interpret() in the interpreter. interpret () accounts for 70% of the time in the benchmarks I've analyzed so performance wise it's the area to focus on. The larger clean primitives could be quickly implemented by calling a C helper function. These could be either compiled as part of their methods or inlined. The larger infrequent unclean primitives are operations that may change the active context. Here Exupery would need to save all the state back into the context, call the C helper function, then load it back and potentially enter a different method. The only overhead that can be saved is some of the message sends by using PICs. Interfacing to C could use some support. I haven't looked at it. Some of the performance optimizations should be replaced with normal Smalltalk as Exupery get's faster. Some should stay as tolerable interpreted performance is still nice. To be inlined a primitive must be able to execute in both it's senders context (in case it isn't inlined) and in it's senders context (in case it is inlined). If you send, or GC from your own context you must save the stack pointer and context state while if you're in the senders context you mustn't save the stack pointer. This is easy to implement using generated code but not using a template. Bryce _______________________________________________ Exupery mailing list [email protected] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/exupery
