Big update to prettier-extension-monkeyc

I've posted about prettier-extension-monkeyc before, but I've added a bunch of new features that developers will probably like (well, I've been missing them, so maybe you have too).

The new features it implements for VSCode include:

  • Goto Definition. Point at a symbol, Ctrl/Cmd click, and it will take you to the definition. Or F12
  • Goto References. Right click on a symbol and select "Goto References". It will show you all the references. Or Shift-F12
  • Peek Definition/Peek References. Same as above, but in a popup window so you don't lose your place in the original document.
  • Rename Symbol. Right click on a local, function, class or module name, and select "Rename Symbol". It will rename all the references. It doesn't yet work for class members/methods.
  • Goto Symbol. Type Ctrl/Cmd-Shift-O and pick a symbol from the drop down (which has a hierarchical view of all symbols in the current file). This also appears as an outline across the top of the file.
  • Open Symbol By Name. Type Ctrl/Cmd-T, then start typing letters from a symbol name. A drop down will be populated with all matching symbols from anywhere in your project.

Older features include a prettier based formatter for monkeyc, and a monkeyc optimizer that will build/run/export an optimized version of your project.

[edit: My last couple of replies seem to have just disappeared, and the whole conversation seems to be in a jumbled order, so tldr: there's a new test-release at https://github.com/markw65/prettier-extension-monkeyc/releases/tag/v2.0.9 which seems to work for me on linux. I'll do more verification tomorrow, and push a proper update to the vscode store once I'm sure everything is working]

  • To elaborate on this, the use of a non-local variable involves a symbol lookup, but the use of a local variable does not.

    I don't think so because I can't see symbol for each local var.

    That's what I said:

    non-local var => symbol lookup

    local var => no symbol lookup

    That's why a usage of a non-local variable takes up more memory - the code has to refer to the symbol(s) in the identifier (and any qualifiers), like markw65 pointed out.

  • I know it but it consumes memory unfortunately and I thought it was good in 'no symbol era '.

  • there is the difference between lookup in runtime/compiletime.

    I CAN see symbol for local var in debug.xml. But probably local vars are on stack, numbered, but 2 bytes it's too much, usually limits is 255 so one byte.

  • The tests need to be done with a few different apps while the beta optimization as it saved some thousands of bytes for some, and < 100 bytes for others

    Here are three open source projects. The numbers are text-size/data-size for a release build, using the first device listed in the manifest.

    https://github.com/HanSolo/digital

    • Old-compiler
      • Garmin: 11026 / 2148
      • My optimizer: 9435 / 2132
    • New Compiler at O2
      • Garmin: 10154 / 2132
      • My optimizer: 9445 / 2132 

    https://github.com/ravenfeld/Connect-IQ-DataField-Speed

    • Old-compiler
      • Garmin: 2316/727
      • My optimizer: 1895/727
    • New Compiler at O2
      • Garmin: 1978/727
      • My optimizer: 1872/727 

    https://github.com/fjbenitog/digital-watch-cas10

    • Old-compiler
      • Garmin: 8596/2226
      • My optimizer: 7567/2194
    • New Compiler at O2
      • Garmin: 7828/2202 (needed a patch to replace "me" with "self")
      • My optimizer: 7508/2194 

    I could do more, but its a bit time consuming, since the only way I know to get these numbers is to run under the simulator, open the memory panel, and then read off the values from there. So although my monkeyc-optimizer is setup to build around 150 different open source projects, getting the size stats is painful. If anyone knows a way to find this (eg from the compiler output with -g), I could automate the process...

  • ****** and respect for you :-)

  • I think that copying to local (stack) is better in both ways: 1. less code, 2. the lookup takes time and CPU and you only need to do it once instead of every time you reference the non-local variable

  • Either you have a typo above in the HanSolo project's numbers or you found some special cases that probably indicate a bug in Compiler Beta (and/or maybe in the optimizer) because the new compiler generated bigger code than the old one: old+optimizer:9435 vs new+optimizer:9445

  • but 2 bytes it's too much, usually limits is 255 so one byte

    Don't forget there's an opcode too. So loading a local needs "LoadLoc <id>". I'm guessing the LoadLoc is 1 byte and the id is one byte. Note that Numbers take 5 bytes per reference. Since the number is 32 bits, or 4 bytes, thats again a 1 byte opcode and 4 byte number. I don't know whether all opcodes are the same size or not...

    I've also not checked what happens when you go over 256 locals... presumably the compiler either errors, or falls back to an alternate opcode with a bigger id. Or maybe the variable id is variable-length-encoded, and the first 127 take one byte, the next 16383 take 2 bytes etc.

  • yes, you can't have more than 255 members/globals/etc.

  • it's very good solution but only for function not used frequently (like onUpdate), because assignment need processor time. But maybe access to local is faster then - tests are needed

    Well, this is one of the reasons I made it an optional optimization. But generally, if a global is used two or more times dynamically, its going to be better to use the local. Otoh if the global is only used on some paths, and is used at most once on any given path, then it might be a *bit* slower to use the local.

    so eg for something like

    if (g) {
      foo(g);
      bar(g);
    }

    pulling out the local will always be better for both size and speed, whereas for something like

    switch (x) {
      case 1: foo(g); break;
      case 2: bar(g); break;
      case 3: baz(); break;
    }

    pulling out the local will be good for size, roughly breakeven for speed when x is 1 or 2, and worse for speed when x is 3.

    Traditional partial redundancy elimination is aimed at speed. It will only put the target expression in a local if the expression was definitely going to be evaluated at least once on every path where the assignment to the local occurs - ie it would do it in the first case, but not the second. On the other hand if you changed the second case to switch on g rather than x, pre would kick in, because now if you get to the switch statement, g is definitely going to be evaluated once, and on two paths will be evaluated twice.

    I may implement this as another option. This will still reduce code size where it kicks in, but it will kick in less often.