GitHub

@@ -166,9 +166,17 @@ typedef struct mrb_heap_page {

166166

struct mrb_heap_page *next;

167167

struct mrb_heap_page *free_next;

168168

mrb_bool old:1;

169+

mrb_bool region:1; /* from contiguous region, not malloc */

169170

RVALUE objects[MRB_HEAP_PAGE_SIZE];

170171

} mrb_heap_page;

171172173+

typedef struct mrb_heap_region {

174+

struct mrb_heap_region *next;

175+

uint8_t *base; /* start of user buffer */

176+

size_t size; /* buffer size in bytes */

177+

uint16_t page_count; /* pages carved from region */

178+

} mrb_heap_region;

179+172180

#define GC_STEP_SIZE 1024

173181174182

/* white: 001 or 010, black: 100, gray: 000, red:111 */

@@ -283,6 +291,17 @@ static mrb_bool

283291

heap_p(mrb_gc *gc, const struct RBasic *object)

284292

{

285293

mrb_heap_page* page;

294+

mrb_heap_region *region;

295+296+

/* fast path: check contiguous regions via arithmetic */

297+

for (region = gc->regions; region; region = region->next) {

298+

uintptr_t addr = (uintptr_t)object;

299+

uintptr_t base = (uintptr_t)region->base;

300+

uintptr_t end = base + (size_t)region->page_count * sizeof(mrb_heap_page);

301+

if (addr >= base && addr < end) {

302+

return TRUE;

303+

}

304+

}

286305287306

page = gc->heaps;

288307

while (page) {

@@ -306,9 +325,17 @@ mrb_object_dead_p(mrb_state *mrb, struct RBasic *object)

306325

}

307326308327

static void

309-

add_heap(mrb_state *mrb, mrb_gc *gc)

328+

link_heap_page(mrb_gc *gc, mrb_heap_page *page)

329+

{

330+

page->next = gc->heaps;

331+

gc->heaps = page;

332+

page->free_next = gc->free_heaps;

333+

gc->free_heaps = page;

334+

}

335+336+

static void

337+

init_heap_page(mrb_heap_page *page)

310338

{

311-

mrb_heap_page *page = (mrb_heap_page*)mrb_calloc(mrb, 1, sizeof(mrb_heap_page));

312339

RVALUE *p, *e;

313340

RVALUE *prev = NULL;

314341

@@ -318,12 +345,50 @@ add_heap(mrb_state *mrb, mrb_gc *gc)

318345

prev = p;

319346

}

320347

page->freelist = prev;

348+

}

321349322-

page->next = gc->heaps;

323-

gc->heaps = page;

350+

static void

351+

add_heap(mrb_state *mrb, mrb_gc *gc)

352+

{

353+

mrb_heap_page *page = (mrb_heap_page*)mrb_calloc(mrb, 1, sizeof(mrb_heap_page));

354+

init_heap_page(page);

355+

link_heap_page(gc, page);

356+

}

324357325-

page->free_next = gc->free_heaps;

326-

gc->free_heaps = page;

358+

MRB_API int

359+

mrb_gc_add_region(mrb_state *mrb, void *start, size_t size)

360+

{

361+

mrb_gc *gc = &mrb->gc;

362+

uint8_t *base = (uint8_t*)start;

363+

mrb_heap_region *region;

364+

uint16_t page_count;

365+

uint16_t i;

366+367+

/* align base to pointer size */

368+

uintptr_t align = sizeof(void*);

369+

uintptr_t offset = ((uintptr_t)base + align - 1) & ~(align - 1);

370+

size -= (size_t)(offset - (uintptr_t)base);

371+

base = (uint8_t*)offset;

372+373+

page_count = (uint16_t)(size / sizeof(mrb_heap_page));

374+

if (page_count == 0) return 0;

375+376+

region = (mrb_heap_region*)mrb_malloc(mrb, sizeof(mrb_heap_region));

377+

region->base = base;

378+

region->size = size;

379+

region->page_count = page_count;

380+

region->next = gc->regions;

381+

gc->regions = region;

382+383+

/* carve pages from the contiguous buffer */

384+

for (i = 0; i < page_count; i++) {

385+

mrb_heap_page *page = (mrb_heap_page*)(base + (size_t)i * sizeof(mrb_heap_page));

386+

memset(page, 0, sizeof(mrb_heap_page));

387+

page->region = TRUE;

388+

init_heap_page(page);

389+

link_heap_page(gc, page);

390+

}

391+

return page_count;

327392

}

328393329394

#define DEFAULT_GC_INTERVAL_RATIO 200

@@ -345,6 +410,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc)

345410

gc->current_white_part = GC_WHITE_A;

346411

gc->heaps = NULL;

347412

gc->free_heaps = NULL;

413+

gc->regions = NULL;

348414

add_heap(mrb, gc);

349415

gc->interval_ratio = DEFAULT_GC_INTERVAL_RATIO;

350416

gc->step_ratio = DEFAULT_GC_STEP_RATIO;

@@ -370,14 +436,25 @@ free_heap(mrb_state *mrb, mrb_gc *gc)

370436

if (p->as.free.tt != MRB_TT_FREE)

371437

obj_free(mrb, &p->as.basic, TRUE);

372438

}

373-

mrb_free(mrb, tmp);

439+

if (!tmp->region) {

440+

mrb_free(mrb, tmp);

441+

}

374442

}

375443

}

376444377445

void

378446

mrb_gc_destroy(mrb_state *mrb, mrb_gc *gc)

379447

{

380448

free_heap(mrb, gc);

449+

/* free region descriptors (buffer memory belongs to the caller) */

450+

{

451+

mrb_heap_region *region = gc->regions;

452+

while (region) {

453+

mrb_heap_region *next = region->next;

454+

mrb_free(mrb, region);

455+

region = next;

456+

}

457+

}

381458

#ifndef MRB_GC_FIXED_ARENA

382459

mrb_free(mrb, gc->arena);

383460

#endif

@@ -1120,7 +1197,7 @@ incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)

11201197

}

1121119811221199

/* free dead slot */

1123-

if (dead_slot) {

1200+

if (dead_slot && !page->region) {

11241201

mrb_heap_page *next = page->next;

1125120211261203

if (prev) prev->next = next;

Read the original on github.com ↗