Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/6model/reprs/MVMHash.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* This representation's function pointer table. */
4
static const MVMREPROps MVMHash_this_repr;
5
6
13.8M
MVM_STATIC_INLINE MVMString * get_string_key(MVMThreadContext *tc, MVMObject *key) {
7
13.8M
    if (!key || REPR(key)->ID != MVM_REPR_ID_MVMString || !IS_CONCRETE(key))
8
0
        MVM_exception_throw_adhoc(tc, "MVMHash representation requires MVMString keys");
9
13.8M
    return (MVMString *)key;
10
13.8M
}
11
12
/* Creates a new type object of this representation, and associates it with
13
 * the given HOW. */
14
130
static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) {
15
130
    MVMSTable *st = MVM_gc_allocate_stable(tc, &MVMHash_this_repr, HOW);
16
130
17
130
    MVMROOT(tc, st, {
18
130
        MVMObject *obj = MVM_gc_allocate_type_object(tc, st);
19
130
        MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj);
20
130
        st->size = sizeof(MVMHash);
21
130
    });
22
130
23
130
    return st->WHAT;
24
130
}
25
26
/* Copies the body of one object to another. */
27
3.35k
static void copy_to(MVMThreadContext *tc, MVMSTable *st, void *src, MVMObject *dest_root, void *dest) {
28
3.35k
    MVMHashBody *src_body  = (MVMHashBody *)src;
29
3.35k
    MVMHashBody *dest_body = (MVMHashBody *)dest;
30
3.35k
    MVMHashEntry *current, *tmp;
31
3.35k
    unsigned bucket_tmp;
32
3.35k
33
3.35k
    /* NOTE: if we really wanted to, we could avoid rehashing... */
34
5.57k
    HASH_ITER(hash_handle, src_body->hash_head, current, tmp, bucket_tmp) {
35
5.57k
        MVMHashEntry *new_entry = MVM_fixed_size_alloc(tc, tc->instance->fsa,
36
5.57k
            sizeof(MVMHashEntry));
37
5.57k
        MVMString *key = MVM_HASH_KEY(current);
38
5.57k
        MVM_ASSIGN_REF(tc, &(dest_root->header), new_entry->value, current->value);
39
5.57k
        MVM_HASH_BIND(tc, dest_body->hash_head, key, new_entry);
40
5.57k
        MVM_gc_write_barrier(tc, &(dest_root->header), &(key->common.header));
41
5.57k
    }
42
3.35k
}
43
44
/* Adds held objects to the GC worklist. */
45
265k
static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data, MVMGCWorklist *worklist) {
46
265k
    MVMHashBody *body = (MVMHashBody *)data;
47
265k
    MVMHashEntry *current, *tmp;
48
265k
    unsigned bucket_tmp;
49
265k
50
512k
    HASH_ITER(hash_handle, body->hash_head, current, tmp, bucket_tmp) {
51
512k
        MVM_gc_worklist_add(tc, worklist, &current->hash_handle.key);
52
512k
        MVM_gc_worklist_add(tc, worklist, &current->value);
53
512k
    }
54
265k
}
55
56
/* Called by the VM in order to free memory associated with this object. */
57
537k
static void gc_free(MVMThreadContext *tc, MVMObject *obj) {
58
537k
    MVMHash *h = (MVMHash *)obj;
59
537k
    MVMHashEntry *current, *tmp;
60
537k
    unsigned bucket_tmp;
61
537k
    HASH_ITER(hash_handle, h->body.hash_head, current, tmp, bucket_tmp) {
62
395k
        if (current != h->body.hash_head)
63
153k
            MVM_fixed_size_free(tc, tc->instance->fsa, sizeof(MVMHashEntry), current);
64
395k
    }
65
537k
    tmp = h->body.hash_head;
66
537k
    HASH_CLEAR(hash_handle, h->body.hash_head);
67
537k
    if (tmp)
68
241k
        MVM_fixed_size_free(tc, tc->instance->fsa, sizeof(MVMHashEntry), tmp);
69
537k
}
70
71
11.4M
static void at_key(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *key_obj, MVMRegister *result, MVMuint16 kind) {
72
11.4M
    MVMHashBody *body = (MVMHashBody *)data;
73
11.4M
    MVMHashEntry *entry;
74
11.4M
    MVMString *key = get_string_key(tc, key_obj);
75
11.4M
    MVM_HASH_GET(tc, body->hash_head, key, entry);
76
11.4M
    if (kind == MVM_reg_obj)
77
11.4M
        result->o = entry != NULL ? entry->value : tc->instance->VMNull;
78
11.4M
    else
79
0
        MVM_exception_throw_adhoc(tc,
80
0
            "MVMHash representation does not support native type storage");
81
11.4M
}
82
83
1.80M
static void bind_key(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *key_obj, MVMRegister value, MVMuint16 kind) {
84
1.80M
    MVMHashBody *body = (MVMHashBody *)data;
85
1.80M
    MVMHashEntry *entry;
86
1.80M
87
1.80M
    MVMString *key = get_string_key(tc, key_obj);
88
1.80M
    if (kind != MVM_reg_obj)
89
0
        MVM_exception_throw_adhoc(tc,
90
0
            "MVMHash representation does not support native type storage");
91
1.80M
92
1.80M
    /* first check whether we can must update the old entry. */
93
1.80M
    MVM_HASH_GET(tc, body->hash_head, key, entry);
94
1.80M
    if (!entry) {
95
1.76M
        entry = MVM_fixed_size_alloc(tc, tc->instance->fsa,
96
1.76M
            sizeof(MVMHashEntry));
97
1.76M
        MVM_ASSIGN_REF(tc, &(root->header), entry->value, value.o);
98
1.76M
        MVM_HASH_BIND(tc, body->hash_head, key, entry);
99
1.76M
        MVM_gc_write_barrier(tc, &(root->header), &(key->common.header));
100
1.76M
    }
101
41.5k
    else {
102
41.5k
        MVM_ASSIGN_REF(tc, &(root->header), entry->value, value.o);
103
41.5k
    }
104
1.80M
}
105
106
760k
static MVMuint64 elems(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) {
107
760k
    MVMHashBody *body = (MVMHashBody *)data;
108
760k
    return HASH_CNT(hash_handle, body->hash_head);
109
760k
}
110
111
488k
static MVMint64 exists_key(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *key_obj) {
112
488k
    MVMHashBody *body = (MVMHashBody *)data;
113
488k
    MVMString *key = get_string_key(tc, key_obj);
114
488k
    MVMHashEntry *entry;
115
488k
    MVM_HASH_GET(tc, body->hash_head, key, entry);
116
488k
    return entry != NULL;
117
488k
}
118
119
127k
static void delete_key(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *key_obj) {
120
127k
    MVMHashBody *body = (MVMHashBody *)data;
121
127k
    MVMString *key = get_string_key(tc, key_obj);
122
127k
    MVMHashEntry *old_entry;
123
127k
    MVM_HASH_GET(tc, body->hash_head, key, old_entry);
124
127k
    if (old_entry) {
125
125k
        HASH_DELETE(hash_handle, body->hash_head, old_entry);
126
125k
        MVM_fixed_size_free(tc, tc->instance->fsa,
127
125k
            sizeof(MVMHashEntry), old_entry);
128
125k
    }
129
127k
}
130
131
0
static MVMStorageSpec get_value_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
132
0
    MVMStorageSpec spec;
133
0
    spec.inlineable      = MVM_STORAGE_SPEC_REFERENCE;
134
0
    spec.boxed_primitive = MVM_STORAGE_SPEC_BP_NONE;
135
0
    spec.can_box         = 0;
136
0
    spec.bits            = 0;
137
0
    spec.align           = 0;
138
0
    spec.is_unsigned     = 0;
139
0
    return spec;
140
0
}
141
142
static const MVMStorageSpec storage_spec = {
143
    MVM_STORAGE_SPEC_REFERENCE, /* inlineable */
144
    0,                          /* bits */
145
    0,                          /* align */
146
    MVM_STORAGE_SPEC_BP_NONE,   /* boxed_primitive */
147
    0,                          /* can_box */
148
    0,                          /* is_unsigned */
149
};
150
151
/* Gets the storage specification for this representation. */
152
6.47k
static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
153
6.47k
    return &storage_spec;
154
6.47k
}
155
156
/* Compose the representation. */
157
0
static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info) {
158
0
    /* XXX key and value types will be communicated here */
159
0
}
160
161
/* Deserialize the representation. */
162
0
static void deserialize(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMSerializationReader *reader) {
163
0
    MVMHashBody *body = (MVMHashBody *)data;
164
0
    MVMint64 elems = MVM_serialization_read_int(tc, reader);
165
0
    MVMint64 i;
166
0
    for (i = 0; i < elems; i++) {
167
0
        MVMString *key = MVM_serialization_read_str(tc, reader);
168
0
        MVMObject *value = MVM_serialization_read_ref(tc, reader);
169
0
        MVMHashEntry *entry = MVM_fixed_size_alloc(tc, tc->instance->fsa,
170
0
            sizeof(MVMHashEntry));
171
0
        MVM_ASSIGN_REF(tc, &(root->header), entry->value, value);
172
0
        MVM_HASH_BIND(tc, body->hash_head, key, entry);
173
0
    }
174
0
}
175
176
/* Serialize the representation. */
177
0
static void serialize(MVMThreadContext *tc, MVMSTable *st, void *data, MVMSerializationWriter *writer) {
178
0
    MVMHashBody *body = (MVMHashBody *)data;
179
0
    MVMHashEntry *current, *tmp;
180
0
    unsigned bucket_tmp;
181
0
    MVM_serialization_write_int(tc, writer, HASH_CNT(hash_handle, body->hash_head));
182
0
    HASH_ITER(hash_handle, body->hash_head, current, tmp, bucket_tmp) {
183
0
        MVMString *key = MVM_HASH_KEY(current);
184
0
        MVM_serialization_write_str(tc, writer, key);
185
0
        MVM_serialization_write_ref(tc, writer, current->value);
186
0
    }
187
0
}
188
189
/* Set the size of the STable. */
190
0
static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
191
0
    st->size = sizeof(MVMHash);
192
0
}
193
194
/* Bytecode specialization for this REPR. */
195
8.39k
static void spesh(MVMThreadContext *tc, MVMSTable *st, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins) {
196
8.39k
    switch (ins->info->opcode) {
197
914
    case MVM_OP_create: {
198
914
        if (!(st->mode_flags & MVM_FINALIZE_TYPE)) {
199
914
            MVMSpeshOperand target   = ins->operands[0];
200
914
            MVMSpeshOperand type     = ins->operands[1];
201
914
            ins->info                = MVM_op_get_op(MVM_OP_sp_fastcreate);
202
914
            ins->operands            = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
203
914
            ins->operands[0]         = target;
204
914
            ins->operands[1].lit_i16 = sizeof(MVMHash);
205
914
            ins->operands[2].lit_i16 = MVM_spesh_add_spesh_slot(tc, g, (MVMCollectable *)st);
206
914
            MVM_spesh_get_facts(tc, g, type)->usages--;
207
914
        }
208
914
        break;
209
914
    }
210
8.39k
    }
211
8.39k
}
212
213
90.3k
static MVMuint64 unmanaged_size(MVMThreadContext *tc, MVMSTable *st, void *data) {
214
90.3k
    MVMHashBody *body = (MVMHashBody *)data;
215
90.3k
216
90.3k
    return sizeof(MVMHashEntry) * HASH_CNT(hash_handle, body->hash_head);
217
90.3k
}
218
219
/* Initializes the representation. */
220
130
const MVMREPROps * MVMHash_initialize(MVMThreadContext *tc) {
221
130
    return &MVMHash_this_repr;
222
130
}
223
224
static const MVMREPROps MVMHash_this_repr = {
225
    type_object_for,
226
    MVM_gc_allocate_object,
227
    NULL, /* initialize */
228
    copy_to,
229
    MVM_REPR_DEFAULT_ATTR_FUNCS,
230
    MVM_REPR_DEFAULT_BOX_FUNCS,
231
    MVM_REPR_DEFAULT_POS_FUNCS,
232
    {
233
        at_key,
234
        bind_key,
235
        exists_key,
236
        delete_key,
237
        get_value_storage_spec
238
    },    /* ass_funcs */
239
    elems,
240
    get_storage_spec,
241
    NULL, /* change_type */
242
    serialize,
243
    deserialize,
244
    NULL, /* serialize_repr_data */
245
    NULL, /* deserialize_repr_data */
246
    deserialize_stable_size,
247
    gc_mark,
248
    gc_free,
249
    NULL, /* gc_cleanup */
250
    NULL, /* gc_mark_repr_data */
251
    NULL, /* gc_free_repr_data */
252
    compose,
253
    spesh,
254
    "VMHash", /* name */
255
    MVM_REPR_ID_MVMHash,
256
    unmanaged_size, /* unmanaged_size */
257
    NULL, /* describe_refs */
258
};