$NetBSD$

Patches for cyclone issue 560
https://github.com/justinethier/cyclone/compare/master...issue-560-compute-stack-limit
https://github.com/justinethier/cyclone/pull/561

--- include/cyclone/runtime.h
+++ include/cyclone/runtime.h
@@ -47,6 +47,8 @@ extern const object Cyc_RECORD_MARKER;
  */
 void GC(void *, closure, object *, int);
 
+int Cyc_stack_remaining(gc_thread_data *td);
+
 /**
  * \ingroup gc_major
  */
--- include/cyclone/types.h
+++ include/cyclone/types.h
@@ -500,6 +500,13 @@ void Cyc_make_shared_object(void *data, object k, object obj);
 #define stack_overflow(x,y) ((x) > (y))
 #endif
 
+/** Determine remaining stack size */
+#if STACK_GROWTH_IS_DOWNWARD
+#define stack_delta(x,y) (((char *)x) - ((char *)y))
+#else
+#define stack_delta(x,y) (((char *)y) - ((char *)x))
+#endif
+
 /**
  * Access an object's forwarding pointer.
  * Note this is only applicable when objects are relocated
@@ -998,10 +1005,13 @@ typedef struct {
  * Allocate a new string, either on the stack or heap depending upon size
  */
 #define alloc_string(_data, _s, _len, _num_cp) \
-  if (_len >= MAX_STACK_OBJ) { \
+ { \
+  int stack_left = Cyc_stack_remaining(data); \
+  int alloc_required = sizeof(string_type) + _len + 1; \
+  if (alloc_required >= stack_left) { \
     int heap_grown; \
     _s = gc_alloc(((gc_thread_data *)data)->heap,  \
-                 sizeof(string_type) + _len + 1, \
+                 alloc_required, \
                  boolean_f, /* OK to populate manually over here */ \
                  (gc_thread_data *)data,  \
                  &heap_grown); \
@@ -1021,16 +1031,20 @@ typedef struct {
     ((string_type *)_s)->len = _len; \
     ((string_type *)_s)->num_cp = _num_cp; \
     ((string_type *)_s)->str = alloca(sizeof(char) * (_len + 1)); \
-  }
+  } \
+ }
 
 /**
  * Allocate a new bytevector, either on the stack or heap depending upon size
  */
 #define alloc_bytevector(_data, _bv, _len) \
-  if (_len >= MAX_STACK_OBJ) { \
+ { \
+  int stack_left = Cyc_stack_remaining(data); \
+  int alloc_required = sizeof(bytevector_type) + _len; \
+  if (alloc_required >= stack_left) { \
     int heap_grown; \
     _bv = gc_alloc(((gc_thread_data *)data)->heap, \
-                  sizeof(bytevector_type) + _len, \
+                  alloc_required, \
                   boolean_f, /* OK to populate manually over here */ \
                   (gc_thread_data *)data, \
                   &heap_grown); \
@@ -1048,7 +1062,8 @@ typedef struct {
     ((bytevector) _bv)->tag = bytevector_tag; \
     ((bytevector) _bv)->len = _len; \
     ((bytevector) _bv)->data = alloca(sizeof(char) * _len); \
-  }
+  } \
+ }
 
 /** Get the length of a string, in characters (code points) */
 #define string_num_cp(x) (((string_type *) x)->num_cp)
--- runtime.c
+++ runtime.c
@@ -2799,10 +2799,18 @@ void dispatch_string_91append(void *data, object clo, int _argc, object * _args)
 {
   int argc = _argc - 1;         // Skip continuation
   object *args = _args + 1;     // Skip continuation
-  int i = 0, total_cp = 0, total_len = 1;
+  int i = 0, total_cp = 0, total_len = 0;
   int *len = alloca(sizeof(int) * argc);
-  char *buffer, *bufferp, **str = alloca(sizeof(char *) * argc);
-  object tmp;
+  char *bufferp, **str = alloca(sizeof(char *) * argc);
+  object tmp, result;
+  if (argc == 0) {
+    make_string(r, "");
+    return_closcall1(data, clo, &r);
+  }
+  if (argc == 1) {
+    Cyc_check_str(data, args[0]);
+    return_closcall1(data, clo, args[0]);
+  }
   for (i = 0; i < argc; i++) {
     tmp = args[i];
     Cyc_check_str(data, tmp);
@@ -2811,32 +2819,39 @@ void dispatch_string_91append(void *data, object clo, int _argc, object * _args)
     total_len += len[i];
     total_cp += string_num_cp((tmp));
   }
-  buffer = bufferp = alloca(sizeof(char) * total_len);
+  alloc_string(data, result, sizeof(char) * total_len, total_cp);
+  bufferp = ((string_type *) result)->str;
   for (i = 0; i < argc; i++) {
     memcpy(bufferp, str[i], len[i]);
     bufferp += len[i];
   }
   *bufferp = '\0';
-  make_string(result, buffer);
-  string_num_cp((&result)) = total_cp;
-  return_closcall1(data, clo, &result);
+  return_closcall1(data, clo, result);
 }
 
 object Cyc_string_append(void *data, object cont, int argc, object str1, ...)
 {
+  int i = 0, total_cp = 0, total_len = 0;
+  int *len;
+  char *bufferp, **str;
+  object tmp, result;
   va_list ap;
-  va_start(ap, str1);
-  int i = 0, total_cp = 0, total_len = 1;
-  int *len = alloca(sizeof(int) * argc);
-  char *buffer, *bufferp, **str = alloca(sizeof(char *) * argc);
-  object tmp;
-  if (argc > 0) {
+  if (argc == 0) {
+    make_string(r, "");
+    _return_closcall1(data, cont, &r);
+  }
+  if (argc == 1) {
     Cyc_check_str(data, str1);
-    str[i] = ((string_type *) str1)->str;
-    len[i] = string_len((str1));
-    total_len += len[i];
-    total_cp += string_num_cp((str1));
+    _return_closcall1(data, cont, str1);
   }
+  len = alloca(sizeof(int) * argc);
+  str = alloca(sizeof(char *) * argc);
+  va_start(ap, str1);
+  Cyc_check_str(data, str1);
+  str[i] = ((string_type *) str1)->str;
+  len[i] = string_len((str1));
+  total_len += len[i];
+  total_cp += string_num_cp((str1));
   for (i = 1; i < argc; i++) {
     tmp = va_arg(ap, object);
     Cyc_check_str(data, tmp);
@@ -2845,16 +2860,15 @@ object Cyc_string_append(void *data, object cont, int argc, object str1, ...)
     total_len += len[i];
     total_cp += string_num_cp((tmp));
   }
-  buffer = bufferp = alloca(sizeof(char) * total_len);
+  alloc_string(data, result, sizeof(char) * total_len, total_cp);
+  bufferp = ((string_type *) result)->str;
   for (i = 0; i < argc; i++) {
     memcpy(bufferp, str[i], len[i]);
     bufferp += len[i];
   }
   *bufferp = '\0';
-  make_string(result, buffer);
-  string_num_cp((&result)) = total_cp;
   va_end(ap);
-  _return_closcall1(data, cont, &result);
+  _return_closcall1(data, cont, result);
 }
 
 object Cyc_string_length(void *data, object str)
@@ -3171,7 +3185,7 @@ object Cyc_make_vector(void *data, object cont, int argc, object len, ...)
   object v = NULL;
   object fill = boolean_f;
   int i, ulen;
-  size_t element_vec_size;
+  size_t element_vec_size, alloc_required;
   va_list ap;
   make_pair(tmp_pair, NULL, NULL);
   make_c_opaque(opq, NULL);
@@ -3183,14 +3197,15 @@ object Cyc_make_vector(void *data, object cont, int argc, object len, ...)
   Cyc_check_num(data, len);
   ulen = unbox_number(len);
   element_vec_size = sizeof(object) * ulen;
+  alloc_required = sizeof(vector_type) + element_vec_size;
 
-  if (element_vec_size >= MAX_STACK_OBJ) {
+  if (alloc_required >= Cyc_stack_remaining(data)) {
     // If vector is too large to allocate on the stack, allocate on heap
     //
     // TODO: mark this thread as potentially blocking before doing
     //       the allocation????
     int heap_grown;
-    v = gc_alloc(((gc_thread_data *) data)->heap, sizeof(vector_type) + element_vec_size, boolean_f,    // OK to populate manually over here
+    v = gc_alloc(((gc_thread_data *) data)->heap, alloc_required, boolean_f,    // OK to populate manually over here
                  (gc_thread_data *) data, &heap_grown);
     ((vector) v)->hdr.mark = ((gc_thread_data *) data)->gc_alloc_color;
     ((vector) v)->hdr.grayed = 0;
@@ -3243,7 +3258,7 @@ object Cyc_make_bytevector(void *data, object cont, int argc, object len, ...)
   Cyc_check_num(data, len);
   length = unbox_number(len);
 
-  if (length >= MAX_STACK_OBJ) {
+  if (length >= Cyc_stack_remaining(data)) {
     int heap_grown;
     bv = gc_alloc(((gc_thread_data *) data)->heap, sizeof(bytevector_type) + length, boolean_f, // OK to populate manually over here
                   (gc_thread_data *) data, &heap_grown);
@@ -3327,11 +3342,18 @@ void dispatch_bytevector_91append(void *data, object clo, int _argc,
   int argc = _argc - 1;         // Skip continuation
   object *args = _args + 1;     // Skip continuation
   int i = 0, buf_idx = 0, total_length = 0;
-  object tmp;
+  object tmp, result;
   char *buffer;
   char **buffers = NULL;
   int *lengths = NULL;
-  make_empty_bytevector(result);
+  if (argc == 0) {
+    make_empty_bytevector(r);
+    return_closcall1(data, clo, &r);
+  }
+  if (argc == 1) {
+    Cyc_check_bvec(data, args[0]);
+    return_closcall1(data, clo, args[0]);
+  }
   if (argc > 0) {
     buffers = alloca(sizeof(char *) * argc);
     lengths = alloca(sizeof(int) * argc);
@@ -3342,26 +3364,32 @@ void dispatch_bytevector_91append(void *data, object clo, int _argc,
       lengths[i] = ((bytevector) tmp)->len;
       buffers[i] = ((bytevector) tmp)->data;
     }
-    buffer = alloca(sizeof(char) * total_length);
+    alloc_bytevector(data, result, total_length);
+    buffer = ((bytevector) result)->data;
     for (i = 0; i < argc; i++) {
       memcpy(&buffer[buf_idx], buffers[i], lengths[i]);
       buf_idx += lengths[i];
     }
-    result.len = total_length;
-    result.data = buffer;
   }
-  return_closcall1(data, clo, &result);
+  return_closcall1(data, clo, result);
 }
 
 object Cyc_bytevector_append(void *data, object cont, int argc, object bv, ...)
 {
   int i = 0, buf_idx = 0, total_length = 0;
   va_list ap;
-  object tmp;
+  object tmp, result;
   char *buffer;
   char **buffers = NULL;
   int *lengths = NULL;
-  make_empty_bytevector(result);
+  if (argc == 0) {
+    make_empty_bytevector(r);
+    _return_closcall1(data, cont, &r);
+  }
+  if (argc == 1) {
+    Cyc_check_bvec(data, bv);
+    _return_closcall1(data, cont, bv);
+  }
   if (argc > 0) {
     buffers = alloca(sizeof(char *) * argc);
     lengths = alloca(sizeof(int) * argc);
@@ -3378,15 +3406,14 @@ object Cyc_bytevector_append(void *data, object cont, int argc, object bv, ...)
       buffers[i] = ((bytevector) tmp)->data;
     }
     va_end(ap);
-    buffer = alloca(sizeof(char) * total_length);
+    alloc_bytevector(data, result, total_length);
+    buffer = ((bytevector) result)->data;
     for (i = 0; i < argc; i++) {
       memcpy(&buffer[buf_idx], buffers[i], lengths[i]);
       buf_idx += lengths[i];
     }
-    result.len = total_length;
-    result.data = buffer;
   }
-  _return_closcall1(data, cont, &result);
+  _return_closcall1(data, cont, result);
 }
 
 object Cyc_bytevector_copy(void *data, object cont, object bv, object start,
@@ -3411,7 +3438,7 @@ object Cyc_bytevector_copy(void *data, object cont, object bv, object start,
     Cyc_rt_raise2(data, "bytevector-copy - invalid end", end);
   }
 
-  if (len >= MAX_STACK_OBJ) {
+  if (len >= Cyc_stack_remaining(data)) {
     int heap_grown;
     object result = gc_alloc(((gc_thread_data *) data)->heap,
                              sizeof(bytevector_type) + len,
@@ -3495,7 +3522,7 @@ object Cyc_string2utf8(void *data, object cont, object str, object start,
   }
   // Fast path
   if (string_num_cp(str) == string_len(str)) {
-    if (len >= MAX_STACK_OBJ) {
+    if (len >= Cyc_stack_remaining(data)) {
       int heap_grown;
       object bv = gc_alloc(((gc_thread_data *) data)->heap,
                            sizeof(bytevector_type) + len,
@@ -3540,7 +3567,7 @@ object Cyc_string2utf8(void *data, object cont, object str, object start,
       }
     }
     len = end_i - start_i;
-    if (len >= MAX_STACK_OBJ) {
+    if (len >= Cyc_stack_remaining(data)) {
       int heap_grown;
       object bv = gc_alloc(((gc_thread_data *) data)->heap,
                            sizeof(bytevector_type) + len,
@@ -3622,16 +3649,17 @@ object Cyc_list2vector(void *data, object cont, object l)
   object len_obj;
   object lst = l;
   int len, i = 0;
-  size_t element_vec_size;
+  size_t element_vec_size, alloc_required;
 
   make_c_opaque(opq, NULL);
   Cyc_check_pair_or_null(data, l);
   len_obj = Cyc_length(data, l);
   len = obj_obj2int(len_obj);
   element_vec_size = sizeof(object) * len;
-  if (element_vec_size >= MAX_STACK_OBJ) {
+  alloc_required = sizeof(vector_type) + element_vec_size;
+  if (alloc_required >= Cyc_stack_remaining(data)) {
     int heap_grown;
-    v = gc_alloc(((gc_thread_data *) data)->heap, sizeof(vector_type) + element_vec_size, boolean_f,    // OK to populate manually over here
+    v = gc_alloc(((gc_thread_data *) data)->heap, alloc_required, boolean_f,    // OK to populate manually over here
                  (gc_thread_data *) data, &heap_grown);
     ((vector) v)->hdr.mark = ((gc_thread_data *) data)->gc_alloc_color;
     ((vector) v)->hdr.grayed = 0;
@@ -8930,3 +8958,11 @@ object Cyc_exact_no_cps(void *data, object ptr, object z)
   }
   return obj_int2obj(i);
 }
+
+int Cyc_stack_remaining(gc_thread_data *td) 
+{
+  int i;
+  int stack_remaining = stack_delta(&i, td->stack_limit);
+  //printf("JAE DEBUG stack remaining = %ld\n", stack_remaining);
+  return stack_remaining;
+}
--- scheme/base.sld
+++ scheme/base.sld
@@ -1132,7 +1132,8 @@
         }
         num_cp = obj_obj2int(count);
         len = num_cp * buflen;
-        if (len >= MAX_STACK_OBJ) {
+        int stack_left = Cyc_stack_remaining(data);
+        if (len >= stack_left) {
           int heap_grown;
           s = gc_alloc(((gc_thread_data *)data)->heap, 
                        sizeof(string_type) + len + 1,
