In case there are no returns in the inlined function, jumps point to the
next instruction and can be omitted. This optimization can be extended
to handle other cases, here we just make sure that already existing code
stays the same.
Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
c.funcs contains function names using base types, while methods can be defined
on pointers and the value returned from c.getFuncNameFromSelector will have an
asterisk. We can't have the same name used for (*T) and (T) methods, so just
stripping the asterisk allows to get the right one.
Notice that this doesn't differentiate between (*T) and (T) receivers always
treating them as is. But we have the same problem with arguments now and the
number of inlined calls is limited, usually we want this behavior.
This has the drawback of traversing expression each time the argument is
used. However this is not the case in our syscall/native wrappers.
The old behaviour can be restored by explicit local assignment.
Create local variables as they are needed and remove `INITSLOT`
if there were no locals. This helps to eliminate a whole class
of bugs when calculated and real amount mismatched.
Selector here is either a struct field access or global package
variable/constant. While technically none of these require an additional
local, inlining actually uses one, so add a test for it.
Some arguments can be inlined functions themselves thus requiring additional
attention. Otherwise we can get less local variables than really used by
STLOCs (and subsequent program crash).
Consider function call `f(1, g(2, 3))` when
both `f` and `g` are inlined. If `f` contains some locals,
inlining `g` will replace them with it's another locals map,
because slices in Go reuse storage on `append`.
Thus scope needs to be copied.
Some control-flow statements drop stack items, for example
`return` when it is used inside of `range` loop.
For inlined calls this `return` should drop only portion of stack
which belongs to inlined call.
When function call-site parameter is an identifier,
we may load it directly. Currently it can be also modified,
this will be fixed in a separate commit.