v.Interaface() could construct an interface in interface value if v was
of type interface. This is not correct, and doesn't follow upstream Go
behavior. Instead, it should return the interface value itself.
This commit will use the memory layout information for heap allocations
added in the previous commit to determine LLVM types, instead of
guessing their types based on the content. This fixes a bug in which
recursive data structures (such as doubly linked lists) would result in
a compiler stack overflow due to infinite recursion.
Not all heap allocations have a memory layout yet, but this can be
incrementally fixed in the future. So far, this commit should fix
(almost?) all cases of this stack overflow issue.
This adds support for a construct like this:
type foo func(fn foo)
Unfortunately, LLVM cannot create function pointers that look like this.
LLVM only supports named types for structs (not for pointers) and thus
can't add a pointer to a function type of the same type to a parameter
of that function type.
The fix is simple: cast all function pointers to a void function, in
LLVM IR:
void ()*
Raw function pointers are cast to this type before storing, and cast
back to the regular function type before calling. This means that
function parameters will never refer to its own type because raw
function types are fixed at that one type.
Somehow, this does have an effect on binary size in some cases. The
effect is small and goes both ways. On top of that, there is work
underway in LLVM which would make all pointer types opaque (without a
pointee type). This would make this whole commit useless and therefore
should fix any size increases that might happen.
https://llvm.org/docs/OpaquePointers.html
The division and remainder operations were lowered directly to LLVM IR.
This is wrong however because the Go specification defines exactly what
happens on a divide by zero or signed integer overflow and LLVM IR
itself treats those cases as undefined behavior. Therefore, this commit
implements divide by zero and signed integer overflow according to the
Go specification.
This does have an impact on the generated code, but it is surprisingly
small. I've used the drivers repo to test the code before and after, and
to my surprise most driver smoke tests are not changed at all. Those
that are, have only a small increase in code size. At the same time,
this change makes TinyGo more compliant to the Go specification.
This adds support for stdio in picolibc and fixes wasm_exec.js so that
it can also support C puts. With this, C stdout works on all supported
platforms.
This is just a first step. It's not complete, but it gets some real
world C code to parse.
This signature, from the ESP-IDF:
esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]);
Was previously converted to something like this (pseudocode):
C.esp_err_t esp_wifi_get_mac(ifx C.wifi_interface_t, mac [6]uint8)
But this is not correct. C array parameters will decay. The array is
passed by reference instead of by value. Instead, this would be the
correct signature:
C.esp_err_t esp_wifi_get_mac(ifx C.wifi_interface_t, mac *uint8)
So that it can be called like this (using CGo):
var mac [6]byte
errCode := C.esp_wifi_get_mac(C.ESP_IF_WIFI_AP, &mac[0])
This stores the result in the 6-element array mac.
For example, the following did not work before but does work with this
change:
// int add(int a, int b) {
// return a + b;
// }
import "C"
func main() {
println("add:", C.add(3, 5))
}
Even better, the functions in the header are compiled together with the
rest of the Go code and so they can be optimized together! Currently,
inlining is not yet allowed but const-propagation across functions
works. This should be improved in the future.
This flag is passed automatically with the (new) -v flag for TinyGo. For
example, this prints all the test outputs:
$ tinygo test -v crypto/md5
=== RUN TestGolden
--- PASS: TestGolden
=== RUN TestGoldenMarshal
--- PASS: TestGoldenMarshal
=== RUN TestLarge
--- PASS: TestLarge
=== RUN TestBlockGeneric
--- PASS: TestBlockGeneric
=== RUN TestLargeHashes
--- PASS: TestLargeHashes
PASS
ok crypto/md5 0.002s
This prints just a summary:
$ tinygo test crypto/md5
PASS
ok crypto/md5 0.002s
(The superfluous 'PASS' message may be removed in the future).
This is especially useful when testing a large number of packages:
$ tinygo test crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512
PASS
ok crypto/md5 0.002s
PASS
ok crypto/sha1 0.043s
PASS
ok crypto/sha256 0.002s
PASS
ok crypto/sha512 0.003s
At the moment, the -test.v flag is not supplied to binaries running in
emulation. I intend to fix this after
https://github.com/tinygo-org/tinygo/pull/2038 lands by refactoring
runPackageTest, Run, and runTestWithConfig in the main package which all
do something similar.
Bug 1790 ("musttail call must precede a ret with an optional bitcast")
is caused by the GC stack slot pass inserting a store instruction
between a musttail call and a return instruction. This is not allowed in
LLVM IR.
One solution would be to remove the musttail. That would probably work,
but 1) the go-llvm API doesn't support this and 2) this might have
unforeseen consequences. What I've done in this commit is to move the
store instruction to a position earlier in the basic block, just after
the last access to the GC stack slot alloca.
Thanks to @fgsch for a very small repro, which I've used as a regression
test.
This fixes https://github.com/tinygo-org/tinygo/issues/1884.
My original plan to fix this was much more complicated, but then I
realized that the output type doesn't matter anyway and I can simply
cast the type to an *i8 and perform a GEP on that pointer.
This commit implements various process related functions like
os.Getuid() and os.Getpid(). It also implements or improves this support
in the syscall package if it isn't available yet.
This package provides access to an operating system resource
(cryptographic numbers) and so needs to be replaced with a TinyGo
version that does this in a different way.
I've made the following choices while adding this feature:
- I'm using the getentropy call whenever possible (most POSIX like
systems), because it is easier to use and more reliable. Linux is
the exception: it only added getentropy relatively recently.
- I've left bare-metal implementations to a future patch. This because
it's hard to reliably get cryptographically secure random numbers on
embedded devices: most devices do not have a hardware PRNG for this
purpose.
Not sure why you would ever do this, but it appears to be allowed by the
Go specification and previously TinyGo would crash with an unhelpful
error message when you would do this. I don't see any practical use of
it.
The implementation simply runs the builtin directly.
While LLVM coroutines are one implementation of goroutines, it is not
the only one. Therefore, rename the tests to 'goroutines' to better
describe what they're for.
The interp package is in many cases able to execute map functions in the
runtime directly. This is probably slower than adding special support
for them in the interp package and also doesn't cover all cases (most
importantly, map keys that contain pointers) but removing this code also
removes a large amount of code that needs to be maintained and is
susceptible to hard-to-find bugs.
As a side effect, this resulted in different output of the
testdata/map.go test because the test relied on the existing iteration
order of TinyGo maps. I've updated the test to not rely on this test,
making the output compatible with what the Go toolchain would output.
This improves compatibility between the regular browser target
(-target=wasm) and the WASI target (-target=wasi). Specifically, it
allows running WASI tests like this:
tinygo test -target=wasi encoding/base32
This commit implements replacing some global variables with a different
value, if the global variable has no initializer. For example, if you
have:
package main
var version string
you can replace the value with -ldflags="-X main.version=0.2".
Right now it only works for uninitialized globals. The Go tooling also
supports initialized globals (var version = "<undefined>") but that is a
bit hard to combine with how initialized globals are currently
implemented.
The current implementation still allows caching package IR files while
making sure the values don't end up in the build cache. This means
compiling a program multiple times with different values will use the
cached package each time, inserting the string value only late in the
build process.
Fixes#1045
- Explicitly list all test cases. This makes it possible to store
tests in testdata/ that aren't tested on all platforms.
- Clean up filesystem and env test, by running them in a subtest and
deduplicating some code and removing the additionalArgs parameter.
This patch adds support for passing CFLAGS added in #cgo lines of the
CGo preprocessing phase to the compiler when compiling C files inside
packages. This is expected and convenient but didn't work before.
This commit adds a new transform that converts reflect Implements()
calls to runtime.interfaceImplements. At the moment, the Implements()
method is not yet implemented (how ironic) but if the value passed to
Implements is known at compile time the method call can be optimized to
runtime.interfaceImplements to make it a regular interface assert.
This commit is the last change necessary to add basic support for the
encoding/json package. The json package is certainly not yet fully
supported, but some trivial objects can be converted to JSON.
This distinction was useful before when reflect wasn't properly
supported. Back then it made sense to only include method sets that were
actually used in an interface. But now that it is possible to get to
other values (for example, by extracting fields from structs) and it is
possible to turn them back into interfaces, it is necessary to preserve
all method sets that can possibly be used in the program in a type
assert, interface assert or interface method call.
In the future, this logic will need to be revisited again when
reflect.New or reflect.Zero gets implemented.
Code size increases a bit in some cases, but usually in a very limited
way (except for one outlier in the drivers smoke tests). The next commit
will improve the situation significantly.
This doesn't yet add support for actually making use of variadic
functions, but at least allows (unintended) variadic functions like the
following to work:
void foo();
This change extends defer support to all supported builitin functions.
Not all of them make sense (such as len, cap, real, imag, etc) but this
change for example adds support for `defer(delete(m, key))` which is
used in the Go 1.15 encoding/json package.
This works around some UB in LLVM, where an out-of-bounds conversion would produce a poison value.
The selected behavior is saturating, except that NaN is mapped to the minimum value.
Before this change, the compiler could panic with the following message:
panic: 20 not an Int
That of course doesn't make much sense. But it apparently is expected
behavior, see https://github.com/golang/go/issues/43165 for details.
This commit fixes this issue by converting the constant to an integer if
needed.
This appears to be allowed by the specification, at least it is allowed
by the main Go implementation: https://play.golang.org/p/S8jxAMytKDB
Allow it in TinyGo too, for consistency.
Found because it is triggered with `tinygo test flags`. This doesn't
make the flags package pass all tests, but is a step closer.
It can be unexpected that printing a float32 involves 64-bit floating
point routines, see for example:
https://github.com/tinygo-org/tinygo/issues/1415
This commit adds a dedicated printfloat32 instead just for printing
float32 values. It comes with a possible code size increase, but only if
both float32 and float64 values are printed. Therefore, this should be
an improvement in almost all cases.
I also tried using printfloat32 for everything (and casting a float64 to
float32 to print) but the printed values are slightly different,
breaking the testdata/math.go test for example.