Beispiel #1
0
static void
gc_mark(pic_state *pic, pic_value v)
{
  if (! obj_p(pic, v))
    return;

  gc_mark_object(pic, obj_ptr(pic, v));
}
Beispiel #2
0
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;
}
Beispiel #3
0
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);
}
Beispiel #4
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();
  }
}
Beispiel #5
0
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;
}