Skip to content

Commit 5b75a77

Browse files
authored
Ref-counted stack frames (#140)
1 parent 0d0acb7 commit 5b75a77

File tree

12 files changed

+129
-116
lines changed

12 files changed

+129
-116
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,16 +176,16 @@ fn childFunc(parent: fiber, buf: ^int) {
176176
}
177177
178178
fn parentFunc() {
179-
a := 0
180-
child := fiberspawn(childFunc, &a)
179+
a := new(int)
180+
child := fiberspawn(childFunc, a)
181181
for i := 0; i < 10; i++ {
182-
std.println("Parent: i=" + std.itoa(i) + " buf=" + std.itoa(a))
183-
a = i * 7
182+
std.println("Parent: i=" + std.itoa(i) + " buf=" + std.itoa(a^))
183+
a^ = i * 7
184184
if fiberalive(child) {
185185
fibercall(child)
186186
}
187187
}
188-
}
188+
}
189189
```
190190
## Umka vs Go
191191
### Purpose

doc/lang.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ type FiberFunc = fn(parent: fiber, anyParam: ^T)
734734
fn fiberspawn(childFunc: FiberFunc, anyParam: ^T): fiber
735735
```
736736

737-
Creates a new fiber and assigns `childFunc` as the fiber function. `anyParam` is a pointer to any data buffer that will be passed to `childFunc` .
737+
Creates a new fiber and assigns `childFunc` as the fiber function. `anyParam` is a pointer to heap-allocated data buffer that will be passed to `childFunc` .
738738

739739
```
740740
fn fibercall(child: fiber)

playground/umka.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

projects/umka.cbp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<Option object_output="obj/Debug/" />
1212
<Option type="1" />
1313
<Option compiler="gcc" />
14-
<Option parameters="-warn ../test.um" />
14+
<Option parameters="-warn ../examples/raytracer/raytracer.um" />
1515
<Compiler>
1616
<Add option="-g" />
1717
</Compiler>

src/umka_gen.c

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,6 @@ static void genAddInstr(CodeGen *gen, const Instruction *instr)
4949
}
5050

5151

52-
static bool genNeedHeapFrame(CodeGen *gen, int ipBegin, int ipEnd)
53-
{
54-
// If any ref count is incremented within a function, it needs a heap frame instead of a stack frame
55-
for (int ip = ipBegin; ip < ipEnd; ip++)
56-
if ((gen->code[ip].opcode == OP_CHANGE_REF_CNT && gen->code[ip].tokKind == TOK_PLUSPLUS) || gen->code[ip].opcode == OP_CHANGE_REF_CNT_ASSIGN)
57-
return true;
58-
return false;
59-
}
60-
61-
6252
// Peephole optimizations
6353

6454
static Instruction *getPrevInstr(CodeGen *gen, int depth)
@@ -650,16 +640,16 @@ void genReturn(CodeGen *gen, int paramSlots)
650640
}
651641

652642

653-
void genEnterFrame(CodeGen *gen, int localVarSlots, int paramSlots, bool inHeap)
643+
void genEnterFrame(CodeGen *gen, int localVarSlots)
654644
{
655-
const Instruction instr = {.opcode = OP_ENTER_FRAME, .tokKind = TOK_NONE, .typeKind = inHeap ? TYPE_PTR : TYPE_NONE, .operand.int32Val = {localVarSlots, paramSlots}};
645+
const Instruction instr = {.opcode = OP_ENTER_FRAME, .tokKind = TOK_NONE, TYPE_NONE, .operand.intVal = localVarSlots};
656646
genAddInstr(gen, &instr);
657647
}
658648

659649

660-
void genLeaveFrame(CodeGen *gen, bool inHeap)
650+
void genLeaveFrame(CodeGen *gen)
661651
{
662-
const Instruction instr = {.opcode = OP_LEAVE_FRAME, .tokKind = TOK_NONE, .typeKind = inHeap ? TYPE_PTR : TYPE_NONE, .operand.intVal = 0};
652+
const Instruction instr = {.opcode = OP_LEAVE_FRAME, .tokKind = TOK_NONE, TYPE_NONE, .operand.intVal = 0};
663653
genAddInstr(gen, &instr);
664654
}
665655

@@ -854,17 +844,16 @@ void genEnterFrameStub(CodeGen *gen)
854844
}
855845

856846

857-
void genLeaveFrameFixup(CodeGen *gen, int localVarSlots, int paramSlots)
847+
void genLeaveFrameFixup(CodeGen *gen, int localVarSlots)
858848
{
859849
// Fixup enter stub
860850
int next = gen->ip;
861851
gen->ip = genRestorePos(gen);
862-
bool inHeap = genNeedHeapFrame(gen, gen->ip, next);
863852

864-
genEnterFrame(gen, localVarSlots, paramSlots, inHeap);
853+
genEnterFrame(gen, localVarSlots);
865854
gen->ip = next;
866855

867-
genLeaveFrame(gen, inHeap);
856+
genLeaveFrame(gen);
868857
}
869858

870859

src/umka_gen.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ void genCallExtern (CodeGen *gen, void *entry);
7979
void genCallBuiltin (CodeGen *gen, TypeKind typeKind, BuiltinFunc builtin);
8080
void genReturn (CodeGen *gen, int paramSlots);
8181

82-
void genEnterFrame(CodeGen *gen, int localVarSlots, int paramSlots, bool inHeap);
83-
void genLeaveFrame(CodeGen *gen, bool inHeap);
82+
void genEnterFrame(CodeGen *gen, int localVarSlots);
83+
void genLeaveFrame(CodeGen *gen);
8484

8585
void genHalt(CodeGen *gen);
8686

@@ -112,7 +112,7 @@ void genShortCircuitProlog(CodeGen *gen, TokenKind op);
112112
void genShortCircuitEpilog(CodeGen *gen);
113113

114114
void genEnterFrameStub (CodeGen *gen);
115-
void genLeaveFrameFixup(CodeGen *gen, int localVarSlots, int paramSlots);
115+
void genLeaveFrameFixup(CodeGen *gen, int localVarSlots);
116116

117117
void genEntryPoint(CodeGen *gen, int start);
118118

src/umka_ident.c

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ void identFree(Idents *idents, int startBlock)
3535
{
3636
Ident *next = ident->next;
3737

38-
// Remove heap-allocated globals
39-
if (ident->inHeap)
38+
// Remove globals
39+
if (ident->globallyAllocated)
4040
free(ident->ptr);
4141

4242
free(ident);
@@ -169,14 +169,14 @@ static Ident *identAdd(Idents *idents, Modules *modules, Blocks *blocks, IdentKi
169169

170170
ident->hash = hash(name);
171171

172-
ident->type = type;
173-
ident->module = blocks->module;
174-
ident->block = blocks->item[blocks->top].block;
175-
ident->exported = exported;
176-
ident->inHeap = false;
177-
ident->used = exported || ident->module == 0 || ident->name[0] == '_' || identIsMain(ident); // Exported, predefined, temporary identifiers and main() are always treated as used
178-
ident->prototypeOffset = -1;
179-
ident->next = NULL;
172+
ident->type = type;
173+
ident->module = blocks->module;
174+
ident->block = blocks->item[blocks->top].block;
175+
ident->exported = exported;
176+
ident->globallyAllocated = false;
177+
ident->used = exported || ident->module == 0 || ident->name[0] == '_' || identIsMain(ident); // Exported, predefined, temporary identifiers and main() are always treated as used
178+
ident->prototypeOffset = -1;
179+
ident->next = NULL;
180180

181181
// Add to list
182182
if (!idents->first)
@@ -250,7 +250,7 @@ int identAllocStack(Idents *idents, Types *types, Blocks *blocks, Type *type)
250250
idents->error->handler(idents->error->context, "No heap frame");
251251

252252
*localVarSize = align(*localVarSize + typeSize(types, type), typeAlignment(types, type));
253-
return -(*localVarSize);
253+
return -sizeof(Slot) - (*localVarSize); // One extra slot for the stack frame ref count
254254
}
255255

256256

@@ -261,7 +261,7 @@ Ident *identAllocVar(Idents *idents, Types *types, Modules *modules, Blocks *blo
261261
{
262262
void *ptr = malloc(typeSize(types, type));
263263
ident = identAddGlobalVar(idents, modules, blocks, name, type, exported, ptr);
264-
ident->inHeap = true;
264+
ident->globallyAllocated = true;
265265
}
266266
else // Local
267267
{

src/umka_ident.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ typedef struct tagIdent
2323
unsigned int hash;
2424
Type *type;
2525
int module, block; // Place of definition (global identifiers are in block 0)
26-
bool exported, inHeap, used;
26+
bool exported, globallyAllocated, used;
2727
int prototypeOffset; // For function prototypes
2828
union
2929
{

src/umka_stmt.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ void doResolveExtern(Compiler *comp)
9090

9191
int paramSlots = align(typeParamSizeTotal(&comp->types, &ident->type->sig), sizeof(Slot)) / sizeof(Slot);
9292

93-
genLeaveFrameFixup(&comp->gen, 0, paramSlots);
93+
genLeaveFrameFixup(&comp->gen, 0);
9494
genReturn(&comp->gen, paramSlots);
9595

9696
blocksLeave(&comp->blocks);
@@ -985,7 +985,7 @@ void parseFnBlock(Compiler *comp, Ident *fn)
985985
const int localVarSlots = align(comp->blocks.item[comp->blocks.top].localVarSize, sizeof(Slot)) / sizeof(Slot);
986986
const int paramSlots = align(typeParamSizeTotal(&comp->types, &fn->type->sig), sizeof(Slot)) / sizeof(Slot);
987987

988-
genLeaveFrameFixup(&comp->gen, localVarSlots, paramSlots);
988+
genLeaveFrameFixup(&comp->gen, localVarSlots);
989989
genReturn(&comp->gen, paramSlots);
990990

991991
comp->lex.debug->fnName = prevDebugFnName;

0 commit comments

Comments
 (0)