Exemplo n.º 1
0
/*-------------------------------------------------------------------------*/
static size_t
svalue_size (svalue_t *v, mp_int * pTotal)

/* Compute the memory usage of *<v> (modified to reflect data sharing),
 * calling svalue_size() recursively if necessary, and return it.
 * The size of *v itself is not included.
 * *<pUnshared> and *<pShared> are set to the total unshared and shared
 * datasize.
 */

{
    mp_int i, composite, total, overhead;

    assert_stack_gap();

    *pTotal = 0;

    total = overhead = composite = 0;

    switch(v->type)
    {
    case T_OBJECT:
    case T_NUMBER:
    case T_FLOAT:
        return 0;

    case T_STRING:
    case T_SYMBOL:
        // If ref==0 the string is probably shared a lot, but we can't estimate
        // the correct number, so we return 0 as memory consumption for the
        // string.
        if (v->u.str->info.ref)
        {
            *pTotal = mstr_mem_size(v->u.str);
            return *pTotal / v->u.str->info.ref;
        }
        else
            return 0;

    case T_MAPPING:
    {
        struct svalue_size_locals locals;

        if (NULL == register_pointer(ptable, v->u.map) ) return 0;

        if (v->u.map->ref)
        {
            overhead = (mp_uint)mapping_overhead(v->u.map);
            locals.total = 0;
            locals.composite = 0;
            locals.num_values = v->u.map->num_values;
            walk_mapping(v->u.map, svalue_size_map_filter, &locals);

            *pTotal = locals.total + overhead;
            return (overhead + locals.composite) / v->u.map->ref;
        }
        else
            return 0;
    }

    case T_POINTER:
    case T_QUOTED_ARRAY:
    {
        if (v->u.vec == &null_vector) return 0;
        if (NULL == register_pointer(ptable, v->u.vec) ) return 0;
        if (v->u.vec->ref)
        {
            overhead = sizeof *v->u.vec - sizeof v->u.vec->item +
                       sizeof(svalue_t) * v->u.vec->size + sizeof(char *);
            for (i=0; i < (mp_int)VEC_SIZE(v->u.vec); i++) {
                composite += svalue_size(&v->u.vec->item[i], &total);
                *pTotal += total;
            }
            *pTotal += overhead;

            return (overhead + composite) / v->u.vec->ref;
        }
        else
            return 0;
    }
    case T_STRUCT:
    {
        struct_t *st = v->u.strct;
        if (NULL == register_pointer(ptable, st) ) return 0;
        if (st->ref)
        {
            overhead = sizeof *st - sizeof st->member
                       + sizeof(svalue_t) * struct_size(st);
            for (i=0; i < (mp_int)struct_size(st); i++) {
                composite += svalue_size(&st->member[i], &total);
                *pTotal += total;
            }
            *pTotal += overhead;

            return (overhead + composite) / st->ref;
        }
        else
            return 0;
    }

    case T_CLOSURE:
    {
        int num_values;
        svalue_t *svp;
        lambda_t *l;

        if (!CLOSURE_MALLOCED(v->x.closure_type)) return 0;
        if (!CLOSURE_REFERENCES_CODE(v->x.closure_type))
        {
            if (v->x.closure_type == CLOSURE_LFUN)
                composite = SIZEOF_LAMBDA(v->u.lambda->function.lfun.context_size);
            else /* CLOSURE_IDENTIFIER || CLOSURE_PRELIMINARY */
                composite = sizeof *v->u.lambda;

            composite += sizeof(char *);
            *pTotal = composite;
            return composite / v->u.lambda->ref;
        }
        /* CLOSURE_LAMBDA */
        composite = overhead = 0;
        l = v->u.lambda;
        if (v->x.closure_type == CLOSURE_BOUND_LAMBDA)
        {
            total = sizeof *l - sizeof l->function + sizeof l->function.lambda;
            *pTotal += total;
            composite += total / l->ref;
            l = l->function.lambda;
        }
        num_values = l->function.code.num_values;
        svp = (svalue_t *)l - num_values;
        if (NULL == register_pointer(ptable, svp)) return 0;
        overhead = sizeof(svalue_t) * num_values + sizeof (char *);
        {
            bytecode_p p = l->function.code.program;
            do {
                switch(GET_CODE(p++)) {
                case F_RETURN:
                case F_RETURN0:
                    break;
                default:
                    continue;
                }
                break;
            } while (1);
            overhead +=   (p - (bytecode_p)l + (sizeof(bytecode_p) - 1))
                          & ~(sizeof(bytecode_p) - 1);
        }

        while (--num_values >= 0)
        {
            composite += svalue_size(svp++, &total);
            *pTotal += total;
        }

        *pTotal += overhead;
        if (l->ref)
            return (overhead + composite) / l->ref;
        else
            return 0;
    }

    default:
        fatal("Illegal type: %d\n", v->type);
    }

    /*NOTREACHED*/
    return 0;
}
Exemplo n.º 2
0
svalue_t *
f_psyc_render(svalue_t *sp) {
    uint8_t i;
    vector_t *v;
    string_t *out;
    char *meth, *body;
    size_t mlen, blen;
    mapping_t *map;

    psycPacket packet;
    psycHeader headers[2];

    // unless (sp->type == T_POINTER) return sp;
    v = sp->u.vec;
    if (VEC_SIZE(v) == PACKET_BODY + 1) {
	for (i = PACKET_ROUTING; i <= PACKET_ENTITY; i++) {
	    headers[i].lines = 0;
	    if (v->item[i].type == T_MAPPING) {
		map = v->item[i].u.map;
		if (!MAP_SIZE(map)) continue;

		headers[i].modifiers = malloc(sizeof(psycModifier) * MAP_SIZE(v->item[i].u.map));
		if (!headers[i].modifiers) {
		    errorf("Out of memory in psyc_render for modifier table.\n");
		    return sp; // not reached
		}

		walk_mapping(map, &fill_header_from_mapping,
		             &(psyc_modifier_t) {
		                 &headers[i], map->num_values,
		                 i == PACKET_ROUTING ?
		                     PSYC_MODIFIER_ROUTING :
		                     PSYC_MODIFIER_CHECK_LENGTH
		             });
	    }
	    // else ... ignoring possibly invalid args
	}
    } else {
	errorf("Wrong number of elements (%" PRIdMPINT ") "
	       "in array argument to psyc_render()\n", VEC_SIZE(v));
	return sp; // not reached
    }

    if (v->item[PACKET_METHOD].type == T_STRING) {
	meth = get_txt(v->item[PACKET_METHOD].u.str);
	mlen = mstrsize(v->item[PACKET_METHOD].u.str);
    } else {
	meth = NULL;
	mlen = 0;
    }

    if (v->item[PACKET_BODY].type == T_STRING) {
	body = get_txt(v->item[PACKET_BODY].u.str);
	blen = mstrsize(v->item[PACKET_BODY].u.str);
    } else {
	body = NULL;
	blen = 0;
    }

    packet = psyc_newPacket2(headers[PACKET_ROUTING].modifiers,
                             headers[PACKET_ROUTING].lines,
                             headers[PACKET_ENTITY].modifiers,
                             headers[PACKET_ENTITY].lines,
                             meth, mlen, body, blen,
                             PSYC_PACKET_CHECK_LENGTH);

#ifdef DEBUG
    printf("rendering... packet.length = %ld\n", packet.length);
#endif
    // alloc_mstring creates an *untabled* string suitable for tmp data 
    memsafe(out = alloc_mstring(packet.length), packet.length, "f_psyc_render");
    psyc_render(&packet, get_txt(out), packet.length);

    free_svalue(sp);
    put_string(sp, out);
    // stack should take care of freeing the string after use
    return sp;

} /* f_psyc_render */