-
-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for inline/stack allocated types #778
Merged
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
yorickpeterse
added
feature
New things to add to Inko, such as a new standard library module
performance
Changes related to improving performance
compiler
Changes related to the compiler
std
Changes related to the standard library
labels
Nov 6, 2024
yorickpeterse
force-pushed
the
inline-types
branch
2 times, most recently
from
November 7, 2024 00:21
393fe24
to
7b068b3
Compare
Test code I'm using: dt.inko
dt_fast.inko
The diff --git a/std/src/std/string.inko b/std/src/std/string.inko
index 861f4f0d..3d0a6d54 100644
--- a/std/src/std/string.inko
+++ b/std/src/std/string.inko
@@ -150,6 +150,10 @@ trait pub Bytes {
fn pub to_pointer -> Pointer[UInt8]
}
+class pub inline OptionalByte {
+ let pub @value: Int
+}
+
# An UTF-8 encoded and immutable string type.
class builtin String {
# The size of the string in bytes, _excluding_ the trailing NULL byte.
@@ -678,6 +682,12 @@ class builtin String {
fn inline byte_unchecked(index: Int) -> Int {
(@ptr as Int + index as Pointer[UInt8]).0 as Int
}
+
+ fn pub opt_fast(index: Int) -> OptionalByte {
+ if index < 0 or index >= size { return OptionalByte(-1) }
+
+ OptionalByte(byte_unchecked(index))
+ }
}
impl Bytes for String { |
yorickpeterse
force-pushed
the
inline-types
branch
5 times, most recently
from
November 9, 2024 01:33
b7778a5
to
b87494f
Compare
This was referenced Nov 9, 2024
yorickpeterse
force-pushed
the
inline-types
branch
13 times, most recently
from
November 14, 2024 19:27
3febb00
to
13b5e73
Compare
yorickpeterse
force-pushed
the
inline-types
branch
3 times, most recently
from
November 21, 2024 14:54
1e55e71
to
b4da7e5
Compare
6 tasks
With these changes in place, the following randomly (though not always) produces allocation errors:
My best guess is that the type sizes aren't calculated correctly, resulting in stack data being overwritten. |
yorickpeterse
force-pushed
the
inline-types
branch
9 times, most recently
from
November 27, 2024 01:03
7441cb8
to
90227b6
Compare
The panic and no_panic tests run in a separate process, and processes don't link their stack traces. The "panic" helper already took care of setting the correct location, but the "no_panic" helper didn't. Changelog: fixed
yorickpeterse
force-pushed
the
inline-types
branch
from
November 27, 2024 01:32
90227b6
to
2334e5d
Compare
yorickpeterse
force-pushed
the
inline-types
branch
from
November 27, 2024 17:03
34ce4ce
to
3476d06
Compare
An inline type is an immutable value type that's allocated inline/on the stack. Both regular and enum types can be defined as "inline". Inline types don't have object headers, and combined with them being stored inline means they don't incur extra indirection/overhead. For example, consider this type: class inline A { let @A: Int let @b: Int } If this were a regular type, its size would be 32 bytes: 16 bytes for the header, and 16 bytes for the two fields. Because it's an inline type though, it only needs 16 bytes. Inline types are restricted to types that can be trivially copied, such as Int, Float, and other inline types. String isn't allowed in inline types at this point as this could result in an unexpected copy cost due to String using atomic reference counting. Inline types are immutable because supporting mutations introduces significant compiler complexity, especially when dealing with closures that capture generic type parameters, as support for mutations would require rewriting part of the generated code as part of type specialization. This fixes #750. Changelog: added
The Instant and Duration types are now "inline" types, removing the need for heap allocations. In addition, various methods are flagged as "inline" to guarantee they're always inlined into their callers. Changelog: performance
This removes the need for heap allocations when creating ranges. In addition, various methods are flagged as "inline" to guarantee they're inlined into their callers. Changelog: performance.
This makes std.io.Error an "inline" type, removing the need for allocations when creating such instances. Changelog: performance
Changelog: performance
This turns Ipv4Address, Ipv6Address and IpAddress into "inline" types, removing the need for heap allocations. Changelog: performance
This removes the need for a heap allocation when getting IP socket addresses. Changelog: performance
yorickpeterse
force-pushed
the
inline-types
branch
from
November 28, 2024 16:39
dfb529c
to
46e3ae7
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
compiler
Changes related to the compiler
feature
New things to add to Inko, such as a new standard library module
performance
Changes related to improving performance
std
Changes related to the standard library
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This adds support for
inline
types. Such types are immutable value types that are copied upon being moved, and are allocated on the stack without an object header.TODO
Initial implementation:
ClassKind::Inline
with just a flag onClass
, making it easier to combine with other class kinds (e.g.Tuple
) without the need for a ton of constructorsinline
typesDrop
implementations forinline
typesinline
types are restricted to types that we can trivially copy aroundinline
types since this is redundantinline
types since they'll never be usedTypeRef::is_permanent
intoTypeRef::is_stack_allocated
, as the former is now redundantmut
andinline
properties of the original parameterinline
type are alsoinline
(String
won't be allowed, at least for now I think)compiler::llvm::layouts::Layouts
handlesinline
types correctly.TypeParameter::inline
field and set this totrue
for any type parameter defined on aninline
typeinline
type parameter, only allow this if the passed type is also aninline
typeclass inline enum
? This might not be useful if we inferenum
types asinline
inline
(dedicated) typesShape::Custom(ClassInstance)
extern
types in genericsShape
implementsEq
andHash
, but that isn't reliable forClassInstance
since different occurrences of e.g.Option[Foo]
use a differenttype_arguments
IDinline
types immutable and disallowfn mut
methodsfn
andfn move
methods exposeself
asT
(owned)ref expr
andmut expr
just return the target register when the value is aninline
typeinline
values by valueinline
classes, such that if theinline
state changes (e.g. through inference in a future setup), we automatically take this into account for object file cachinginline
types as moved is a noop (i.e.move R₁
does nothing ifR₁
contains stack data)inline
types are sendableinline
types to traits failsstd.net.socket.SocketAddress
asinline
causes an invalidfree()
byval
extractvalue
just uses the type of the field its loading, rather thanload
which takes a type, so we need to bitcast thingsT: inline
, otherwise you can't define e.g. amap
that takes aT
fromself
that happens to beT: inline
and map that toR: inline
inline
types to anything (e.g.UInt64
) because that doesn't make sense for data on the stackVerification:
class inline
T: inline