confused about E.memoryArea

Posted on
  • I'm a bit confused about "executing out of flash memory" using E.memoryArea. Here's what I tried on an esp8266.

    First write a simple function to flash memory and check that it's there:

    >fl.erasePage(487424)
    =undefined
    >fl.write("function hello(t) { t1 = t.toUpperCase(); console.log('hello', t1); }   ", 487424)
    =undefined
    >fl.read(72, 487424)
    =new Uint8Array([102, 117, 110, 99, 116,  ... 32, 125, 32, 32, 32])
    

    Now eval it (I know I didn't need "ma"):

    >ma = eval(E.memoryArea(0x40200000+487424, 72));
    =function (t) { ... }
    >ma=null;
    =null
    

    Now see what's in memory:

    >trace()
    #1[r2,l1] Object {
      ... lots of stuff skipped ...
      #58[r1,l2] Name String [2 blocks] "hello"    #79[r1,l1] Function { return
          #81[r1,l2] Name Param "t"         undefined
          #80[r1,l2] Name String [1 blocks] "\xFFcod"        #138[r1,l1] String [5 blocks] "t1 = t.toUp
        }
    }
    

    Doesn't this mean that the function "hello" uses just as much memory as if it had been normally loaded, or is #138 really all in flash and doesn't use any jsVars?

    Is there a different trick that's eluding me here to get the code in "hello" to stay in flash? Or am I just confused?

  • Well, at the moment your code is executed from flash, but 'executing' here is means that the function declaration is being executed from flash (but then the execution of the declaration loads it into RAM).

    While Espruino could store the code in flash directly, if you then did fl.erasePage(...) the whole thing would just stop working - it seemed like a bit of a scary thing to do automatically, especially as E.memoryArea could easily also point to RAM. I guess it could be enabled by default, I'd just be worried about it.

    So what you could do is:

    fl.write("t1 = t.toUpperCase(); console.log('hello', t1); ", 487424)
    function hello(t) {
     return eval(E.memoryArea(0x40200000+487424, ??));
    }
    

    Or actually you could do some fixup code like:

    var base = 0x40200000+487424;
    var s = E.memoryArea(base, 72);
    eval(s);
    for (var i in global) {
      if (typeof global[i] == "function") {
        var f = global[i];
        if ("\xFFcod" in f && s.indexOf(f["\xFFcod"])>=0) {
          var c = f["\xFFcod"];
          f["\xFFcod"] = E.memoryArea(base+s.indexOf(c), c.length);
        }
      }
    }
    

    Not tested, but something like that should work.

  • If you try the builds from GitHub as of just now, I've enabled the native string copying.

    I guess we'll see if anyone complains - the main issue I see is using the new E.setBootCode which is the Save on Send option in the Web IDE. If you upload code, then call E.setBootCode again it'll break the code.

    But on the plus side, you should save some memory when using it, as all functions declared in the root scope will then have their code in flash.

  • Ah, very interesting! What I would love to achieve is to be able to move modules into flash. I hope to get two benefits from this: reduce RAM consumption and also reduce code load time when iterating on app code (under the assumption that the modules don't change).

  • This should allow that if each string sent to Modules.addCached is a native string - but the function declarations themselves will stay in RAM, so it's only the code that ends up in flash. In a module with lots of small functions you may not see any difference at all (in fact it could be worse).

    I probably ought to add some code that checks the length of the function. Anything 10 chars or less is better stored in RAM (because the Native String takes up a var anyway).

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

confused about E.memoryArea

Posted by Avatar for tve @tve

Actions