static void gc_mark(pic_state *pic, pic_value v) { if (! obj_p(pic, v)) return; gc_mark_object(pic, obj_ptr(pic, v)); }
pic_value pic_protect(pic_state *pic, pic_value v) { if (! obj_p(pic, v)) return v; gc_protect(pic, obj_ptr(pic, v)); return v; }
static void gc_mark_phase(pic_state *pic) { struct context *cxt; size_t j; assert(pic->heap->weaks == NULL); /* context */ for (cxt = pic->cxt; cxt != NULL; cxt = cxt->prev) { if (cxt->fp) gc_mark_object(pic, (struct object *)cxt->fp); if (cxt->sp) gc_mark_object(pic, (struct object *)cxt->sp); if (cxt->irep) gc_mark_object(pic, (struct object *)cxt->irep); } /* arena */ for (j = 0; j < pic->ai; ++j) { gc_mark_object(pic, (struct object *)pic->arena[j]); } /* global variables */ gc_mark(pic, pic->globals); /* dynamic environment */ gc_mark(pic, pic->dyn_env); /* top continuation */ gc_mark(pic, pic->halt); /* features */ gc_mark(pic, pic->features); /* weak maps */ do { struct object *key; pic_value val; int it; khash_t(weak) *h; struct weak *weak; j = 0; weak = pic->heap->weaks; while (weak != NULL) { h = &weak->hash; for (it = kh_begin(h); it != kh_end(h); ++it) { if (! kh_exist(h, it)) continue; key = kh_key(h, it); val = kh_val(h, it); if (is_alive(key)) { if (obj_p(pic, val) && ! is_alive(obj_ptr(pic, val))) { gc_mark(pic, val); ++j; } } } weak = weak->prev; } } while (j > 0); }
static void gc_mark_object(pic_state *pic, struct object *obj) { loop: if (is_alive(obj)) return; mark(obj); #define LOOP(o) obj = (struct object *)(o); goto loop switch (obj_type(pic, obj)) { case PIC_TYPE_PAIR: { gc_mark(pic, obj->u.pair.car); if (obj_p(pic, obj->u.pair.cdr)) { LOOP(obj_ptr(pic, obj->u.pair.cdr)); } break; } case PIC_TYPE_FRAME: { int i; for (i = 0; i < obj->u.frame.regc; ++i) { gc_mark(pic, obj->u.frame.regs[i]); } if (obj->u.frame.up) { LOOP(obj->u.frame.up); } break; } case PIC_TYPE_PROC_FUNC: { if (obj->u.proc.env) { LOOP(obj->u.proc.env); } break; } case PIC_TYPE_PROC_IREP: { if (obj->u.proc.env) { gc_mark_object(pic, (struct object *)obj->u.proc.env); } LOOP(obj->u.proc.u.irep); break; } case PIC_TYPE_IREP: { size_t i; for (i = 0; i < obj->u.irep.objc; ++i) { gc_mark(pic, obj->u.irep.obj[i]); } for (i = 0; i < obj->u.irep.irepc; ++i) { gc_mark_object(pic, (struct object *)obj->u.irep.irep[i]); } break; } case PIC_TYPE_PORT: { break; } case PIC_TYPE_ERROR: { gc_mark_object(pic, (struct object *)obj->u.err.type); gc_mark(pic, obj->u.err.irrs); LOOP(obj->u.err.msg); break; } case PIC_TYPE_STRING: { break; } case PIC_TYPE_VECTOR: { int i; for (i = 0; i < obj->u.vec.len; ++i) { gc_mark(pic, obj->u.vec.data[i]); } break; } case PIC_TYPE_BLOB: { break; } case PIC_TYPE_DATA: { break; } case PIC_TYPE_DICT: { pic_value key, val; int it = 0; while (pic_dict_next(pic, obj_value(pic, &obj->u.dict), &it, &key, &val)) { gc_mark(pic, key); gc_mark(pic, val); } break; } case PIC_TYPE_RECORD: { gc_mark(pic, obj->u.rec.datum); LOOP(obj->u.rec.type); break; } case PIC_TYPE_SYMBOL: { LOOP(obj->u.sym.str); break; } case PIC_TYPE_WEAK: { struct weak *weak = (struct weak *)obj; weak->prev = pic->heap->weaks; pic->heap->weaks = weak; break; } default: PIC_UNREACHABLE(); } }
obj* php_load_impl(const char* base, const char*& beg, const char* end) { #define THROW_INPUT_ERROR2(msg, ptr) \ do{ char buf[256]; \ int blen = snprintf(buf, sizeof(buf), "%s at pos: %ld", msg, long(ptr-base)); \ std::string strMsg(buf, blen); \ throw std::logic_error(strMsg); \ } while (0) #define THROW_INPUT_ERROR(msg) THROW_INPUT_ERROR2(msg, beg) switch (*beg) { default: { std::string msg = "php_load: invalid type: "; msg.push_back(*beg); msg += ", input:"; msg.append(beg, std::min<size_t>(100, end-beg)); throw std::logic_error(msg); } case 'i': { // i:val; if (++beg >= end) THROW_INPUT_ERROR("php_load: Incompleted php integer"); if (':' != *beg) THROW_INPUT_ERROR("php_load: integer, expect ':'"); char* pp = NULL; long long val = strtoll(beg+1, &pp, 10); if (';' != *pp) THROW_INPUT_ERROR2("php_load: integer, expect ';'", pp); beg = pp + 1; if (sizeof(long) == sizeof(long long) || (LONG_MIN <= val&&val <= LONG_MAX)) return new obj_long((long)val); else return new obj_llong(val); } case 'b': { // b:val; if (++beg >= end) THROW_INPUT_ERROR("php_load: Incompleted php boolean"); if (':' != *beg) THROW_INPUT_ERROR("php_load: boolean, expect ':'"); char* pp = NULL; long val = strtol(beg+1, &pp, 10); if (';' != *pp) THROW_INPUT_ERROR2("php_load: boolean, expect ';'", pp); beg = pp + 1; return new obj_bool(val ? 1 : 0); } #if 0 case 'd': { // d:val; if (++beg >= end) THROW_INPUT_ERROR("php_load: Incompleted php double"); if (':' != *beg) THROW_INPUT_ERROR("php_load: double, expect ':'"); char* pp = NULL; double val = strtod(beg+1, &pp); if (';' != *pp) THROW_INPUT_ERROR("php_load: double, expect ';'"); beg = pp + 1; return new obj_double(val); } #else case 'd': { // d:val; if (++beg >= end) THROW_INPUT_ERROR("php_load: Incompleted php double"); if (':' != *beg) THROW_INPUT_ERROR("php_load: long double, expect ':'"); char* pp = NULL; #ifdef __CYGWIN__ //_LDBL_EQ_DBL double val = strtod(beg+1, &pp); #else long double val = strtold(beg+1, &pp); #endif if (';' != *pp) THROW_INPUT_ERROR2("php_load: long double, expect ';'", pp); beg = pp + 1; return new obj_ldouble(val); } #endif case 's': { // s:size:"content"; if (++beg >= end) THROW_INPUT_ERROR("php_load: Incompleted php string"); if (':' != *beg) THROW_INPUT_ERROR("php_load: string.size expect ':'"); char* pp = NULL; long len = strtol(beg+1, &pp, 10); if (':' != *pp) THROW_INPUT_ERROR2("php_load: string.content expect ':'", pp); if (len < 0) THROW_INPUT_ERROR2("php_load: string.size is negtive", beg+1); if ('"' != pp[1]) THROW_INPUT_ERROR2("php_load: string.content expect '\"'", pp+1); if ('"' != pp[len+2]) THROW_INPUT_ERROR2("php_load: string.content not found right quote", pp+len+2); if (';' != pp[len+3]) THROW_INPUT_ERROR2("php_load: string didn't end with ';'", pp+len+3); std::auto_ptr<obj_string> x(new obj_string); x->resize(len); x->assign(pp+2, len); beg = pp + len + 4; // s:size:"content"; return x.release(); } case 'a': { // A:size:{key;value; ....} // fprintf(stderr, "loading array: "); if (++beg >= end) THROW_INPUT_ERROR("php_load: Incompleted php array"); if (':' != *beg) THROW_INPUT_ERROR("php_load: array.size expect ':'"); char* pp = NULL; long len = strtol(beg+1, &pp, 10); // fprintf(stderr, "size=%ld\n", len); if (':' != pp[0] || '{' != pp[1]) THROW_INPUT_ERROR2("php_load: array.size should followed by ':{'", pp); std::auto_ptr<obj_array> arr(new obj_array); std::auto_ptr<php_array> map; arr->resize(2*len); beg = pp + 2; long max_idx = -1; for (long i = 0; i < len; ++i) { // fprintf(stderr, "loading array[%ld]:\n", i); const char* key_pos = beg; std::auto_ptr<obj> key(php_load_impl(base, beg, end)); if (key.get() == NULL) { THROW_INPUT_ERROR2("php_load: array.key must not be NULL", key_pos); } if (arr.get()) { obj_long* l = dynamic_cast<obj_long*>(key.get()); if (l) { long idx = l->t; if (idx >= 0 && idx < (long)arr->size()) { (*arr)[idx].reset(php_load_impl(base, beg, end)); max_idx = std::max(idx, max_idx); continue; } } } if (map.get() == NULL) map.reset(new php_array); if (arr.get()) { for (long j = 0; j <= max_idx; ++j) { if ((*arr)[j]) (*map)[obj_ptr(new obj_long(j))] = (*arr)[j]; } arr.reset(NULL); } (*map)[obj_ptr(key.get())].reset(php_load_impl(base, beg, end)); key.release(); } if ('}' != *beg) THROW_INPUT_ERROR("php_load: array not correctly closed"); beg += 1; if (arr.get()) { arr->resize(max_idx+1); arr->shrink_to_fit(); return arr.release(); } return map.release(); } case 'N': { if (++beg >= end) THROW_INPUT_ERROR("php_load: Incompleted php NULL"); if (';' != *beg) THROW_INPUT_ERROR("php_load: NULL expect ';'"); beg += 1; return NULL; } case 'O': { // O:strlen(class name):"class name":fields_num:{s:strlen(field name):"field name":field definition;(repeated per field)} if (++beg >= end) THROW_INPUT_ERROR("php_load: Incompleted php Object"); if (':' != *beg) THROW_INPUT_ERROR("php_load: Object.namelen expect ':' 1"); char* pp = NULL; long len = strtol(beg+1, &pp, 10); if (':' != pp[0] && '"' != pp[1]) THROW_INPUT_ERROR2("php_load: Object.namelen expect ':\"' 2", pp); if (pp + 4 + len > end) THROW_INPUT_ERROR2("php_load: Object 3", pp); std::auto_ptr<php_object> tree(new php_object); tree->cls_name.assign(pp + 2, len); long fields = strtol(pp + 4 + len, &pp, 10); if (':' != pp[0] || '{' != pp[1]) THROW_INPUT_ERROR2("php_load: Object 4", pp); beg = pp + 2; for (long i = 0; i < fields; ++i) { std::auto_ptr<obj> pname(php_load_impl(base, beg, end)); obj_string* name = dynamic_cast<obj_string*>(pname.get()); if (NULL == name) THROW_INPUT_ERROR("object field name is not a string"); std::auto_ptr<obj> value(php_load_impl(base, beg, end)); tree->fields[*name].reset(value.release()); } if ('}' != beg[0]) THROW_INPUT_ERROR("php_load: Object not correctly closed"); beg += 1; return tree.release(); } } assert(0); return NULL; }