ArachnidAbby / BCL

BCL Compiled Language (BCL)
https://discord.gg/sShr7fMNFn
GNU General Public License v3.0
21 stars 0 forks source link

[BUG] Compiler needs to call destructors after each loop iteration #20

Open ArachnidAbby opened 10 months ago

ArachnidAbby commented 10 months ago

Describe the bug After an iteration of a loop, the compiler should run destructors for all local variables and constants. Otherwise, objects that need destruction are overwritten in memory and unable to be accessed for destruction at the end of the loop.

To Reproduce

for _ in 0..10 {
    Box::<i32>::new(0);
    // This will create a `%"CONST.1" = alloca @"thisModule.STRUCT.Box::<i32>"`
    //   instruction used for destruction later, issue being we override the value constantly without calling destructors.
    //   The same happens with vars. This must be fixed in all types of loops.
}

Expected behavior destructors get called after each loop iteration, for local vars and temp vars.

platform information

compiler-version: >=0.7.0 (on all version that include destructors)
os: platform-independent

Additional context This will require blocks to have access to all consts the allocate. Adding a "is_destructed" flag to vars and consts/temp vars would be wise here.

ArachnidAbby commented 10 months ago

btw, the fix was pretty simple. (although i have yet to 100% ensure its all working).

Essentially an aditional block is used when iterating. this causes more jumps to be created, but not really a big deal. LLVM probably optimizes it as well (since an extra jump isn't technically required if codegened properly by llvm).

This is what loops used to look like (roughly):

entry:
    ; code used elsewhere
    %"cond" = ; do condition
    br %"cond", label %"entry.for", label %"entry.endfor" ; jump into loop body or skip
entry.for:
    ; code inside loop body
    %"cond" = ; do condition
    br %"cond", label %"entry.for", label %"entry.endfor" ; loop or exit
entry.endfor:
    ; code after loop

now they look like:

entry:
    ; code used elsewhere
    %"cond" = ; do condition
    br %"cond", label %"entry.for", label %"entry.endfor" ; jump into loop body or skip
entry.pre_loop:
    ; destructor calls for the for-body
    br label %"entry.for" ; jump to loop body
entry.for:
    ; code inside loop body
    %"cond" = ; do condition
    br %"cond", label %"entry.pre_for", label %"entry.endfor" ; jump to destructor calls or exit loop
entry.endfor:
    ; code after loop

This should mean that destructors wont get called on the first iteration (there is nothing to destruct yet!) and also not on the last iteration (destruction needs to happen at the end of the function for these variables/values since we can allow local variables to break scope by using references).