Skip to content

Commit a675619

Browse files
committed
E.defrag now defrags with interrupts enabled (also fix potential crash with 2 flat strings end to end)
1 parent 19b1170 commit a675619

File tree

2 files changed

+17
-6
lines changed

2 files changed

+17
-6
lines changed

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Espruino Pico: Removed 'tv' library by default to free up flash storage
1212
Fix jshPopIOEventOfType when the event to be popped is right at the start
1313
STM32: Tidy up WAKEUP timer handling to ensure the Wakeup is always the first item in the queue
14+
E.defrag now defrags with interrupts enabled (also fix potential crash with 2 flat strings end to end)
1415

1516
2v28 : Add `E.internal` as a way to access the 'hidden root' containing Espruino internal variables that previously needed `global["\xff"]`
1617
Bangle.js: Fix back handler not removed when using E.setUI with a back button but without widgets (#2636)

src/jsvar.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ const unsigned int jsVarsSize = JSVAR_CACHE_SIZE;
5858
typedef enum {
5959
MEM_NOT_BUSY,
6060
MEMBUSY_SYSTEM,
61-
MEMBUSY_GC
61+
MEMBUSY_GC,
62+
MEMBUSY_DEFRAG
6263
} PACKED_FLAGS MemBusyType;
6364

6465
volatile bool touchedFreeList = false;
@@ -4400,18 +4401,20 @@ static void _jsvDefragment_moveReferences(JsVarRef defragFromRef, JsVarRef defra
44004401
void 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

Comments
 (0)