mirror of
https://github.com/justinethier/cyclone.git
synced 2025-07-14 00:07:36 +02:00
Merge branch 'gc-opt5-dev'
This commit is contained in:
commit
884a4a1c08
7 changed files with 761 additions and 303 deletions
129
examples/threading/benchmarks/ctak.scm
Normal file
129
examples/threading/benchmarks/ctak.scm
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
;;; CTAK -- A version of the TAK procedure that uses continuations.
|
||||||
|
|
||||||
|
(import (scheme base) (scheme read) (scheme write) (scheme time) (srfi 18))
|
||||||
|
|
||||||
|
(define (ctak x y z)
|
||||||
|
(call-with-current-continuation
|
||||||
|
(lambda (k) (ctak-aux k x y z))))
|
||||||
|
|
||||||
|
(define (ctak-aux k x y z)
|
||||||
|
(if (not (< y x))
|
||||||
|
(k z)
|
||||||
|
(call-with-current-continuation
|
||||||
|
(lambda (k)
|
||||||
|
(ctak-aux
|
||||||
|
k
|
||||||
|
(call-with-current-continuation
|
||||||
|
(lambda (k) (ctak-aux k (- x 1) y z)))
|
||||||
|
(call-with-current-continuation
|
||||||
|
(lambda (k) (ctak-aux k (- y 1) z x)))
|
||||||
|
(call-with-current-continuation
|
||||||
|
(lambda (k) (ctak-aux k (- z 1) x y))))))))
|
||||||
|
|
||||||
|
(define (main)
|
||||||
|
(let* ((count (read))
|
||||||
|
(input1 (read))
|
||||||
|
(input2 (read))
|
||||||
|
(input3 (read))
|
||||||
|
(output (read))
|
||||||
|
(s4 (number->string count))
|
||||||
|
(s3 (number->string input3))
|
||||||
|
(s2 (number->string input2))
|
||||||
|
(s1 (number->string input1))
|
||||||
|
(name "ctak"))
|
||||||
|
(run-r7rs-benchmark
|
||||||
|
(string-append name ":" s1 ":" s2 ":" s3 ":" s4)
|
||||||
|
count
|
||||||
|
(lambda ()
|
||||||
|
#;(thread-start!
|
||||||
|
(make-thread
|
||||||
|
(lambda ()
|
||||||
|
(ctak (hide count input1) (hide count input2) (hide count input3)))))
|
||||||
|
#;(thread-start!
|
||||||
|
(make-thread
|
||||||
|
(lambda ()
|
||||||
|
(ctak (hide count input1) (hide count input2) (hide count input3)))))
|
||||||
|
#;(thread-start!
|
||||||
|
(make-thread
|
||||||
|
(lambda ()
|
||||||
|
(ctak (hide count input1) (hide count input2) (hide count input3)))))
|
||||||
|
(thread-start!
|
||||||
|
(make-thread
|
||||||
|
(lambda ()
|
||||||
|
(ctak (hide count input1) (hide count input2) (hide count input3)))))
|
||||||
|
(thread-sleep! 10000)
|
||||||
|
(ctak (hide count input1) (hide count input2) (hide count input3))
|
||||||
|
|
||||||
|
;; TODO: thread-join
|
||||||
|
)
|
||||||
|
(lambda (result) (equal? result output)))))
|
||||||
|
|
||||||
|
;;; The following code is appended to all benchmarks.
|
||||||
|
|
||||||
|
;;; Given an integer and an object, returns the object
|
||||||
|
;;; without making it too easy for compilers to tell
|
||||||
|
;;; the object will be returned.
|
||||||
|
|
||||||
|
(define (hide r x)
|
||||||
|
(call-with-values
|
||||||
|
(lambda ()
|
||||||
|
(values (vector values (lambda (x) x))
|
||||||
|
(if (< r 100) 0 1)))
|
||||||
|
(lambda (v i)
|
||||||
|
((vector-ref v i) x))))
|
||||||
|
|
||||||
|
;;; Given the name of a benchmark,
|
||||||
|
;;; the number of times it should be executed,
|
||||||
|
;;; a thunk that runs the benchmark once,
|
||||||
|
;;; and a unary predicate that is true of the
|
||||||
|
;;; correct results the thunk may return,
|
||||||
|
;;; runs the benchmark for the number of specified iterations.
|
||||||
|
|
||||||
|
(define (run-r7rs-benchmark name count thunk ok?)
|
||||||
|
|
||||||
|
;; Rounds to thousandths.
|
||||||
|
(define (rounded x)
|
||||||
|
(/ (round (* 1000 x)) 1000))
|
||||||
|
|
||||||
|
(display "Running ")
|
||||||
|
(display name)
|
||||||
|
(newline)
|
||||||
|
(flush-output-port (current-output-port))
|
||||||
|
(let* ((j/s (jiffies-per-second))
|
||||||
|
(t0 (current-second))
|
||||||
|
(j0 (current-jiffy)))
|
||||||
|
(let loop ((i 0)
|
||||||
|
(result #f))
|
||||||
|
(cond ((< i count)
|
||||||
|
(loop (+ i 1) (thunk)))
|
||||||
|
((ok? result)
|
||||||
|
(let* ((j1 (current-jiffy))
|
||||||
|
(t1 (current-second))
|
||||||
|
(jifs (- j1 j0))
|
||||||
|
(secs (inexact (/ jifs j/s)))
|
||||||
|
(secs2 (rounded (- t1 t0))))
|
||||||
|
(display "Elapsed time: ")
|
||||||
|
(write secs)
|
||||||
|
(display " seconds (")
|
||||||
|
(write secs2)
|
||||||
|
(display ") for ")
|
||||||
|
(display name)
|
||||||
|
(newline)
|
||||||
|
(display "+!CSVLINE!+")
|
||||||
|
(display (this-scheme-implementation-name))
|
||||||
|
(display ",")
|
||||||
|
(display name)
|
||||||
|
(display ",")
|
||||||
|
(display secs)
|
||||||
|
(newline)
|
||||||
|
(flush-output-port (current-output-port)))
|
||||||
|
result)
|
||||||
|
(else
|
||||||
|
(display "ERROR: returned incorrect result: ")
|
||||||
|
(write result)
|
||||||
|
(newline)
|
||||||
|
(flush-output-port (current-output-port))
|
||||||
|
result)))))
|
||||||
|
(define (this-scheme-implementation-name)
|
||||||
|
(string-append "cyclone-" (Cyc-version)))
|
||||||
|
(main)
|
270
examples/threading/benchmarks/paraffins.scm
Normal file
270
examples/threading/benchmarks/paraffins.scm
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
;;; PARAFFINS -- Compute how many paraffins exist with N carbon atoms.
|
||||||
|
|
||||||
|
(import (scheme base) (scheme read) (scheme write) (scheme time) (srfi 18))
|
||||||
|
|
||||||
|
;;; This benchmark uses the following R6RS procedures.
|
||||||
|
|
||||||
|
(define (div x y)
|
||||||
|
(quotient x y))
|
||||||
|
|
||||||
|
;;; End of (faked) R6RS procedures.
|
||||||
|
|
||||||
|
(define (gen n)
|
||||||
|
(let* ((n/2 (div n 2))
|
||||||
|
(radicals (make-vector (+ n/2 1) '(H))))
|
||||||
|
|
||||||
|
(define (rads-of-size n)
|
||||||
|
(let loop1 ((ps
|
||||||
|
(three-partitions (- n 1)))
|
||||||
|
(lst
|
||||||
|
'()))
|
||||||
|
(if (null? ps)
|
||||||
|
lst
|
||||||
|
(let* ((p (car ps))
|
||||||
|
(nc1 (vector-ref p 0))
|
||||||
|
(nc2 (vector-ref p 1))
|
||||||
|
(nc3 (vector-ref p 2)))
|
||||||
|
(let loop2 ((rads1
|
||||||
|
(vector-ref radicals nc1))
|
||||||
|
(lst
|
||||||
|
(loop1 (cdr ps)
|
||||||
|
lst)))
|
||||||
|
(if (null? rads1)
|
||||||
|
lst
|
||||||
|
(let loop3 ((rads2
|
||||||
|
(if (= nc1 nc2)
|
||||||
|
rads1
|
||||||
|
(vector-ref radicals nc2)))
|
||||||
|
(lst
|
||||||
|
(loop2 (cdr rads1)
|
||||||
|
lst)))
|
||||||
|
(if (null? rads2)
|
||||||
|
lst
|
||||||
|
(let loop4 ((rads3
|
||||||
|
(if (= nc2 nc3)
|
||||||
|
rads2
|
||||||
|
(vector-ref radicals nc3)))
|
||||||
|
(lst
|
||||||
|
(loop3 (cdr rads2)
|
||||||
|
lst)))
|
||||||
|
(if (null? rads3)
|
||||||
|
lst
|
||||||
|
(cons (vector 'C
|
||||||
|
(car rads1)
|
||||||
|
(car rads2)
|
||||||
|
(car rads3))
|
||||||
|
(loop4 (cdr rads3)
|
||||||
|
lst))))))))))))
|
||||||
|
|
||||||
|
(define (bcp-generator j)
|
||||||
|
(if (odd? j)
|
||||||
|
'()
|
||||||
|
(let loop1 ((rads1
|
||||||
|
(vector-ref radicals (div j 2)))
|
||||||
|
(lst
|
||||||
|
'()))
|
||||||
|
(if (null? rads1)
|
||||||
|
lst
|
||||||
|
(let loop2 ((rads2
|
||||||
|
rads1)
|
||||||
|
(lst
|
||||||
|
(loop1 (cdr rads1)
|
||||||
|
lst)))
|
||||||
|
(if (null? rads2)
|
||||||
|
lst
|
||||||
|
(cons (vector 'BCP
|
||||||
|
(car rads1)
|
||||||
|
(car rads2))
|
||||||
|
(loop2 (cdr rads2)
|
||||||
|
lst))))))))
|
||||||
|
|
||||||
|
(define (ccp-generator j)
|
||||||
|
(let loop1 ((ps
|
||||||
|
(four-partitions (- j 1)))
|
||||||
|
(lst
|
||||||
|
'()))
|
||||||
|
(if (null? ps)
|
||||||
|
lst
|
||||||
|
(let* ((p (car ps))
|
||||||
|
(nc1 (vector-ref p 0))
|
||||||
|
(nc2 (vector-ref p 1))
|
||||||
|
(nc3 (vector-ref p 2))
|
||||||
|
(nc4 (vector-ref p 3)))
|
||||||
|
(let loop2 ((rads1
|
||||||
|
(vector-ref radicals nc1))
|
||||||
|
(lst
|
||||||
|
(loop1 (cdr ps)
|
||||||
|
lst)))
|
||||||
|
(if (null? rads1)
|
||||||
|
lst
|
||||||
|
(let loop3 ((rads2
|
||||||
|
(if (= nc1 nc2)
|
||||||
|
rads1
|
||||||
|
(vector-ref radicals nc2)))
|
||||||
|
(lst
|
||||||
|
(loop2 (cdr rads1)
|
||||||
|
lst)))
|
||||||
|
(if (null? rads2)
|
||||||
|
lst
|
||||||
|
(let loop4 ((rads3
|
||||||
|
(if (= nc2 nc3)
|
||||||
|
rads2
|
||||||
|
(vector-ref radicals nc3)))
|
||||||
|
(lst
|
||||||
|
(loop3 (cdr rads2)
|
||||||
|
lst)))
|
||||||
|
(if (null? rads3)
|
||||||
|
lst
|
||||||
|
(let loop5 ((rads4
|
||||||
|
(if (= nc3 nc4)
|
||||||
|
rads3
|
||||||
|
(vector-ref radicals nc4)))
|
||||||
|
(lst
|
||||||
|
(loop4 (cdr rads3)
|
||||||
|
lst)))
|
||||||
|
(if (null? rads4)
|
||||||
|
lst
|
||||||
|
(cons (vector 'CCP
|
||||||
|
(car rads1)
|
||||||
|
(car rads2)
|
||||||
|
(car rads3)
|
||||||
|
(car rads4))
|
||||||
|
(loop5 (cdr rads4)
|
||||||
|
lst))))))))))))))
|
||||||
|
|
||||||
|
(let loop ((i 1))
|
||||||
|
(if (> i n/2)
|
||||||
|
(vector (bcp-generator n)
|
||||||
|
(ccp-generator n))
|
||||||
|
(begin
|
||||||
|
(vector-set! radicals i (rads-of-size i))
|
||||||
|
(loop (+ i 1)))))))
|
||||||
|
|
||||||
|
(define (three-partitions m)
|
||||||
|
(let loop1 ((lst '())
|
||||||
|
(nc1 (div m 3)))
|
||||||
|
(if (< nc1 0)
|
||||||
|
lst
|
||||||
|
(let loop2 ((lst lst)
|
||||||
|
(nc2 (div (- m nc1) 2)))
|
||||||
|
(if (< nc2 nc1)
|
||||||
|
(loop1 lst
|
||||||
|
(- nc1 1))
|
||||||
|
(loop2 (cons (vector nc1 nc2 (- m (+ nc1 nc2))) lst)
|
||||||
|
(- nc2 1)))))))
|
||||||
|
|
||||||
|
(define (four-partitions m)
|
||||||
|
(let loop1 ((lst '())
|
||||||
|
(nc1 (div m 4)))
|
||||||
|
(if (< nc1 0)
|
||||||
|
lst
|
||||||
|
(let loop2 ((lst lst)
|
||||||
|
(nc2 (div (- m nc1) 3)))
|
||||||
|
(if (< nc2 nc1)
|
||||||
|
(loop1 lst
|
||||||
|
(- nc1 1))
|
||||||
|
(let ((start (max nc2 (- (div (+ m 1) 2) (+ nc1 nc2)))))
|
||||||
|
(let loop3 ((lst lst)
|
||||||
|
(nc3 (div (- m (+ nc1 nc2)) 2)))
|
||||||
|
(if (< nc3 start)
|
||||||
|
(loop2 lst (- nc2 1))
|
||||||
|
(loop3 (cons (vector nc1 nc2 nc3 (- m (+ nc1 (+ nc2 nc3)))) lst)
|
||||||
|
(- nc3 1))))))))))
|
||||||
|
|
||||||
|
(define (nb n)
|
||||||
|
(let ((x (gen n)))
|
||||||
|
(+ (length (vector-ref x 0))
|
||||||
|
(length (vector-ref x 1)))))
|
||||||
|
|
||||||
|
(define (main)
|
||||||
|
(let* ((count (read))
|
||||||
|
(input1 (read))
|
||||||
|
(output (read))
|
||||||
|
(s2 (number->string count))
|
||||||
|
(s1 (number->string input1))
|
||||||
|
(name "paraffins"))
|
||||||
|
(run-r7rs-benchmark
|
||||||
|
(string-append name ":" s1 ":" s2)
|
||||||
|
count
|
||||||
|
(lambda ()
|
||||||
|
#;(thread-start!
|
||||||
|
(make-thread
|
||||||
|
(lambda ()
|
||||||
|
(nb (hide count input1)))))
|
||||||
|
(thread-start!
|
||||||
|
(make-thread
|
||||||
|
(lambda ()
|
||||||
|
(nb (hide count input1)))))
|
||||||
|
(nb (hide count input1))
|
||||||
|
)
|
||||||
|
(lambda (result) (= result output)))))
|
||||||
|
|
||||||
|
;;; The following code is appended to all benchmarks.
|
||||||
|
|
||||||
|
;;; Given an integer and an object, returns the object
|
||||||
|
;;; without making it too easy for compilers to tell
|
||||||
|
;;; the object will be returned.
|
||||||
|
|
||||||
|
(define (hide r x)
|
||||||
|
(call-with-values
|
||||||
|
(lambda ()
|
||||||
|
(values (vector values (lambda (x) x))
|
||||||
|
(if (< r 100) 0 1)))
|
||||||
|
(lambda (v i)
|
||||||
|
((vector-ref v i) x))))
|
||||||
|
|
||||||
|
;;; Given the name of a benchmark,
|
||||||
|
;;; the number of times it should be executed,
|
||||||
|
;;; a thunk that runs the benchmark once,
|
||||||
|
;;; and a unary predicate that is true of the
|
||||||
|
;;; correct results the thunk may return,
|
||||||
|
;;; runs the benchmark for the number of specified iterations.
|
||||||
|
|
||||||
|
(define (run-r7rs-benchmark name count thunk ok?)
|
||||||
|
|
||||||
|
;; Rounds to thousandths.
|
||||||
|
(define (rounded x)
|
||||||
|
(/ (round (* 1000 x)) 1000))
|
||||||
|
|
||||||
|
(display "Running ")
|
||||||
|
(display name)
|
||||||
|
(newline)
|
||||||
|
(flush-output-port (current-output-port))
|
||||||
|
(let* ((j/s (jiffies-per-second))
|
||||||
|
(t0 (current-second))
|
||||||
|
(j0 (current-jiffy)))
|
||||||
|
(let loop ((i 0)
|
||||||
|
(result #f))
|
||||||
|
(cond ((< i count)
|
||||||
|
(loop (+ i 1) (thunk)))
|
||||||
|
((ok? result)
|
||||||
|
(let* ((j1 (current-jiffy))
|
||||||
|
(t1 (current-second))
|
||||||
|
(jifs (- j1 j0))
|
||||||
|
(secs (inexact (/ jifs j/s)))
|
||||||
|
(secs2 (rounded (- t1 t0))))
|
||||||
|
(display "Elapsed time: ")
|
||||||
|
(write secs)
|
||||||
|
(display " seconds (")
|
||||||
|
(write secs2)
|
||||||
|
(display ") for ")
|
||||||
|
(display name)
|
||||||
|
(newline)
|
||||||
|
(display "+!CSVLINE!+")
|
||||||
|
(display (this-scheme-implementation-name))
|
||||||
|
(display ",")
|
||||||
|
(display name)
|
||||||
|
(display ",")
|
||||||
|
(display secs)
|
||||||
|
(newline)
|
||||||
|
(flush-output-port (current-output-port)))
|
||||||
|
result)
|
||||||
|
(else
|
||||||
|
(display "ERROR: returned incorrect result: ")
|
||||||
|
(write result)
|
||||||
|
(newline)
|
||||||
|
(flush-output-port (current-output-port))
|
||||||
|
result)))))
|
||||||
|
(define (this-scheme-implementation-name)
|
||||||
|
(string-append "cyclone-" (Cyc-version)))
|
||||||
|
(main)
|
432
gc.c
432
gc.c
|
@ -55,12 +55,11 @@ static void **mark_stack = NULL;
|
||||||
static int mark_stack_len = 0;
|
static int mark_stack_len = 0;
|
||||||
static int mark_stack_i = 0;
|
static int mark_stack_i = 0;
|
||||||
|
|
||||||
// Lock to protect the heap from concurrent modifications
|
// Data for the "main" thread which is guaranteed to always be there.
|
||||||
static pthread_mutex_t heap_lock;
|
// Per SRFI 18:
|
||||||
|
// All threads are terminated when the primordial
|
||||||
// Cached heap statistics
|
// thread terminates (normally or not).
|
||||||
static int cached_heap_free_sizes[7] = { 0, 0, 0, 0, 0, 0, 0 };
|
static gc_thread_data *primordial_thread = NULL;
|
||||||
static int cached_heap_total_sizes[7] = { 0, 0, 0, 0, 0, 0, 0 };
|
|
||||||
|
|
||||||
// Data for each individual mutator thread
|
// Data for each individual mutator thread
|
||||||
ck_array_t Cyc_mutators, old_mutators;
|
ck_array_t Cyc_mutators, old_mutators;
|
||||||
|
@ -144,10 +143,6 @@ void gc_initialize()
|
||||||
mark_stack = vpbuffer_realloc(mark_stack, &(mark_stack_len));
|
mark_stack = vpbuffer_realloc(mark_stack, &(mark_stack_len));
|
||||||
|
|
||||||
// Here is as good a place as any to do this...
|
// Here is as good a place as any to do this...
|
||||||
if (pthread_mutex_init(&(heap_lock), NULL) != 0) {
|
|
||||||
fprintf(stderr, "Unable to initialize heap_lock mutex\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (pthread_mutex_init(&(mutators_lock), NULL) != 0) {
|
if (pthread_mutex_init(&(mutators_lock), NULL) != 0) {
|
||||||
fprintf(stderr, "Unable to initialize mutators_lock mutex\n");
|
fprintf(stderr, "Unable to initialize mutators_lock mutex\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -164,6 +159,11 @@ void gc_add_mutator(gc_thread_data * thd)
|
||||||
}
|
}
|
||||||
ck_array_commit(&Cyc_mutators);
|
ck_array_commit(&Cyc_mutators);
|
||||||
pthread_mutex_unlock(&mutators_lock);
|
pthread_mutex_unlock(&mutators_lock);
|
||||||
|
|
||||||
|
// Main thread is always the first one added
|
||||||
|
if (primordial_thread == NULL) {
|
||||||
|
primordial_thread = thd;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove selected mutator from the mutator list.
|
// Remove selected mutator from the mutator list.
|
||||||
|
@ -211,8 +211,11 @@ void gc_free_old_thread_data()
|
||||||
pthread_mutex_unlock(&mutators_lock);
|
pthread_mutex_unlock(&mutators_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new heap page. The caller must hold the necessary locks.
|
||||||
|
*/
|
||||||
gc_heap *gc_heap_create(int heap_type, size_t size, size_t max_size,
|
gc_heap *gc_heap_create(int heap_type, size_t size, size_t max_size,
|
||||||
size_t chunk_size)
|
size_t chunk_size, gc_thread_data *thd)
|
||||||
{
|
{
|
||||||
gc_free_list *free, *next;
|
gc_free_list *free, *next;
|
||||||
gc_heap *h;
|
gc_heap *h;
|
||||||
|
@ -222,12 +225,12 @@ gc_heap *gc_heap_create(int heap_type, size_t size, size_t max_size,
|
||||||
return NULL;
|
return NULL;
|
||||||
h->type = heap_type;
|
h->type = heap_type;
|
||||||
h->size = size;
|
h->size = size;
|
||||||
h->newly_created = 1;
|
h->ttl = 10;
|
||||||
h->next_free = h;
|
h->next_free = h;
|
||||||
h->last_alloc_size = 0;
|
h->last_alloc_size = 0;
|
||||||
//h->free_size = size;
|
//h->free_size = size;
|
||||||
cached_heap_total_sizes[heap_type] += size;
|
ck_pr_add_ptr(&(thd->cached_heap_total_sizes[heap_type]), size);
|
||||||
cached_heap_free_sizes[heap_type] += size;
|
ck_pr_add_ptr(&(thd->cached_heap_free_sizes[heap_type]), size);
|
||||||
h->chunk_size = chunk_size;
|
h->chunk_size = chunk_size;
|
||||||
h->max_size = max_size;
|
h->max_size = max_size;
|
||||||
h->data = (char *)gc_heap_align(sizeof(h->data) + (uintptr_t) & (h->data));
|
h->data = (char *)gc_heap_align(sizeof(h->data) + (uintptr_t) & (h->data));
|
||||||
|
@ -263,7 +266,7 @@ gc_heap *gc_heap_free(gc_heap *page, gc_heap *prev_page)
|
||||||
{
|
{
|
||||||
// At least for now, do not free first page
|
// At least for now, do not free first page
|
||||||
if (prev_page == NULL || page == NULL) {
|
if (prev_page == NULL || page == NULL) {
|
||||||
return page;
|
return NULL;
|
||||||
}
|
}
|
||||||
#if GC_DEBUG_TRACE
|
#if GC_DEBUG_TRACE
|
||||||
fprintf(stderr, "DEBUG freeing heap type %d page at addr: %p\n", page->type, page);
|
fprintf(stderr, "DEBUG freeing heap type %d page at addr: %p\n", page->type, page);
|
||||||
|
@ -474,11 +477,11 @@ char *gc_copy_obj(object dest, char *obj, gc_thread_data * thd)
|
||||||
return (char *)obj;
|
return (char *)obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gc_grow_heap(gc_heap * h, int heap_type, size_t size, size_t chunk_size)
|
int gc_grow_heap(gc_heap * h, int heap_type, size_t size, size_t chunk_size, gc_thread_data *thd)
|
||||||
{
|
{
|
||||||
size_t /*cur_size,*/ new_size;
|
size_t /*cur_size,*/ new_size;
|
||||||
gc_heap *h_last = h, *h_new;
|
gc_heap *h_last = h, *h_new;
|
||||||
pthread_mutex_lock(&heap_lock);
|
pthread_mutex_lock(&(thd->heap_lock));
|
||||||
// Compute size of new heap page
|
// Compute size of new heap page
|
||||||
if (heap_type == HEAP_HUGE) {
|
if (heap_type == HEAP_HUGE) {
|
||||||
new_size = gc_heap_align(size) + 128;
|
new_size = gc_heap_align(size) + 128;
|
||||||
|
@ -493,6 +496,9 @@ int gc_grow_heap(gc_heap * h, int heap_type, size_t size, size_t chunk_size)
|
||||||
if (new_size < HEAP_SIZE) {
|
if (new_size < HEAP_SIZE) {
|
||||||
new_size = prev_size + h_last->size;
|
new_size = prev_size + h_last->size;
|
||||||
prev_size = h_last->size;
|
prev_size = h_last->size;
|
||||||
|
if (new_size > HEAP_SIZE) {
|
||||||
|
new_size = HEAP_SIZE;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
new_size = HEAP_SIZE;
|
new_size = HEAP_SIZE;
|
||||||
}
|
}
|
||||||
|
@ -516,9 +522,9 @@ int gc_grow_heap(gc_heap * h, int heap_type, size_t size, size_t chunk_size)
|
||||||
// allocate larger pages if size will not fit on the page
|
// allocate larger pages if size will not fit on the page
|
||||||
//new_size = gc_heap_align(((cur_size > size) ? cur_size : size));
|
//new_size = gc_heap_align(((cur_size > size) ? cur_size : size));
|
||||||
// Done with computing new page size
|
// Done with computing new page size
|
||||||
h_new = gc_heap_create(heap_type, new_size, h_last->max_size, chunk_size);
|
h_new = gc_heap_create(heap_type, new_size, h_last->max_size, chunk_size, thd);
|
||||||
h_last->next = h_new;
|
h_last->next = h_new;
|
||||||
pthread_mutex_unlock(&heap_lock);
|
pthread_mutex_unlock(&(thd->heap_lock));
|
||||||
#if GC_DEBUG_TRACE
|
#if GC_DEBUG_TRACE
|
||||||
fprintf(stderr, "DEBUG - grew heap\n");
|
fprintf(stderr, "DEBUG - grew heap\n");
|
||||||
#endif
|
#endif
|
||||||
|
@ -530,7 +536,7 @@ void *gc_try_alloc(gc_heap * h, int heap_type, size_t size, char *obj,
|
||||||
{
|
{
|
||||||
gc_heap *h_passed = h;
|
gc_heap *h_passed = h;
|
||||||
gc_free_list *f1, *f2, *f3;
|
gc_free_list *f1, *f2, *f3;
|
||||||
pthread_mutex_lock(&heap_lock);
|
pthread_mutex_lock(&(thd->heap_lock));
|
||||||
// Start searching from the last heap page we had a successful
|
// Start searching from the last heap page we had a successful
|
||||||
// allocation from, unless the current request is for a smaller
|
// allocation from, unless the current request is for a smaller
|
||||||
// block in which case there may be available memory closer to
|
// block in which case there may be available memory closer to
|
||||||
|
@ -557,17 +563,17 @@ void *gc_try_alloc(gc_heap * h, int heap_type, size_t size, char *obj,
|
||||||
// Copy object into heap now to avoid any uninitialized memory issues
|
// Copy object into heap now to avoid any uninitialized memory issues
|
||||||
gc_copy_obj(f2, obj, thd);
|
gc_copy_obj(f2, obj, thd);
|
||||||
//h->free_size -= gc_allocated_bytes(obj, NULL, NULL);
|
//h->free_size -= gc_allocated_bytes(obj, NULL, NULL);
|
||||||
cached_heap_free_sizes[heap_type] -=
|
ck_pr_sub_ptr(&(thd->cached_heap_free_sizes[heap_type]),
|
||||||
gc_allocated_bytes(obj, NULL, NULL);
|
gc_allocated_bytes(obj, NULL, NULL));
|
||||||
}
|
}
|
||||||
h_passed->next_free = h;
|
h_passed->next_free = h;
|
||||||
h_passed->last_alloc_size = size;
|
h_passed->last_alloc_size = size;
|
||||||
pthread_mutex_unlock(&heap_lock);
|
pthread_mutex_unlock(&(thd->heap_lock));
|
||||||
return f2;
|
return f2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&heap_lock);
|
pthread_mutex_unlock(&(thd->heap_lock));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,11 +613,15 @@ void *gc_alloc(gc_heap_root * hrt, size_t size, char *obj, gc_thread_data * thd,
|
||||||
// A vanilla mark&sweep collector would collect now, but unfortunately
|
// A vanilla mark&sweep collector would collect now, but unfortunately
|
||||||
// we can't do that because we have to go through multiple stages, some
|
// we can't do that because we have to go through multiple stages, some
|
||||||
// of which are asynchronous. So... no choice but to grow the heap.
|
// of which are asynchronous. So... no choice but to grow the heap.
|
||||||
gc_grow_heap(h, heap_type, size, 0);
|
gc_grow_heap(h, heap_type, size, 0, thd);
|
||||||
*heap_grown = 1;
|
*heap_grown = 1;
|
||||||
result = gc_try_alloc(h, heap_type, size, obj, thd);
|
result = gc_try_alloc(h, heap_type, size, obj, thd);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
fprintf(stderr, "out of memory error allocating %zu bytes\n", size);
|
fprintf(stderr, "out of memory error allocating %zu bytes\n", size);
|
||||||
|
fprintf(stderr, "Heap type %d diagnostics:\n", heap_type);
|
||||||
|
pthread_mutex_lock(&(thd->heap_lock));
|
||||||
|
gc_print_stats(h);
|
||||||
|
pthread_mutex_unlock(&(thd->heap_lock)); // why not
|
||||||
exit(1); // could throw error, but OOM is a major issue, so...
|
exit(1); // could throw error, but OOM is a major issue, so...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -690,18 +700,18 @@ gc_heap *gc_heap_last(gc_heap * h)
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t gc_heap_total_size(gc_heap * h)
|
//size_t gc_heap_total_size(gc_heap * h)
|
||||||
{
|
//{
|
||||||
size_t total_size = 0;
|
// size_t total_size = 0;
|
||||||
pthread_mutex_lock(&heap_lock);
|
// pthread_mutex_lock(&heap_lock);
|
||||||
while (h) {
|
// while (h) {
|
||||||
total_size += h->size;
|
// total_size += h->size;
|
||||||
h = h->next;
|
// h = h->next;
|
||||||
}
|
// }
|
||||||
pthread_mutex_unlock(&heap_lock);
|
// pthread_mutex_unlock(&heap_lock);
|
||||||
return total_size;
|
// return total_size;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
//size_t gc_heap_total_free_size(gc_heap *h)
|
//size_t gc_heap_total_free_size(gc_heap *h)
|
||||||
//{
|
//{
|
||||||
// size_t total_size = 0;
|
// size_t total_size = 0;
|
||||||
|
@ -714,7 +724,71 @@ size_t gc_heap_total_size(gc_heap * h)
|
||||||
// return total_size;
|
// return total_size;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr)
|
// A convenient front-end to the actual gc_sweep function.
|
||||||
|
void gc_collector_sweep()
|
||||||
|
{
|
||||||
|
ck_array_iterator_t iterator;
|
||||||
|
gc_thread_data *m;
|
||||||
|
gc_heap *h;
|
||||||
|
int heap_type;
|
||||||
|
size_t freed_tmp = 0, freed = 0;
|
||||||
|
#if GC_DEBUG_TRACE
|
||||||
|
size_t total_size;
|
||||||
|
size_t total_free;
|
||||||
|
time_t gc_collector_start = time(NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CK_ARRAY_FOREACH(&Cyc_mutators, &iterator, &m) {
|
||||||
|
for (heap_type = 0; heap_type < NUM_HEAP_TYPES; heap_type++) {
|
||||||
|
h = m->heap->heap[heap_type];
|
||||||
|
if (h) {
|
||||||
|
gc_sweep(h, heap_type, &freed_tmp, m);
|
||||||
|
freed += freed_tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this loop only includes smallest 2 heaps, is that sufficient??
|
||||||
|
for (heap_type = 0; heap_type < 2; heap_type++) {
|
||||||
|
while ( ck_pr_load_ptr(&(m->cached_heap_free_sizes[heap_type])) <
|
||||||
|
(ck_pr_load_ptr(&(m->cached_heap_total_sizes[heap_type])) * GC_FREE_THRESHOLD)) {
|
||||||
|
#if GC_DEBUG_TRACE
|
||||||
|
fprintf(stderr, "Less than %f%% of the heap %d is free, growing it\n",
|
||||||
|
100.0 * GC_FREE_THRESHOLD, heap_type);
|
||||||
|
#endif
|
||||||
|
if (heap_type == HEAP_SM) {
|
||||||
|
gc_grow_heap(m->heap->heap[heap_type], heap_type, 0, 0, m);
|
||||||
|
} else if (heap_type == HEAP_64) {
|
||||||
|
gc_grow_heap(m->heap->heap[heap_type], heap_type, 0, 0, m);
|
||||||
|
} else if (heap_type == HEAP_REST) {
|
||||||
|
gc_grow_heap(m->heap->heap[heap_type], heap_type, 0, 0, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if GC_DEBUG_TRACE
|
||||||
|
total_size = ck_pr_load_ptr(&(m->cached_heap_total_sizes[HEAP_SM])) +
|
||||||
|
ck_pr_load_ptr(&(m->cached_heap_total_sizes[HEAP_64])) +
|
||||||
|
#if INTPTR_MAX == INT64_MAX
|
||||||
|
ck_pr_load_ptr(&(m->cached_heap_total_sizes[HEAP_96])) +
|
||||||
|
#endif
|
||||||
|
ck_pr_load_ptr(&(m->cached_heap_total_sizes[HEAP_REST]));
|
||||||
|
total_free = ck_pr_load_ptr(&(m->cached_heap_free_sizes[HEAP_SM])) +
|
||||||
|
ck_pr_load_ptr(&(m->cached_heap_free_sizes[HEAP_64])) +
|
||||||
|
#if INTPTR_MAX == INT64_MAX
|
||||||
|
ck_pr_load_ptr(&(m->cached_heap_free_sizes[HEAP_96])) +
|
||||||
|
#endif
|
||||||
|
ck_pr_load_ptr(&(m->cached_heap_free_sizes[HEAP_REST]));
|
||||||
|
fprintf(stderr,
|
||||||
|
"sweep done, total_size = %zu, total_free = %zu, freed = %zu, elapsed = %ld\n",
|
||||||
|
total_size, total_free, freed,
|
||||||
|
(time(NULL) - gc_collector_start));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if GC_DEBUG_TRACE
|
||||||
|
fprintf(stderr, "all thread heap sweeps done\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr, gc_thread_data *thd)
|
||||||
{
|
{
|
||||||
size_t freed, max_freed = 0, heap_freed = 0, sum_freed = 0, size;
|
size_t freed, max_freed = 0, heap_freed = 0, sum_freed = 0, size;
|
||||||
object p, end;
|
object p, end;
|
||||||
|
@ -726,13 +800,9 @@ size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr)
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lock the heap to prevent issues with allocations during sweep
|
// Lock the heap to prevent issues with allocations during sweep
|
||||||
// It sucks to have to use a coarse-grained lock like this, but let's
|
// This coarse-grained lock actually performed better than a fine-grained one.
|
||||||
// be safe and prevent threading issues right now. Once the new GC
|
|
||||||
// works we can go back and try to speed things up (if possible)
|
|
||||||
// by using more fine-grained locking. Can also profile to see
|
|
||||||
// how much time is even spent sweeping
|
|
||||||
//
|
//
|
||||||
pthread_mutex_lock(&heap_lock);
|
pthread_mutex_lock(&(thd->heap_lock));
|
||||||
h->next_free = h;
|
h->next_free = h;
|
||||||
h->last_alloc_size = 0;
|
h->last_alloc_size = 0;
|
||||||
|
|
||||||
|
@ -840,7 +910,7 @@ size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//h->free_size += heap_freed;
|
//h->free_size += heap_freed;
|
||||||
cached_heap_free_sizes[heap_type] += heap_freed;
|
ck_pr_add_ptr(&(thd->cached_heap_free_sizes[heap_type]), heap_freed);
|
||||||
// Free the heap page if possible.
|
// Free the heap page if possible.
|
||||||
//
|
//
|
||||||
// With huge heaps, this becomes more important. one of the huge
|
// With huge heaps, this becomes more important. one of the huge
|
||||||
|
@ -855,13 +925,16 @@ size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr)
|
||||||
// remaining without them.
|
// remaining without them.
|
||||||
//
|
//
|
||||||
// Experimenting with only freeing huge heaps
|
// Experimenting with only freeing huge heaps
|
||||||
if (h->type == HEAP_HUGE && gc_is_heap_empty(h) && !h->newly_created){
|
if (gc_is_heap_empty(h) &&
|
||||||
|
(h->type == HEAP_HUGE || !(h->ttl--))) {
|
||||||
unsigned int h_size = h->size;
|
unsigned int h_size = h->size;
|
||||||
h = gc_heap_free(h, prev_h);
|
gc_heap *new_h = gc_heap_free(h, prev_h);
|
||||||
cached_heap_free_sizes[heap_type] -= h_size;
|
if (new_h) { // Ensure free succeeded
|
||||||
cached_heap_total_sizes[heap_type] -= h_size;
|
h = new_h;
|
||||||
|
ck_pr_sub_ptr(&(thd->cached_heap_free_sizes[heap_type] ), h_size);
|
||||||
|
ck_pr_sub_ptr(&(thd->cached_heap_total_sizes[heap_type]), h_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
h->newly_created = 0;
|
|
||||||
sum_freed += heap_freed;
|
sum_freed += heap_freed;
|
||||||
heap_freed = 0;
|
heap_freed = 0;
|
||||||
}
|
}
|
||||||
|
@ -872,7 +945,7 @@ size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr)
|
||||||
gc_print_stats(orig_heap_ptr);
|
gc_print_stats(orig_heap_ptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pthread_mutex_unlock(&heap_lock);
|
pthread_mutex_unlock(&(thd->heap_lock));
|
||||||
if (sum_freed_ptr)
|
if (sum_freed_ptr)
|
||||||
*sum_freed_ptr = sum_freed;
|
*sum_freed_ptr = sum_freed;
|
||||||
return max_freed;
|
return max_freed;
|
||||||
|
@ -1073,16 +1146,16 @@ void gc_mut_cooperate(gc_thread_data * thd, int buf_len)
|
||||||
// Threshold is intentially low because we have to go through an
|
// Threshold is intentially low because we have to go through an
|
||||||
// entire handshake/trace/sweep cycle, ideally without growing heap.
|
// entire handshake/trace/sweep cycle, ideally without growing heap.
|
||||||
if (ck_pr_load_int(&gc_stage) == STAGE_RESTING &&
|
if (ck_pr_load_int(&gc_stage) == STAGE_RESTING &&
|
||||||
((cached_heap_free_sizes[HEAP_SM] <
|
((ck_pr_load_ptr(&(thd->cached_heap_free_sizes[HEAP_SM])) <
|
||||||
cached_heap_total_sizes[HEAP_SM] * GC_COLLECTION_THRESHOLD) ||
|
ck_pr_load_ptr(&(thd->cached_heap_total_sizes[HEAP_SM])) * GC_COLLECTION_THRESHOLD) ||
|
||||||
(cached_heap_free_sizes[HEAP_64] <
|
(ck_pr_load_ptr(&(thd->cached_heap_free_sizes[HEAP_64])) <
|
||||||
cached_heap_total_sizes[HEAP_64] * GC_COLLECTION_THRESHOLD) ||
|
ck_pr_load_ptr(&(thd->cached_heap_total_sizes[HEAP_64])) * GC_COLLECTION_THRESHOLD) ||
|
||||||
#if INTPTR_MAX == INT64_MAX
|
#if INTPTR_MAX == INT64_MAX
|
||||||
(cached_heap_free_sizes[HEAP_96] <
|
(ck_pr_load_ptr(&(thd->cached_heap_free_sizes[HEAP_96])) <
|
||||||
cached_heap_total_sizes[HEAP_96] * GC_COLLECTION_THRESHOLD) ||
|
ck_pr_load_ptr(&(thd->cached_heap_total_sizes[HEAP_96])) * GC_COLLECTION_THRESHOLD) ||
|
||||||
#endif
|
#endif
|
||||||
(cached_heap_free_sizes[HEAP_REST] <
|
(ck_pr_load_ptr(&(thd->cached_heap_free_sizes[HEAP_REST])) <
|
||||||
cached_heap_total_sizes[HEAP_REST] * GC_COLLECTION_THRESHOLD))) {
|
ck_pr_load_ptr(&(thd->cached_heap_total_sizes[HEAP_REST])) * GC_COLLECTION_THRESHOLD))) {
|
||||||
#if GC_DEBUG_TRACE
|
#if GC_DEBUG_TRACE
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Less than %f%% of the heap is free, initiating collector\n",
|
"Less than %f%% of the heap is free, initiating collector\n",
|
||||||
|
@ -1146,71 +1219,26 @@ void gc_mark_gray2(gc_thread_data * thd, object obj)
|
||||||
// they should never be added to the mark stack. Which would be bad because it
|
// they should never be added to the mark stack. Which would be bad because it
|
||||||
// could lead to stack corruption.
|
// could lead to stack corruption.
|
||||||
//
|
//
|
||||||
|
#if GC_DEBUG_VERBOSE
|
||||||
|
static void gc_collector_mark_gray(object parent, object obj)
|
||||||
|
{
|
||||||
|
if (is_object_type(obj) && mark(obj) == gc_color_clear) {
|
||||||
|
mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, obj);
|
||||||
|
fprintf(stderr, "mark gray parent = %p (%d) obj = %p\n", parent,
|
||||||
|
type_of(parent), obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
//
|
||||||
// Attempt to speed this up by forcing an inline
|
// Attempt to speed this up by forcing an inline
|
||||||
//
|
//
|
||||||
#define gc_collector_mark_gray(parent, gobj) \
|
#define gc_collector_mark_gray(parent, gobj) \
|
||||||
if (is_object_type(gobj) && mark(gobj) == gc_color_clear) { \
|
if (is_object_type(gobj) && mark(gobj) == gc_color_clear) { \
|
||||||
mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, gobj); \
|
mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, gobj); \
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//static void gc_collector_mark_gray(object parent, object obj)
|
#if GC_DEBUG_VERBOSE
|
||||||
//{
|
|
||||||
// if (is_object_type(obj) && mark(obj) == gc_color_clear) {
|
|
||||||
// mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, obj);
|
|
||||||
//#if GC_DEBUG_VERBOSE
|
|
||||||
// fprintf(stderr, "mark gray parent = %p (%d) obj = %p\n", parent,
|
|
||||||
// type_of(parent), obj);
|
|
||||||
//#endif
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
// See full version below for debugging purposes.
|
|
||||||
// Also sync any changes to this macro with the function version
|
|
||||||
#define gc_mark_black(obj) \
|
|
||||||
{ \
|
|
||||||
int markColor = ck_pr_load_int(&gc_color_mark); \
|
|
||||||
if (is_object_type(obj) && mark(obj) != markColor) { \
|
|
||||||
switch (type_of(obj)) { \
|
|
||||||
case pair_tag:{ \
|
|
||||||
gc_collector_mark_gray(obj, car(obj)); \
|
|
||||||
gc_collector_mark_gray(obj, cdr(obj)); \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
case closure1_tag: \
|
|
||||||
gc_collector_mark_gray(obj, ((closure1) obj)->element); \
|
|
||||||
break; \
|
|
||||||
case closureN_tag:{ \
|
|
||||||
int i, n = ((closureN) obj)->num_elements; \
|
|
||||||
for (i = 0; i < n; i++) { \
|
|
||||||
gc_collector_mark_gray(obj, ((closureN) obj)->elements[i]); \
|
|
||||||
} \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
case vector_tag:{ \
|
|
||||||
int i, n = ((vector) obj)->num_elements; \
|
|
||||||
for (i = 0; i < n; i++) { \
|
|
||||||
gc_collector_mark_gray(obj, ((vector) obj)->elements[i]); \
|
|
||||||
} \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
case cvar_tag:{ \
|
|
||||||
cvar_type *c = (cvar_type *) obj; \
|
|
||||||
object pvar = *(c->pvar); \
|
|
||||||
if (pvar) { \
|
|
||||||
gc_collector_mark_gray(obj, pvar); \
|
|
||||||
} \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
default: \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
if (mark(obj) != gc_color_red) { \
|
|
||||||
mark(obj) = markColor; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
void gc_mark_black(object obj)
|
void gc_mark_black(object obj)
|
||||||
{
|
{
|
||||||
// TODO: is sync required to get colors? probably not on the collector
|
// TODO: is sync required to get colors? probably not on the collector
|
||||||
|
@ -1259,16 +1287,60 @@ void gc_mark_black(object obj)
|
||||||
// Only blacken objects on the heap
|
// Only blacken objects on the heap
|
||||||
mark(obj) = markColor;
|
mark(obj) = markColor;
|
||||||
}
|
}
|
||||||
#if GC_DEBUG_VERBOSE
|
|
||||||
if (mark(obj) != gc_color_red) {
|
if (mark(obj) != gc_color_red) {
|
||||||
fprintf(stderr, "marked %p %d\n", obj, markColor);
|
fprintf(stderr, "marked %p %d\n", obj, markColor);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "not marking stack obj %p %d\n", obj, markColor);
|
fprintf(stderr, "not marking stack obj %p %d\n", obj, markColor);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
#else
|
||||||
|
// See full version above for debugging purposes.
|
||||||
|
// Also sync any changes to this macro with the function version
|
||||||
|
#define gc_mark_black(obj) \
|
||||||
|
{ \
|
||||||
|
int markColor = ck_pr_load_int(&gc_color_mark); \
|
||||||
|
if (is_object_type(obj) && mark(obj) != markColor) { \
|
||||||
|
switch (type_of(obj)) { \
|
||||||
|
case pair_tag:{ \
|
||||||
|
gc_collector_mark_gray(obj, car(obj)); \
|
||||||
|
gc_collector_mark_gray(obj, cdr(obj)); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
case closure1_tag: \
|
||||||
|
gc_collector_mark_gray(obj, ((closure1) obj)->element); \
|
||||||
|
break; \
|
||||||
|
case closureN_tag:{ \
|
||||||
|
int i, n = ((closureN) obj)->num_elements; \
|
||||||
|
for (i = 0; i < n; i++) { \
|
||||||
|
gc_collector_mark_gray(obj, ((closureN) obj)->elements[i]); \
|
||||||
|
} \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
case vector_tag:{ \
|
||||||
|
int i, n = ((vector) obj)->num_elements; \
|
||||||
|
for (i = 0; i < n; i++) { \
|
||||||
|
gc_collector_mark_gray(obj, ((vector) obj)->elements[i]); \
|
||||||
|
} \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
case cvar_tag:{ \
|
||||||
|
cvar_type *c = (cvar_type *) obj; \
|
||||||
|
object pvar = *(c->pvar); \
|
||||||
|
if (pvar) { \
|
||||||
|
gc_collector_mark_gray(obj, pvar); \
|
||||||
|
} \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
default: \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
if (mark(obj) != gc_color_red) { \
|
||||||
|
mark(obj) = markColor; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void gc_collector_trace()
|
void gc_collector_trace()
|
||||||
|
@ -1425,12 +1497,8 @@ void debug_dump_globals();
|
||||||
// Main collector function
|
// Main collector function
|
||||||
void gc_collector()
|
void gc_collector()
|
||||||
{
|
{
|
||||||
int old_clear, old_mark, heap_type;
|
int old_clear, old_mark;
|
||||||
size_t freed_tmp = 0, freed = 0;
|
|
||||||
#if GC_DEBUG_TRACE
|
#if GC_DEBUG_TRACE
|
||||||
size_t total_size;
|
|
||||||
size_t total_free;
|
|
||||||
time_t gc_collector_start = time(NULL);
|
|
||||||
print_allocated_obj_counts();
|
print_allocated_obj_counts();
|
||||||
print_current_time();
|
print_current_time();
|
||||||
fprintf(stderr, " - Starting gc_collector\n");
|
fprintf(stderr, " - Starting gc_collector\n");
|
||||||
|
@ -1476,50 +1544,8 @@ void gc_collector()
|
||||||
ck_pr_cas_int(&gc_stage, STAGE_TRACING, STAGE_SWEEPING);
|
ck_pr_cas_int(&gc_stage, STAGE_TRACING, STAGE_SWEEPING);
|
||||||
//
|
//
|
||||||
//sweep :
|
//sweep :
|
||||||
|
gc_collector_sweep();
|
||||||
|
|
||||||
for (heap_type = 0; heap_type < NUM_HEAP_TYPES; heap_type++) {
|
|
||||||
gc_heap *h = gc_get_heap()->heap[heap_type];
|
|
||||||
if (h) {
|
|
||||||
gc_sweep(h, heap_type, &freed_tmp);
|
|
||||||
freed += freed_tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: this loop only includes smallest 2 heaps, is that sufficient??
|
|
||||||
for (heap_type = 0; heap_type < 2; heap_type++) {
|
|
||||||
while (cached_heap_free_sizes[heap_type] <
|
|
||||||
(cached_heap_total_sizes[heap_type] * GC_FREE_THRESHOLD)) {
|
|
||||||
#if GC_DEBUG_TRACE
|
|
||||||
fprintf(stderr, "Less than %f%% of the heap %d is free, growing it\n",
|
|
||||||
100.0 * GC_FREE_THRESHOLD, heap_type);
|
|
||||||
#endif
|
|
||||||
if (heap_type == HEAP_SM) {
|
|
||||||
gc_grow_heap(gc_get_heap()->heap[heap_type], heap_type, 0, 0);
|
|
||||||
} else if (heap_type == HEAP_64) {
|
|
||||||
gc_grow_heap(gc_get_heap()->heap[heap_type], heap_type, 0, 0);
|
|
||||||
} else if (heap_type == HEAP_REST) {
|
|
||||||
gc_grow_heap(gc_get_heap()->heap[heap_type], heap_type, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if GC_DEBUG_TRACE
|
|
||||||
total_size = cached_heap_total_sizes[HEAP_SM] +
|
|
||||||
cached_heap_total_sizes[HEAP_64] +
|
|
||||||
#if INTPTR_MAX == INT64_MAX
|
|
||||||
cached_heap_total_sizes[HEAP_96] +
|
|
||||||
#endif
|
|
||||||
cached_heap_total_sizes[HEAP_REST];
|
|
||||||
total_free = cached_heap_free_sizes[HEAP_SM] +
|
|
||||||
cached_heap_free_sizes[HEAP_64] +
|
|
||||||
#if INTPTR_MAX == INT64_MAX
|
|
||||||
cached_heap_free_sizes[HEAP_96] +
|
|
||||||
#endif
|
|
||||||
cached_heap_free_sizes[HEAP_REST];
|
|
||||||
fprintf(stderr,
|
|
||||||
"sweep done, total_size = %zu, total_free = %zu, freed = %zu, elapsed = %ld\n",
|
|
||||||
total_size, total_free, freed,
|
|
||||||
(time(NULL) - gc_collector_start));
|
|
||||||
#endif
|
|
||||||
#if GC_DEBUG_TRACE
|
#if GC_DEBUG_TRACE
|
||||||
fprintf(stderr, "cleaning up any old thread data\n");
|
fprintf(stderr, "cleaning up any old thread data\n");
|
||||||
#endif
|
#endif
|
||||||
|
@ -1637,10 +1663,25 @@ void gc_thread_data_init(gc_thread_data * thd, int mut_num, char *stack_base,
|
||||||
thd->mark_buffer_len = 128;
|
thd->mark_buffer_len = 128;
|
||||||
thd->mark_buffer =
|
thd->mark_buffer =
|
||||||
vpbuffer_realloc(thd->mark_buffer, &(thd->mark_buffer_len));
|
vpbuffer_realloc(thd->mark_buffer, &(thd->mark_buffer_len));
|
||||||
|
if (pthread_mutex_init(&(thd->heap_lock), NULL) != 0) {
|
||||||
|
fprintf(stderr, "Unable to initialize thread mutex\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
if (pthread_mutex_init(&(thd->lock), NULL) != 0) {
|
if (pthread_mutex_init(&(thd->lock), NULL) != 0) {
|
||||||
fprintf(stderr, "Unable to initialize thread mutex\n");
|
fprintf(stderr, "Unable to initialize thread mutex\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
thd->cached_heap_free_sizes = calloc(5, sizeof(uintptr_t));
|
||||||
|
thd->cached_heap_total_sizes = calloc(5, sizeof(uintptr_t));
|
||||||
|
thd->heap = calloc(1, sizeof(gc_heap_root));
|
||||||
|
thd->heap->heap = calloc(1, sizeof(gc_heap *) * NUM_HEAP_TYPES);
|
||||||
|
thd->heap->heap[HEAP_REST] = gc_heap_create(HEAP_REST, INITIAL_HEAP_SIZE, 0, 0, thd);
|
||||||
|
thd->heap->heap[HEAP_SM] = gc_heap_create(HEAP_SM, INITIAL_HEAP_SIZE, 0, 0, thd);
|
||||||
|
thd->heap->heap[HEAP_64] = gc_heap_create(HEAP_64, INITIAL_HEAP_SIZE, 0, 0, thd);
|
||||||
|
if (sizeof(void *) == 8) { // Only use this heap on 64-bit platforms
|
||||||
|
thd->heap->heap[HEAP_96] = gc_heap_create(HEAP_96, INITIAL_HEAP_SIZE, 0, 0, thd);
|
||||||
|
}
|
||||||
|
thd->heap->heap[HEAP_HUGE] = gc_heap_create(HEAP_HUGE, 1024, 0, 0, thd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gc_thread_data_free(gc_thread_data * thd)
|
void gc_thread_data_free(gc_thread_data * thd)
|
||||||
|
@ -1653,6 +1694,23 @@ void gc_thread_data_free(gc_thread_data * thd)
|
||||||
fprintf(stderr, "Thread mutex is locked, unable to free\n");
|
fprintf(stderr, "Thread mutex is locked, unable to free\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
if (pthread_mutex_destroy(&thd->heap_lock) != 0) {
|
||||||
|
fprintf(stderr, "Thread heap mutex is locked, unable to free\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// Merge heaps for the terminating thread into the main thread's heap.
|
||||||
|
// Eventually any data that is unused will be freed, but we need to
|
||||||
|
// keep the heap pages for now because they could still contain live
|
||||||
|
// objects.
|
||||||
|
// Lock the primordial thread (hopefully will not cause any deadlocks)
|
||||||
|
// but don't bother locking thd since it is already done by now.
|
||||||
|
pthread_mutex_lock(&(primordial_thread->heap_lock));
|
||||||
|
gc_merge_all_heaps(primordial_thread, thd);
|
||||||
|
pthread_mutex_unlock(&(primordial_thread->heap_lock));
|
||||||
|
if (thd->cached_heap_free_sizes)
|
||||||
|
free(thd->cached_heap_free_sizes);
|
||||||
|
if (thd->cached_heap_total_sizes)
|
||||||
|
free(thd->cached_heap_total_sizes);
|
||||||
if (thd->jmp_start)
|
if (thd->jmp_start)
|
||||||
free(thd->jmp_start);
|
free(thd->jmp_start);
|
||||||
if (thd->gc_args)
|
if (thd->gc_args)
|
||||||
|
@ -1670,6 +1728,40 @@ void gc_thread_data_free(gc_thread_data * thd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge one heap into another. Assumes appropriate locks are already held.
|
||||||
|
*/
|
||||||
|
void gc_heap_merge(gc_heap *hdest, gc_heap *hsrc)
|
||||||
|
{
|
||||||
|
gc_heap *last = gc_heap_last(hdest);
|
||||||
|
last->next = hsrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge all thread heaps into another.
|
||||||
|
* Assumes appropriate locks are already held.
|
||||||
|
*/
|
||||||
|
void gc_merge_all_heaps(gc_thread_data *dest, gc_thread_data *src)
|
||||||
|
{
|
||||||
|
gc_heap *hdest, *hsrc;
|
||||||
|
int heap_type;
|
||||||
|
|
||||||
|
for (heap_type = 0; heap_type < NUM_HEAP_TYPES; heap_type++) {
|
||||||
|
hdest = dest->heap->heap[heap_type];
|
||||||
|
hsrc = src->heap->heap[heap_type];
|
||||||
|
if (hdest && hsrc) {
|
||||||
|
gc_heap_merge(hdest, hsrc);
|
||||||
|
ck_pr_add_ptr(&(dest->cached_heap_total_sizes[heap_type]),
|
||||||
|
ck_pr_load_ptr(&(src->cached_heap_total_sizes[heap_type])));
|
||||||
|
ck_pr_add_ptr(&(dest->cached_heap_free_sizes[heap_type]),
|
||||||
|
ck_pr_load_ptr(&(src->cached_heap_free_sizes[heap_type])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef GC_DEBUG_TRACE
|
||||||
|
fprintf(stderr, "Finished merging old heap data\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called explicitly from a mutator thread to let the collector know
|
* Called explicitly from a mutator thread to let the collector know
|
||||||
* it (may) block for an unknown period of time.
|
* it (may) block for an unknown period of time.
|
||||||
|
@ -1679,6 +1771,8 @@ void gc_thread_data_free(gc_thread_data * thd)
|
||||||
*/
|
*/
|
||||||
void gc_mutator_thread_blocked(gc_thread_data * thd, object cont)
|
void gc_mutator_thread_blocked(gc_thread_data * thd, object cont)
|
||||||
{
|
{
|
||||||
|
thd->gc_cont = cont;
|
||||||
|
thd->gc_num_args = 0; // Will be set later, after collection
|
||||||
if (!ck_pr_cas_int((int *)&(thd->thread_state),
|
if (!ck_pr_cas_int((int *)&(thd->thread_state),
|
||||||
CYC_THREAD_STATE_RUNNABLE, CYC_THREAD_STATE_BLOCKED)) {
|
CYC_THREAD_STATE_RUNNABLE, CYC_THREAD_STATE_BLOCKED)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -1686,8 +1780,6 @@ void gc_mutator_thread_blocked(gc_thread_data * thd, object cont)
|
||||||
thd->thread_state);
|
thd->thread_state);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
thd->gc_cont = cont;
|
|
||||||
thd->gc_num_args = 0; // Will be set later, after collection
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cyc_apply_from_buf(void *data, int argc, object prim, object * buf);
|
void Cyc_apply_from_buf(void *data, int argc, object prim, object * buf);
|
||||||
|
|
|
@ -179,7 +179,6 @@ object Cyc_set_cell(void *, object l, object val);
|
||||||
object Cyc_set_car(void *, object l, object val);
|
object Cyc_set_car(void *, object l, object val);
|
||||||
object Cyc_set_cdr(void *, object l, object val);
|
object Cyc_set_cdr(void *, object l, object val);
|
||||||
object Cyc_length(void *d, object l);
|
object Cyc_length(void *d, object l);
|
||||||
integer_type Cyc_length_as_object(void *d, object l);
|
|
||||||
object Cyc_vector_length(void *data, object v);
|
object Cyc_vector_length(void *data, object v);
|
||||||
object Cyc_vector_ref(void *d, object v, object k);
|
object Cyc_vector_ref(void *d, object v, object k);
|
||||||
object Cyc_vector_set(void *d, object v, object k, object obj);
|
object Cyc_vector_set(void *d, object v, object k, object obj);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// Maximum number of args that GC will accept
|
// Maximum number of args that GC will accept
|
||||||
#define NUM_GC_ARGS 128
|
#define NUM_GC_ARGS 128
|
||||||
|
@ -34,7 +35,7 @@
|
||||||
// Parameters for size of a "page" on the heap (the second generation GC), in bytes.
|
// Parameters for size of a "page" on the heap (the second generation GC), in bytes.
|
||||||
#define GROW_HEAP_BY_SIZE (2 * 1024 * 1024) // Grow first page by adding this amount to it
|
#define GROW_HEAP_BY_SIZE (2 * 1024 * 1024) // Grow first page by adding this amount to it
|
||||||
#define INITIAL_HEAP_SIZE (3 * 1024 * 1024) // Size of the first page
|
#define INITIAL_HEAP_SIZE (3 * 1024 * 1024) // Size of the first page
|
||||||
#define HEAP_SIZE (377 * 1024 * 1024) // Normal size of a page
|
#define HEAP_SIZE (32 * 1024 * 1024) // Normal size of a page
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
// Major GC tuning parameters
|
// Major GC tuning parameters
|
||||||
|
@ -63,7 +64,7 @@
|
||||||
/* Additional runtime checking of the GC system.
|
/* Additional runtime checking of the GC system.
|
||||||
This is here because these checks should not be
|
This is here because these checks should not be
|
||||||
necessary if GC is working correctly. */
|
necessary if GC is working correctly. */
|
||||||
#define GC_SAFETY_CHECKS 1
|
#define GC_SAFETY_CHECKS 0
|
||||||
|
|
||||||
// General constants
|
// General constants
|
||||||
#define NANOSECONDS_PER_MILLISECOND 1000000
|
#define NANOSECONDS_PER_MILLISECOND 1000000
|
||||||
|
@ -102,53 +103,6 @@ enum object_tag {
|
||||||
// Define the size of object tags
|
// Define the size of object tags
|
||||||
typedef unsigned char tag_type;
|
typedef unsigned char tag_type;
|
||||||
|
|
||||||
/* Threading */
|
|
||||||
typedef enum { CYC_THREAD_STATE_NEW, CYC_THREAD_STATE_RUNNABLE,
|
|
||||||
CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_BLOCKED_COOPERATING,
|
|
||||||
CYC_THREAD_STATE_TERMINATED
|
|
||||||
} cyc_thread_state_type;
|
|
||||||
|
|
||||||
/* Thread data structures */
|
|
||||||
typedef struct gc_thread_data_t gc_thread_data;
|
|
||||||
struct gc_thread_data_t {
|
|
||||||
// Thread object, if applicable
|
|
||||||
object scm_thread_obj;
|
|
||||||
cyc_thread_state_type thread_state;
|
|
||||||
// Data needed to initiate stack-based minor GC
|
|
||||||
char *stack_start;
|
|
||||||
char *stack_limit;
|
|
||||||
// Minor GC write barrier
|
|
||||||
void **mutations;
|
|
||||||
int mutation_buflen;
|
|
||||||
int mutation_count;
|
|
||||||
// List of objects moved to heap during minor GC
|
|
||||||
void **moveBuf;
|
|
||||||
int moveBufLen;
|
|
||||||
// Need the following to perform longjmp's
|
|
||||||
//int mutator_num;
|
|
||||||
jmp_buf *jmp_start;
|
|
||||||
// After longjmp, pick up execution using continuation/arguments
|
|
||||||
object gc_cont;
|
|
||||||
object *gc_args;
|
|
||||||
short gc_num_args;
|
|
||||||
// Data needed for heap GC
|
|
||||||
int gc_alloc_color;
|
|
||||||
int gc_status;
|
|
||||||
int last_write;
|
|
||||||
int last_read;
|
|
||||||
int pending_writes;
|
|
||||||
void **mark_buffer;
|
|
||||||
int mark_buffer_len;
|
|
||||||
pthread_mutex_t lock;
|
|
||||||
pthread_t thread_id;
|
|
||||||
// Data needed for call history
|
|
||||||
char **stack_traces;
|
|
||||||
int stack_trace_idx;
|
|
||||||
char *stack_prev_frame;
|
|
||||||
// Exception handler stack
|
|
||||||
object exception_handler_stack;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* GC data structures */
|
/* GC data structures */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -191,7 +145,7 @@ struct gc_heap_t {
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
unsigned int chunk_size; // 0 for any size, other and heap will only alloc chunks of that size
|
unsigned int chunk_size; // 0 for any size, other and heap will only alloc chunks of that size
|
||||||
unsigned int max_size;
|
unsigned int max_size;
|
||||||
unsigned int newly_created;
|
unsigned int ttl; // Keep empty page alive this many times before freeing
|
||||||
//
|
//
|
||||||
gc_heap *next_free;
|
gc_heap *next_free;
|
||||||
unsigned int last_alloc_size;
|
unsigned int last_alloc_size;
|
||||||
|
@ -229,6 +183,57 @@ typedef enum { STAGE_CLEAR_OR_MARKING, STAGE_TRACING
|
||||||
#define gc_color_red 0 // Memory not to be GC'd, such as on the stack
|
#define gc_color_red 0 // Memory not to be GC'd, such as on the stack
|
||||||
#define gc_color_blue 2 // Unallocated memory
|
#define gc_color_blue 2 // Unallocated memory
|
||||||
|
|
||||||
|
/* Threading */
|
||||||
|
typedef enum { CYC_THREAD_STATE_NEW, CYC_THREAD_STATE_RUNNABLE,
|
||||||
|
CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_BLOCKED_COOPERATING,
|
||||||
|
CYC_THREAD_STATE_TERMINATED
|
||||||
|
} cyc_thread_state_type;
|
||||||
|
|
||||||
|
/* Thread data structures */
|
||||||
|
typedef struct gc_thread_data_t gc_thread_data;
|
||||||
|
struct gc_thread_data_t {
|
||||||
|
// Thread object, if applicable
|
||||||
|
object scm_thread_obj;
|
||||||
|
cyc_thread_state_type thread_state;
|
||||||
|
// Data needed to initiate stack-based minor GC
|
||||||
|
char *stack_start;
|
||||||
|
char *stack_limit;
|
||||||
|
// Minor GC write barrier
|
||||||
|
void **mutations;
|
||||||
|
int mutation_buflen;
|
||||||
|
int mutation_count;
|
||||||
|
// List of objects moved to heap during minor GC
|
||||||
|
void **moveBuf;
|
||||||
|
int moveBufLen;
|
||||||
|
// Need the following to perform longjmp's
|
||||||
|
//int mutator_num;
|
||||||
|
jmp_buf *jmp_start;
|
||||||
|
// After longjmp, pick up execution using continuation/arguments
|
||||||
|
object gc_cont;
|
||||||
|
object *gc_args;
|
||||||
|
short gc_num_args;
|
||||||
|
// Data needed for heap GC
|
||||||
|
int gc_alloc_color;
|
||||||
|
int gc_status;
|
||||||
|
int last_write;
|
||||||
|
int last_read;
|
||||||
|
int pending_writes;
|
||||||
|
void **mark_buffer;
|
||||||
|
int mark_buffer_len;
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
pthread_mutex_t heap_lock;
|
||||||
|
pthread_t thread_id;
|
||||||
|
gc_heap_root *heap;
|
||||||
|
uintptr_t *cached_heap_free_sizes;
|
||||||
|
uintptr_t *cached_heap_total_sizes;
|
||||||
|
// Data needed for call history
|
||||||
|
char **stack_traces;
|
||||||
|
int stack_trace_idx;
|
||||||
|
char *stack_prev_frame;
|
||||||
|
// Exception handler stack
|
||||||
|
object exception_handler_stack;
|
||||||
|
};
|
||||||
|
|
||||||
// Determine if stack has overflowed
|
// Determine if stack has overflowed
|
||||||
#if STACK_GROWTH_IS_DOWNWARD
|
#if STACK_GROWTH_IS_DOWNWARD
|
||||||
#define stack_overflow(x,y) ((x) < (y))
|
#define stack_overflow(x,y) ((x) < (y))
|
||||||
|
@ -350,12 +355,6 @@ typedef struct {
|
||||||
int value;
|
int value;
|
||||||
int padding; // Prevent mem corruption if sizeof(int) < sizeof(ptr)
|
int padding; // Prevent mem corruption if sizeof(int) < sizeof(ptr)
|
||||||
} integer_type;
|
} integer_type;
|
||||||
#define make_int(n,v) \
|
|
||||||
integer_type n; \
|
|
||||||
n.hdr.mark = gc_color_red; \
|
|
||||||
n.hdr.grayed = 0; \
|
|
||||||
n.tag = integer_tag; \
|
|
||||||
n.value = v;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gc_header_type hdr;
|
gc_header_type hdr;
|
||||||
|
@ -656,10 +655,12 @@ void gc_initialize();
|
||||||
void gc_add_mutator(gc_thread_data * thd);
|
void gc_add_mutator(gc_thread_data * thd);
|
||||||
void gc_remove_mutator(gc_thread_data * thd);
|
void gc_remove_mutator(gc_thread_data * thd);
|
||||||
gc_heap *gc_heap_create(int heap_type, size_t size, size_t max_size,
|
gc_heap *gc_heap_create(int heap_type, size_t size, size_t max_size,
|
||||||
size_t chunk_size);
|
size_t chunk_size, gc_thread_data *thd);
|
||||||
gc_heap *gc_heap_free(gc_heap *page, gc_heap *prev_page);
|
gc_heap *gc_heap_free(gc_heap *page, gc_heap *prev_page);
|
||||||
|
void gc_heap_merge(gc_heap *hdest, gc_heap *hsrc);
|
||||||
|
void gc_merge_all_heaps(gc_thread_data *dest, gc_thread_data *src);
|
||||||
void gc_print_stats(gc_heap * h);
|
void gc_print_stats(gc_heap * h);
|
||||||
int gc_grow_heap(gc_heap * h, int heap_type, size_t size, size_t chunk_size);
|
int gc_grow_heap(gc_heap * h, int heap_type, size_t size, size_t chunk_size, gc_thread_data *thd);
|
||||||
char *gc_copy_obj(object hp, char *obj, gc_thread_data * thd);
|
char *gc_copy_obj(object hp, char *obj, gc_thread_data * thd);
|
||||||
void *gc_try_alloc(gc_heap * h, int heap_type, size_t size, char *obj,
|
void *gc_try_alloc(gc_heap * h, int heap_type, size_t size, char *obj,
|
||||||
gc_thread_data * thd);
|
gc_thread_data * thd);
|
||||||
|
@ -673,7 +674,7 @@ size_t gc_heap_total_size(gc_heap * h);
|
||||||
//void gc_mark(gc_heap *h, object obj);
|
//void gc_mark(gc_heap *h, object obj);
|
||||||
void gc_request_mark_globals(void);
|
void gc_request_mark_globals(void);
|
||||||
void gc_mark_globals(object globals, object global_table);
|
void gc_mark_globals(object globals, object global_table);
|
||||||
size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr);
|
size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr, gc_thread_data *thd);
|
||||||
void gc_thr_grow_move_buffer(gc_thread_data * d);
|
void gc_thr_grow_move_buffer(gc_thread_data * d);
|
||||||
void gc_thr_add_to_move_buffer(gc_thread_data * d, int *alloci, object obj);
|
void gc_thr_add_to_move_buffer(gc_thread_data * d, int *alloci, object obj);
|
||||||
void gc_thread_data_init(gc_thread_data * thd, int mut_num, char *stack_base,
|
void gc_thread_data_init(gc_thread_data * thd, int mut_num, char *stack_base,
|
||||||
|
@ -703,7 +704,6 @@ void gc_mutator_thread_runnable(gc_thread_data * thd, object result);
|
||||||
// body \
|
// body \
|
||||||
// return_thread_runnable((data), (result));
|
// return_thread_runnable((data), (result));
|
||||||
*/
|
*/
|
||||||
gc_heap_root *gc_get_heap();
|
|
||||||
int gc_minor(void *data, object low_limit, object high_limit, closure cont,
|
int gc_minor(void *data, object low_limit, object high_limit, closure cont,
|
||||||
object * args, int num_args);
|
object * args, int num_args);
|
||||||
/* Mutation table to support minor GC write barrier */
|
/* Mutation table to support minor GC write barrier */
|
||||||
|
|
108
runtime.c
108
runtime.c
|
@ -140,7 +140,6 @@ if (type_is_pair_prim(clo)) { \
|
||||||
/*END closcall section */
|
/*END closcall section */
|
||||||
|
|
||||||
/* Global variables. */
|
/* Global variables. */
|
||||||
static gc_heap_root *Cyc_heap;
|
|
||||||
object Cyc_global_variables = NULL;
|
object Cyc_global_variables = NULL;
|
||||||
int _cyc_argc = 0;
|
int _cyc_argc = 0;
|
||||||
char **_cyc_argv = NULL;
|
char **_cyc_argv = NULL;
|
||||||
|
@ -261,17 +260,6 @@ static bool set_insert(ck_hs_t * hs, const void *value)
|
||||||
|
|
||||||
void gc_init_heap(long heap_size)
|
void gc_init_heap(long heap_size)
|
||||||
{
|
{
|
||||||
size_t initial_heap_size = INITIAL_HEAP_SIZE;
|
|
||||||
Cyc_heap = calloc(1, sizeof(gc_heap_root));
|
|
||||||
Cyc_heap->heap = calloc(1, sizeof(gc_heap *) * NUM_HEAP_TYPES);
|
|
||||||
Cyc_heap->heap[HEAP_REST] = gc_heap_create(HEAP_REST, initial_heap_size, 0, 0);
|
|
||||||
Cyc_heap->heap[HEAP_SM] = gc_heap_create(HEAP_SM, initial_heap_size, 0, 0);
|
|
||||||
Cyc_heap->heap[HEAP_64] = gc_heap_create(HEAP_64, initial_heap_size, 0, 0);
|
|
||||||
if (sizeof(void *) == 8) { // Only use this heap on 64-bit platforms
|
|
||||||
Cyc_heap->heap[HEAP_96] = gc_heap_create(HEAP_96, initial_heap_size, 0, 0);
|
|
||||||
}
|
|
||||||
Cyc_heap->heap[HEAP_HUGE] = gc_heap_create(HEAP_HUGE, 1024, 0, 0);
|
|
||||||
|
|
||||||
if (!ck_hs_init(&symbol_table,
|
if (!ck_hs_init(&symbol_table,
|
||||||
CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC,
|
CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC,
|
||||||
hs_hash, hs_compare,
|
hs_hash, hs_compare,
|
||||||
|
@ -285,11 +273,6 @@ void gc_init_heap(long heap_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gc_heap_root *gc_get_heap()
|
|
||||||
{
|
|
||||||
return Cyc_heap;
|
|
||||||
}
|
|
||||||
|
|
||||||
object cell_get(object cell)
|
object cell_get(object cell)
|
||||||
{
|
{
|
||||||
// FUTURE: always use unsafe car here, since computed by compiler
|
// FUTURE: always use unsafe car here, since computed by compiler
|
||||||
|
@ -1071,7 +1054,7 @@ object Cyc_heap_alloc_port(void *data, port_type *stack_p)
|
||||||
{
|
{
|
||||||
object p = NULL;
|
object p = NULL;
|
||||||
int heap_grown;
|
int heap_grown;
|
||||||
p = gc_alloc(Cyc_heap,
|
p = gc_alloc(((gc_thread_data *)data)->heap,
|
||||||
sizeof(port_type),
|
sizeof(port_type),
|
||||||
(char *)stack_p,
|
(char *)stack_p,
|
||||||
(gc_thread_data *)data,
|
(gc_thread_data *)data,
|
||||||
|
@ -1385,8 +1368,8 @@ object Cyc_is_procedure(void *data, object o)
|
||||||
tag == closure1_tag || tag == closureN_tag || tag == primitive_tag) {
|
tag == closure1_tag || tag == closureN_tag || tag == primitive_tag) {
|
||||||
return boolean_t;
|
return boolean_t;
|
||||||
} else if (tag == pair_tag) {
|
} else if (tag == pair_tag) {
|
||||||
integer_type l = Cyc_length_as_object(data, o);
|
int i = obj_obj2int(Cyc_length(data, o));
|
||||||
if (l.value > 0 && Cyc_is_symbol(car(o)) == boolean_t) {
|
if (i > 0 && Cyc_is_symbol(car(o)) == boolean_t) {
|
||||||
if (strncmp(((symbol) car(o))->desc, "primitive", 10) == 0 ||
|
if (strncmp(((symbol) car(o))->desc, "primitive", 10) == 0 ||
|
||||||
strncmp(((symbol) car(o))->desc, "procedure", 10) == 0) {
|
strncmp(((symbol) car(o))->desc, "procedure", 10) == 0) {
|
||||||
return boolean_t;
|
return boolean_t;
|
||||||
|
@ -1498,19 +1481,6 @@ object Cyc_vector_ref(void *data, object v, object k)
|
||||||
return ((vector) v)->elements[idx];
|
return ((vector) v)->elements[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
integer_type Cyc_length_as_object(void *data, object l)
|
|
||||||
{
|
|
||||||
make_int(len, 0);
|
|
||||||
while ((l != NULL)) {
|
|
||||||
if (is_value_type(l) || ((list) l)->tag != pair_tag) {
|
|
||||||
Cyc_rt_raise2(data, "length - invalid parameter, expected list", l);
|
|
||||||
}
|
|
||||||
l = cdr(l);
|
|
||||||
len.value++;
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
object Cyc_vector_length(void *data, object v)
|
object Cyc_vector_length(void *data, object v)
|
||||||
{
|
{
|
||||||
if ((v != NULL) && !is_value_type(v) && ((list) v)->tag == vector_tag) {
|
if ((v != NULL) && !is_value_type(v) && ((list) v)->tag == vector_tag) {
|
||||||
|
@ -2019,7 +1989,7 @@ object Cyc_make_vector(void *data, object cont, int argc, object len, ...)
|
||||||
// TODO: mark this thread as potentially blocking before doing
|
// TODO: mark this thread as potentially blocking before doing
|
||||||
// the allocation????
|
// the allocation????
|
||||||
int heap_grown;
|
int heap_grown;
|
||||||
v = gc_alloc(Cyc_heap,
|
v = gc_alloc(((gc_thread_data *)data)->heap,
|
||||||
sizeof(vector_type) + element_vec_size,
|
sizeof(vector_type) + element_vec_size,
|
||||||
boolean_f, // OK to populate manually over here
|
boolean_f, // OK to populate manually over here
|
||||||
(gc_thread_data *)data,
|
(gc_thread_data *)data,
|
||||||
|
@ -2065,7 +2035,7 @@ object Cyc_make_bytevector(void *data, object cont, int argc, object len, ...)
|
||||||
|
|
||||||
if (length >= MAX_STACK_OBJ) {
|
if (length >= MAX_STACK_OBJ) {
|
||||||
int heap_grown;
|
int heap_grown;
|
||||||
bv = gc_alloc(Cyc_heap,
|
bv = gc_alloc(((gc_thread_data *)data)->heap,
|
||||||
sizeof(bytevector_type) + length,
|
sizeof(bytevector_type) + length,
|
||||||
boolean_f, // OK to populate manually over here
|
boolean_f, // OK to populate manually over here
|
||||||
(gc_thread_data *)data,
|
(gc_thread_data *)data,
|
||||||
|
@ -3267,30 +3237,30 @@ void _Cyc_91end_91thread_67(void *data, object cont, object args)
|
||||||
|
|
||||||
void __87(void *data, object cont, object args)
|
void __87(void *data, object cont, object args)
|
||||||
{
|
{
|
||||||
integer_type argc = Cyc_length_as_object(data, args);
|
int argc = obj_obj2int(Cyc_length(data, args));
|
||||||
dispatch(data, argc.value, (function_type) dispatch_sum, cont, cont, args);
|
dispatch(data, argc, (function_type) dispatch_sum, cont, cont, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __91(void *data, object cont, object args)
|
void __91(void *data, object cont, object args)
|
||||||
{
|
{
|
||||||
Cyc_check_num_args(data, "-", 1, args);
|
Cyc_check_num_args(data, "-", 1, args);
|
||||||
{
|
{
|
||||||
integer_type argc = Cyc_length_as_object(data, args);
|
int argc = obj_obj2int(Cyc_length(data, args));
|
||||||
dispatch(data, argc.value, (function_type) dispatch_sub, cont, cont, args);
|
dispatch(data, argc, (function_type) dispatch_sub, cont, cont, args);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
void __85(void *data, object cont, object args)
|
void __85(void *data, object cont, object args)
|
||||||
{
|
{
|
||||||
integer_type argc = Cyc_length_as_object(data, args);
|
int argc = obj_obj2int(Cyc_length(data, args));
|
||||||
dispatch(data, argc.value, (function_type) dispatch_mul, cont, cont, args);
|
dispatch(data, argc, (function_type) dispatch_mul, cont, cont, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __95(void *data, object cont, object args)
|
void __95(void *data, object cont, object args)
|
||||||
{
|
{
|
||||||
Cyc_check_num_args(data, "/", 1, args);
|
Cyc_check_num_args(data, "/", 1, args);
|
||||||
{
|
{
|
||||||
integer_type argc = Cyc_length_as_object(data, args);
|
int argc = obj_obj2int(Cyc_length(data, args));
|
||||||
dispatch(data, argc.value, (function_type) dispatch_div, cont, cont, args);
|
dispatch(data, argc, (function_type) dispatch_div, cont, cont, args);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
void _Cyc_91cvar_127(void *data, object cont, object args)
|
void _Cyc_91cvar_127(void *data, object cont, object args)
|
||||||
|
@ -3449,33 +3419,33 @@ void _cell(void *data, object cont, object args)
|
||||||
|
|
||||||
void __123(void *data, object cont, object args)
|
void __123(void *data, object cont, object args)
|
||||||
{
|
{
|
||||||
integer_type argc = Cyc_length_as_object(data, args);
|
int argc = obj_obj2int(Cyc_length(data, args));
|
||||||
dispatch(data, argc.value, (function_type) dispatch_num_eq, cont, cont, args);
|
dispatch(data, argc, (function_type) dispatch_num_eq, cont, cont, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __125(void *data, object cont, object args)
|
void __125(void *data, object cont, object args)
|
||||||
{
|
{
|
||||||
integer_type argc = Cyc_length_as_object(data, args);
|
int argc = obj_obj2int(Cyc_length(data, args));
|
||||||
dispatch(data, argc.value, (function_type) dispatch_num_gt, cont, cont, args);
|
dispatch(data, argc, (function_type) dispatch_num_gt, cont, cont, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __121(void *data, object cont, object args)
|
void __121(void *data, object cont, object args)
|
||||||
{
|
{
|
||||||
integer_type argc = Cyc_length_as_object(data, args);
|
int argc = obj_obj2int(Cyc_length(data, args));
|
||||||
dispatch(data, argc.value, (function_type) dispatch_num_lt, cont, cont, args);
|
dispatch(data, argc, (function_type) dispatch_num_lt, cont, cont, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __125_123(void *data, object cont, object args)
|
void __125_123(void *data, object cont, object args)
|
||||||
{
|
{
|
||||||
integer_type argc = Cyc_length_as_object(data, args);
|
int argc = obj_obj2int(Cyc_length(data, args));
|
||||||
dispatch(data, argc.value, (function_type) dispatch_num_gte, cont, cont,
|
dispatch(data, argc, (function_type) dispatch_num_gte, cont, cont,
|
||||||
args);
|
args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __121_123(void *data, object cont, object args)
|
void __121_123(void *data, object cont, object args)
|
||||||
{
|
{
|
||||||
integer_type argc = Cyc_length_as_object(data, args);
|
int argc = obj_obj2int(Cyc_length(data, args));
|
||||||
dispatch(data, argc.value, (function_type) dispatch_num_lte, cont, cont,
|
dispatch(data, argc, (function_type) dispatch_num_lte, cont, cont,
|
||||||
args);
|
args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3598,9 +3568,6 @@ void _cyc_system(void *data, object cont, object args)
|
||||||
return_closcall1(data, cont, obj);
|
return_closcall1(data, cont, obj);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
//void _error(void *data, object cont, object args) {
|
|
||||||
// integer_type argc = Cyc_length_as_object(args);
|
|
||||||
// dispatch_va(data, argc.value, dispatch_error, cont, cont, args); }
|
|
||||||
void _Cyc_91current_91exception_91handler(void *data, object cont, object args)
|
void _Cyc_91current_91exception_91handler(void *data, object cont, object args)
|
||||||
{
|
{
|
||||||
object handler = Cyc_current_exception_handler(data);
|
object handler = Cyc_current_exception_handler(data);
|
||||||
|
@ -4054,30 +4021,31 @@ char *gc_fixup_moved_obj(gc_thread_data * thd, int *alloci, char *obj,
|
||||||
|
|
||||||
char *gc_move(char *obj, gc_thread_data * thd, int *alloci, int *heap_grown)
|
char *gc_move(char *obj, gc_thread_data * thd, int *alloci, int *heap_grown)
|
||||||
{
|
{
|
||||||
|
gc_heap_root *heap = thd->heap;
|
||||||
if (!is_object_type(obj))
|
if (!is_object_type(obj))
|
||||||
return obj;
|
return obj;
|
||||||
switch (type_of(obj)) {
|
switch (type_of(obj)) {
|
||||||
case pair_tag:{
|
case pair_tag:{
|
||||||
list hp = gc_alloc(Cyc_heap, sizeof(pair_type), obj, thd, heap_grown);
|
list hp = gc_alloc(heap, sizeof(pair_type), obj, thd, heap_grown);
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case macro_tag:{
|
case macro_tag:{
|
||||||
macro_type *hp =
|
macro_type *hp =
|
||||||
gc_alloc(Cyc_heap, sizeof(macro_type), obj, thd, heap_grown);
|
gc_alloc(heap, sizeof(macro_type), obj, thd, heap_grown);
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case closure0_tag:{
|
case closure0_tag:{
|
||||||
closure0_type *hp =
|
closure0_type *hp =
|
||||||
gc_alloc(Cyc_heap, sizeof(closure0_type), obj, thd, heap_grown);
|
gc_alloc(heap, sizeof(closure0_type), obj, thd, heap_grown);
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case closure1_tag:{
|
case closure1_tag:{
|
||||||
closure1_type *hp =
|
closure1_type *hp =
|
||||||
gc_alloc(Cyc_heap, sizeof(closure1_type), obj, thd, heap_grown);
|
gc_alloc(heap, sizeof(closure1_type), obj, thd, heap_grown);
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case closureN_tag:{
|
case closureN_tag:{
|
||||||
closureN_type *hp = gc_alloc(Cyc_heap,
|
closureN_type *hp = gc_alloc(heap,
|
||||||
sizeof(closureN_type) +
|
sizeof(closureN_type) +
|
||||||
sizeof(object) *
|
sizeof(object) *
|
||||||
(((closureN) obj)->num_elements),
|
(((closureN) obj)->num_elements),
|
||||||
|
@ -4085,7 +4053,7 @@ char *gc_move(char *obj, gc_thread_data * thd, int *alloci, int *heap_grown)
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case vector_tag:{
|
case vector_tag:{
|
||||||
vector_type *hp = gc_alloc(Cyc_heap,
|
vector_type *hp = gc_alloc(heap,
|
||||||
sizeof(vector_type) +
|
sizeof(vector_type) +
|
||||||
sizeof(object) *
|
sizeof(object) *
|
||||||
(((vector) obj)->num_elements),
|
(((vector) obj)->num_elements),
|
||||||
|
@ -4093,41 +4061,41 @@ char *gc_move(char *obj, gc_thread_data * thd, int *alloci, int *heap_grown)
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case bytevector_tag:{
|
case bytevector_tag:{
|
||||||
bytevector_type *hp = gc_alloc(Cyc_heap,
|
bytevector_type *hp = gc_alloc(heap,
|
||||||
sizeof(bytevector_type) +
|
sizeof(bytevector_type) +
|
||||||
sizeof(char) * (((bytevector) obj)->len),
|
sizeof(char) * (((bytevector) obj)->len),
|
||||||
obj, thd, heap_grown);
|
obj, thd, heap_grown);
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case string_tag:{
|
case string_tag:{
|
||||||
string_type *hp = gc_alloc(Cyc_heap,
|
string_type *hp = gc_alloc(heap,
|
||||||
sizeof(string_type) + ((string_len(obj) + 1)),
|
sizeof(string_type) + ((string_len(obj) + 1)),
|
||||||
obj, thd, heap_grown);
|
obj, thd, heap_grown);
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case integer_tag:{
|
case integer_tag:{
|
||||||
integer_type *hp =
|
integer_type *hp =
|
||||||
gc_alloc(Cyc_heap, sizeof(integer_type), obj, thd, heap_grown);
|
gc_alloc(heap, sizeof(integer_type), obj, thd, heap_grown);
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case double_tag:{
|
case double_tag:{
|
||||||
double_type *hp =
|
double_type *hp =
|
||||||
gc_alloc(Cyc_heap, sizeof(double_type), obj, thd, heap_grown);
|
gc_alloc(heap, sizeof(double_type), obj, thd, heap_grown);
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case port_tag:{
|
case port_tag:{
|
||||||
port_type *hp =
|
port_type *hp =
|
||||||
gc_alloc(Cyc_heap, sizeof(port_type), obj, thd, heap_grown);
|
gc_alloc(heap, sizeof(port_type), obj, thd, heap_grown);
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case cvar_tag:{
|
case cvar_tag:{
|
||||||
cvar_type *hp =
|
cvar_type *hp =
|
||||||
gc_alloc(Cyc_heap, sizeof(cvar_type), obj, thd, heap_grown);
|
gc_alloc(heap, sizeof(cvar_type), obj, thd, heap_grown);
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case c_opaque_tag:{
|
case c_opaque_tag:{
|
||||||
c_opaque_type *hp =
|
c_opaque_type *hp =
|
||||||
gc_alloc(Cyc_heap, sizeof(c_opaque_type), obj, thd, heap_grown);
|
gc_alloc(heap, sizeof(c_opaque_type), obj, thd, heap_grown);
|
||||||
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
return gc_fixup_moved_obj(thd, alloci, obj, hp);
|
||||||
}
|
}
|
||||||
case forward_tag:
|
case forward_tag:
|
||||||
|
@ -4847,7 +4815,7 @@ object copy2heap(void *data, object obj)
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
return gc_alloc(Cyc_heap, gc_allocated_bytes(obj, NULL, NULL), obj, data,
|
return gc_alloc(((gc_thread_data *)data)->heap, gc_allocated_bytes(obj, NULL, NULL), obj, data,
|
||||||
&on_stack);
|
&on_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,7 @@
|
||||||
tmp.hdr.mark = gc_color_red;
|
tmp.hdr.mark = gc_color_red;
|
||||||
tmp.hdr.grayed = 0;
|
tmp.hdr.grayed = 0;
|
||||||
tmp.tag = mutex_tag;
|
tmp.tag = mutex_tag;
|
||||||
lock = gc_alloc(gc_get_heap(), sizeof(mutex_type), (char *)(&tmp), (gc_thread_data *)data, &heap_grown);
|
lock = gc_alloc(((gc_thread_data *)data)->heap, sizeof(mutex_type), (char *)(&tmp), (gc_thread_data *)data, &heap_grown);
|
||||||
if (pthread_mutex_init(&(lock->lock), NULL) != 0) {
|
if (pthread_mutex_init(&(lock->lock), NULL) != 0) {
|
||||||
fprintf(stderr, \"Unable to make mutex\\n\");
|
fprintf(stderr, \"Unable to make mutex\\n\");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -214,7 +214,7 @@
|
||||||
tmp.hdr.mark = gc_color_red;
|
tmp.hdr.mark = gc_color_red;
|
||||||
tmp.hdr.grayed = 0;
|
tmp.hdr.grayed = 0;
|
||||||
tmp.tag = cond_var_tag;
|
tmp.tag = cond_var_tag;
|
||||||
cond = gc_alloc(gc_get_heap(), sizeof(cond_var_type), (char *)(&tmp), (gc_thread_data *)data, &heap_grown);
|
cond = gc_alloc(((gc_thread_data *)data)->heap, sizeof(cond_var_type), (char *)(&tmp), (gc_thread_data *)data, &heap_grown);
|
||||||
if (pthread_cond_init(&(cond->cond), NULL) != 0) {
|
if (pthread_cond_init(&(cond->cond), NULL) != 0) {
|
||||||
fprintf(stderr, \"Unable to make condition variable\\n\");
|
fprintf(stderr, \"Unable to make condition variable\\n\");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
Loading…
Add table
Reference in a new issue