// @args finalizer allows NULL. pone_val* pone_opaque_new(pone_world* world, pone_val* klass, void* ptr, pone_finalizer_t finalizer) { struct pone_opaque_body* body = pone_malloc(world, sizeof(struct pone_opaque_body)); body->ptr = ptr; body->finalizer = finalizer; body->refcnt = 1; body->klass = klass; pone_val* opaque = pone_obj_alloc(world, PONE_OPAQUE); opaque->as.opaque.body = body; return opaque; }
// Caller must get GC_RD_LOCK. pone_val* pone_obj_alloc(pone_world* world, pone_t type) { pone_universe* universe = world->universe; assert(universe); assert(world->arena_last != NULL); pone_val* val; #ifdef STRESS_GC // pone_gc_log(world->universe, "stress gc\n"); world->gc_requested = true; #endif // check free-ed values if (world->freelist) { // reuse it. val = world->freelist; world->freelist = world->freelist->as.free.next; } else { // there is no free-ed value. // then, use value from arena. if (world->arena_last->idx == PONE_ARENA_SIZE) { // arena doesn't have an empty slot // Run GC. pone_gc_log(world->universe, "there's no empty slot in the arena %p\n", world->arena_last); world->gc_requested = true; // alloc new arena pone_arena* arena = pone_malloc(world, sizeof(pone_arena)); arena->next = NULL; arena->idx = 0; world->arena_last->next = arena; world->arena_last = arena; val = &(arena->values[arena->idx]); arena->idx++; } else { // use last arena entry val = &(world->arena_last->values[world->arena_last->idx++]); } } val->as.basic.flags = 0; val->as.basic.type = type; pone_save_tmp(world, val); return val; }
pone_val* pone_regex_new(pone_world* world, const char* str, size_t len) { pone_universe* universe = world->universe; pone_val* obj = pone_obj_new(world, universe->class_regex); OnigErrorInfo errinfo; regex_t* re = pone_malloc(world, sizeof(regex_t)); int err_code; if ((err_code = onig_new_without_alloc(re, (const OnigUChar*)str, (const OnigUChar*)str + len, ONIG_OPTION_NONE, ONIG_ENCODING_UTF8, ONIG_SYNTAX_PERL, &errinfo)) != ONIG_NORMAL) { char buf[ONIG_MAX_ERROR_MESSAGE_LEN]; int errsize = onig_error_code_to_str((OnigUChar*)buf, err_code, errinfo); pone_throw(world, pone_str_new_strdup(world, buf, errsize)); // TODO create X::Regexp } pone_obj_set_ivar(world, obj, "$!re", pone_opaque_new(world, universe->class_onig, re, re_finalizer)); pone_obj_set_ivar(world, obj, "$!str", pone_str_new_strdup(world, str, len)); return obj; }
pone_val* pone_new_hash(pone_world* world, int n, ...) { va_list list; pone_hash* hv = (pone_hash*)pone_malloc(world, sizeof(pone_hash)); hv->refcnt = 1; hv->type = PONE_HASH; hv->h = kh_init(str); va_start(list, n); // we can optimize in case of `{a => 3}`. we can omit mortalize. for (int i=0; i<n; i+=2) { pone_val* k = va_arg(list, pone_val*); pone_val* v = va_arg(list, pone_val*); pone_hash_put(world, (pone_val*)hv, k, v); } va_end(list); return (pone_val*)hv; }