Under Review
over 1 year ago

bug with HAS or inline SYMBOL on venusq and maybe other devices

One venuSQ user reported that the battery stopped working. After few tests I have found that there is a bug with HAS or SYMBOLS.

This code 4.2.4/win10/eclipse on sim/venusq:

var

Symbol_getBB = :getBodyBatteryHistory;

lg("getInitialView :getBB1=" + :getBodyBatteryHistory + " hasBB=" + (Toybox.SensorHistory has :getBodyBatteryHistory));

lg("getInitialView :getBB2=" + Symbol_getBB + " hasBB=" + (Toybox.SensorHistory has Symbol_getBB));

shows

getInitialView :getBB1=symbol (8391839) hasBB=false

getInitialView :getBB2=symbol (8391839) hasBB=true

so I don't try to read BB to not allow to exception and show no data.

on f7 (on my real device there is no problem):

getInitialView :getBB1=symbol (8391839) hasBB=true

getInitialView :getBB2=symbol (8391839) hasBB=true

Parents
  • I'm using Visual Studio Code rather than Eclipse, but that shouldn't matter in this case.

    It turns out that it does. VSCode doesn't pass in an "--api-level" argument to the compiler, while eclipse does. And if you *do* pass that option, the optimizer uses it to constant fold "has" expressions. Note that the manifest also specifies the min sdk level, but setting it there doesn't seem to have the same effect on the compiler.

    So I can repro in VSCode by adding "--api-level=3.2.0" to monkeyC.compilerOptions. If I also add "-g", I can see that the "has" expression was optimized to "bpush 0" (which pushes false onto the stack). On the other hand, putting the symbol in a local, prevents the constant folding (even at -O3), so the has expression is evaluated at runtime, and gets the correct results. If I set  "--api-level=3.3.0", then the has is optimized to "bpush 1", giving the correct results.

    Adding -O0 to compilerOptions (or setting monkeyC.optimizationLevel to "None") also fixes the problem, by turning off constant folding.

    Obviously, its wrong for it to resolve a has expression to false on the basis that you're targeting a min api level that doesn't support it; just because the *minimum* api level you're targeting doesn't support it, doesn't mean that there won't be devices that *do* support it. On the other hand, optimizing it to true (when the symbol is guaranteed to be there at the minimum api level) should be fine.

    Finally, this is only a problem for devices like the venusq which has some part numbers that support 3.2.x and some that support 3.3.x, because the compiler will ignore the user supplied api-level if its lower than the minimum supported by the device (so compiling for fenix7 will always optimize it to true).

Comment
  • I'm using Visual Studio Code rather than Eclipse, but that shouldn't matter in this case.

    It turns out that it does. VSCode doesn't pass in an "--api-level" argument to the compiler, while eclipse does. And if you *do* pass that option, the optimizer uses it to constant fold "has" expressions. Note that the manifest also specifies the min sdk level, but setting it there doesn't seem to have the same effect on the compiler.

    So I can repro in VSCode by adding "--api-level=3.2.0" to monkeyC.compilerOptions. If I also add "-g", I can see that the "has" expression was optimized to "bpush 0" (which pushes false onto the stack). On the other hand, putting the symbol in a local, prevents the constant folding (even at -O3), so the has expression is evaluated at runtime, and gets the correct results. If I set  "--api-level=3.3.0", then the has is optimized to "bpush 1", giving the correct results.

    Adding -O0 to compilerOptions (or setting monkeyC.optimizationLevel to "None") also fixes the problem, by turning off constant folding.

    Obviously, its wrong for it to resolve a has expression to false on the basis that you're targeting a min api level that doesn't support it; just because the *minimum* api level you're targeting doesn't support it, doesn't mean that there won't be devices that *do* support it. On the other hand, optimizing it to true (when the symbol is guaranteed to be there at the minimum api level) should be fine.

    Finally, this is only a problem for devices like the venusq which has some part numbers that support 3.2.x and some that support 3.3.x, because the compiler will ignore the user supplied api-level if its lower than the minimum supported by the device (so compiling for fenix7 will always optimize it to true).

Children
  • I had always assumed that the compiler's api level option did nothing since the UI was removed in VS Code

    I had assumed that the minApiLevel manifest setting was equivalent to the command line option - but from my testing that's not the case.

    For example, System 6 is 3.4 / 4.2 (for CIQ 3 devices and CIQ 4 devices, respectively) so it isn't possible to select a min API level which includes System 6 devices and only System 6 devices

    That doesn't sound good. In fact, looking at api.mir, it does seem that the presence/absence of api entries (ie methods and classes) is predicated on "minSdk" - which seems to be an api level, rather than an actual sdk version, as far as I can tell. Does that mean that features aren't associated with system 6 per se? Looking through api.mir, there are a bunch of things with minSdk=4.2.0, and a few things with minSdk=3.4.0. Does that mean the things marked 3.4.0 work with 4.1.0 (ie they don't require system 6), while the 4.2.0 features only work on CIQ 4 devices with system 6?

  • Very interesting analysis, thanks. I had always assumed that the compiler's api level option did nothing since the UI was removed in VS Code, but now I know better.

    On the other hand, optimizing it to true (when the symbol is guaranteed to be there at the minimum api level) should be fine.

    This goes back to my favorite complaint about the concept of minimum API level itself: it doesn't really work with the System X scheme. For example, System 6 is 3.4 / 4.2 (for CIQ 3 devices and CIQ 4 devices, respectively) so it isn't possible to select a min API level which includes System 6 devices and only System 6 devices.