find_all.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*
  2. * Part of Scheme 48 1.9. See file COPYING for notices and license.
  3. *
  4. * Authors: David Frese
  5. */
  6. #include "generation_gc.h"
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include "scheme48.h"
  10. #include "areas.h"
  11. #include "data.h"
  12. #include "memory.h"
  13. #define INITIAL_AREA_SIZE 4
  14. #define AREA_SIZE_MULTIPLICATOR 2
  15. static Area* target_area;
  16. static unsigned long target_area_size; /* pages */
  17. static void initialize_find() {
  18. target_area_size = INITIAL_AREA_SIZE;
  19. target_area = s48_allocate_area(target_area_size, target_area_size,
  20. 0, AREA_TYPE_SIZE_SMALL);
  21. /* reserve space for the header */
  22. target_area->frontier = target_area->start + S48_STOB_OVERHEAD_IN_BYTES;
  23. }
  24. static void add_stob(s48_value stob) {
  25. if (AREA_REMAINING(target_area) < S48_CELLS_TO_BYTES(1)) {
  26. /* if there isn't enough space, create a bigger area, copy
  27. everything and free the old one. */
  28. unsigned long size = target_area->frontier - target_area->start;
  29. Area* new_area;
  30. target_area_size = target_area_size * AREA_SIZE_MULTIPLICATOR;
  31. new_area = s48_allocate_area(target_area_size, target_area_size,
  32. 0, AREA_TYPE_SIZE_SMALL);
  33. memcpy((void*)new_area->start, (void*)target_area->start, size);
  34. new_area->frontier = new_area->start + size;
  35. s48_free_area(target_area);
  36. target_area = new_area;
  37. }
  38. *((s48_value*)target_area->frontier) = stob;
  39. target_area->frontier += S48_CELLS_TO_BYTES(1);
  40. }
  41. /* S48_GATHER_OBJECTS: The iterator FOR_EACH_OBJECT must be called
  42. once, it then calls it's argument for every object that should be
  43. looked at. Store every such object, that also fulfills PREDICATE in
  44. a vector, return FALSE if the gathering cannot continue - in which
  45. case FOR_EACH_OBJECT returns FALSE either. S48_GATHER_OBJECTS then
  46. returns the vector or FALSE */
  47. static char(*gather_predicate)(s48_value);
  48. static char look_at_object(s48_value obj) {
  49. if (gather_predicate(obj))
  50. add_stob(obj);
  51. return TRUE;
  52. }
  53. s48_value s48_gather_objects(char(*predicate)(s48_value),
  54. char(*for_each_object)(char(*)(s48_value))) {
  55. /* sets up target_area */
  56. initialize_find();
  57. gather_predicate = predicate;
  58. if (for_each_object(&look_at_object)) {
  59. /* everything is fine, vector filled, complete it */
  60. s48_address addr_after_header = target_area->start + S48_STOB_OVERHEAD_IN_BYTES;
  61. unsigned long size = target_area->frontier - addr_after_header;
  62. *((long*)target_area->start) = S48_MAKE_HEADER(S48_STOBTYPE_VECTOR, size);
  63. s48_integrate_area(target_area);
  64. target_area = NULL;
  65. return S48_ADDRESS_TO_STOB_DESCRIPTOR(addr_after_header);
  66. } else {
  67. /* something went wrong, destroy area and give up */
  68. s48_free_area(target_area);
  69. target_area = NULL;
  70. return S48_FALSE;
  71. }
  72. }
  73. /* S48_FIND_ALL gathers everything in the heap with the given type.
  74. S48_FIND_ALL_RECORDS gathers all records in the heap with the given
  75. record type. */
  76. static long find_type;
  77. static s48_value find_record_type; /* S48_FALSE for s48_find_all */
  78. static char find_predicate(s48_value stob) {
  79. return ( (S48_STOB_TYPE(stob) == find_type)
  80. && ((find_record_type == S48_FALSE)
  81. || (S48_RECORD_TYPE(stob) == find_record_type)) );
  82. }
  83. static char find_iterator_result;
  84. static char(*find_iterator_look_at)(s48_value);
  85. static void find_iterator_scan(s48_address start, s48_address end) {
  86. /* PROBLEM/TODO: we cannot stop s48_walk_heap. So for now just do
  87. nothing, if we should've already stopped. */
  88. if (!find_iterator_result)
  89. return;
  90. else {
  91. s48_address addr = start;
  92. while (addr < end) {
  93. s48_address content = addr + S48_STOB_OVERHEAD_IN_BYTES;
  94. s48_value stob = S48_ADDRESS_TO_STOB_DESCRIPTOR(content);
  95. if (! find_iterator_look_at(stob)) {
  96. find_iterator_result = FALSE;
  97. return;
  98. }
  99. addr = content + S48_BYTES_TO_A_UNITS(S48_STOB_BYTE_LENGTH(stob));
  100. }
  101. }
  102. }
  103. static char find_iterator(char(*look_at)(s48_value)) {
  104. find_iterator_result = TRUE;
  105. find_iterator_look_at = look_at;
  106. s48_walk_heap(&find_iterator_scan);
  107. return find_iterator_result;
  108. }
  109. static s48_value do_find() {
  110. return s48_gather_objects(&find_predicate, &find_iterator);
  111. }
  112. s48_value s48_find_all(long type) {
  113. find_type = type;
  114. find_record_type = S48_FALSE;
  115. return do_find();
  116. }
  117. s48_value s48_find_all_records(s48_value record_type) {
  118. find_type = S48_STOBTYPE_RECORD;
  119. find_record_type = record_type;
  120. return do_find();
  121. }