This makes it easier to get an overview of everything interface related,
because interfaces are quite complicated and were scattered through the
(huge!) compiler.go file.
This interpreter currently complements the Go SSA level interpreter. It
may stay complementary or may be the only interpreter in the future.
This interpreter is experimental and not yet finished (there are known
bugs!) so it is disabled by default. It can be enabled by passing the
-initinterp flag.
The goal is to be able to run all initializations at compile time except
for the ones having side effects. This mostly works except perhaps for a
few edge cases.
In the future, this interpeter may be used to actually run regular Go
code, perhaps in a shell.
I don't know why they sometimes have them, but apparently some packages
do. Don't panic in that case, the interpreter will stop anyway on the
first branch.
In Go, function pointers are not comparable. This means that the address
itself is not significant and functions can therefore be merged.
Add the unnamed_addr attribute to all functions to learn LLVM about this
fact. At the moment the mergefunc pass hasn't been enabled, but it
should be in the future to reduce code size.
JavaScript does not support i64 directly, so make sure we pass a pointer
instead which can be read from JavaScript.
This is a temporary workaround which should be removed once JavaScript
supports some form of i64 (probably in the form of BigInt).
When doing a slice operation on a slice, use the capacity value instead
of the length. Of course, for strings and arrays, the slice operation
checks the length because there is no capacity. But according to the
spec, this check should be based on cap for slice instead of len:
> For slices, the upper index bound is the slice capacity cap(a) rather
> than the length.
https://golang.org/ref/spec#Slice_expressions
Fixes: https://github.com/aykevl/tinygo/issues/65
Assume any external function won't let pointers live longer than the
call itself. This is true in the vast majority of cases (apparently
everywhere currently) but might not always be true.
TODO: add a //go:noescape (or maybe //go:escape) to handle this, instead
of this assumption.
A single *ssa.BasicBlock may be split in multiple LLVM basic blocks due
to typeassert instructions. This means the incoming block and outgoing
block are different. PHI nodes need to get the result from the outgoing
block, which was fixed before, but incoming branches need to branch to
the incoming block, not the outgoing block.
Branching to the outgoing block led to a LLVM verification error when
compiling the fmt package.
Originally found in (*fmt.pp).handleMethods.
This is a common operation:
freevar := ...
defer func() {
println("I am deferred:", freevar)
}()
The function is thus an immediately applied closure. Only this form is
currently supported, support for regular (fat) function pointers should
be trivial to add but is not currently implemented as it wasn't
necessary to get fmt to compile.
It is allowed to index with an int64 even on a 32-bit platform, so we
have to handle that case. But make sure the normal case isn't penalized
by using 32-bit numbers when possible.
Static map generation used the last bucket instead of the first bucket
in the chain, which caused lots of missing entries in hashmaps with
multiple buckets (size > 8).
This optimization makes sure the following pattern doesn't do a heap
allocation (assuming Write doesn't modify the slice):
var w *machine.UART = ...
w.Write([]byte("foo"))
As long as Write doesn't modify the slice and LLVM can detect this, a
call to runtime.stringToBytes with the necessary allocation + copy is
avoided.
When the underlying value of an interface does not fit in a pointer, a
pointer to the value was correctly inserted in the heap. However, the
receiving method still assumed it got the underlying value instead of a
pointer to it leading to a crash.
This commit inserts wrapper functions for method calls on interfaces.
The bug wasn't obvious as on a 64-bit system, the underlying value was
almost always put directly in the interface. However, it led to a crash
on the AVR platform where pointer are (usually) just 16 bits making it
far more likely that underlying values cannot be directly stored in an
interface.
Make sure package initializers show up in backtraces, as they should. In
practice, it doesn't actually break backtraces as these functions are
usually inlined anyway, but it may help to debug an error in
initialization code.