Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/6model/reprs/P6bigint.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
#ifndef MIN
4
   #define MIN(x,y) ((x)<(y)?(x):(y))
5
#endif
6
7
/* Get a native int64 from an mp_int. */
8
15
static MVMint64 mp_get_int64(MVMThreadContext *tc, mp_int * a) {
9
15
    MVMuint64 res;
10
15
    MVMuint64 signed_max = 9223372036854775807ULL;
11
15
    const int bits = mp_count_bits(a);
12
15
13
15
    /* For 64-bit 2's complement numbers the positive max is 2**63-1, which is 63 bits,
14
15
     * but the negative max is -(2**63), which is 64 bits. */
15
15
    if (MP_NEG == SIGN(a)) {
16
9
        if (bits > 64) {
17
0
            MVM_exception_throw_adhoc(tc, "Cannot unbox %d bit wide bigint into native integer", bits);
18
0
        }
19
9
        ++signed_max;
20
9
    }
21
6
  else {
22
6
        if (bits > 63) {
23
0
            MVM_exception_throw_adhoc(tc, "Cannot unbox %d bit wide bigint into native integer", bits);
24
0
        }
25
6
    }
26
15
27
15
    res = mp_get_long_long(a);
28
15
29
15
    if (res > signed_max) {
30
0
        /* The mp_int was bigger than a signed result could be. */
31
0
        MVM_exception_throw_adhoc(tc, "Cannot unbox %d bit wide bigint into native integer", bits);
32
0
    }
33
15
34
15
    return MP_NEG == SIGN(a) ? -res : res;
35
15
}
36
37
/* Get a native uint64 from an mp_int. */
38
0
static MVMuint64 mp_get_uint64(MVMThreadContext *tc, mp_int * a) {
39
0
    const int bits = mp_count_bits(a);
40
0
41
0
    if (bits > 64) {
42
0
        MVM_exception_throw_adhoc(tc, "Cannot unbox %d bit wide bigint into native integer", bits);
43
0
    }
44
0
45
0
    return mp_get_long_long(a);
46
0
}
47
48
/* This representation's function pointer table. */
49
static const MVMREPROps P6bigint_this_repr;
50
51
/* Creates a new type object of this representation, and associates it with
52
 * the given HOW. */
53
138
static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) {
54
138
    MVMSTable *st  = MVM_gc_allocate_stable(tc, &P6bigint_this_repr, HOW);
55
138
56
138
    MVMROOT(tc, st, {
57
138
        MVMObject *obj = MVM_gc_allocate_type_object(tc, st);
58
138
        MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj);
59
138
        st->size = sizeof(MVMP6bigint);
60
138
    });
61
138
62
138
    return st->WHAT;
63
138
}
64
65
/* Initializes a new instance. */
66
1.33k
static void initialize(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) {
67
1.33k
    MVMP6bigintBody *body = (MVMP6bigintBody *)data;
68
1.33k
    body->u.smallint.flag = MVM_BIGINT_32_FLAG;
69
1.33k
}
70
71
/* Copies the body of one object to another. */
72
2
static void copy_to(MVMThreadContext *tc, MVMSTable *st, void *src, MVMObject *dest_root, void *dest) {
73
2
    MVMP6bigintBody *src_body = (MVMP6bigintBody *)src;
74
2
    MVMP6bigintBody *dest_body = (MVMP6bigintBody *)dest;
75
2
    if (MVM_BIGINT_IS_BIG(src_body)) {
76
0
        dest_body->u.bigint = MVM_malloc(sizeof(mp_int));
77
0
        mp_init_copy(dest_body->u.bigint, src_body->u.bigint);
78
0
    }
79
2
    else {
80
2
        dest_body->u.smallint.flag = src_body->u.smallint.flag;
81
2
        dest_body->u.smallint.value = src_body->u.smallint.value;
82
2
    }
83
2
}
84
85
402
static void set_int(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 value) {
86
402
    MVMP6bigintBody *body = (MVMP6bigintBody *)data;
87
402
    if (MVM_IS_32BIT_INT(value)) {
88
402
        body->u.smallint.flag = MVM_BIGINT_32_FLAG;
89
402
        body->u.smallint.value = (MVMint32)value;
90
402
    }
91
0
    else {
92
0
        mp_int *i = MVM_malloc(sizeof(mp_int));
93
0
        mp_init(i);
94
0
        if (value >= 0) {
95
0
            MVM_bigint_mp_set_uint64(i, (MVMuint64)value);
96
0
        }
97
0
        else {
98
0
            MVM_bigint_mp_set_uint64(i, (MVMuint64)-value);
99
0
            mp_neg(i, i);
100
0
        }
101
0
        body->u.bigint = i;
102
0
    }
103
402
}
104
44
static MVMint64 get_int(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) {
105
44
    MVMP6bigintBody *body = (MVMP6bigintBody *)data;
106
44
    if (MVM_BIGINT_IS_BIG(body)) {
107
15
        mp_int *i = body->u.bigint;
108
15
        return mp_get_int64(tc, i);
109
15
    }
110
29
    else {
111
29
        return body->u.smallint.value;
112
29
    }
113
44
}
114
115
0
static void set_uint(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMuint64 value) {
116
0
    MVMP6bigintBody *body = (MVMP6bigintBody *)data;
117
0
    if (value < 2147483647ULL) {
118
0
        body->u.smallint.flag = MVM_BIGINT_32_FLAG;
119
0
        body->u.smallint.value = (MVMint32)value;
120
0
    }
121
0
    else {
122
0
        mp_int *i = MVM_malloc(sizeof(mp_int));
123
0
        mp_init(i);
124
0
        MVM_bigint_mp_set_uint64(i, value);
125
0
        body->u.bigint = i;
126
0
    }
127
0
}
128
0
static MVMuint64 get_uint(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) {
129
0
    MVMP6bigintBody *body = (MVMP6bigintBody *)data;
130
0
    if (MVM_BIGINT_IS_BIG(body)) {
131
0
        mp_int *i = body->u.bigint;
132
0
        if (MP_NEG == SIGN(i))
133
0
            MVM_exception_throw_adhoc(tc, "Cannot unbox negative bigint into native unsigned integer");
134
0
        else
135
0
            return mp_get_uint64(tc, i);
136
0
    }
137
0
    else {
138
0
        return body->u.smallint.value;
139
0
    }
140
0
}
141
142
2.68k
static void * get_boxed_ref(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMuint32 repr_id) {
143
2.68k
    if (repr_id == MVM_REPR_ID_P6bigint)
144
2.68k
        return data;
145
2.68k
146
0
    MVM_exception_throw_adhoc(tc,
147
0
        "P6bigint representation cannot unbox to other types");
148
0
}
149
150
151
static const MVMStorageSpec storage_spec = {
152
    MVM_STORAGE_SPEC_INLINED,      /* inlineable */
153
    sizeof(MVMP6bigintBody) * 8,   /* bits */
154
    ALIGNOF(MVMP6bigintBody),      /* align */
155
    MVM_STORAGE_SPEC_BP_INT,       /* boxed_primitive */
156
    MVM_STORAGE_SPEC_CAN_BOX_INT,  /* can_box */
157
    0,                             /* is_unsigned */
158
};
159
160
161
/* Gets the storage specification for this representation. */
162
27
static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
163
27
    return &storage_spec;
164
27
}
165
166
/* Compose the representation. */
167
7
static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info) {
168
7
    /* Nothing to do for this REPR. */
169
7
}
170
171
0
static void gc_cleanup(MVMThreadContext *tc, MVMSTable *st, void *data) {
172
0
    MVMP6bigintBody *body = (MVMP6bigintBody *)data;
173
0
    if (MVM_BIGINT_IS_BIG(body)) {
174
0
        mp_clear(body->u.bigint);
175
0
        MVM_free(body->u.bigint);
176
0
    }
177
0
}
178
179
174
static void gc_free(MVMThreadContext *tc, MVMObject *obj) {
180
174
    MVMP6bigintBody *body = &((MVMP6bigint *)obj)->body;
181
174
    if (MVM_BIGINT_IS_BIG(body)) {
182
117
        mp_clear(body->u.bigint);
183
117
        MVM_free(body->u.bigint);
184
117
    }
185
174
}
186
187
/* Serializes the bigint. */
188
3
static void serialize(MVMThreadContext *tc, MVMSTable *st, void *data, MVMSerializationWriter *writer) {
189
3
    MVMP6bigintBody *body = (MVMP6bigintBody *)data;
190
3
    if (MVM_BIGINT_IS_BIG(body)) {
191
0
        mp_int *i = body->u.bigint;
192
0
        int len;
193
0
        char *buf;
194
0
        MVMString *str;
195
0
        mp_radix_size(i, 10, &len);
196
0
        buf = (char *)MVM_malloc(len);
197
0
        mp_toradix(i, buf, 10);
198
0
199
0
        /* len - 1 because buf is \0-terminated */
200
0
        str = MVM_string_ascii_decode(tc, tc->instance->VMString, buf, len - 1);
201
0
202
0
        /* write the "is small" flag */
203
0
        MVM_serialization_write_int(tc, writer, 0);
204
0
        MVM_serialization_write_str(tc, writer, str);
205
0
        MVM_free(buf);
206
0
    }
207
3
    else {
208
3
        /* write the "is small" flag */
209
3
        MVM_serialization_write_int(tc, writer, 1);
210
3
        MVM_serialization_write_int(tc, writer, body->u.smallint.value);
211
3
    }
212
3
}
213
214
/* Set the size on the STable. */
215
2
static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
216
2
    st->size = sizeof(MVMP6bigint);
217
2
}
218
219
/* Deserializes the bigint. */
220
3
static void deserialize(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMSerializationReader *reader) {
221
3
    MVMP6bigintBody *body = (MVMP6bigintBody *)data;
222
3
223
3
    if (MVM_serialization_read_int(tc, reader) == 1) { /* Is it small int? */
224
3
        body->u.smallint.flag = MVM_BIGINT_32_FLAG;
225
3
        body->u.smallint.value = MVM_serialization_read_int(tc, reader);
226
0
    } else {  /* big int */
227
0
        char *buf = MVM_string_ascii_encode(tc, MVM_serialization_read_str(tc, reader), NULL, 0);
228
0
        body->u.bigint = MVM_malloc(sizeof(mp_int));
229
0
        mp_init(body->u.bigint);
230
0
        mp_read_radix(body->u.bigint, buf, 10);
231
0
        MVM_free(buf);
232
0
    }
233
3
}
234
235
/* Calculates the non-GC-managed memory we hold on to. */
236
18
static MVMuint64 unmanaged_size(MVMThreadContext *tc, MVMSTable *st, void *data) {
237
18
    MVMP6bigintBody *body = (MVMP6bigintBody *)data;
238
18
    if (MVM_BIGINT_IS_BIG(body))
239
0
        return body->u.bigint->alloc;
240
18
    else
241
18
        return 0;
242
18
}
243
244
/* Initializes the representation. */
245
130
const MVMREPROps * MVMP6bigint_initialize(MVMThreadContext *tc) {
246
130
    return &P6bigint_this_repr;
247
130
}
248
249
static const MVMREPROps P6bigint_this_repr = {
250
    type_object_for,
251
    MVM_gc_allocate_object,
252
    initialize,
253
    copy_to,
254
    MVM_REPR_DEFAULT_ATTR_FUNCS,
255
    {
256
        set_int,
257
        get_int,
258
        MVM_REPR_DEFAULT_SET_NUM,
259
        MVM_REPR_DEFAULT_GET_NUM,
260
        MVM_REPR_DEFAULT_SET_STR,
261
        MVM_REPR_DEFAULT_GET_STR,
262
        set_uint,
263
        get_uint,
264
        get_boxed_ref
265
    },    /* box_funcs */
266
    MVM_REPR_DEFAULT_POS_FUNCS,
267
    MVM_REPR_DEFAULT_ASS_FUNCS,
268
    MVM_REPR_DEFAULT_ELEMS,
269
    get_storage_spec,
270
    NULL, /* change_type */
271
    serialize,
272
    deserialize,
273
    NULL, /* serialize_repr_data */
274
    NULL, /* deserialize_repr_data */
275
    deserialize_stable_size,
276
    NULL, /* gc_mark */
277
    gc_free,
278
    gc_cleanup,
279
    NULL, /* gc_mark_repr_data */
280
    NULL, /* gc_free_repr_data */
281
    compose,
282
    NULL, /* spesh */
283
    "P6bigint", /* name */
284
    MVM_REPR_ID_P6bigint,
285
    unmanaged_size, /* unmanaged_size */
286
    NULL, /* describe_refs */
287
};