| commit 20: | 46cf4e66fbcd |
| parent 19: | 6a6759dde047 |
| branch: | default |
Minor changes.
Changed (Δ934 bytes):
raw changeset »
src/ginger.h (73 lines added, 51 lines removed)
1 |
1 |
/* |
2 |
2 |
Copyright 2009 by James Dean Palmer and others. |
3 |
3 |
|
4 |
Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 |
you may not use this file except in compliance with the License. |
|
6 |
You may obtain a copy of the License at |
|
7 |
||
8 |
http://www.apache.org/licenses/LICENSE-2.0 |
|
9 |
||
10 |
Unless required by applicable law or agreed to in writing, software |
|
11 |
distributed under the License is distributed on an "AS IS" BASIS, |
|
12 |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 |
See the License for the specific language governing permissions and |
|
14 |
limitations under the License. |
|
15 |
||
4 |
Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 |
you may not use this file except in compliance with the License. |
|
6 |
You may obtain a copy of the License at |
|
7 |
||
8 |
http://www.apache.org/licenses/LICENSE-2.0 |
|
9 |
||
10 |
Unless required by applicable law or agreed to in writing, software |
|
11 |
distributed under the License is distributed on an "AS IS" BASIS, |
|
12 |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 |
See the License for the specific language governing permissions and |
|
14 |
limitations under the License. |
|
15 |
||
16 |
16 |
Please report all bugs and problems to "bugs@ging3r.org". |
17 |
17 |
*/ |
18 |
18 |
|
19 |
19 |
#ifndef GINGER_H |
20 |
20 |
#define GINGER_H |
21 |
21 |
|
22 |
#define DEBUG |
|
22 |
//#define DEBUG 1 |
|
23 |
23 |
//#define GC_DEBUG |
24 |
24 |
|
25 |
25 |
/// Section 0: Includes |
35 |
35 |
|
36 |
36 |
/// This is the primary reference used internally by Ginger. It can hold |
37 |
37 |
/// immediate (chars, fixed ints, symbols, etc.) and non-immediates (a pointer |
38 |
/// to more complex data structures (foreign objects, floats, dictionaries, |
|
38 |
/// to more complex data structures (foreign objects, floats, dictionaries, |
|
39 |
39 |
/// etc.) |
40 |
40 |
|
41 |
41 |
#define GIN_OBJ void* |
| … | … | @@ -64,6 +64,7 @@ typedef struct { |
64 |
64 |
} Frame_Narg; |
65 |
65 |
|
66 |
66 |
typedef struct { |
67 |
GIN_OBJ dispatch_table; |
|
67 |
68 |
GIN_OBJ type_index; |
68 |
69 |
GIN_OBJ left; |
69 |
70 |
GIN_OBJ right; |
| … | … | @@ -72,6 +73,7 @@ typedef struct { |
72 |
73 |
} GingerDictionaryCell; |
73 |
74 |
|
74 |
75 |
typedef struct { |
76 |
GIN_OBJ dispatch_table; |
|
75 |
77 |
GIN_OBJ type_index; |
76 |
78 |
GIN_OBJ root; |
77 |
79 |
} GingerDictionary; |
| … | … | @@ -85,7 +87,7 @@ typedef struct GingerClassDefinition_t { |
85 |
87 |
GIN_OBJ unmake; |
86 |
88 |
} GingerClassDefinition; |
87 |
89 |
|
88 |
/// Function are first class objects and we have to maintain some metadata |
|
90 |
/// Function are first class objects and we have to maintain some metadata |
|
89 |
91 |
/// for them. |
90 |
92 |
|
91 |
93 |
typedef struct { |
| … | … | @@ -97,6 +99,7 @@ typedef struct { |
97 |
99 |
/// This is the primary object type. |
98 |
100 |
|
99 |
101 |
typedef struct { |
102 |
GIN_OBJ dispatch_table; |
|
100 |
103 |
GIN_OBJ type_index; |
101 |
104 |
union { |
102 |
105 |
void* f0; |
| … | … | @@ -108,67 +111,75 @@ typedef struct { |
108 |
111 |
}; |
109 |
112 |
union { |
110 |
113 |
void* f1; |
114 |
Frame* previous_lexical_frame; |
|
111 |
115 |
}; |
112 |
116 |
union { |
113 |
117 |
void* f2; |
114 |
118 |
long str_length; |
115 |
Frame* previous_lexical_frame; |
|
116 |
119 |
}; |
117 |
120 |
} GingerObject; |
118 |
121 |
|
119 |
122 |
typedef struct { |
123 |
GIN_OBJ dispatch_table; |
|
120 |
124 |
GIN_OBJ type_index; |
121 |
125 |
double value; |
122 |
126 |
} GingerFlonum; |
123 |
127 |
|
124 |
128 |
typedef struct { |
129 |
GIN_OBJ dispatch_table; |
|
125 |
130 |
GIN_OBJ type_index; |
126 |
131 |
long value; |
127 |
132 |
} GingerInteger; |
128 |
133 |
|
129 |
134 |
typedef struct { |
135 |
GIN_OBJ dispatch_table; |
|
130 |
136 |
GIN_OBJ type_index; |
131 |
137 |
unsigned long length; |
132 |
138 |
unsigned long value[]; |
133 |
139 |
} GingerBinary; |
134 |
140 |
|
135 |
141 |
typedef struct { |
142 |
GIN_OBJ dispatch_table; |
|
136 |
143 |
GIN_OBJ type_index; |
137 |
144 |
long length; |
145 |
long pool_length; |
|
138 |
146 |
GIN_OBJ *value; |
139 |
147 |
} GingerVector; |
140 |
148 |
|
141 |
149 |
typedef struct { |
150 |
GIN_OBJ dispatch_table; |
|
142 |
151 |
GIN_OBJ type_index; |
143 |
152 |
GIN_OBJ index; // Always NIM |
144 |
153 |
// GIN_OBJ make; |
145 |
154 |
// GIN_OBJ unmake; |
146 |
155 |
GIN_OBJ(*c_make) (); |
147 |
156 |
void(*c_unmake) (GIN_OBJ); |
148 |
||
157 |
||
149 |
158 |
} GingerType; |
150 |
159 |
|
151 |
160 |
typedef struct { |
152 |
161 |
short num_bytes; |
153 |
162 |
short visited; |
163 |
short active; |
|
154 |
164 |
} GCFastAllocHeader; |
155 |
165 |
|
156 |
166 |
typedef struct GCSysAllocHeader_t { |
157 |
167 |
short num_bytes; |
158 |
168 |
short visited; |
169 |
short active; |
|
159 |
170 |
short requires_cleanup; |
160 |
171 |
struct GCSysAllocHeader_t* next; |
161 |
172 |
} GCSysAllocHeader; |
162 |
173 |
|
163 |
174 |
typedef struct GarbageCollector_t { |
164 |
void* fast_heap_alpha; |
|
165 |
void* fast_heap_beta; |
|
175 |
char* fast_heap_alpha; |
|
176 |
char* fast_heap_beta; |
|
166 |
177 |
|
167 |
178 |
// not set until collection starts |
168 |
void* fast_heap_alpha_end; |
|
169 |
void* fast_heap_beta_end; |
|
179 |
char* fast_heap_alpha_end; |
|
180 |
char* fast_heap_beta_end; |
|
170 |
181 |
|
171 |
|
|
182 |
char* alpha_allocation_cursor; |
|
172 |
183 |
int alpha_remaining_bytes; |
173 |
184 |
|
174 |
185 |
void (*collection_callback)(struct GarbageCollector_t* data); |
| … | … | @@ -197,7 +208,7 @@ typedef struct GarbageCollector_t { |
197 |
208 |
// their cleanup method called. |
198 |
209 |
GCSysAllocHeader* pending_cleanup; |
199 |
210 |
|
200 |
// Items on the persistent_list do not need to be referenced |
|
211 |
// Items on the persistent_list do not need to be referenced |
|
201 |
212 |
// during collections and are only freed at the end of the program. |
202 |
213 |
GCSysAllocHeader* persistent_list; |
203 |
214 |
|
| … | … | @@ -206,16 +217,21 @@ typedef struct GarbageCollector_t { |
206 |
217 |
/// Section 2: Macro definitions |
207 |
218 |
/// |
208 |
219 |
|
209 |
#define GIN_GC_MB 5 |
|
220 |
#define GIN_GC_MB 50 |
|
210 |
221 |
#define GIN_GC_INIT mm = gc_new(1024*1024*GIN_GC_MB); gc_set_collection_callback(mm, collect); |
211 |
222 |
#define GIN_ALLOCATE(v, type, size) safe_allocate = (GIN_OBJ)gc_allocate(mm, size); \ |
212 |
223 |
v = (type)safe_allocate; |
213 |
224 |
|
225 |
#define GIN_ALLOCATE_FRAME(v, type, size) safe_allocate = (GIN_OBJ)gc_allocate_call(mm, size); \ |
|
226 |
v = (type)safe_allocate; |
|
227 |
||
228 |
#define GIN_DEALLOCATE_FRAME(v) gc_deallocate_call(mm, v); |
|
229 |
||
214 |
230 |
#define GIN_ALLOCATE_WITH_CLEANUP(v, type, size) safe_allocate = (GIN_OBJ)gc_allocate_system(mm, size); \ |
215 |
231 |
v = (type)safe_allocate; \ |
216 |
232 |
gc_mark_as_requiring_cleanup(mm, v); |
217 |
233 |
|
218 |
/// Calls are split into two macros. First we allocate the call frame with |
|
234 |
/// Calls are split into two macros. First we allocate the call frame with |
|
219 |
235 |
/// CALL_ALLOCATE. Then you copy any parameters. Then use CALL. |
220 |
236 |
|
221 |
237 |
#define CALL_ALLOCATE(function) \ |
| … | … | @@ -240,11 +256,12 @@ gc_mark_as_requiring_cleanup(mm, v); |
240 |
256 |
position_ ## seed : \ |
241 |
257 |
result0 = frame->next_frame->result; \ |
242 |
258 |
frame->next_frame->previous_frame = 0; \ |
243 |
frame->next_frame |
|
259 |
frame->next_frame->previous_lexical_frame = 0; \ |
|
244 |
260 |
ENDDEBUG \ |
245 |
DEALLOCATE_FRAME___ ## function (frame->next_frame) |
|
261 |
DEALLOCATE_FRAME___ ## function (frame->next_frame) \ |
|
262 |
frame->next_frame = 0; |
|
246 |
263 |
|
247 |
#define CALLN(previous_lframe,function,seed,result0,varn) |
|
264 |
#define CALLN(previous_lframe,function,seed,result0,varn) \ |
|
248 |
265 |
ALLOCATE_FRAME___ ## function (frame->next_frame) \ |
249 |
266 |
frame->next_frame->previous_lexical_frame = previous_lframe; \ |
250 |
267 |
frame->next_frame->previous_frame = frame; \ |
| … | … | @@ -263,13 +280,14 @@ position_ ## seed : \ |
263 |
280 |
position_ ## seed : \ |
264 |
281 |
result0 = frame->next_frame->result; \ |
265 |
282 |
frame->next_frame->previous_frame = 0; \ |
266 |
frame->next_frame = 0; \ |
|
267 |
DEALLOCATE_FRAME___ ## function (frame->next_frame) |
|
283 |
frame->next_frame->previous_lexical_frame = 0; \ |
|
284 |
DEALLOCATE_FRAME___ ## function (frame->next_frame); \ |
|
285 |
frame->next_frame = 0; |
|
268 |
286 |
|
269 |
287 |
// 1. if it's not a function and has no args, return the value. |
270 |
288 |
// 2. if it's not a function and has args - we need to determine the method to call. then do 3. |
271 |
289 |
// 3. if it is a function, use the signature to properly order the arguments and make the call. |
272 |
#define CALLNDYNAMIC(function,seed,result0,varn) |
|
290 |
#define CALLNDYNAMIC(function,seed,result0,varn) \ |
|
273 |
291 |
if ((varn == GIN_NULL) && !(GIN_IS_FUNCTION(function))) result0 = function; \ |
274 |
292 |
else { \ |
275 |
293 |
if (!GIN_IS_FUNCTION(function)) { \ |
| … | … | @@ -294,9 +312,10 @@ position_ ## seed : \ |
294 |
312 |
position_ ## seed : \ |
295 |
313 |
result0 = frame->next_frame->result; \ |
296 |
314 |
frame->next_frame->previous_frame = 0; \ |
315 |
frame->next_frame->previous_lexical_frame = 0; \ |
|
316 |
GIN_DEALLOCATE_FRAME(frame->next_frame); \ |
|
297 |
317 |
frame->next_frame = 0; \ |
298 |
318 |
} |
299 |
//DEALLOCATE_FRAME___ ## function (frame->next_frame) |
|
300 |
319 |
|
301 |
320 |
#define GLOBALS int next_seed = 5000; \ |
302 |
321 |
GIN_OBJ calln_temp; \ |
| … | … | @@ -308,7 +327,7 @@ GIN_OBJ safe_allocate; \ |
308 |
327 |
GarbageCollector* mm; \ |
309 |
328 |
int gin_argc; \ |
310 |
329 |
char **gin_argv; \ |
311 |
int gin_debug = |
|
330 |
int gin_debug = 1; \ |
|
312 |
331 |
int gin_debug_max_depth = -1; \ |
313 |
332 |
int debug_depth = 0; \ |
314 |
333 |
int debug_depth_iterator = 0; \ |
| … | … | @@ -328,19 +347,19 @@ GIN_OBJ ginExec (GIN_OBJ fn, GIN_OBJ arg |
328 |
347 |
|
329 |
348 |
#define END_CODE end_code_return: return frame->result; \ |
330 |
349 |
} \ |
331 |
int main(int argc, char *argv[]) { |
|
350 |
int main(int argc, char *argv[]) { \ |
|
332 |
351 |
gin_argc = argc; \ |
333 |
352 |
gin_argv = argv; \ |
334 |
353 |
GIN_GC_INIT; \ |
335 |
354 |
frame = 0; \ |
336 |
GIN_ALLOCATE(frame, Frame*, sizeof(Frame)); \ |
|
337 |
frame->previous_frame = 0; \ |
|
355 |
GIN_ALLOCATE_FRAME(frame, Frame*, sizeof(Frame)); \ |
|
356 |
frame->previous_frame = 0; \ |
|
338 |
357 |
frame->result = 0; \ |
339 |
358 |
frame->next_frame = 0; \ |
340 |
frame->previous_lexical_frame = 0; |
|
359 |
frame->previous_lexical_frame = 0; \ |
|
341 |
360 |
ginExec(0, GIN_NULL); \ |
342 |
361 |
GIN_OBJ main_fn; \ |
343 |
GIN_NEW_FN(main_fn, &(gin_function_table[0]), 0); |
|
362 |
GIN_NEW_FN(main_fn, &(gin_function_table[0]), 0); \ |
|
344 |
363 |
ginExec(main_fn, GIN_NULL); \ |
345 |
364 |
return 0; \ |
346 |
365 |
} |
| … | … | @@ -350,7 +369,7 @@ int main(int argc, char *argv[]) { \ |
350 |
369 |
#define END_FUNCTION() frame = frame->previous_frame; \ |
351 |
370 |
goto *(frame->next_frame->return_address); |
352 |
371 |
|
353 |
// GIN_OBJ is defined as a void* but in reality it can hold |
|
372 |
// GIN_OBJ is defined as a void* but in reality it can hold |
|
354 |
373 |
// pointers (non-immediates) and certain useful primitives |
355 |
374 |
// (immediates). The following describes how the bit string |
356 |
375 |
// works: |
| … | … | @@ -465,7 +484,7 @@ int main(int argc, char *argv[]) { \ |
465 |
484 |
#define GIN_TYPE_BOOL GIN_IM_FROM_INT(13) |
466 |
485 |
#define GIN_TYPE_NULL GIN_IM_FROM_INT(14) |
467 |
486 |
#define GIN_TYPE_CHAR GIN_IM_FROM_INT(15) |
468 |
//#define GIN_TYPE_FOREIGN |
|
487 |
//#define GIN_TYPE_FOREIGN |
|
469 |
488 |
|
470 |
489 |
/* |
471 |
490 |
#define GIN_TYPE_STR8 1 |
| … | … | @@ -541,11 +560,11 @@ int main(int argc, char *argv[]) { \ |
541 |
560 |
v = safe_pair; |
542 |
561 |
#define GIN_NEW_FIXNUM(v,a) v=GIN_IM_FROM_INT(a); |
543 |
562 |
/* #define GIN_NEW_INTEGER_FROM_INT(v, a) GIN_ALLOCATE_WITH_CLEANUP(v, GingerInteger*, sizeof(GingerInteger)); \ */ |
544 |
/* ((GingerInteger*)v)->type_index = GIN_TYPE_INT; |
|
563 |
/* ((GingerInteger*)v)->type_index = GIN_TYPE_INT; \ */ |
|
545 |
564 |
/* mpz_init_set_si(((GingerInteger*)v)->value, a); */ |
546 |
565 |
/* #define GIN_NEW_INTEGER_FROM_STR(v, a) GIN_ALLOCATE_WITH_CLEANUP(v, GingerInteger*, sizeof(GingerInteger)); \ */ |
547 |
/* ((GingerInteger*)v)->type_index = GIN_TYPE_INT; \ */ |
|
548 |
/* printf("herez!!?\n\n"); \ */ |
|
566 |
/* ((GingerInteger*)v)->type_index = GIN_TYPE_INT; \ */ |
|
567 |
/* printf("herez!!?\n\n"); \ */ |
|
549 |
568 |
/* mpz_init ((((GingerInteger*)v)->value)); */ |
550 |
569 |
/* mpz_init_set_str((((GingerInteger*)v)->value), a, 10); */ |
551 |
570 |
#define GIN_NEW_FN(v,a,frame) GIN_ALLOCATE(v, void*, sizeof(GingerObject)); \ |
| … | … | @@ -563,14 +582,14 @@ memcpy(((GingerObject*)v)->str8_value, a |
563 |
582 |
#define GIN_NEW_EMPTY_STR8(v) GIN_ALLOCATE(v, void*, sizeof(GingerObject)); \ |
564 |
583 |
((GingerObject*)v)->type_index = GIN_TYPE_STR8; \ |
565 |
584 |
((GingerObject*)v)->str_length = 0; |
566 |
#define GIN_NEW_STR16(v,a) GIN_ALLOCATE(v, void*, sizeof(GingerObject)); |
|
585 |
#define GIN_NEW_STR16(v,a) GIN_ALLOCATE(v, void*, sizeof(GingerObject)); \ |
|
567 |
586 |
((GingerObject*)v)->type_index = GIN_TYPE_STR16; \ |
568 |
587 |
((GingerObject*)v)->str16_value = a; |
569 |
588 |
#define GIN_NEW_SYM(v,a) v=GIN_IM_FROM_SYM(a); |
570 |
589 |
#define GIN_NEW_LABEL(v,a) v=GIN_IM_FROM_LABEL(a); |
571 |
590 |
#define GIN_NEW_BOOL(v,a) v=GIN_IM_FROM_BOOL(a); |
572 |
591 |
#define GIN_NEW_OBJ(v,a) v=a; |
573 |
#define GIN_NEW_FLONUM(v,a) GIN_ALLOCATE(v, void*, sizeof(GingerFlonum)); |
|
592 |
#define GIN_NEW_FLONUM(v,a) GIN_ALLOCATE(v, void*, sizeof(GingerFlonum)); \ |
|
574 |
593 |
((GingerFlonum*)v)->type_index = GIN_TYPE_FLONUM; \ |
575 |
594 |
((GingerFlonum*)v)->value = a; |
576 |
595 |
#define GIN_NEW_NIM(v) GIN_ALLOCATE(v, void*, sizeof(GingerObject)); |
| … | … | @@ -604,14 +623,14 @@ GIN_NIM_SET_STREAM_MODE(v,m); |
604 |
623 |
((GingerObject*)v)->type_index = GIN_TYPE_STRING_STREAM; \ |
605 |
624 |
GIN_NIM_SET_STRING_STREAM_LENGTH(v,strlen(s)); \ |
606 |
625 |
GIN_NIM_SET_STRING_STREAM_POSITION(v,0); \ |
607 |
GIN_ALLOCATE(((GingerObject*)v)->str8_value, char*, strlen(s)+1); |
|
626 |
GIN_ALLOCATE(((GingerObject*)v)->str8_value, char*, strlen(s)+1); \ |
|
608 |
627 |
memcpy(((GingerObject*)v)->str8_value, s, strlen(s)+1); |
609 |
628 |
|
610 |
629 |
#define GIN_NEW_EMPTY_STRING_STREAM(v,m) GIN_ALLOCATE(v, void*, sizeof(GingerObject)); \ |
611 |
630 |
((GingerObject*)v)->type_index = GIN_TYPE_STRING_STREAM; \ |
612 |
631 |
GIN_NIM_SET_STRING_STREAM_LENGTH(v,0); \ |
613 |
632 |
GIN_NIM_SET_STRING_STREAM_POSITION(v,0); \ |
614 |
GIN_ALLOCATE(((GingerObject*)v)->str8_value, char*, 1); |
|
633 |
GIN_ALLOCATE(((GingerObject*)v)->str8_value, char*, 1); \ |
|
615 |
634 |
((GingerObject*)v)->str8_value[0] = 0; |
616 |
635 |
|
617 |
636 |
|
| … | … | @@ -684,11 +703,11 @@ GIN_ALLOCATE(v, void*, sizeof(GingerObje |
684 |
703 |
// GC_DEFAULT_FAST_PAGE_SIZE |
685 |
704 |
// |
686 |
705 |
// 5 MB default fast memory page size. Two of these will be |
687 |
// allocated for a total of 10MB. Larger sizes result in less |
|
706 |
// allocated for a total of 10MB. Larger sizes result in less |
|
688 |
707 |
// frequent data collections with no other impact besides |
689 |
708 |
// the use of the memory itself. Smaller allocations are certainly |
690 |
709 |
// viable when memory is tight. |
691 |
#define GC_DEFAULT_FAST_PAGE_SIZE ( |
|
710 |
#define GC_DEFAULT_FAST_PAGE_SIZE (20*1024*1024) |
|
692 |
711 |
|
693 |
712 |
|
694 |
713 |
// GC_FAST_HEAP_THRESHOLD |
| … | … | @@ -701,10 +720,10 @@ GIN_ALLOCATE(v, void*, sizeof(GingerObje |
701 |
720 |
// |
702 |
721 |
// This is also the size limit of how many bytes may need to be |
703 |
722 |
// copied over per single long-lived object. Larger sizes will |
704 |
// make the program faster only IF objects of the larger size |
|
723 |
// make the program faster only IF objects of the larger size |
|
705 |
724 |
// are usually short-lived. If they're more often long-lived, |
706 |
725 |
// the program will run slower due to frequent recopying. |
707 |
// This value should always been some fraction of the |
|
726 |
// This value should always been some fraction of the |
|
708 |
727 |
// fast_heap_page_size - the heap threshold vs the page size |
709 |
728 |
// should be a fraction of (a guess here:) 1/100 or smaller. |
710 |
729 |
#if !defined(GC_FAST_HEAP_THRESHOLD) |
| … | … | @@ -729,6 +748,8 @@ extern void gc_report(GarbageCollector * |
729 |
748 |
extern void gc_mark_as_requiring_cleanup(GarbageCollector *mm, void *m); |
730 |
749 |
extern void* gc_get_next_pending_cleanup(GarbageCollector *mm); |
731 |
750 |
extern void gc_analyze(GarbageCollector* mm, void* addr); |
751 |
extern void* gc_allocate_call(GarbageCollector* mm, int num_bytes); |
|
752 |
extern void gc_deallocate_call(GarbageCollector* mm, void* data); |
|
732 |
753 |
|
733 |
754 |
extern GIN_OBJ ginExec (GIN_OBJ fn, GIN_OBJ args); |
734 |
755 |
extern void GIN_display(GIN_OBJ x, GIN_OBJ out, int was_not_cdr); |
| … | … | @@ -753,6 +774,7 @@ extern void collect (GarbageCollector* m |
753 |
774 |
|
754 |
775 |
extern GIN_OBJ gin_getenv(GIN_OBJ name, GIN_OBJ default_value); |
755 |
776 |
extern GIN_OBJ gin_file_exists(GIN_OBJ filename); |
777 |
extern GIN_OBJ gin_string_to_value(GIN_OBJ str); |
|
756 |
778 |
|
757 |
779 |
/// Section 4: Global variables |
758 |
780 |
/// |
