1 /*
2  * Copyright (c) 2005
3  *      David Leonard.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of David Leonard nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #if HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 
35 #if STDC_HEADERS
36 # include <stdio.h>
37 # include <stdlib.h>
38 #endif
39 
40 #if HAVE_TIME
41 # if TIME_WITH_SYS_TIME
42 #  include <sys/time.h>
43 #  include <time.h>
44 # else
45 #  if HAVE_SYS_TIME_H
46 #   include <sys/time.h>
47 #  else
48 #   include <time.h>
49 #  endif
50 # endif
51 #endif
52 
53 #if WITH_BOEHM_GC
54 # include <gc/gc.h>
55 #endif
56 
57 #include <see/interpreter.h>
58 #include <see/system.h>
59 
60 #include "dprint.h"
61 #include "platform.h"
62 #include "code.h"
63 #include "regex.h"
64 
65 /* Prototypes */
66 static unsigned int simple_random_seed(void);
67 #if WITH_BOEHM_GC
68 static void *simple_gc_malloc(struct SEE_interpreter *, SEE_size_t,
69 	const char *, int);
70 static void *simple_gc_malloc_string(struct SEE_interpreter *, SEE_size_t,
71 	const char *, int);
72 static void *simple_gc_malloc_finalize(struct SEE_interpreter *, SEE_size_t,
73         void (*)(struct SEE_interpreter *, void *, void *), void *,
74 		const char *, int);
75 static void simple_gc_free(struct SEE_interpreter *, void *,
76 	const char *, int);
77 static void simple_gc_finalizer(void *, void *);
78 static void simple_gc_gcollect(struct SEE_interpreter *);
79 #else
80 static void *simple_malloc(struct SEE_interpreter *, SEE_size_t,
81 	const char *, int);
82 static void *simple_malloc_finalize(struct SEE_interpreter *, SEE_size_t,
83         void (*)(struct SEE_interpreter *, void *, void *), void *,
84 		const char *, int);
85 static void simple_free(struct SEE_interpreter *, void *,
86 	const char *, int);
87 static void simple_finalize_all(void);
88 #endif
89 static void simple_mem_exhausted(struct SEE_interpreter *) SEE_dead;
90 
91 /*
92  * System defaults. This structure should be not be modified after
93  * interpreters are created.
94  */
95 struct SEE_system SEE_system = {
96 	NULL,				/* default_locale */
97 	-1,				/* default_recursion_limit */
98 	NULL,				/* default_trace */
99 
100 	SEE_COMPAT_262_3B, 		/* default_compat_flags */
101 
102 	simple_random_seed,		/* random_seed */
103 
104 	_SEE_platform_abort,		/* abort */
105 	NULL,				/* periodic */
106 
107 #if WITH_BOEHM_GC
108 	simple_gc_malloc,		/* malloc */
109 	simple_gc_malloc_finalize,	/* malloc_finalize */
110 	simple_gc_malloc_string,	/* malloc_string */
111 	simple_gc_free,			/* free */
112 	simple_mem_exhausted,		/* mem_exhausted */
113 	simple_gc_gcollect,		/* gcollect */
114 #else
115 	simple_malloc,			/* malloc */
116 	simple_malloc_finalize,		/* malloc_finalize */
117 	simple_malloc,			/* malloc_string */
118 	simple_free,			/* free */
119 	simple_mem_exhausted,		/* mem_exhausted */
120 	NULL,				/* gcollect */
121 #endif
122 	NULL,				/* transit_sec_domain */
123 #if WITH_PARSER_CODEGEN
124 	_SEE_code1_alloc,		/* code_alloc */
125 #else
126 	NULL,            		/* code_alloc */
127 #endif
128 	NULL,				/* object_construct */
129 	&_SEE_ecma_regex_engine		/* default_regex_engine */
130 };
131 
132 /*
133  * A simple random number seed generator. It is not thread safe.
134  */
135 static unsigned int
simple_random_seed()136 simple_random_seed()
137 {
138 	static unsigned int counter = 0;
139 	unsigned int r;
140 
141 	r = counter++;
142 #if HAVE_TIME
143 	r += (unsigned int)time(0);
144 #endif
145 	return r;
146 }
147 
148 /*
149  * A simple memory exhausted handler.
150  */
151 static void
simple_mem_exhausted(interp)152 simple_mem_exhausted(interp)
153 	struct SEE_interpreter *interp;
154 {
155 	SEE_ABORT(interp, "memory exhausted");
156 }
157 
158 
159 #if WITH_BOEHM_GC
160 
161 /* Redefine GC_EXTRAS as a quick, happy way to pass through the file,line */
162 #undef GC_EXTRAS
163 #ifdef GC_ADD_CALLER
164 #  define GC_EXTRAS GC_RETURN_ADDR, file, line
165 #else
166 #  define GC_EXTRAS file, line
167 #endif
168 
169 /*
170  * Memory allocator using Boehm GC
171  */
172 static void *
simple_gc_malloc(interp,size,file,line)173 simple_gc_malloc(interp, size, file, line)
174 	struct SEE_interpreter *interp;
175 	SEE_size_t size;
176 	const char *file;
177 	int line;
178 {
179 	return GC_MALLOC(size);
180 }
181 
182 /*
183  * A private structure to hold finalization info. This is appended onto
184  * objects that are allocated with finalization requirements.
185  */
186 struct finalize_info {
187 	struct SEE_interpreter *interp;
188         void (*finalizefn)(struct SEE_interpreter *, void *, void *);
189 	void *closure;
190 };
191 
192 static void
simple_gc_finalizer(p,cd)193 simple_gc_finalizer(p, cd)
194 	void *p;
195 	void *cd;
196 {
197 	struct finalize_info *info =
198 	    (struct finalize_info *)((char *)p + (SEE_size_t)cd);
199 
200 	(*info->finalizefn)(info->interp, (void *)p, info->closure);
201 }
202 
203 static void *
simple_gc_malloc_finalize(interp,size,finalizefn,closure,file,line)204 simple_gc_malloc_finalize(interp, size, finalizefn, closure, file, line)
205 	struct SEE_interpreter *interp;
206 	SEE_size_t size;
207         void (*finalizefn)(struct SEE_interpreter *, void *, void *);
208 	void *closure;
209 	const char *file;
210 	int line;
211 {
212 	SEE_size_t padsz;
213 	void *data;
214 	struct finalize_info *info;
215 
216 	/* Round up to align the finalize_info */
217 	padsz = size;
218 	padsz += sizeof (struct finalize_info) - 1;
219 	padsz -= padsz % sizeof (struct finalize_info);
220 
221 	/* Allocate, with space for the finalize_info */
222 	data = GC_MALLOC(padsz + sizeof (struct finalize_info));
223 
224 	/* Fill in the finalize_info now */
225 	info = (struct finalize_info *)((char *)data + padsz);
226 	info->interp = interp;
227 	info->finalizefn = finalizefn;
228 	info->closure = closure;
229 
230 	/* Ask the GC to call the finalizer when data is unreachable */
231 	GC_REGISTER_FINALIZER(data, simple_gc_finalizer, (void *)padsz, NULL, NULL);
232 
233 	return data;
234 }
235 
236 /*
237  * Non-pointer memory allocator using Boehm GC
238  */
239 static void *
simple_gc_malloc_string(interp,size,file,line)240 simple_gc_malloc_string(interp, size, file, line)
241 	struct SEE_interpreter *interp;
242 	SEE_size_t size;
243 	const char *file;
244 	int line;
245 {
246 	return GC_MALLOC_ATOMIC(size);
247 }
248 
249 /*
250  * Non-pointer memory allocator using Boehm GC
251  */
252 static void
simple_gc_free(interp,ptr,file,line)253 simple_gc_free(interp, ptr, file, line)
254 	struct SEE_interpreter *interp;
255 	void *ptr;
256 	const char *file;
257 	int line;
258 {
259 	GC_FREE(ptr);
260 }
261 
262 static void
simple_gc_gcollect(interp)263 simple_gc_gcollect(interp)
264 	struct SEE_interpreter *interp;
265 {
266 	GC_gcollect();
267 }
268 
269 #else /* !WITH_BOEHM_GC */
270 
271 
272 /*
273  * Memory allocator using system malloc().
274  * Note: most mallocs do not get freed!
275  * System strongly assumes a garbage collector.
276  * This is a stub function.
277  */
278 static void *
simple_malloc(interp,size,file,line)279 simple_malloc(interp, size, file, line)
280 	struct SEE_interpreter *interp;
281 	SEE_size_t size;
282 	const char *file;
283 	int line;
284 {
285 #ifndef NDEBUG
286 	static int warning_printed = 0;
287 
288 	if (!warning_printed) {
289 		warning_printed++;
290 		dprintf("WARNING: SEE is using non-release malloc\n");
291 	}
292 
293 #endif
294 	return malloc(size);
295 }
296 
297 /* Linked list of all finalizers to run on exit */
298 static struct finalize_entry {
299 	struct SEE_interpreter *interp;
300 	void *ptr;
301 	void (*finalizefn)(struct SEE_interpreter *, void *, void *);
302 	void *closure;
303 	struct finalize_entry *next;
304 } *simple_finalize_list;
305 
306 /* Runs all the finalizers */
307 static void
simple_finalize_all()308 simple_finalize_all()
309 {
310 	struct finalize_entry *entry;
311 #ifndef NDEBUG
312 	extern int SEE_mem_debug;
313 #endif
314 
315 #ifndef NDEBUG
316 	if (SEE_mem_debug)
317 	    dprintf("Running finalizers\n");
318 #endif
319 
320 	while (simple_finalize_list) {
321 	    entry = simple_finalize_list;
322 	    simple_finalize_list = entry->next;
323 	    (*entry->finalizefn)(entry->interp, entry->ptr, entry->closure);
324 	    free(entry);
325 	}
326 }
327 
328 static void *
simple_malloc_finalize(interp,size,finalizefn,closure,file,line)329 simple_malloc_finalize(interp, size, finalizefn, closure, file, line)
330 	struct SEE_interpreter *interp;
331 	SEE_size_t size;
332         void (*finalizefn)(struct SEE_interpreter *, void *, void *);
333 	void *closure;
334 	const char *file;
335 	int line;
336 {
337 	static int called = 0;
338 	struct finalize_entry *entry;
339 	void *ptr;
340 
341 	ptr = malloc(size);
342 	if (!ptr)
343 	    return NULL;
344 
345 	/* Record the finalization function to call at exit */
346 	entry = (struct finalize_entry *)malloc(sizeof *entry);
347 	if (entry) {
348 	    entry->interp = interp;
349 	    entry->ptr = ptr;
350 	    entry->finalizefn = finalizefn;
351 	    entry->closure = closure;
352 	    /* Insert at head of list */
353 	    entry->next = simple_finalize_list;
354 	    simple_finalize_list = entry;
355 	    /* Set up finalizers to be run during exit() */
356 	    if (!called) {
357 		called = 1;
358 		atexit(simple_finalize_all);
359 	    }
360 	}
361 
362 	return ptr;
363 }
364 
365 /*
366  * Memory deallocator using system free().
367  */
368 static void
simple_free(interp,ptr,file,line)369 simple_free(interp, ptr, file, line)
370 	struct SEE_interpreter *interp;
371 	void *ptr;
372 	const char *file;
373 	int line;
374 {
375 	free(ptr);
376 }
377 
378 #endif /* !WITH_BOEHM_GC */
379 
380 
381 /* Reserved for future use */
382 void
SEE_init()383 SEE_init()
384 {
385 	static int initialised = 0;
386 
387 	if (initialised)
388 	    return;
389 	initialised = 1;
390 
391 	SEE_regex_init();
392 }
393