Skip to content

Commit f019041

Browse files
authored
Merge pull request #4 from NJdevPro/extend
Fix crashes
2 parents 8247af3 + 3225bb5 commit f019041

8 files changed

Lines changed: 469 additions & 523 deletions

File tree

examples/library.lisp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
(defun list (x . y)
66
(cons x y))
77

8-
8+
(defmacro progn (expr . rest)
9+
(list (cons 'lambda (cons () (cons expr rest)))))
10+
911
;; (and e1 e2 ...)
1012
;; => (if e1 (and e2 ...))
1113
;; (and e1)

examples/test

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
; test include
2+
(load "examples/library.lisp")
3+
4+
; Make a set (remove duplicates)
5+
(println(reduce (lambda (acc x)
6+
(if (member acc x)
7+
acc
8+
(cons x acc)))
9+
'(1 2 2 3 1 4 3 5)
10+
()))
11+
12+
; sort
13+
14+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8)))
15+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8 12 35 48 453 75 90 53 90 456785 785 789)))
16+
(println(quicksort (iota 100)))
17+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8)))
18+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8 12 35 48 453 75 90 53 90 456785 785 789)))
19+
(println(quicksort (iota 100)))
20+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8)))
21+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8 12 35 48 453 75 90 53 90 456785 785 789)))
22+
(println(quicksort (reverse (iota 100))))
23+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8)))
24+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8 12 35 48 453 75 90 53 90 456785 785 789)))
25+
(println(reverse (iota 100)))
26+
(println(quicksort (reverse (iota 100))))
27+
28+
(println(reduce (lambda (acc x)
29+
(if (member acc x)
30+
acc
31+
(cons x acc)))
32+
'(1 2 2 3 1 4 3 5)
33+
()))
34+
35+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8)))
36+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8 12 35 48 453 75 90 53 90 456785 785 789)))
37+
(println(quicksort (iota 100)))
38+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8)))
39+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8 12 35 48 453 75 90 53 90 456785 785 789)))
40+
(println(quicksort (iota 100)))
41+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8)))
42+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8 12 35 48 453 75 90 53 90 456785 785 789)))
43+
(println(quicksort (reverse (iota 100))))
44+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8)))
45+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8 12 35 48 453 75 90 53 90 456785 785 789)))
46+
(println(quicksort (reverse (iota 100))))
47+
48+
(println(reduce (lambda (acc x)
49+
(if (member acc x)
50+
acc
51+
(cons x acc)))
52+
'(1 2 2 3 1 4 3 5)
53+
()))
54+
(println(quicksort (iota 100)))
55+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8)))
56+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8 12 35 48 453 75 90 53 90 456785 785 789)))
57+
(println(quicksort (iota 100)))
58+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8)))
59+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8 12 35 48 453 75 90 53 90 456785 785 789)))
60+
(println(quicksort (iota 100)))
61+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8)))
62+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8 12 35 48 453 75 90 53 90 456785 785 789)))
63+
(println(quicksort (reverse (iota 100))))
64+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8)))
65+
(println(quicksort '(3 1 4 1 5 9 2 8 5 3 5 8 9 8 12 35 48 453 75 90 53 90 456785 785 789)))
66+
(println(quicksort (reverse (iota 100))))
67+
68+
(println(reduce (lambda (acc x)
69+
(if (member acc x)
70+
acc
71+
(cons x acc)))
72+
'(1 2 2 3 1 4 3 5)
73+
()))
74+

src/gc.c

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include <sys/mman.h>
77
#include "gc.h"
88

9-
extern __attribute((noreturn)) void error(char *fmt, ...);
9+
extern void error(char *fmt, ...);
1010

1111
// The pointer pointing to the beginning of the current heap
1212
void *memory;
@@ -18,32 +18,30 @@ static void *from_space;
1818
static size_t mem_nused = 0;
1919

2020
// Flags to debug GC
21-
static bool gc_running = false;
22-
static bool debug_gc = false;
23-
static bool always_gc = false;
21+
bool gc_running = false;
22+
bool debug_gc = false;
23+
bool always_gc = false;
2424

2525

2626
// The list containing all symbols. Such data structure is traditionally called the "obarray", but I
2727
// avoid using it as a variable name as this is not an array but a list.
28-
extern Obj *Symbols;
29-
30-
static void gc(void *root); // forward decl
28+
Obj *Symbols;
3129

3230
// Round up the given value to a multiple of size. Size must be a power of 2. It adds size - 1
3331
// first, then zero-ing the least significant bits to make the result a multiple of size. I know
3432
// these bit operations may look a little bit tricky, but it's efficient and thus frequently used.
3533
static inline size_t roundup(size_t var, size_t size) {
36-
return (var + size - 1) & ~(size - 1); // 傳回的大小必須是 2 的次方
34+
return (var + size - 1) & ~(size - 1);
3735
}
3836

3937
// Allocates memory block. This may start GC if we don't have enough memory.
40-
Obj *alloc(void *root, int type, size_t size) { // 分配比 size 大的記憶體給 type 的物件
38+
Obj *alloc(void *root, int type, size_t size) {
4139
// The object must be large enough to contain a pointer for the forwarding pointer. Make it
4240
// larger if it's smaller than that.
4341
size = roundup(size, sizeof(void *));
4442

4543
// Add the size of the type tag and size fields.
46-
size += offsetof(Obj, value); // offsetof 的功能 -- 參考 https://en.cppreference.com/w/cpp/types/offsetof
44+
size += offsetof(Obj, value);
4745

4846
// Round up the object size to the nearest alignment boundary, so that the next object will be
4947
// allocated at the proper alignment boundary. Currently we align the object at the same
@@ -55,20 +53,20 @@ Obj *alloc(void *root, int type, size_t size) { // 分配比 size 大的記憶
5553
// more predictable and repeatable. If there's a memory bug that the C variable has a direct
5654
// reference to a Lisp object, the pointer will become invalid by this GC call. Dereferencing
5755
// that will immediately cause SEGV.
58-
if (always_gc && !gc_running) // 每次分配前都做垃圾收集
56+
if (always_gc && !gc_running)
5957
gc(root);
6058

6159
// Otherwise, run GC only when the available memory is not large enough.
62-
if (!always_gc && MEMORY_SIZE < mem_nused + size) // 只有記憶體不足時才做垃圾收集
60+
if (!always_gc && MEMORY_SIZE < mem_nused + size)
6361
gc(root);
6462

6563
// Terminate the program if we couldn't satisfy the memory request. This can happen if the
6664
// requested size was too large or the from-space was filled with too many live objects.
67-
if (MEMORY_SIZE < mem_nused + size) // heap 記憶體用完了
65+
if (MEMORY_SIZE < mem_nused + size)
6866
error("Memory exhausted");
6967

7068
// Allocate the object.
71-
Obj *obj = memory + mem_nused; // memory: heap 起點 men_nused: 目前用掉的大小。
69+
Obj *obj = memory + mem_nused;
7270
obj->type = type;
7371
obj->size = size;
7472
mem_nused += size;
@@ -84,12 +82,12 @@ Obj *alloc(void *root, int type, size_t size) { // 分配比 size 大的記憶
8482
// to-space. The objects before "scan1" are the objects that are fully copied. The objects between
8583
// "scan1" and "scan2" have already been copied, but may contain pointers to the from-space. "scan2"
8684
// points to the beginning of the free space.
87-
static Obj *scan1; // Cheney 算法請參考 -- https://blog.csdn.net/MrLiii/article/details/113521913
88-
static Obj *scan2; // scan1, scan2 就是上文中的 SCAN 與 Free
85+
static Obj *scan1;
86+
static Obj *scan2;
8987

9088
// Moves one object from the from-space to the to-space. Returns the object's new address. If the
9189
// object has already been moved, does nothing but just returns the new address.
92-
static inline Obj *forward(Obj *obj) { // 將 obj 從 from 區移到 to 區
90+
static inline Obj *forward(Obj *obj) {
9391
// If the object's address is not in the from-space, the object is not managed by GC nor it
9492
// has already been moved to the to-space.
9593
ptrdiff_t offset = (uint8_t *)obj - (uint8_t *)from_space;
@@ -98,29 +96,29 @@ static inline Obj *forward(Obj *obj) { // 將 obj 從 from 區移到 to 區
9896

9997
// The pointer is pointing to the from-space, but the object there was a tombstone. Follow the
10098
// forwarding pointer to find the new location of the object.
101-
if (obj->type == TMOVED) // 已經移過去了,不用再移
99+
if (obj->type == TMOVED)
102100
return obj->moved;
103101

104-
// Otherwise, the object has not been moved yet. Move it. // 還沒移過去,開始移
105-
Obj *newloc = scan2; // 目標位址
106-
memcpy(newloc, obj, obj->size); // 移過去
107-
scan2 = (Obj *)((uint8_t *)scan2 + obj->size); // 將 scan2 往後移動
102+
// Otherwise, the object has not been moved yet. Move it.
103+
Obj *newloc = scan2;
104+
memcpy(newloc, obj, obj->size);
105+
scan2 = (Obj *)((uint8_t *)scan2 + obj->size);
108106

109107
// Put a tombstone at the location where the object used to occupy, so that the following call
110108
// of forward() can find the object's new location.
111-
obj->type = TMOVED; // 標示該物件已完成移動
112-
obj->moved = newloc; // 標示該物件的新位址
113-
return newloc; // 傳回該物件的新位址
109+
obj->type = TMOVED;
110+
obj->moved = newloc;
111+
return newloc;
114112
}
115113

116114
void *alloc_semispace() {
117115
return mmap(NULL, MEMORY_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
118116
}
119117

120-
// Copies the root objects. // 移動 root 環境的物件
118+
// Copies the root objects.
121119
static void forward_root_objects(void *root) {
122-
Symbols = forward(Symbols); // 移動符號表到新記憶體區
123-
for (void **frame = root; frame; frame = *(void ***)frame) // 移動 frame 到新記憶體區
120+
Symbols = forward(Symbols);
121+
for (void **frame = root; frame; frame = *(void ***)frame)
124122
for (int i = 1; frame[i] != ROOT_END; i++)
125123
if (frame[i])
126124
frame[i] = forward(frame[i]);
@@ -135,14 +133,14 @@ static bool getEnvFlag(char *name) {
135133

136134
// Implements Cheney's copying garbage collection algorithm.
137135
// http://en.wikipedia.org/wiki/Cheney%27s_algorithm
138-
static void gc(void *root) {
136+
void gc(void *root) {
139137
assert(!gc_running);
140138
gc_running = true; // 開始垃圾蒐集
141139

142140
// Debug flags
143141
debug_gc = getEnvFlag("MINILISP_DEBUG_GC");
144142
always_gc = getEnvFlag("MINILISP_ALWAYS_GC");
145-
143+
146144
// Allocate a new semi-space.
147145
from_space = memory;
148146
memory = alloc_semispace();
@@ -151,40 +149,40 @@ static void gc(void *root) {
151149
scan1 = scan2 = memory;
152150

153151
// Copy the GC root objects first. This moves the pointer scan2.
154-
forward_root_objects(root); // 移動 root 環境的物件
152+
forward_root_objects(root);
155153

156154
// Copy the objects referenced by the GC root objects located between scan1 and scan2. Once it's
157155
// finished, all live objects (i.e. objects reachable from the root) will have been copied to
158156
// the to-space.
159-
while (scan1 < scan2) { // 將 root 指向的物件從 scan1 (FROM) 搬到 scan2 (to) 去
157+
while (scan1 < scan2) {
160158
switch (scan1->type) {
161159
case TINT:
162-
case TSTRING:
163160
case TSYMBOL:
164161
case TPRIMITIVE:
162+
case TSTRING:
165163
// Any of the above types does not contain a pointer to a GC-managed object.
166164
break;
167165
case TCELL:
168-
scan1->car = forward(scan1->car); // 每個 list 的 car, cdr 都搬到新位址
166+
scan1->car = forward(scan1->car);
169167
scan1->cdr = forward(scan1->cdr);
170168
break;
171169
case TFUNCTION:
172170
case TMACRO:
173-
scan1->params = forward(scan1->params); // 每個 macro 的 params, body, env 都搬到新位址
171+
scan1->params = forward(scan1->params);
174172
scan1->body = forward(scan1->body);
175173
scan1->env = forward(scan1->env);
176174
break;
177175
case TENV:
178-
scan1->vars = forward(scan1->vars); // 每個 env 的 vars, up 都搬到新位址
176+
scan1->vars = forward(scan1->vars);
179177
scan1->up = forward(scan1->up);
180178
break;
181179
default:
182180
error("Bug: copy: unknown type %d", scan1->type);
183181
}
184-
scan1 = (Obj *)((uint8_t *)scan1 + scan1->size); // 前進到下一個物件
182+
scan1 = (Obj *)((uint8_t *)scan1 + scan1->size);
185183
}
186184

187-
// Finish up GC. // 結束垃圾蒐集
185+
// Finish up GC.
188186
munmap(from_space, MEMORY_SIZE);
189187
size_t old_nused = mem_nused;
190188
mem_nused = (size_t)((uint8_t *)scan1 - (uint8_t *)memory);

src/gc.h

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
//======================================================================
1111

1212
// The size of the heap in byte
13-
#define MEMORY_SIZE 262144
13+
#define MEMORY_SIZE 65536 * 4
1414

15-
extern void *root; // root of memory
15+
extern void *gc_root; // root of memory
1616

1717
// Currently we are using Cheney's copying GC algorithm, with which the available memory is split
1818
// into two halves and all objects are moved from one half to another every time GC is invoked. That
@@ -34,35 +34,43 @@ extern void *root; // root of memory
3434

3535
#define ROOT_END ((void *)-1)
3636

37-
// 初始化 frame (env) 陣列
38-
#define ADD_ROOT(size) \
39-
void *root_ADD_ROOT_[size + 2]; \
40-
root_ADD_ROOT_[0] = root; \
41-
for (int i = 1; i <= size; i++) \
42-
root_ADD_ROOT_[i] = NULL; \
43-
root_ADD_ROOT_[size + 1] = ROOT_END; \
44-
root = root_ADD_ROOT_
45-
// 新增 1 個變數物件
46-
#define DEFINE1(var1) \
47-
ADD_ROOT(1); \
48-
Obj **var1 = (Obj **)(root_ADD_ROOT_ + 1)
49-
// 新增 2 個變數物件
50-
#define DEFINE2(var1, var2) \
51-
ADD_ROOT(2); \
52-
Obj **var1 = (Obj **)(root_ADD_ROOT_ + 1); \
53-
Obj **var2 = (Obj **)(root_ADD_ROOT_ + 2)
54-
// 新增 3 個變數物件
55-
#define DEFINE3(var1, var2, var3) \
56-
ADD_ROOT(3); \
57-
Obj **var1 = (Obj **)(root_ADD_ROOT_ + 1); \
58-
Obj **var2 = (Obj **)(root_ADD_ROOT_ + 2); \
59-
Obj **var3 = (Obj **)(root_ADD_ROOT_ + 3)
60-
// 新增 4 個變數物件
61-
#define DEFINE4(var1, var2, var3, var4) \
62-
ADD_ROOT(4); \
63-
Obj **var1 = (Obj **)(root_ADD_ROOT_ + 1); \
64-
Obj **var2 = (Obj **)(root_ADD_ROOT_ + 2); \
65-
Obj **var3 = (Obj **)(root_ADD_ROOT_ + 3); \
66-
Obj **var4 = (Obj **)(root_ADD_ROOT_ + 4)
67-
68-
#endif
37+
static inline void** add_root_frame(void **prev_frame, int size, void *frame[]) {
38+
frame[0] = prev_frame;
39+
for (int i = 1; i <= size; i++)
40+
frame[i] = NULL;
41+
frame[size + 1] = ROOT_END;
42+
return frame;
43+
}
44+
45+
#define DEFINE1(prev_frame, var1) \
46+
void *root_frame[3]; \
47+
prev_frame = add_root_frame(prev_frame, 1, root_frame); \
48+
Obj **var1 = (Obj **)(root_frame + 1);
49+
50+
#define DEFINE2(prev_frame, var1, var2) \
51+
void *root_frame[4]; \
52+
prev_frame = add_root_frame(prev_frame, 2, root_frame); \
53+
Obj **var1 = (Obj **)(root_frame + 1); \
54+
Obj **var2 = (Obj **)(root_frame + 2);
55+
56+
#define DEFINE3(prev_frame, var1, var2, var3) \
57+
void *root_frame[5]; \
58+
prev_frame = add_root_frame(prev_frame, 3, root_frame); \
59+
Obj **var1 = (Obj **)(root_frame + 1); \
60+
Obj **var2 = (Obj **)(root_frame + 2); \
61+
Obj **var3 = (Obj **)(root_frame + 3);
62+
63+
#define DEFINE4(prev_frame, var1, var2, var3, var4) \
64+
void *root_frame[6]; \
65+
prev_frame = add_root_frame(prev_frame, 4, root_frame); \
66+
Obj **var1 = (Obj **)(root_frame + 1); \
67+
Obj **var2 = (Obj **)(root_frame + 2); \
68+
Obj **var3 = (Obj **)(root_frame + 3); \
69+
Obj **var4 = (Obj **)(root_frame + 4);
70+
71+
72+
void *alloc_semispace();
73+
Obj *alloc(void *root, int type, size_t size);
74+
void gc(void *root);
75+
76+
#endif

0 commit comments

Comments
 (0)