forked from rui314/minilisp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
68 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#ifndef _MEMORY_H_ | ||
#define _MEMORY_H_ | ||
|
||
#include <stddef.h> | ||
#include <stdbool.h> | ||
#include "minilisp.h" | ||
|
||
//====================================================================== | ||
// Memory management | ||
//====================================================================== | ||
|
||
// The size of the heap in byte | ||
#define MEMORY_SIZE 65536 | ||
|
||
extern void *root; // root of memory | ||
|
||
// Currently we are using Cheney's copying GC algorithm, with which the available memory is split | ||
// into two halves and all objects are moved from one half to another every time GC is invoked. That | ||
// means the address of the object keeps changing. If you take the address of an object and keep it | ||
// in a C variable, dereferencing it could cause SEGV because the address becomes invalid after GC | ||
// runs. | ||
// | ||
// In order to deal with that, all access from C to Lisp objects will go through two levels of | ||
// pointer dereferences. The C local variable is pointing to a pointer on the C stack, and the | ||
// pointer is pointing to the Lisp object. GC is aware of the pointers in the stack and updates | ||
// their contents with the objects' new addresses when GC happens. | ||
// | ||
// The following is a macro to reserve the area in the C stack for the pointers. The contents of | ||
// this area are considered to be GC root. | ||
// | ||
// Be careful not to bypass the two levels of pointer indirections. If you create a direct pointer | ||
// to an object, it'll cause a subtle bug. Such code would work in most cases but fails with SEGV if | ||
// GC happens during the execution of the code. Any code that allocates memory may invoke GC. | ||
|
||
#define ROOT_END ((void *)-1) | ||
|
||
// 初始化 frame (env) 陣列 | ||
#define ADD_ROOT(size) \ | ||
void *root_ADD_ROOT_[size + 2]; \ | ||
root_ADD_ROOT_[0] = root; \ | ||
for (int i = 1; i <= size; i++) \ | ||
root_ADD_ROOT_[i] = NULL; \ | ||
root_ADD_ROOT_[size + 1] = ROOT_END; \ | ||
root = root_ADD_ROOT_ | ||
// 新增 1 個變數物件 | ||
#define DEFINE1(var1) \ | ||
ADD_ROOT(1); \ | ||
Obj **var1 = (Obj **)(root_ADD_ROOT_ + 1) | ||
// 新增 2 個變數物件 | ||
#define DEFINE2(var1, var2) \ | ||
ADD_ROOT(2); \ | ||
Obj **var1 = (Obj **)(root_ADD_ROOT_ + 1); \ | ||
Obj **var2 = (Obj **)(root_ADD_ROOT_ + 2) | ||
// 新增 3 個變數物件 | ||
#define DEFINE3(var1, var2, var3) \ | ||
ADD_ROOT(3); \ | ||
Obj **var1 = (Obj **)(root_ADD_ROOT_ + 1); \ | ||
Obj **var2 = (Obj **)(root_ADD_ROOT_ + 2); \ | ||
Obj **var3 = (Obj **)(root_ADD_ROOT_ + 3) | ||
// 新增 4 個變數物件 | ||
#define DEFINE4(var1, var2, var3, var4) \ | ||
ADD_ROOT(4); \ | ||
Obj **var1 = (Obj **)(root_ADD_ROOT_ + 1); \ | ||
Obj **var2 = (Obj **)(root_ADD_ROOT_ + 2); \ | ||
Obj **var3 = (Obj **)(root_ADD_ROOT_ + 3); \ | ||
Obj **var4 = (Obj **)(root_ADD_ROOT_ + 4) | ||
|
||
#endif |