1 /* This file is part of NIT ( http://www.nitlanguage.org ).
3 * Copyright 2006-2009 Jean Privat <jean@pryen.org>
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
14 #include "nit_common.h"
20 #include <android/log.h>
21 #define PRINT_ERROR(...) ((void)__android_log_print(ANDROID_LOG_WARN, "nit", __VA_ARGS__))
23 #define PRINT_ERROR(...) ((void)fprintf(stderr, __VA_ARGS__))
26 bigint object_id_counter
= 1000000;
27 enum gc_option
{ large
, gc_opt_malloc
, boehm
, nitgc
} gc_option
;
34 void *raw_alloc(size_t s0
)
37 case nitgc
: return malloc(s0
);
38 case gc_opt_malloc
: return malloc(s0
);
39 default: return alloc(s0
);
43 void register_static_object(val_t
*o
)
46 case nitgc
: GC_add_static_object(o
); break;
52 void *large_alloc(size_t s0
)
54 static char * alloc_pos
= NULL
;
55 static size_t alloc_size
= 0;
57 size_t s
= ((s0
+3)/4)*4;
59 alloc_size
= s
+ 1024*1024;
60 alloc_pos
= (char *)calloc(alloc_size
, 1);
68 void * alloc(size_t s0
)
72 case boehm
: return GC_MALLOC(s0
);
74 case nitgc
: return Nit_gc_malloc(s0
);
75 case gc_opt_malloc
: return calloc(1, s0
);
77 default: return large_alloc(s0
);
85 void exithandler(int s
) {
86 PRINT_ERROR( "Recieved signal %d\n", s
);
89 void initialize_gc_option(void) {
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) {
102 PRINT_ERROR( "Compiled without Boehm GC support. Using default '%s'.\n", def
);
104 } else if (strcmp(opt
, "nitgc")==0) {
106 } else if (strcmp(opt
, "malloc")==0) {
107 gc_option
= gc_opt_malloc
;
108 } else if (strcmp(opt
, "large")==0) {
110 } else if (strcmp(opt
, "help")==0) {
111 PRINT_ERROR( "NIT_GC_OPTION accepts 'nitgc'"
115 ", 'large', 'malloc'. Default is '%s'.\n", def
);
118 PRINT_ERROR( "Invalid GC option in NIT_GC_OPTION environment variable. Using default '%s'.\n", def
);
122 /* Initialize GC (if needed) */
125 case boehm
: GC_INIT(); break;
127 case nitgc
: Nit_gc_init(); break;
128 default: break; /* Nothing */
131 /* Initialize global references list */
132 nitni_global_ref_list_init();
134 void prepare_signals(void) {
135 initialize_gc_option();
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
);
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
;
155 PRINT_ERROR( "`------------------- - - -\n");
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
);
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
;
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
);
181 /* create link if needed */
182 if ( *link_p
== NULL
) {
183 link
= malloc( sizeof(struct nitni_ref_array_link
) );
193 link
->reg
[ link
->count
] = ref
;
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
,
203 link
= stack_frame_head
->nitni_local_ref_head
;
204 while ( link
!= NULL
)
206 for ( i
= 0; i
< link
->count
; i
++ ) {
207 if ( link
->reg
[i
]->count
== 0 ) { /* not registered globally */
208 free( link
->reg
[ i
] );
213 if ( link
->count
== NITNI_REF_ARRAY_LINK_SIZE
)
221 stack_frame_head
->nitni_local_ref_head
= NULL
;
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
;
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
;
236 nitni_global_ref_list
->tail
->next
= ref
;
237 ref
->prev
= nitni_global_ref_list
->tail
;
239 nitni_global_ref_list
->tail
= ref
;
244 void nitni_global_ref_remove( struct nitni_ref
*ref
) {
245 if ( ref
->prev
== NULL
) {
246 nitni_global_ref_list
->head
= ref
->next
;
248 ref
->prev
->next
= ref
->next
;
251 if ( ref
->next
== NULL
) {
252 nitni_global_ref_list
->tail
= ref
->prev
;
254 ref
->next
->prev
= ref
->prev
;
258 extern void nitni_global_ref_incr( struct nitni_ref
*ref
) {
259 if ( ref
->count
== 0 ) /* not registered */
262 nitni_global_ref_add( ref
);
268 extern void nitni_global_ref_decr( struct nitni_ref
*ref
) {
269 if ( ref
->count
== 1 ) /* was last reference */
271 /* remove from list */
272 nitni_global_ref_remove( ref
);