Merge: doc: fixed some typos and other misc. corrections
[nit.git] / clib / nit_main.c
1 /* This file is part of NIT ( http://www.nitlanguage.org ).
2 *
3 * Copyright 2006-2009 Jean Privat <jean@pryen.org>
4 *
5 * This file is free software, which comes along with NIT. This software is
6 * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
7 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
8 * PARTICULAR PURPOSE. You can modify it is you want, provided this header
9 * is kept unaltered, and a notification of the changes is added.
10 * You are allowed to redistribute it and sell it, alone or is a part of
11 * another product.
12 */
13
14 #include "nit_common.h"
15 #include <signal.h>
16 #include <stdarg.h>
17 #include "gc.h"
18
19 #ifdef ANDROID
20 #include <android/log.h>
21 #define PRINT_ERROR(...) ((void)__android_log_print(ANDROID_LOG_WARN, "nit", __VA_ARGS__))
22 #else
23 #define PRINT_ERROR(...) ((void)fprintf(stderr, __VA_ARGS__))
24 #endif
25
26 bigint object_id_counter = 1000000;
27 enum gc_option { large, gc_opt_malloc, boehm, nitgc } gc_option;
28
29 #ifdef WITH_LIBGC
30 #define GC_DEBUG
31 #include <gc/gc.h>
32 #endif
33
34 void *raw_alloc(size_t s0)
35 {
36 switch (gc_option) {
37 case nitgc: return malloc(s0);
38 case gc_opt_malloc: return malloc(s0);
39 default: return alloc(s0);
40 }
41 }
42
43 void register_static_object(val_t *o)
44 {
45 switch (gc_option) {
46 case nitgc: GC_add_static_object(o); break;
47 default: break;
48 }
49 return;
50 }
51
52 void *large_alloc(size_t s0)
53 {
54 static char * alloc_pos = NULL;
55 static size_t alloc_size = 0;
56 void * res;
57 size_t s = ((s0+3)/4)*4;
58 if(alloc_size < s) {
59 alloc_size = s + 1024*1024;
60 alloc_pos = (char *)calloc(alloc_size, 1);
61 }
62 res = alloc_pos;
63 alloc_size -= s;
64 alloc_pos += s;
65 return res;
66 }
67
68 void * alloc(size_t s0)
69 {
70 switch (gc_option) {
71 #ifdef WITH_LIBGC
72 case boehm: return GC_MALLOC(s0);
73 #endif
74 case nitgc: return Nit_gc_malloc(s0);
75 case gc_opt_malloc: return calloc(1, s0);
76 case large:
77 default: return large_alloc(s0);
78 }
79 }
80
81 int glob_argc;
82 char **glob_argv;
83 val_t G_sys;
84
85 void exithandler(int s) {
86 PRINT_ERROR( "Recieved signal %d\n", s);
87 nit_exit(1);
88 }
89 void initialize_gc_option(void) {
90 /* GC default */
91 char *def;
92 gc_option = nitgc;
93 def = "nitgc";
94
95 /* Process GC runtime selection */
96 if (getenv("NIT_GC_OPTION") != NULL) {
97 char *opt=getenv("NIT_GC_OPTION");
98 if (strcmp(opt, "boehm")==0) {
99 #ifdef WITH_LIBGC
100 gc_option = boehm;
101 #else
102 PRINT_ERROR( "Compiled without Boehm GC support. Using default '%s'.\n", def);
103 #endif
104 } else if (strcmp(opt, "nitgc")==0) {
105 gc_option = nitgc;
106 } else if (strcmp(opt, "malloc")==0) {
107 gc_option = gc_opt_malloc;
108 } else if (strcmp(opt, "large")==0) {
109 gc_option = large;
110 } else if (strcmp(opt, "help")==0) {
111 PRINT_ERROR( "NIT_GC_OPTION accepts 'nitgc'"
112 #ifdef WITH_LIBGC
113 ", 'boehm'"
114 #endif
115 ", 'large', 'malloc'. Default is '%s'.\n", def);
116 exit(1);
117 } else {
118 PRINT_ERROR( "Invalid GC option in NIT_GC_OPTION environment variable. Using default '%s'.\n", def);
119 }
120 }
121
122 /* Initialize GC (if needed) */
123 switch(gc_option) {
124 #ifdef WITH_LIBGC
125 case boehm: GC_INIT(); break;
126 #endif
127 case nitgc: Nit_gc_init(); break;
128 default: break; /* Nothing */
129 }
130
131 /* Initialize global references list */
132 nitni_global_ref_list_init();
133 }
134 void prepare_signals(void) {
135 initialize_gc_option();
136
137 signal(SIGINT,exithandler);
138 signal(SIGABRT,exithandler);
139 signal(SIGSEGV,exithandler);
140 signal(SIGILL, exithandler);
141 signal(SIGFPE, exithandler);
142 signal(SIGTERM,exithandler);
143 signal(SIGBUS, exithandler);
144 }
145 struct stack_frame_t *stack_frame_head = NULL;
146 void nit_exit(int i) {
147 char *opt=getenv("NIT_NO_STACK");
148 if (opt == NULL || strcmp(opt, "0")==0) {
149 PRINT_ERROR( ",---- Stack trace -- - - -\n");
150 while(stack_frame_head != NULL) {
151 PRINT_ERROR( "| %s (%s:%d)\n", stack_frame_head->meth, stack_frame_head->file, stack_frame_head->line);
152 if (stack_frame_head == stack_frame_head->prev) break;
153 stack_frame_head = stack_frame_head->prev;
154 }
155 PRINT_ERROR( "`------------------- - - -\n");
156 }
157 exit(i);
158 }
159
160 void nit_abort(const char* s, const char* msg, const char* loc, int line) {
161 PRINT_ERROR( "Runtime error: ");
162 PRINT_ERROR( s, msg);
163 PRINT_ERROR( " (%s", loc);
164 if (line != 0) PRINT_ERROR( ":%d", line);
165 PRINT_ERROR( ")\n");
166 nit_exit(1);
167 }
168
169 /* Register reference to Nit object with the latest extern method called. */
170 void nitni_local_ref_add( struct nitni_ref *ref ) {
171 struct nitni_ref_array_link **link_p;
172 struct nitni_ref_array_link * link = NULL;
173
174 /* find usable link or link to create */
175 link_p = &( stack_frame_head->nitni_local_ref_head );
176 while ( (*link_p) != NULL &&
177 (*link_p)->count >= NITNI_REF_ARRAY_LINK_SIZE ) {
178 link_p = &((*link_p)->next);
179 }
180
181 /* create link if needed */
182 if ( *link_p == NULL ) {
183 link = malloc( sizeof(struct nitni_ref_array_link) );
184 link->count = 0;
185 link->next = NULL;
186
187 (*link_p) = link;
188 } else {
189 link = *link_p;
190 }
191
192 /* add to link */
193 link->reg[ link->count ] = ref;
194 link->count ++;
195 }
196
197 /* Clean all references associated to the current (but returning) extern method. */
198 void nitni_local_ref_clean( void ) {
199 struct nitni_ref_array_link * link,
200 * last_link;
201 int i;
202
203 link = stack_frame_head->nitni_local_ref_head;
204 while ( link != NULL )
205 {
206 for ( i = 0; i < link->count; i ++ ) {
207 if ( link->reg[i]->count == 0 ) { /* not registered globally */
208 free( link->reg[ i ] );
209 }
210 }
211
212 last_link = link;
213 if ( link->count == NITNI_REF_ARRAY_LINK_SIZE )
214 link = link->next;
215 else
216 link = NULL;
217
218 free(last_link);
219 }
220
221 stack_frame_head->nitni_local_ref_head = NULL;
222 }
223
224 struct nitni_global_ref_list_t *nitni_global_ref_list;
225 void nitni_global_ref_list_init() {
226 nitni_global_ref_list = (struct nitni_global_ref_list_t*)malloc(sizeof(struct nitni_global_ref_list_t));
227 nitni_global_ref_list->head = NULL;
228 nitni_global_ref_list->tail = NULL;
229 }
230
231 void nitni_global_ref_add( struct nitni_ref *ref ) {
232 if ( nitni_global_ref_list->head == NULL ) {
233 nitni_global_ref_list->head = ref;
234 ref->prev = NULL;
235 } else {
236 nitni_global_ref_list->tail->next = ref;
237 ref->prev = nitni_global_ref_list->tail;
238 }
239 nitni_global_ref_list->tail = ref;
240
241 ref->next = NULL;
242 }
243
244 void nitni_global_ref_remove( struct nitni_ref *ref ) {
245 if ( ref->prev == NULL ) {
246 nitni_global_ref_list->head = ref->next;
247 } else {
248 ref->prev->next = ref->next;
249 }
250
251 if ( ref->next == NULL ) {
252 nitni_global_ref_list->tail = ref->prev;
253 } else {
254 ref->next->prev = ref->prev;
255 }
256 }
257
258 extern void nitni_global_ref_incr( struct nitni_ref *ref ) {
259 if ( ref->count == 0 ) /* not registered */
260 {
261 /* add to list */
262 nitni_global_ref_add( ref );
263 }
264
265 ref->count ++;
266 }
267
268 extern void nitni_global_ref_decr( struct nitni_ref *ref ) {
269 if ( ref->count == 1 ) /* was last reference */
270 {
271 /* remove from list */
272 nitni_global_ref_remove( ref );
273 }
274
275 ref->count --;
276 }