@@ -58,7 +58,8 @@ const unsigned int jsVarsSize = JSVAR_CACHE_SIZE;
5858typedef enum {
5959 MEM_NOT_BUSY ,
6060 MEMBUSY_SYSTEM ,
61- MEMBUSY_GC
61+ MEMBUSY_GC ,
62+ MEMBUSY_DEFRAG
6263} PACKED_FLAGS MemBusyType ;
6364
6465volatile bool touchedFreeList = false;
@@ -4400,18 +4401,20 @@ static void _jsvDefragment_moveReferences(JsVarRef defragFromRef, JsVarRef defra
44004401void jsvDefragment () {
44014402 // https://github.com/espruino/Espruino/issues/1740
44024403 // garbage collect - removes cruft, also puts free list in order
4404+ if (isMemoryBusy ) return 0 ;
44034405 jsvGarbageCollect ();
4404- jshInterruptOff ();
4406+ // Set memory busy so nobody can allocate, and we can defrag with IRQ on
4407+ isMemoryBusy = MEMBUSY_DEFRAG ;
44054408 const unsigned int minMove = 20 ; // don't move vars back less than this or we're just wasting CPU time
44064409 // find last allocated block of memory - speeds up searches!
44074410 unsigned int lastAllocated = 0 ;
44084411 for (JsVarRef i = 1 ;i <=jsVarsSize ;i ++ ) {
44094412 JsVar * v = _jsvGetAddressOf (i );
44104413 if ((v -> flags & JSV_VARTYPEMASK )!= JSV_UNUSED ) {
4414+ lastAllocated = i ;
44114415 if (jsvIsFlatString (v )) {
4412- i += 1 + (unsigned int )jsvGetFlatStringBlocks (v ); // skip forward
4416+ i += (unsigned int )jsvGetFlatStringBlocks (v ); // skip forward (loop will add 1 too)
44134417 }
4414- lastAllocated = i ;
44154418 }
44164419 }
44174420 // the var we're planning on writing to
@@ -4425,8 +4428,8 @@ void jsvDefragment() {
44254428 defragToRef += 1 + (unsigned int )jsvGetFlatStringBlocks (defragTo ); // skip forward
44264429 } else defragToRef ++ ;
44274430 if (defragToRef > lastAllocated ) { // no more free blocks? quit
4431+ isMemoryBusy = MEM_NOT_BUSY ;
44284432 jsvCreateEmptyVarList ();
4429- jshInterruptOn ();
44304433 return ;
44314434 }
44324435 defragTo = _jsvGetAddressOf (defragToRef );
@@ -4435,6 +4438,8 @@ void jsvDefragment() {
44354438 JsVar * defragFrom = _jsvGetAddressOf (defragFromRef );
44364439 if ((defragFrom -> flags & JSV_VARTYPEMASK )!= JSV_UNUSED ) {
44374440 bool canMove = jsvGetLocks (defragFrom )== 0 ;
4441+ if (defragFromRef - defragToRef < 32 )
4442+ canMove = false; // don't bother moving if it's only going to be a short way (other stuff will fill up the gap)
44384443 if (jsvIsFlatString (defragFrom )) {
44394444 unsigned int blocksNeeded = 1 + (unsigned int )jsvGetFlatStringBlocks (defragFrom );
44404445 if (canMove ) { // moving a flat string
@@ -4470,32 +4475,37 @@ void jsvDefragment() {
44704475 if (isClear && (defragFromRef > fsToRef + minMove )) { // can we move it earlier in memory?
44714476 //jsiConsolePrintf("Move FlatString %d -> %d\n", defragFromRef, fsToRef);
44724477 defragTo = _jsvGetAddressOf (fsToRef );
4478+ jshInterruptOff (); // IRQ off while moving - jstimer might be reading vars
44734479 // copy data and clear old var
44744480 memmove (defragTo , defragFrom , sizeof (JsVar )* blocksNeeded );
44754481 memset (defragFrom , 0 , sizeof (JsVar )* blocksNeeded );
44764482 // copy references
44774483 _jsvDefragment_moveReferences (defragFromRef , fsToRef , lastAllocated );
4484+ jshInterruptOn ();
44784485 }
44794486 }
44804487 defragFromRef += blocksNeeded - 1 ; // skip forward (for loop adds 1)
44814488 } else if (canMove ) { // moving a single var
44824489 if (defragFromRef > defragToRef + minMove ) { // can we move it earlier in memory?
44834490 //jsiConsolePrintf("Move JsVar %d -> %d\n", defragFromRef, defragToRef);
44844491 // copy data and clear old var
4492+ jshInterruptOff (); // IRQ off while moving - jstimer might be reading vars
44854493 * defragTo = * defragFrom ;
44864494 memset (defragFrom , 0 , sizeof (JsVar )); // set flags to 0=unused
44874495 // copy references
44884496 _jsvDefragment_moveReferences (defragFromRef , defragToRef , lastAllocated );
4497+ jshInterruptOn ();
44894498 }
44904499 }
44914500 }
44924501 // bump watchdog just in case it took too long
44934502 jshKickWatchDog ();
44944503 jshKickSoftWatchDog ();
44954504 }
4505+ isMemoryBusy = MEM_NOT_BUSY ;
44964506 // rebuild free var list
44974507 jsvCreateEmptyVarList ();
4498- jshInterruptOn ();
4508+
44994509}
45004510#endif
45014511
0 commit comments