Skip to content
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

experimental_compact_vars broke InlineC native code (unaligned flat strings) #2040

Closed
fanoush opened this issue Aug 28, 2021 · 10 comments
Closed

Comments

@fanoush
Copy link
Contributor

@fanoush fanoush commented Aug 28, 2021

InlineC code stopped working after commit 47d22f8

Looks like flat strings produced by atob() are no longer aligned to 4 bytes because 13 byte variables themselves are no longer aligned. Calling into unaligned code causes reboot.

Tried to revert to 16 byte variables via -DJSVAR_FORCE_16_BYTE=1 however it didn't work alone, I had to also add __attribute__((aligned(4))) to JsVar jsVars[JSVAR_CACHE_SIZE]; array definition in src/jsvar.c because JsVar type had this attribute before but it was removed.

Not sure how to fix this properly, maybe (all?) flat strings could be aligned to 4 bytes possibly wasting up to 3 bytes on the beginning? or maybe E.toString() or atob() could have alignment parameter so that at least some flat strings are aligned like this and then inline code definition could use it - however that is not backward compatible with existing source code like this one.

@gfwilliams
Copy link
Member

@gfwilliams gfwilliams commented Aug 31, 2021

Argh. that's a tricky one. I guess the code only actually needs alignment to 2 bytes for ARM Thumb? Even so it'd fail half the time.

Making flat strings 4 byte aligned does seem like the easy option, but it is a bit of a waste, especially as they get used quite widely now.

I guess 'nativeCall' could attempt to relocate the string if it wasn't aligned properly?

@fanoush
Copy link
Contributor Author

@fanoush fanoush commented Aug 31, 2021

guess the code only actually needs alignment to 2 bytes for ARM Thumb?

my code crashes also when aligned on 2 byte boundary but maybe it can be also compiler thing? didn't found it anywhere so far what are requirements for code alignment for cortex-m

also as later mentioned in forum post http://forum.espruino.com/conversations/366505/#comment16154608 alignment of Uint16 an Uint32 array could be performance issue as unaligned access is slower

@fanoush
Copy link
Contributor Author

@fanoush fanoush commented Aug 31, 2021

I guess 'nativeCall' could attempt to relocate the string if it wasn't aligned properly?

well, that is probably too late and you have multiple methods in one big string, e.g. here
https://gist.github.com/fanoush/1efde25636cd62a82a857cf8b6a5c86f#file-espruino-fpu-mandel-bench-js-L158
so how do you know when to relocate? you would need to check and possibly fix before each and every native call

Oh, but nativeCall is called once when defining the method, not when actually executing it? then yes, the first one could do it

@gfwilliams
Copy link
Member

@gfwilliams gfwilliams commented Aug 31, 2021

my code crashes also when aligned on 2 byte boundary

Ahh - it could be how the compiler expects constants to be in memory I guess? Either way, 4 byte align is sensible.

alignment of Uint16 an Uint32 array could be performance issue

Honestly, with Espruino I think the performance hit of everything else far outweighs that of unaligned access I'm afraid :) I was hesitant about the compact_vars for that very reason but actually it didn't have a massive impact.

how do you know when to relocate? Oh, but nativeCall is called once when defining the method, not when actually executing it? then yes, the first one could do it

Yes - It'd just look at the string itself and see if that was aligned.

Actually I just had an idea - maybe the Flat String allocator could only start Flat Strings from a JsVar in memory that meant that subsequent data would be aligned. While it makes it slightly more difficult to allocate flat strings, it's about the same speed and doesn't waste memory, because other stuff can fill in around them

@fanoush
Copy link
Contributor Author

@fanoush fanoush commented Aug 31, 2021

Honestly, with Espruino I think the performance hit of everything else far outweighs that of unaligned access I'm afraid :)

was more thinking native/InlineC code that you pass the array to, like framebuffer or pallete table for display driver or some data (even 32bit floats) to some math code

Actually I just had an idea - maybe the Flat String allocator could only start Flat Strings from a JsVar in memory that meant that subsequent data would be aligned.

Yes, was thinking about that too but it looked too complicated and at low memory conditions it may not find such free space, then wasting up to 3 bytes inside non aligned one would be preferable which makes it even more complicated. but yes if you feel it is actually easy then lets't try it

@gfwilliams
Copy link
Member

@gfwilliams gfwilliams commented Aug 31, 2021

Just pushed a fix - seems to work ok for me now

@fanoush
Copy link
Contributor Author

@fanoush fanoush commented Aug 31, 2021

as per https://stackoverflow.com/a/17185320 floats must be aligned even if cpu can otherwise do unaligned access, so e.g. working with unaligned Float32Array can be tricky

@gfwilliams
Copy link
Member

@gfwilliams gfwilliams commented Aug 31, 2021

Wow, thanks - that's a really good one to know! Due to the way it works Espruino can probably still read/write float32 - hence not noticing any issues, but that'd be a complete pain for any native code

@fanoush
Copy link
Contributor Author

@fanoush fanoush commented Sep 1, 2021

I can confirm it works fine with all native code I tried. Also arrays look good. At least those which are practical to be passed to native code - those ones where E.getAddress(array,true) does not give zero and those are (always?) backed by flat strings so are aligned too.

@gfwilliams
Copy link
Member

@gfwilliams gfwilliams commented Sep 1, 2021

where E.getAddress(array,true) does not give zero and those are (always?) backed by flat strings so are aligned too.

Yep, correct - so I reckon we're good. Phew!

I don't think it'll be too much of an impact in speed or memory usage either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants