memory.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #include "memory.h"
  2. #include "vm.h"
  3. #ifdef DEBUG_LOG_GC
  4. #include "debug.h"
  5. #include <stdlib.h>
  6. #endif
  7. // oldSize newSize Operation
  8. // 0 Non‑zero Allocate new block.
  9. // Non‑zero 0 Free allocation.
  10. // Non‑zero Smaller than oldSize Shrink existing allocation.
  11. // Non‑zero Larger than oldSize Grow existing allocation.
  12. void *reallocate(void *pointer, size_t oldSize, size_t newSize) {
  13. if (newSize > oldSize) {
  14. #ifdef DEBUG_STRESS_GC
  15. collectGarbage();
  16. #endif
  17. }
  18. if (newSize == 0) {
  19. free(pointer);
  20. return NULL;
  21. }
  22. /*
  23. The realloc() function tries to change the size of the allocation pointed
  24. to by ptr to size, and returns ptr. If there is not enough room to
  25. enlarge the memory allocation pointed to by ptr, realloc() creates a new
  26. allocation, copies as much of the old data pointed to by ptr as will fit
  27. to the new allocation, frees the old allocation, and returns a pointer to
  28. the allocated memory. If ptr is NULL, realloc() is identical to a call
  29. to malloc() for size bytes. If size is zero and ptr is not NULL, a new,
  30. minimum sized object is allocated and the original object is freed. When
  31. extending a region allocated with calloc(3), realloc(3) does not guaran-
  32. tee that the additional memory is also zero-filled
  33. */
  34. void *result = realloc(pointer, newSize);
  35. if (result == NULL) exit(1);
  36. return result;
  37. }
  38. static void freeObject(Obj *object) {
  39. #ifdef DEBUG_LOG_GC
  40. printf("%p free type %d\n", (void *) object, object->type);
  41. #endif
  42. switch (object->type) {
  43. case OBJ_NATIVE:
  44. FREE(ObjNative, object);
  45. break;
  46. case OBJ_FUNCTION: {
  47. ObjFunction *function = (ObjFunction *) object;
  48. freeChunk(&function->chunk);
  49. FREE(ObjFunction, object);
  50. break;
  51. }
  52. case OBJ_STRING:
  53. FREE_ARRAY(char, ((ObjString *) object)->chars, ((ObjString *) object)->length + 1);
  54. FREE(ObjString, object);
  55. break;
  56. case OBJ_CLOSURE: {
  57. ObjClosure *closure = (ObjClosure *) object;
  58. FREE_ARRAY(ObjUpvalue *, closure->upvalues, closure->upvalueCount);
  59. FREE(ObjClosure, object);
  60. break;
  61. }
  62. case OBJ_UPVALUE:
  63. FREE(ObjUpvalue, object);
  64. break;
  65. }
  66. }
  67. void freeObjects() {
  68. Obj *object = vm.objects;
  69. while (object != NULL) {
  70. Obj *next = object->next;
  71. freeObject(object);
  72. object = next;
  73. }
  74. }
  75. static void markRoots() {
  76. for (Value *slot = vm.stack; slot < vm.stackTop; slot++) {
  77. markValue(*slot);
  78. }
  79. for (int i = 0; i < vm.frameCount; i++) {
  80. markObject((Obj *) vm.frames[i].closure);
  81. }
  82. for (ObjUpvalue *upvalue = vm.openUpvalues; upvalue != NULL; upvalue = upvalue->next) {
  83. markObject((Obj *) upvalue);
  84. }
  85. markTable(&vm.globals);
  86. markCompilerRoots();
  87. }
  88. void collectGarbage() {
  89. #ifdef DEBUG_LOG_GC
  90. printf("-- gc begin\n");
  91. #endif
  92. markRoots();
  93. #ifdef DEBUG_LOG_GC
  94. printf("-- gc end\n");
  95. #endif
  96. }
  97. void markValue(Value value) {
  98. if (IS_OBJ(value)) markObject(AS_OBJ(value));
  99. }
  100. void markObject(Obj *object) {
  101. if (object == NULL) return;
  102. #ifdef DEBUG_LOG_GC
  103. printf("%p mark ", (void *) object);
  104. printValue(OBJ_VAL(object));
  105. printf("\n");
  106. #endif
  107. object->isMarked = true;
  108. }