Граф коммитов

31 коммит

Автор SHA1 Сообщение Дата
Damian Gryski
e3c96803c3 runtime: fix structField.data comment 2023-05-16 19:02:08 +02:00
Damian Gryski
07fb3a0cad compiler,reflect: make field offsets varints
Fixes #3686
2023-05-16 19:02:08 +02:00
Damian Gryski
4c0fbbfc7f add struct size and field offsets to reflect data 2023-04-27 11:15:41 +02:00
Ayke van Laethem
4e8453167f all: refactor reflect package
This is a big commit that changes the way runtime type information is stored in
the binary. Instead of compressing it and storing it in a number of sidetables,
it is stored similar to how the Go compiler toolchain stores it (but still more
compactly).

This has a number of advantages:

  * It is much easier to add new features to reflect support. They can simply
    be added to these structs without requiring massive changes (especially in
    the reflect lowering pass).
  * It removes the reflect lowering pass, which was a large amount of hard to
    understand and debug code.
  * The reflect lowering pass also required merging all LLVM IR into one
    module, which is terrible for performance especially when compiling large
    amounts of code. See issue 2870 for details.
  * It is (probably!) easier to reason about for the compiler.

The downside is that it increases code size a bit, especially when reflect is
involved. I hope to fix some of that in later patches.
2023-02-17 22:54:34 +01:00
Ayke van Laethem
caf405b01d reflect: add Value.UnsafePointer method
This was added in Go 1.18.
2022-06-12 01:08:02 +02:00
Damian Gryski
18242bc26a runtime: allow comparing interfaces in reflectValueEqual() 2021-11-24 14:17:47 +01:00
Ayke van Laethem
a4afc3b4b0 compiler: simplify interface lowering
This commit simplifies the IR a little bit: instead of calling
pseudo-functions runtime.interfaceImplements and
runtime.interfaceMethod, real declared functions are being called that
are then defined in the interface lowering pass. This should simplify
the interaction between various transformation passes. It also reduces
the number of lines of code, which is generally a good thing.
2021-10-31 14:17:25 +01:00
Ayke van Laethem
e587b1d1b4 reflect: implement New function
This is very important for some use cases, for example for Vecty.
2021-04-12 14:49:26 +02:00
Ayke van Laethem
c849bccb83 reflect: let reflect.Type be of interface type
This matches the main Go implementation and (among others) fixes a
compatibility issue with the encoding/json package. The encoding/json
package compares reflect.Type variables against nil, which does not work
as long as reflect.Type is of integer type.

This also adds a reflect.RawType() function (like reflect.Type()) that
makes it easier to avoid working with interfaces in the runtime package.
It is internal only, but exported to let the runtime package use it.

This change introduces a small code size increase when working with the
reflect package, but I've tried to keep it to a minimum. Most programs
that don't make extensive use of the reflect package (and don't use
package like fmt) should not be impacted by this.
2021-03-23 14:32:33 +01:00
Ayke van Laethem
19dec048b0 compiler: do not check for impossible type asserts
Previously there was code to avoid impossible type asserts but it wasn't
great and in fact was too aggressive when combined with reflection.

This commit improves this by checking all types that exist in the
program that may appear in an interface (even struct fields and the
like) but without creating runtime.typecodeID objects with the type
assert. This has two advantages:

  * As mentioned, it optimizes impossible type asserts away.
  * It allows methods on types that were only asserted on (in
    runtime.typeAssert) but never used in an interface to be optimized
    away using GlobalDCE. This may have a cascading effect so that other
    parts of the code can be further optimized.

This sometimes massively improves code size and mostly negates the code
size regression of the previous commit.
2021-03-23 14:32:33 +01:00
Ayke van Laethem
bbb2909283 compiler: merge runtime.typecodeID and runtime.typeInInterface
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.
2021-03-23 14:32:33 +01:00
Ayke van Laethem
30df912565 interp: rewrite entire package
For a full explanation, see interp/README.md. In short, this rewrite is
a redesign of the partial evaluator which improves it over the previous
partial evaluator. The main functional difference is that when
interpreting a function, the interpretation can be rolled back when an
unsupported instruction is encountered (for example, an actual unknown
instruction or a branch on a value that's only known at runtime). This
also means that it is no longer necessary to scan functions to see
whether they can be interpreted: instead, this package now just tries to
interpret it and reverts when it can't go further.

This new design has several benefits:

  * Most errors coming from the interp package are avoided, as it can
    simply skip the code it can't handle. This has long been an issue.
  * The memory model has been improved, which means some packages now
    pass all tests that previously didn't pass them.
  * Because of a better design, it is in fact a bit faster than the
    previous version.

This means the following packages now pass tests with `tinygo test`:

  * hash/adler32: previously it would hang in an infinite loop
  * math/cmplx: previously it resulted in errors

This also means that the math/big package can be imported. It would
previously fail with a "interp: branch on a non-constant" error.
2020-12-22 15:54:23 +01:00
Ayke van Laethem
45b5decb4e runtime: implement comparing uintptr values in interfaces
This was an oversight in https://github.com/tinygo-org/tinygo/pull/686.
With this PR, it's possible to compare interface values that contain
values/fields of type uintptr.
2019-11-09 13:41:27 -05:00
Konstantin Itskov
ac330f4a70 runtime: implement interface equality
Code copied from Konstantin Itskov and modified by Ayke van Laethem.
For details: https://github.com/tinygo-org/tinygo/pull/569
2019-11-04 15:19:41 +01:00
Jaden Weiss
d17f500c8b replace reflect.interfaceHeader with strongly typed runtime functions 2019-09-22 16:36:11 +02:00
Ayke van Laethem
c19c738f52 reflect: implement support for array types 2019-08-19 11:08:26 +02:00
Ayke van Laethem
e2c8654237 reflect: add support for struct types 2019-08-08 15:23:47 +02:00
Ayke van Laethem
33dc4b5121 compiler: fix crash with linked lists in interfaces
This commit fixes the following issue:
https://github.com/tinygo-org/tinygo/issues/309
Also, it prepares for some other reflect-related changes that should
make it easier to add support for named types (etc.) in the future.
2019-08-05 14:44:30 +02:00
Ayke van Laethem
7de3d4be2b all: support interface asserts in interp
This adds support for the math/rand package.
2019-04-13 20:55:56 +02:00
Ayke van Laethem
c7b91da8c4 compiler: support function pointers outside of addrspace 0
In LLVM 8, the AVR backend has moved all function pointers to address
space 1 by default. Much of the code still assumes function pointers
live in address space 0, leading to assertion failures.

This commit fixes this problem by autodetecting function pointers and
avoiding them in interface pseudo-calls.
2019-03-05 19:54:55 +01:00
Ayke van Laethem
f0904779a5
reflect: add reflect.TypeOf
This is the beginning of true reflection support in TinyGo.
2019-02-05 17:11:08 +01:00
Ayke van Laethem
b4c90f3677
compiler: lower interfaces in a separate pass
This commit changes many things:

  * Most interface-related operations are moved into an optimization
    pass for more modularity. IR construction creates pseudo-calls which
    are lowered in this pass.
  * Type codes are assigned in this interface lowering pass, after DCE.
  * Type codes are sorted by usage: types more often used in type
    asserts are assigned lower numbers to ease jump table construction
    during machine code generation.
  * Interface assertions are optimized: they are replaced by constant
    false, comparison against a constant, or a typeswitch with only
    concrete types in the general case.
  * Interface calls are replaced with unreachable, direct calls, or a
    concrete type switch with direct calls depending on the number of
    implementing types. This hopefully makes some interface patterns
    zero-cost.

These changes lead to a ~0.5K reduction in code size on Cortex-M for
testdata/interface.go. It appears that a major cause for this is the
replacement of function pointers with direct calls, which are far more
susceptible to optimization. Also, not having a fixed global array of
function pointers greatly helps dead code elimination.

This change also makes future optimizations easier, like optimizations
on interface value comparisons.
2018-12-01 13:26:06 +01:00
Ayke van Laethem
d1c0d6120a
compiler: simplify runtime.interfaceMethod signature slightly
Code size is not affected, as dead arguments are eliminated anyway.
It makes future interface optimizations hopefully easier to implement.
2018-11-09 15:20:38 +01:00
Ayke van Laethem
8675025fc8
compiler: implement type assert without comma-ok 2018-09-11 19:51:31 +02:00
Ayke van Laethem
4ad6df3227
all: complete the implementation of interface asserts
Because a few things were left unimplemented it only happened to kind-of
work before in my test cases.
This commit should complete interface-to-interface type asserts.
2018-09-11 19:39:25 +02:00
Ayke van Laethem
43b8c24226
compiler: implement interface assertions
This is a lot harder than 'regular' type assertions as the actual
methods need to be checked.
2018-09-06 20:18:18 +02:00
Ayke van Laethem
a7fcef62e0
compiler: implement comparing interfaces to nil
Comparing an interface to nil is easy, as the dynamic type is also nil.
Comparing the dynamic values (when the dynamic types match) is much
harder and depends on reflection capabilities, so is not yet implemented.
2018-09-03 01:13:07 +02:00
Ayke van Laethem
88b6b2e7f5
Optimize/eliminate bounds checking
TODO: do better at it by tracking min/max values of integers. The
following straightforward code doesn't have its bounds checks removed:

    for _, n := range slice {
        println(n)
    }
2018-09-02 16:28:46 +02:00
Ayke van Laethem
0c71ed81a4
Rename runtime.itfmethod -> runtime.interfaceMethod 2018-08-27 00:49:33 +02:00
Ayke van Laethem
64e478ef36
Switch to 16-bit typecodes and method IDs
It took Android some time to even hit the 64K limit for regular method
calls, so switching to 16-bit IDs should be fine for method IDs of
interfaces. At least for the time being. When this limit is ever hit,
I'll think of another way, probably involving some platform-dependent
interface code (e.g. microcontrollers won't need 64K of methods) or
detecting the limit at build time.

https://android-developers.googleblog.com/2014/12/google-play-services-and-dex-method.html

Code size isn't changed, probably because the compiler optimizes away
all method calls.
2018-08-27 00:32:30 +02:00
Ayke van Laethem
539de9db9e
Move interface method calls in Go from LLVM IR + documentation
This commit moves the itfmethod call implemented directly in LLVM IR to
a Go implementation in the runtime. Additionally, it fixes variable
names to be more obvious and adds a lot of documentation to explain how
interfaces actually work in TinyGo.

Code size changes for src/examples/hello:
nrf:  -144
unix: -93

I'm guessing this code size reduction is a result of removing the
'noinline' function attribute.
2018-08-26 23:40:11 +02:00