Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/gravity
Path: blob/master/src/shared/gravity_value.c
1214 views
1
//
2
// gravity_value.c
3
// gravity
4
//
5
// Created by Marco Bambini on 11/12/14.
6
// Copyright (c) 2014 CreoLabs. All rights reserved.
7
//
8
9
#include "gravity_hash.h"
10
#include "gravity_core.h"
11
#include "gravity_value.h"
12
#include "gravity_utils.h"
13
#include "gravity_memory.h"
14
#include "gravity_macros.h"
15
#include "gravity_opcodes.h"
16
#include "gravity_vmmacros.h"
17
18
static void gravity_function_special_serialize (gravity_function_t *f, const char *key, json_t *json);
19
static gravity_map_t *gravity_map_deserialize (gravity_vm *vm, json_value *json);
20
21
static void gravity_hash_serialize (gravity_hash_t *table, gravity_value_t key, gravity_value_t value, void *data) {
22
#pragma unused(table)
23
json_t *json = (json_t *)data;
24
25
if (VALUE_ISA_FUNCTION(value)) {
26
gravity_function_t *f = VALUE_AS_FUNCTION(value);
27
if (f->tag == EXEC_TYPE_SPECIAL) gravity_function_special_serialize(f, VALUE_AS_CSTRING(key), json);
28
else {
29
// there was an issue here due to the fact that when a subclass needs to use a $init from a superclass
30
// internally it has a unique name (key) but f->identifier continue to be called $init
31
// without this fix the subclass would continue to have 2 or more $init functions
32
gravity_string_t *s = VALUE_AS_STRING(key);
33
bool is_super_function = ((s->len > 5) && (string_casencmp(s->s, CLASS_INTERNAL_INIT_NAME, 5) == 0));
34
const char *saved = f->identifier;
35
if (is_super_function) f->identifier = s->s;
36
gravity_function_serialize(f, json);
37
if (is_super_function) f->identifier = saved;
38
}
39
}
40
else if (VALUE_ISA_CLASS(value)) {
41
gravity_class_serialize(VALUE_AS_CLASS(value), json);
42
}
43
else
44
assert(0);
45
}
46
47
void gravity_hash_keyvaluefree (gravity_hash_t *table, gravity_value_t key, gravity_value_t value, void *data) {
48
#pragma unused(table)
49
gravity_vm *vm = (gravity_vm *)data;
50
gravity_value_free(vm, key);
51
gravity_value_free(vm, value);
52
}
53
54
void gravity_hash_keyfree (gravity_hash_t *table, gravity_value_t key, gravity_value_t value, void *data) {
55
#pragma unused(table, value)
56
gravity_vm *vm = (gravity_vm *)data;
57
gravity_value_free(vm, key);
58
}
59
60
void gravity_hash_valuefree (gravity_hash_t *table, gravity_value_t key, gravity_value_t value, void *data) {
61
#pragma unused(table, key)
62
gravity_vm *vm = (gravity_vm *)data;
63
gravity_value_free(vm, value);
64
}
65
66
static void gravity_hash_internalsize (gravity_hash_t *table, gravity_value_t key, gravity_value_t value, void *data1, void *data2) {
67
#pragma unused(table)
68
uint32_t *size = (uint32_t *)data1;
69
gravity_vm *vm = (gravity_vm *)data2;
70
*size = gravity_value_size(vm, key);
71
*size += gravity_value_size(vm, value);
72
}
73
74
static void gravity_hash_gray (gravity_hash_t *table, gravity_value_t key, gravity_value_t value, void *data1) {
75
#pragma unused(table)
76
gravity_vm *vm = (gravity_vm *)data1;
77
gravity_gray_value(vm, key);
78
gravity_gray_value(vm, value);
79
}
80
81
// MARK: -
82
83
gravity_module_t *gravity_module_new (gravity_vm *vm, const char *identifier) {
84
gravity_module_t *m = (gravity_module_t *)mem_alloc(sizeof(gravity_module_t));
85
assert(m);
86
87
m->isa = gravity_class_module;
88
m->identifier = string_dup(identifier);
89
m->htable = gravity_hash_create(0, gravity_value_hash, gravity_value_equals, gravity_hash_keyvaluefree, (void*)vm);
90
91
gravity_vm_transfer(vm, (gravity_object_t*)m);
92
return m;
93
}
94
95
void gravity_module_free (gravity_vm *vm, gravity_module_t *m) {
96
#pragma unused(vm)
97
98
if (m->identifier) mem_free(m->identifier);
99
gravity_hash_free(m->htable);
100
mem_free(m);
101
}
102
103
uint32_t gravity_module_size (gravity_vm *vm, gravity_module_t *m) {
104
uint32_t hash_size = 0;
105
gravity_hash_iterate2(m->htable, gravity_hash_internalsize, (void*)&hash_size, (void*)vm);
106
return (sizeof(gravity_module_t)) + string_size(m->identifier) + hash_size + gravity_hash_memsize(m->htable);
107
}
108
109
void gravity_module_blacken (gravity_vm *vm, gravity_module_t *m) {
110
gravity_vm_memupdate(vm, gravity_module_size(vm, m));
111
gravity_hash_iterate(m->htable, gravity_hash_gray, (void*)vm);
112
}
113
114
// MARK: -
115
116
void gravity_class_bind (gravity_class_t *c, const char *key, gravity_value_t value) {
117
if (VALUE_ISA_CLASS(value)) {
118
// set outer has_outer when bind a class inside another class
119
gravity_class_t *obj = VALUE_AS_CLASS(value);
120
obj->has_outer = true;
121
}
122
gravity_hash_insert(c->htable, VALUE_FROM_CSTRING(NULL, key), value);
123
}
124
125
gravity_class_t *gravity_class_getsuper (gravity_class_t *c) {
126
return c->superclass;
127
}
128
129
bool gravity_class_grow (gravity_class_t *c, uint32_t n) {
130
if (c->ivars) mem_free(c->ivars);
131
if (c->nivars + n >= MAX_IVARS) return false;
132
c->nivars += n;
133
c->ivars = (gravity_value_t *)mem_alloc(c->nivars * sizeof(gravity_value_t));
134
for (uint32_t i=0; i<c->nivars; ++i) c->ivars[i] = VALUE_FROM_NULL;
135
return true;
136
}
137
138
bool gravity_class_setsuper (gravity_class_t *baseclass, gravity_class_t *superclass) {
139
if (!superclass) return true;
140
baseclass->superclass = superclass;
141
142
// check meta class first
143
gravity_class_t *supermeta = (superclass) ? gravity_class_get_meta(superclass) : NULL;
144
uint32_t n1 = (supermeta) ? supermeta->nivars : 0;
145
if (n1) if (!gravity_class_grow (gravity_class_get_meta(baseclass), n1)) return false;
146
147
// then check real class
148
uint32_t n2 = (superclass) ? superclass->nivars : 0;
149
if (n2) if (!gravity_class_grow (baseclass, n2)) return false;
150
151
return true;
152
}
153
154
gravity_class_t *gravity_class_new_single (gravity_vm *vm, const char *identifier, uint32_t nivar) {
155
gravity_class_t *c = (gravity_class_t *)mem_alloc(sizeof(gravity_class_t));
156
assert(c);
157
158
c->isa = gravity_class_class;
159
c->identifier = string_dup(identifier);
160
c->superclass = NULL;
161
c->nivars = nivar;
162
c->htable = gravity_hash_create(0, gravity_value_hash, gravity_value_equals, gravity_hash_keyfree, NULL);
163
if (nivar) {
164
c->ivars = (gravity_value_t *)mem_alloc(nivar * sizeof(gravity_value_t));
165
for (uint32_t i=0; i<nivar; ++i) c->ivars[i] = VALUE_FROM_NULL;
166
}
167
168
if (vm) gravity_vm_transfer(vm, (gravity_object_t*) c);
169
return c;
170
}
171
172
gravity_class_t *gravity_class_new_pair (gravity_vm *vm, const char *identifier, gravity_class_t *superclass, uint32_t nivar, uint32_t nsvar) {
173
// each class must have a valid identifier
174
if (!identifier) return NULL;
175
176
char buffer[512];
177
snprintf(buffer, sizeof(buffer), "%s meta", identifier);
178
179
gravity_class_t *supermeta = (superclass) ? gravity_class_get_meta(superclass) : NULL;
180
uint32_t n1 = (supermeta) ? supermeta->nivars : 0;
181
182
gravity_class_t *meta = gravity_class_new_single(vm, buffer, nsvar + n1);
183
meta->objclass = gravity_class_object;
184
gravity_class_setsuper(meta, gravity_class_class);
185
186
uint32_t n2 = (superclass) ? superclass->nivars : 0;
187
gravity_class_t *c = gravity_class_new_single(vm, identifier, nivar + n2);
188
c->objclass = meta;
189
190
// a class without a superclass in a subclass of Object.
191
gravity_class_setsuper(c, (superclass) ? superclass : gravity_class_object);
192
193
return c;
194
}
195
196
gravity_class_t *gravity_class_get_meta (gravity_class_t *c) {
197
// meta classes have objclass set to class object
198
if (c->objclass == gravity_class_object) return c;
199
return c->objclass;
200
}
201
202
bool gravity_class_is_meta (gravity_class_t *c) {
203
// meta classes have objclass set to class object
204
return (c->objclass == gravity_class_object);
205
}
206
207
uint32_t gravity_class_count_ivars (gravity_class_t *c) {
208
return (uint32_t)c->nivars;
209
}
210
211
int16_t gravity_class_add_ivar (gravity_class_t *c, const char *identifier) {
212
#pragma unused(identifier)
213
// TODO: add identifier in array (for easier debugging)
214
++c->nivars;
215
return c->nivars-1; // its a C array so index is 0 based
216
}
217
218
void gravity_class_dump (gravity_class_t *c) {
219
gravity_hash_dump(c->htable);
220
}
221
222
void gravity_class_setxdata (gravity_class_t *c, void *xdata) {
223
c->xdata = xdata;
224
}
225
226
void gravity_class_serialize (gravity_class_t *c, json_t *json) {
227
json_begin_object(json, c->identifier);
228
json_add_cstring(json, GRAVITY_JSON_LABELTYPE, GRAVITY_JSON_CLASS); // MANDATORY 1st FIELD
229
json_add_cstring(json, GRAVITY_JSON_LABELIDENTIFIER, c->identifier); // MANDATORY 2nd FIELD
230
231
// avoid write superclass name if it is the default Object one
232
if ((c->superclass) && (c->superclass->identifier) && (strcmp(c->superclass->identifier, GRAVITY_CLASS_OBJECT_NAME) != 0)) {
233
json_add_cstring(json, GRAVITY_JSON_LABELSUPER, c->superclass->identifier);
234
}
235
236
// get c meta class
237
gravity_class_t *meta = gravity_class_get_meta(c);
238
239
// number of instance (and static) variables
240
json_add_int(json, GRAVITY_JSON_LABELNIVAR, c->nivars);
241
if ((c != meta) && (meta->nivars > 0)) json_add_int(json, GRAVITY_JSON_LABELSIVAR, meta->nivars);
242
243
// struct flag
244
if (c->is_struct) json_add_bool(json, GRAVITY_JSON_LABELSTRUCT, true);
245
246
// serialize htable
247
if (c->htable) {
248
gravity_hash_iterate(c->htable, gravity_hash_serialize, (void *)json);
249
}
250
251
// serialize meta class
252
if (c != meta) {
253
// further proceed only if it has something to be serialized
254
if ((meta->htable) && (gravity_hash_count(meta->htable) > 0)) {
255
json_begin_array(json, GRAVITY_JSON_LABELMETA);
256
gravity_hash_iterate(meta->htable, gravity_hash_serialize, (void *)json);
257
json_end_array(json);
258
}
259
}
260
261
json_end_object(json);
262
}
263
264
gravity_class_t *gravity_class_deserialize (gravity_vm *vm, json_value *json) {
265
// sanity check
266
if (json->type != json_object) return NULL;
267
if (json->u.object.length < 3) return NULL;
268
269
// scan identifier
270
json_value *value = json->u.object.values[1].value;
271
const char *key = json->u.object.values[1].name;
272
273
// sanity check identifier
274
if (string_casencmp(key, GRAVITY_JSON_LABELIDENTIFIER, strlen(key)) != 0) return NULL;
275
assert(value->type == json_string);
276
277
// create class and meta
278
gravity_class_t *c = gravity_class_new_pair(vm, value->u.string.ptr, NULL, 0, 0);
279
DEBUG_DESERIALIZE("DESERIALIZE CLASS: %p %s\n", c, value->u.string.ptr);
280
281
// get its meta class
282
gravity_class_t *meta = gravity_class_get_meta(c);
283
284
uint32_t n = json->u.object.length;
285
for (uint32_t i=2; i<n; ++i) { // from 2 to skip type and identifier
286
287
// parse values
288
value = json->u.object.values[i].value;
289
key = json->u.object.values[i].name;
290
291
if (value->type != json_object) {
292
293
// super
294
if (string_casencmp(key, GRAVITY_JSON_LABELSUPER, strlen(key)) == 0) {
295
// the trick here is to re-use a runtime field to store a temporary static data like superclass name
296
// (only if different than the default Object one)
297
if (strcmp(value->u.string.ptr, GRAVITY_CLASS_OBJECT_NAME) != 0) {
298
c->xdata = (void *)string_dup(value->u.string.ptr);
299
}
300
continue;
301
}
302
303
// nivar
304
if (string_casencmp(key, GRAVITY_JSON_LABELNIVAR, strlen(key)) == 0) {
305
gravity_class_grow(c, (uint32_t)value->u.integer);
306
continue;
307
}
308
309
// sivar
310
if (string_casencmp(key, GRAVITY_JSON_LABELSIVAR, strlen(key)) == 0) {
311
gravity_class_grow(meta, (uint32_t)value->u.integer);
312
continue;
313
}
314
315
// struct
316
if (string_casencmp(key, GRAVITY_JSON_LABELSTRUCT, strlen(key)) == 0) {
317
c->is_struct = true;
318
continue;
319
}
320
321
// meta
322
if (string_casencmp(key, GRAVITY_JSON_LABELMETA, strlen(key)) == 0) {
323
uint32_t m = value->u.array.length;
324
for (uint32_t j=0; j<m; ++j) {
325
json_value *r = value->u.array.values[j];
326
if (r->type != json_object) continue;
327
gravity_object_t *obj = NULL;
328
bool result = gravity_object_deserialize(vm, r, &obj);
329
330
const char *identifier = obj->identifier;
331
if (OBJECT_ISA_FUNCTION(obj)) obj = (gravity_object_t *)gravity_closure_new(vm, (gravity_function_t *)obj);
332
if ((result) && (obj)) gravity_class_bind(meta, identifier, VALUE_FROM_OBJECT(obj));
333
else goto abort_load;
334
}
335
continue;
336
}
337
338
// error here
339
assert(0);
340
}
341
342
if (value->type == json_object) {
343
gravity_object_t *obj = NULL;
344
if (!gravity_object_deserialize(vm, value, &obj)) goto abort_load;
345
if (!obj) goto abort_load;
346
347
const char *identifier = obj->identifier;
348
if (OBJECT_ISA_FUNCTION(obj)) obj = (gravity_object_t *)gravity_closure_new(vm, (gravity_function_t *)obj);
349
gravity_class_bind(c, identifier, VALUE_FROM_OBJECT(obj));
350
}
351
}
352
353
return c;
354
355
abort_load:
356
if (c) gravity_class_free(vm, c);
357
return NULL;
358
}
359
360
static void gravity_class_free_internal (gravity_vm *vm, gravity_class_t *c, bool skip_base) {
361
if (skip_base && gravity_iscore_class(c)) return;
362
363
DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)c));
364
365
// check if bridged data needs to be freeed too
366
if (c->xdata && vm) {
367
gravity_delegate_t *delegate = gravity_vm_delegate(vm);
368
if (delegate && delegate->bridge_free) delegate->bridge_free(vm, (gravity_object_t *)c);
369
}
370
371
if (c->identifier) mem_free((void *)c->identifier);
372
if (!skip_base) {
373
// base classes have functions not registered inside VM so manually free all of them
374
gravity_hash_iterate(c->htable, gravity_hash_valuefree, NULL);
375
}
376
377
gravity_hash_free(c->htable);
378
if (c->ivars) mem_free((void *)c->ivars);
379
mem_free((void *)c);
380
}
381
382
void gravity_class_free_core (gravity_vm *vm, gravity_class_t *c) {
383
gravity_class_free_internal(vm, c, false);
384
}
385
386
void gravity_class_free (gravity_vm *vm, gravity_class_t *c) {
387
gravity_class_free_internal(vm, c, true);
388
}
389
390
inline gravity_object_t *gravity_class_lookup (gravity_class_t *c, gravity_value_t key) {
391
while (c) {
392
gravity_value_t *v = gravity_hash_lookup(c->htable, key);
393
if (v) return (gravity_object_t *)v->p;
394
c = c->superclass;
395
}
396
return NULL;
397
}
398
399
inline gravity_closure_t *gravity_class_lookup_closure (gravity_class_t *c, gravity_value_t key) {
400
gravity_object_t *obj = gravity_class_lookup(c, key);
401
if (obj && OBJECT_ISA_CLOSURE(obj)) return (gravity_closure_t *)obj;
402
return NULL;
403
}
404
405
inline gravity_closure_t *gravity_class_lookup_constructor (gravity_class_t *c, uint32_t nparams) {
406
if (c->xdata) {
407
// bridged class so check for special $initN function
408
if (nparams == 0) {
409
STATICVALUE_FROM_STRING(key, CLASS_INTERNAL_INIT_NAME, strlen(CLASS_INTERNAL_INIT_NAME));
410
return (gravity_closure_t *)gravity_class_lookup(c, key);
411
}
412
413
// for bridged classed (which can have more than one init constructor like in objc) the convention is
414
// to map each bridged init with a special $initN function (where N>0 is num params)
415
char name[256]; snprintf(name, sizeof(name), "%s%d", CLASS_INTERNAL_INIT_NAME, nparams);
416
STATICVALUE_FROM_STRING(key, name, strlen(name));
417
return (gravity_closure_t *)gravity_class_lookup(c, key);
418
}
419
420
// for non bridge classes just check for constructor
421
STATICVALUE_FROM_STRING(key, CLASS_CONSTRUCTOR_NAME, strlen(CLASS_CONSTRUCTOR_NAME));
422
return (gravity_closure_t *)gravity_class_lookup(c, key);
423
}
424
425
uint32_t gravity_class_size (gravity_vm *vm, gravity_class_t *c) {
426
uint32_t class_size = sizeof(gravity_class_t) + (c->nivars * sizeof(gravity_value_t)) + string_size(c->identifier);
427
428
uint32_t hash_size = 0;
429
gravity_hash_iterate2(c->htable, gravity_hash_internalsize, (void *)&hash_size, (void *)vm);
430
hash_size += gravity_hash_memsize(c->htable);
431
432
gravity_delegate_t *delegate = gravity_vm_delegate(vm);
433
if ((c->xdata) && (delegate) && (delegate->bridge_size))
434
class_size += delegate->bridge_size(vm, c->xdata);
435
436
return class_size;
437
}
438
439
void gravity_class_blacken (gravity_vm *vm, gravity_class_t *c) {
440
gravity_vm_memupdate(vm, gravity_class_size(vm, c));
441
442
// metaclass
443
gravity_gray_object(vm, (gravity_object_t *)c->objclass);
444
445
// superclass
446
gravity_gray_object(vm, (gravity_object_t *)c->superclass);
447
448
// internals
449
gravity_hash_iterate(c->htable, gravity_hash_gray, (void *)vm);
450
451
// ivars
452
for (uint32_t i=0; i<c->nivars; ++i) {
453
gravity_gray_value(vm, c->ivars[i]);
454
}
455
}
456
457
// MARK: -
458
459
gravity_function_t *gravity_function_new (gravity_vm *vm, const char *identifier, uint16_t nparams, uint16_t nlocals, uint16_t ntemps, void *code) {
460
gravity_function_t *f = (gravity_function_t *)mem_alloc(sizeof(gravity_function_t));
461
assert(f);
462
463
f->isa = gravity_class_function;
464
f->identifier = (identifier) ? string_dup(identifier) : NULL;
465
f->tag = EXEC_TYPE_NATIVE;
466
f->nparams = nparams;
467
f->nlocals = nlocals;
468
f->ntemps = ntemps;
469
f->nupvalues = 0;
470
471
// only available in EXEC_TYPE_NATIVE case
472
f->useargs = false;
473
f->bytecode = (uint32_t *)code;
474
marray_init(f->cpool);
475
476
if (vm) gravity_vm_transfer(vm, (gravity_object_t*)f);
477
return f;
478
}
479
480
gravity_function_t *gravity_function_new_internal (gravity_vm *vm, const char *identifier, gravity_c_internal exec, uint16_t nparams) {
481
gravity_function_t *f = gravity_function_new(vm, identifier, nparams, 0, 0, NULL);
482
f->tag = EXEC_TYPE_INTERNAL;
483
f->internal = exec;
484
return f;
485
}
486
487
gravity_function_t *gravity_function_new_special (gravity_vm *vm, const char *identifier, uint16_t index, void *getter, void *setter) {
488
gravity_function_t *f = gravity_function_new(vm, identifier, 0, 0, 0, NULL);
489
f->tag = EXEC_TYPE_SPECIAL;
490
f->index = index;
491
f->special[0] = getter;
492
f->special[1] = setter;
493
return f;
494
}
495
496
gravity_function_t *gravity_function_new_bridged (gravity_vm *vm, const char *identifier, void *xdata) {
497
gravity_function_t *f = gravity_function_new(vm, identifier, 0, 0, 0, NULL);
498
f->tag = EXEC_TYPE_BRIDGED;
499
f->xdata = xdata;
500
return f;
501
}
502
503
uint16_t gravity_function_cpool_add (gravity_vm *vm, gravity_function_t *f, gravity_value_t v) {
504
assert(f->tag == EXEC_TYPE_NATIVE);
505
506
size_t n = marray_size(f->cpool);
507
for (size_t i=0; i<n; i++) {
508
gravity_value_t v2 = marray_get(f->cpool, i);
509
if (gravity_value_equals(v,v2)) {
510
gravity_value_free(NULL, v);
511
return i;
512
}
513
}
514
515
// vm is required here because I cannot know in advance if v is already in the pool or not
516
// and value object v must be added to the VM only once
517
if ((vm) && (gravity_value_isobject(v))) gravity_vm_transfer(vm, VALUE_AS_OBJECT(v));
518
519
marray_push(gravity_value_t, f->cpool, v);
520
return (uint16_t)marray_size(f->cpool)-1;
521
}
522
523
gravity_value_t gravity_function_cpool_get (gravity_function_t *f, uint16_t i) {
524
assert(f->tag == EXEC_TYPE_NATIVE);
525
return marray_get(f->cpool, i);
526
}
527
528
void gravity_function_setxdata (gravity_function_t *f, void *xdata) {
529
f->xdata = xdata;
530
}
531
532
static void gravity_function_cpool_serialize (gravity_function_t *f, json_t *json) {
533
assert(f->tag == EXEC_TYPE_NATIVE);
534
size_t n = marray_size(f->cpool);
535
536
for (size_t i=0; i<n; i++) {
537
gravity_value_t v = marray_get(f->cpool, i);
538
gravity_value_serialize(v, json);
539
}
540
}
541
542
static void gravity_function_cpool_dump (gravity_function_t *f) {
543
assert(f->tag == EXEC_TYPE_NATIVE);
544
size_t n = marray_size(f->cpool);
545
546
for (size_t i=0; i<n; i++) {
547
gravity_value_t v = marray_get(f->cpool, i);
548
549
if (v.isa == gravity_class_bool) {
550
printf("%05zu\tBOOL: %d\n", i, (v.n == 0) ? 0 : 1);
551
} else if (v.isa == gravity_class_int) {
552
printf("%05zu\tINT: %lld\n", i, (int64_t)v.n);
553
} else if (v.isa == gravity_class_float) {
554
printf("%05zu\tFLOAT: %f\n", i, (double)v.f);
555
} else if (v.isa == gravity_class_function) {
556
gravity_function_t *vf = VALUE_AS_FUNCTION(v);
557
printf("%05zu\tFUNC: %s\n", i, (vf->identifier) ? vf->identifier : "$anon");
558
} else if (v.isa == gravity_class_class) {
559
gravity_class_t *c = VALUE_AS_CLASS(v);
560
printf("%05zu\tCLASS: %s\n", i, (c->identifier) ? c->identifier: "$anon");
561
} else if (v.isa == gravity_class_string) {
562
printf("%05zu\tSTRING: %s\n", i, VALUE_AS_CSTRING(v));
563
} else if (v.isa == gravity_class_list) {
564
gravity_list_t *value = VALUE_AS_LIST(v);
565
size_t count = marray_size(value->array);
566
printf("%05zu\tLIST: %zu items\n", i, count);
567
} else if (v.isa == gravity_class_map) {
568
gravity_map_t *map = VALUE_AS_MAP(v);
569
printf("%05zu\tMAP: %u items\n", i, gravity_hash_count(map->hash));
570
} else {
571
assert(0);
572
}
573
}
574
}
575
576
static void gravity_function_bytecode_serialize (gravity_function_t *f, json_t *json) {
577
if (!f->bytecode) {
578
json_add_null(json, GRAVITY_JSON_LABELBYTECODE);
579
return;
580
}
581
582
uint32_t ninst = f->ninsts;
583
uint32_t length = ninst * 2 * sizeof(uint32_t);
584
uint8_t *hexchar = (uint8_t*) mem_alloc(sizeof(uint8_t) * length);
585
586
for (uint32_t k=0, i=0; i < ninst; ++i) {
587
uint32_t value = f->bytecode[i];
588
589
for (int32_t j=2*sizeof(value)-1; j>=0; --j) {
590
uint8_t c = "0123456789ABCDEF"[((value >> (j*4)) & 0xF)];
591
hexchar[k++] = c;
592
}
593
}
594
595
json_add_string(json, GRAVITY_JSON_LABELBYTECODE, (const char *)hexchar, length);
596
mem_free(hexchar);
597
}
598
599
uint32_t *gravity_bytecode_deserialize (const char *buffer, size_t len, uint32_t *n) {
600
uint32_t ninst = (uint32_t)len / 8;
601
uint32_t *bytecode = (uint32_t *)mem_alloc(sizeof(uint32_t) * (ninst + 1)); // +1 to get a 0 terminated bytecode (0 is opcode RET0)
602
603
for (uint32_t j=0; j<ninst; ++j) {
604
register uint32_t v = 0;
605
606
for (uint32_t i=(j*8); i<=(j*8)+7; ++i) {
607
// I was using a conversion code from
608
// https://code.google.com/p/yara-project/source/browse/trunk/libyara/xtoi.c?r=150
609
// but it caused issues under ARM processor so I decided to switch to an easier to read/maintain code
610
// http://codereview.stackexchange.com/questions/42976/hexadecimal-to-integer-conversion-function
611
612
// no needs to have also the case:
613
// if (c >= 'a' && c <= 'f') {
614
// c = c - 'a' + 10;
615
// }
616
// because bytecode is always uppercase
617
register uint32_t c = buffer[i];
618
619
if (c >= 'A' && c <= 'F') {
620
c = c - 'A' + 10;
621
} else if (c >= '0' && c <= '9') {
622
c -= '0';
623
} else goto abort_conversion;
624
625
v = v << 4 | c;
626
627
}
628
629
bytecode[j] = v;
630
}
631
632
*n = ninst;
633
return bytecode;
634
635
abort_conversion:
636
if (bytecode) mem_free(bytecode);
637
*n = 0;
638
return NULL;
639
}
640
641
void gravity_function_dump (gravity_function_t *f, code_dump_function codef) {
642
printf("Function: %s\n", (f->identifier) ? f->identifier : "$anon");
643
printf("Params:%d Locals:%d Temp:%d Upvalues:%d\n", f->nparams, f->nlocals, f->ntemps, f->nupvalues);
644
645
if (f->tag == EXEC_TYPE_NATIVE) {
646
if (marray_size(f->cpool)) printf("======= CPOOL =======\n");
647
gravity_function_cpool_dump(f);
648
649
printf("======= BYTECODE ====\n");
650
if ((f->bytecode) && (codef)) codef(f->bytecode);
651
}
652
653
printf("\n");
654
}
655
656
void gravity_function_special_serialize (gravity_function_t *f, const char *key, json_t *json) {
657
json_begin_object(json, key);
658
659
json_add_cstring(json, GRAVITY_JSON_LABELTYPE, GRAVITY_JSON_FUNCTION); // MANDATORY 1st FIELD
660
json_add_cstring(json, GRAVITY_JSON_LABELIDENTIFIER, key); // MANDATORY 2nd FIELD
661
json_add_int(json, GRAVITY_JSON_LABELTAG, f->tag);
662
663
// common fields
664
json_add_int(json, GRAVITY_JSON_LABELNPARAM, f->nparams);
665
json_add_bool(json, GRAVITY_JSON_LABELARGS, f->useargs);
666
json_add_int(json, GRAVITY_JSON_LABELINDEX, f->index);
667
668
if (f->special[0]) {
669
gravity_function_t *f2 = (gravity_function_t*)f->special[0];
670
f2->identifier = GRAVITY_JSON_GETTER;
671
gravity_function_serialize(f2, json);
672
f2->identifier = NULL;
673
}
674
if (f->special[1]) {
675
gravity_function_t *f2 = (gravity_function_t*)f->special[1];
676
f2->identifier = GRAVITY_JSON_SETTER;
677
gravity_function_serialize(f2, json);
678
f2->identifier = NULL;
679
}
680
681
json_end_object(json);
682
}
683
684
void gravity_function_serialize (gravity_function_t *f, json_t *json) {
685
// special functions need a special serialization
686
if (f->tag == EXEC_TYPE_SPECIAL) {
687
gravity_function_special_serialize(f, f->identifier, json);
688
return;
689
}
690
691
// compute identifier (cannot be NULL)
692
const char *identifier = f->identifier;
693
char temp[256];
694
if (!identifier) {snprintf(temp, sizeof(temp), "$anon_%p", f); identifier = temp;}
695
696
if (identifier) json_begin_object(json, identifier);
697
json_add_cstring(json, GRAVITY_JSON_LABELTYPE, GRAVITY_JSON_FUNCTION); // MANDATORY 1st FIELD
698
if (identifier) json_add_cstring(json, GRAVITY_JSON_LABELIDENTIFIER, identifier); // MANDATORY 2nd FIELD (not for getter/setter)
699
json_add_int(json, GRAVITY_JSON_LABELTAG, f->tag);
700
701
// common fields
702
json_add_int(json, GRAVITY_JSON_LABELNPARAM, f->nparams);
703
json_add_bool(json, GRAVITY_JSON_LABELARGS, f->useargs);
704
705
if (f->tag == EXEC_TYPE_NATIVE) {
706
// native only fields
707
json_add_int(json, GRAVITY_JSON_LABELNLOCAL, f->nlocals);
708
json_add_int(json, GRAVITY_JSON_LABELNTEMP, f->ntemps);
709
json_add_int(json, GRAVITY_JSON_LABELNUPV, f->nupvalues);
710
json_add_double(json, GRAVITY_JSON_LABELPURITY, f->purity);
711
712
// bytecode
713
gravity_function_bytecode_serialize(f, json);
714
715
// constant pool
716
json_begin_array(json, GRAVITY_JSON_LABELPOOL);
717
gravity_function_cpool_serialize(f, json);
718
json_end_array(json);
719
}
720
721
if (identifier) json_end_object(json);
722
}
723
724
gravity_function_t *gravity_function_deserialize (gravity_vm *vm, json_value *json) {
725
gravity_function_t *f = gravity_function_new(vm, NULL, 0, 0, 0, NULL);
726
727
DEBUG_DESERIALIZE("DESERIALIZE FUNCTION: %p\n", f);
728
729
uint32_t n = json->u.object.length;
730
for (uint32_t i=1; i<n; ++i) { // from 1 to skip type
731
const char *label = json->u.object.values[i].name;
732
json_value *value = json->u.object.values[i].value;
733
size_t label_size = strlen(label);
734
735
// identifier
736
if (string_casencmp(label, GRAVITY_JSON_LABELIDENTIFIER, label_size) == 0) {
737
assert(value->type == json_string);
738
if (strncmp(value->u.string.ptr, "$anon", 5) != 0) {
739
f->identifier = string_dup(value->u.string.ptr);
740
DEBUG_DESERIALIZE("IDENTIFIER: %s\n", value->u.string.ptr);
741
}
742
continue;
743
}
744
745
// tag
746
if (string_casencmp(label, GRAVITY_JSON_LABELTAG, label_size) == 0) {
747
assert(value->type == json_integer);
748
f->tag = (uint16_t)value->u.integer;
749
continue;
750
}
751
752
// index (only in special functions)
753
if (string_casencmp(label, GRAVITY_JSON_LABELINDEX, label_size) == 0) {
754
assert(value->type == json_integer);
755
assert(f->tag == EXEC_TYPE_SPECIAL);
756
f->index = (uint16_t)value->u.integer;
757
continue;
758
}
759
760
// getter (only in special functions)
761
if (string_casencmp(label, GRAVITY_JSON_GETTER, strlen(GRAVITY_JSON_GETTER)) == 0) {
762
assert(f->tag == EXEC_TYPE_SPECIAL);
763
gravity_function_t *getter = gravity_function_deserialize(vm, value);
764
f->special[0] = gravity_closure_new(vm, getter);
765
continue;
766
}
767
768
// setter (only in special functions)
769
if (string_casencmp(label, GRAVITY_JSON_SETTER, strlen(GRAVITY_JSON_SETTER)) == 0) {
770
assert(f->tag == EXEC_TYPE_SPECIAL);
771
gravity_function_t *setter = gravity_function_deserialize(vm, value);
772
f->special[1] = gravity_closure_new(vm, setter);
773
continue;
774
}
775
776
// nparams
777
if (string_casencmp(label, GRAVITY_JSON_LABELNPARAM, label_size) == 0) {
778
assert(value->type == json_integer);
779
f->nparams = (uint16_t)value->u.integer;
780
continue;
781
}
782
783
// nlocals
784
if (string_casencmp(label, GRAVITY_JSON_LABELNLOCAL, label_size) == 0) {
785
assert(value->type == json_integer);
786
f->nlocals = (uint16_t)value->u.integer;
787
continue;
788
}
789
790
// ntemps
791
if (string_casencmp(label, GRAVITY_JSON_LABELNTEMP, label_size) == 0) {
792
assert(value->type == json_integer);
793
f->ntemps = (uint16_t)value->u.integer;
794
continue;
795
}
796
797
// nupvalues
798
if (string_casencmp(label, GRAVITY_JSON_LABELNUPV, label_size) == 0) {
799
assert(value->type == json_integer);
800
f->nupvalues = (uint16_t)value->u.integer;
801
continue;
802
}
803
804
// args
805
if (string_casencmp(label, GRAVITY_JSON_LABELARGS, label_size) == 0) {
806
assert(value->type == json_boolean);
807
f->useargs = (bool)value->u.boolean;
808
continue;
809
}
810
811
// bytecode
812
if (string_casencmp(label, GRAVITY_JSON_LABELBYTECODE, label_size) == 0) {
813
if (value->type == json_null) continue;
814
assert(value->type == json_string);
815
f->bytecode = gravity_bytecode_deserialize(value->u.string.ptr, value->u.string.length, &f->ninsts);
816
continue;
817
}
818
819
// cpool
820
if (string_casencmp(label, GRAVITY_JSON_LABELPOOL, label_size) == 0) {
821
assert(value->type == json_array);
822
uint32_t m = value->u.array.length;
823
for (uint32_t j=0; j<m; ++j) {
824
json_value *r = value->u.array.values[j];
825
switch (r->type) {
826
case json_integer:
827
gravity_function_cpool_add(NULL, f, VALUE_FROM_INT((gravity_int_t)r->u.integer));
828
break;
829
830
case json_double:
831
gravity_function_cpool_add(NULL, f, VALUE_FROM_FLOAT((gravity_float_t)r->u.dbl));
832
break;
833
834
case json_boolean:
835
gravity_function_cpool_add(NULL, f, VALUE_FROM_BOOL(r->u.boolean));
836
break;
837
838
case json_string:
839
gravity_function_cpool_add(vm, f, VALUE_FROM_STRING(NULL, r->u.string.ptr, r->u.string.length));
840
break;
841
842
case json_object: {
843
gravity_object_t *obj = NULL;
844
bool result = gravity_object_deserialize(vm, r, &obj);
845
if ((result) && (obj)) gravity_function_cpool_add(NULL, f, VALUE_FROM_OBJECT(obj));
846
else goto abort_load;
847
break;
848
}
849
850
case json_array: {
851
uint32_t count = r->u.array.length;
852
gravity_list_t *list = gravity_list_new(NULL, count);
853
for (uint32_t k=0; k<count; ++k) {
854
json_value *jsonv = r->u.array.values[k];
855
gravity_value_t v;
856
857
// only literals allowed here
858
switch (jsonv->type) {
859
case json_integer: v = VALUE_FROM_INT((gravity_int_t)jsonv->u.integer); break;
860
case json_double: v = VALUE_FROM_FLOAT((gravity_float_t)jsonv->u.dbl); break;
861
case json_boolean: v = VALUE_FROM_BOOL(jsonv->u.boolean); break;
862
case json_string: v = VALUE_FROM_STRING(vm, jsonv->u.string.ptr, jsonv->u.string.length); break;
863
default:assert(0);
864
}
865
866
marray_push(gravity_value_t, list->array, v);
867
}
868
gravity_function_cpool_add(vm, f, VALUE_FROM_OBJECT(list));
869
}
870
871
case json_none:
872
case json_null:
873
gravity_function_cpool_add(NULL, f, VALUE_FROM_NULL);
874
break;
875
}
876
}
877
}
878
}
879
880
return f;
881
882
abort_load:
883
if (f) gravity_function_free(vm, f);
884
return NULL;
885
}
886
887
void gravity_function_free (gravity_vm *vm, gravity_function_t *f) {
888
if (!f) return;
889
890
DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)f));
891
892
// check if bridged data needs to be freed too
893
if (f->xdata && vm) {
894
gravity_delegate_t *delegate = gravity_vm_delegate(vm);
895
if (delegate && delegate->bridge_free) delegate->bridge_free(vm, (gravity_object_t *)f);
896
}
897
898
if (f->identifier) mem_free((void *)f->identifier);
899
if (f->tag == EXEC_TYPE_NATIVE) {
900
if (f->bytecode) mem_free((void *)f->bytecode);
901
// DO NOT FREE EACH INDIVIDUAL CPOOL ITEM HERE
902
marray_destroy(f->cpool);
903
}
904
mem_free((void *)f);
905
}
906
907
uint32_t gravity_function_size (gravity_vm *vm, gravity_function_t *f) {
908
uint32_t func_size = sizeof(gravity_function_t) + string_size(f->identifier);
909
910
if (f->tag == EXEC_TYPE_NATIVE) {
911
if (f->bytecode) func_size += f->ninsts * sizeof(uint32_t);
912
// cpool size
913
size_t n = marray_size(f->cpool);
914
for (size_t i=0; i<n; i++) {
915
gravity_value_t v = marray_get(f->cpool, i);
916
func_size += gravity_value_size(vm, v);
917
}
918
} else if (f->tag == EXEC_TYPE_SPECIAL) {
919
if (f->special[0]) func_size += gravity_closure_size(vm, (gravity_closure_t *)f->special[0]);
920
if ((f->special[1]) && (f->special[0] != f->special[1])) func_size += gravity_closure_size(vm, (gravity_closure_t *)f->special[1]);
921
} else if (f->tag == EXEC_TYPE_BRIDGED) {
922
gravity_delegate_t *delegate = gravity_vm_delegate(vm);
923
if ((f->xdata) && (delegate) && (delegate->bridge_size))
924
func_size += delegate->bridge_size(vm, f->xdata);
925
}
926
927
return func_size;
928
}
929
930
void gravity_function_blacken (gravity_vm *vm, gravity_function_t *f) {
931
gravity_vm_memupdate(vm, gravity_function_size(vm, f));
932
933
if (f->tag == EXEC_TYPE_SPECIAL) {
934
if (f->special[0]) gravity_gray_object(vm, (gravity_object_t *)f->special[0]);
935
if (f->special[1]) gravity_gray_object(vm, (gravity_object_t *)f->special[1]);
936
}
937
938
if (f->tag == EXEC_TYPE_NATIVE) {
939
// constant pool
940
size_t n = marray_size(f->cpool);
941
for (size_t i=0; i<n; i++) {
942
gravity_value_t v = marray_get(f->cpool, i);
943
gravity_gray_value(vm, v);
944
}
945
}
946
}
947
948
// MARK: -
949
950
gravity_closure_t *gravity_closure_new (gravity_vm *vm, gravity_function_t *f) {
951
#pragma unused(vm)
952
953
gravity_closure_t *closure = (gravity_closure_t *)mem_alloc(sizeof(gravity_closure_t));
954
assert(closure);
955
956
closure->isa = gravity_class_closure;
957
closure->f = f;
958
959
// allocate upvalue array (+1 so I can simplify the iterator without the needs to access closure->f->nupvalues)
960
uint16_t nupvalues = (f) ? f->nupvalues : 0;
961
closure->upvalue = (nupvalues) ? (gravity_upvalue_t **)mem_alloc(sizeof(gravity_upvalue_t*) * (f->nupvalues + 1)) : NULL;
962
963
if (vm) gravity_vm_transfer(vm, (gravity_object_t*)closure);
964
return closure;
965
}
966
967
void gravity_closure_free (gravity_vm *vm, gravity_closure_t *closure) {
968
#pragma unused(vm)
969
970
DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)closure));
971
972
if (closure->upvalue) mem_free(closure->upvalue);
973
mem_free(closure);
974
}
975
976
uint32_t gravity_closure_size (gravity_vm *vm, gravity_closure_t *closure) {
977
#pragma unused(vm)
978
979
uint32_t closure_size = sizeof(gravity_closure_t);
980
gravity_upvalue_t **upvalue = closure->upvalue;
981
while (upvalue) {
982
closure_size += sizeof(gravity_upvalue_t*);
983
++upvalue;
984
}
985
return closure_size;
986
}
987
988
void gravity_closure_blacken (gravity_vm *vm, gravity_closure_t *closure) {
989
gravity_vm_memupdate(vm, gravity_closure_size(vm, closure));
990
991
// mark function
992
gravity_gray_object(vm, (gravity_object_t*)closure->f);
993
994
// mark each upvalue
995
gravity_upvalue_t **upvalue = closure->upvalue;
996
while (upvalue) {
997
gravity_gray_object(vm, (gravity_object_t*)upvalue[0]);
998
++upvalue;
999
}
1000
}
1001
1002
// MARK: -
1003
1004
gravity_upvalue_t *gravity_upvalue_new (gravity_vm *vm, gravity_value_t *value) {
1005
#pragma unused(vm)
1006
gravity_upvalue_t *upvalue = (gravity_upvalue_t *)mem_alloc(sizeof(gravity_upvalue_t));
1007
1008
upvalue->isa = gravity_class_upvalue;
1009
upvalue->value = value;
1010
upvalue->closed = VALUE_FROM_NULL;
1011
upvalue->next = NULL;
1012
1013
if (vm) gravity_vm_transfer(vm, (gravity_object_t*)upvalue);
1014
return upvalue;
1015
}
1016
1017
uint32_t gravity_upvalue_size (gravity_vm *vm, gravity_upvalue_t *upvalue) {
1018
#pragma unused(vm, upvalue)
1019
return sizeof(gravity_upvalue_t);
1020
}
1021
1022
void gravity_upvalue_blacken (gravity_vm *vm, gravity_upvalue_t *upvalue) {
1023
#pragma unused(vm)
1024
gravity_vm_memupdate(vm, gravity_upvalue_size(vm, upvalue));
1025
gravity_gray_value(vm, upvalue->closed);
1026
}
1027
1028
void gravity_upvalue_free(gravity_vm *vm, gravity_upvalue_t *upvalue) {
1029
#pragma unused(vm)
1030
1031
DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)upvalue));
1032
mem_free(upvalue);
1033
}
1034
1035
// MARK: -
1036
1037
gravity_fiber_t *gravity_fiber_new (gravity_vm *vm, gravity_closure_t *closure, uint32_t nstack, uint32_t nframes) {
1038
gravity_fiber_t *fiber = (gravity_fiber_t *)mem_alloc(sizeof(gravity_fiber_t));
1039
assert(fiber);
1040
1041
fiber->isa = gravity_class_fiber;
1042
fiber->caller = NULL;
1043
fiber->result = VALUE_FROM_NULL;
1044
1045
if (nstack < DEFAULT_MINSTACK_SIZE) nstack = DEFAULT_MINSTACK_SIZE;
1046
fiber->stack = (gravity_value_t *)mem_alloc(sizeof(gravity_value_t) * nstack);
1047
fiber->stacktop = fiber->stack;
1048
fiber->stackalloc = nstack;
1049
1050
if (nframes < DEFAULT_MINCFRAME_SIZE) nframes = DEFAULT_MINCFRAME_SIZE;
1051
fiber->frames = (gravity_callframe_t *)mem_alloc(sizeof(gravity_callframe_t) * nframes);
1052
fiber->framesalloc = nframes;
1053
fiber->nframes = 1;
1054
1055
fiber->upvalues = NULL;
1056
1057
gravity_callframe_t *frame = &fiber->frames[0];
1058
if (closure) {
1059
frame->closure = closure;
1060
frame->ip = (closure->f->tag == EXEC_TYPE_NATIVE) ? closure->f->bytecode : NULL;
1061
}
1062
frame->dest = 0;
1063
frame->stackstart = fiber->stack;
1064
1065
gravity_vm_transfer(vm, (gravity_object_t*) fiber);
1066
return fiber;
1067
}
1068
1069
void gravity_fiber_free (gravity_vm *vm, gravity_fiber_t *fiber) {
1070
#pragma unused(vm)
1071
1072
DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)fiber));
1073
if (fiber->error) mem_free(fiber->error);
1074
mem_free(fiber->stack);
1075
mem_free(fiber->frames);
1076
mem_free(fiber);
1077
}
1078
1079
void gravity_fiber_reassign (gravity_fiber_t *fiber, gravity_closure_t *closure, uint16_t nargs) {
1080
gravity_callframe_t *frame = &fiber->frames[0];
1081
frame->closure = closure;
1082
frame->ip = (closure->f->tag == EXEC_TYPE_NATIVE) ? closure->f->bytecode : NULL;
1083
1084
frame->dest = 0;
1085
frame->stackstart = fiber->stack;
1086
1087
fiber->nframes = 1;
1088
fiber->upvalues = NULL;
1089
1090
// update stacktop in order to be GC friendly
1091
fiber->stacktop += FN_COUNTREG(closure->f, nargs);
1092
}
1093
1094
void gravity_fiber_seterror (gravity_fiber_t *fiber, const char *error) {
1095
if (fiber->error) mem_free(fiber->error);
1096
fiber->error = (char *)string_dup(error);
1097
}
1098
1099
uint32_t gravity_fiber_size (gravity_vm *vm, gravity_fiber_t *fiber) {
1100
// internal size
1101
uint32_t fiber_size = sizeof(gravity_fiber_t);
1102
fiber_size += fiber->stackalloc * sizeof(gravity_value_t);
1103
fiber_size += fiber->framesalloc * sizeof(gravity_callframe_t);
1104
1105
// stack size
1106
for (gravity_value_t* slot = fiber->stack; slot < fiber->stacktop; ++slot) {
1107
fiber_size += gravity_value_size(vm, *slot);
1108
}
1109
1110
fiber_size += string_size(fiber->error);
1111
fiber_size += gravity_object_size(vm, (gravity_object_t *)fiber->caller);
1112
1113
return fiber_size;
1114
}
1115
1116
void gravity_fiber_blacken (gravity_vm *vm, gravity_fiber_t *fiber) {
1117
gravity_vm_memupdate(vm, gravity_fiber_size(vm, fiber));
1118
1119
// gray call frame functions
1120
for (uint32_t i=0; i < fiber->nframes; ++i) {
1121
gravity_gray_object(vm, (gravity_object_t *)fiber->frames[i].closure);
1122
}
1123
1124
// gray stack variables
1125
for (gravity_value_t* slot = fiber->stack; slot < fiber->stacktop; ++slot) {
1126
gravity_gray_value(vm, *slot);
1127
}
1128
1129
// gray upvalues
1130
gravity_upvalue_t* upvalue = fiber->upvalues;
1131
while (upvalue) {
1132
gravity_gray_object(vm, (gravity_object_t *)upvalue);
1133
upvalue = upvalue->next;
1134
}
1135
1136
gravity_gray_object(vm, (gravity_object_t *)fiber->caller);
1137
}
1138
1139
// MARK: -
1140
1141
void gravity_object_serialize (gravity_object_t *obj, json_t *json) {
1142
if (obj->isa == gravity_class_function)
1143
gravity_function_serialize((gravity_function_t *)obj, json);
1144
else if (obj->isa == gravity_class_class)
1145
gravity_class_serialize((gravity_class_t *)obj, json);
1146
else assert(0);
1147
}
1148
1149
bool gravity_object_deserialize (gravity_vm *vm, json_value *entry, gravity_object_t **obj) {
1150
// this function is able to deserialize ONLY objects with a type label
1151
1152
// sanity check
1153
if (entry->type != json_object) return false;
1154
if (entry->u.object.length == 0) return false;
1155
1156
// the first entry value must specify gravity object type
1157
const char *label = entry->u.object.values[0].name;
1158
json_value *value = entry->u.object.values[0].value;
1159
1160
if (string_casencmp(label, GRAVITY_JSON_LABELTYPE, 4) != 0) return false;
1161
if (value->type != json_string) return false;
1162
1163
// FUNCTION case
1164
if (string_casencmp(value->u.string.ptr, GRAVITY_JSON_FUNCTION, value->u.string.length) == 0) {
1165
gravity_function_t *f = gravity_function_deserialize(vm, entry);
1166
if (!f) return false;
1167
*obj = (gravity_object_t *)f;
1168
return true;
1169
}
1170
1171
// CLASS case
1172
if (string_casencmp(value->u.string.ptr, GRAVITY_JSON_CLASS, value->u.string.length) == 0) {
1173
gravity_class_t *c = gravity_class_deserialize(vm, entry);
1174
if (!c) return false;
1175
*obj = (gravity_object_t *)c;
1176
return true;
1177
}
1178
1179
// MAP/ENUM case
1180
if ((string_casencmp(value->u.string.ptr, GRAVITY_JSON_MAP, value->u.string.length) == 0) ||
1181
(string_casencmp(value->u.string.ptr, GRAVITY_JSON_ENUM, value->u.string.length) == 0)) {
1182
gravity_map_t *m = gravity_map_deserialize(vm, entry);
1183
if (!m) return false;
1184
*obj = (gravity_object_t *)m;
1185
return true;
1186
}
1187
1188
// unhandled case
1189
DEBUG_DESERIALIZE("gravity_object_deserialize unknown type");
1190
return false;
1191
}
1192
#undef REPORT_JSON_ERROR
1193
1194
const char *gravity_object_debug (gravity_object_t *obj) {
1195
if ((!obj) || (!OBJECT_IS_VALID(obj))) return "";
1196
1197
if (OBJECT_ISA_INT(obj)) return "INT";
1198
if (OBJECT_ISA_FLOAT(obj)) return "FLOAT";
1199
if (OBJECT_ISA_BOOL(obj)) return "BOOL";
1200
if (OBJECT_ISA_NULL(obj)) return "NULL";
1201
1202
static char buffer[512];
1203
if (OBJECT_ISA_FUNCTION(obj)) {
1204
const char *name = ((gravity_function_t*)obj)->identifier;
1205
if (!name) name = "ANONYMOUS";
1206
snprintf(buffer, sizeof(buffer), "FUNCTION %p %s", obj, name);
1207
return buffer;
1208
}
1209
1210
if (OBJECT_ISA_CLOSURE(obj)) {
1211
const char *name = ((gravity_closure_t*)obj)->f->identifier;
1212
if (!name) name = "ANONYMOUS";
1213
snprintf(buffer, sizeof(buffer), "CLOSURE %p %s", obj, name);
1214
return buffer;
1215
}
1216
1217
if (OBJECT_ISA_CLASS(obj)) {
1218
const char *name = ((gravity_class_t*)obj)->identifier;
1219
if (!name) name = "ANONYMOUS";
1220
snprintf(buffer, sizeof(buffer), "CLASS %p %s", obj, name);
1221
return buffer;
1222
}
1223
1224
if (OBJECT_ISA_STRING(obj)) {
1225
snprintf(buffer, sizeof(buffer), "STRING %p %s", obj, ((gravity_string_t*)obj)->s);
1226
return buffer;
1227
}
1228
1229
if (OBJECT_ISA_INSTANCE(obj)) {
1230
gravity_class_t *c = ((gravity_instance_t*)obj)->objclass;
1231
const char *name = (c->identifier) ? c->identifier : "ANONYMOUS";
1232
snprintf(buffer, sizeof(buffer), "INSTANCE %p OF %s", obj, name);
1233
return buffer;
1234
}
1235
1236
if (OBJECT_ISA_RANGE(obj)) {
1237
snprintf(buffer, sizeof(buffer), "RANGE %p %ld %ld", obj, (long)((gravity_range_t*)obj)->from, (long)((gravity_range_t*)obj)->to);
1238
return buffer;
1239
}
1240
1241
if (OBJECT_ISA_LIST(obj)) {
1242
snprintf(buffer, sizeof(buffer), "LIST %p (%ld items)", obj, (long)marray_size(((gravity_list_t*)obj)->array));
1243
return buffer;
1244
}
1245
1246
if (OBJECT_ISA_MAP(obj)) {
1247
snprintf(buffer, sizeof(buffer), "MAP %p (%ld items)", obj, (long)gravity_hash_count(((gravity_map_t*)obj)->hash));
1248
return buffer;
1249
}
1250
1251
if (OBJECT_ISA_FIBER(obj)) {
1252
snprintf(buffer, sizeof(buffer), "FIBER %p", obj);
1253
return buffer;
1254
}
1255
1256
if (OBJECT_ISA_UPVALUE(obj)) {
1257
snprintf(buffer, sizeof(buffer), "UPVALUE %p", obj);
1258
return buffer;
1259
}
1260
1261
return "N/A";
1262
}
1263
1264
void gravity_object_free (gravity_vm *vm, gravity_object_t *obj) {
1265
if ((!obj) || (!OBJECT_IS_VALID(obj))) return;
1266
1267
if (OBJECT_ISA_CLASS(obj)) gravity_class_free(vm, (gravity_class_t *)obj);
1268
else if (OBJECT_ISA_FUNCTION(obj)) gravity_function_free(vm, (gravity_function_t *)obj);
1269
else if (OBJECT_ISA_CLOSURE(obj)) gravity_closure_free(vm, (gravity_closure_t *)obj);
1270
else if (OBJECT_ISA_INSTANCE(obj)) gravity_instance_free(vm, (gravity_instance_t *)obj);
1271
else if (OBJECT_ISA_LIST(obj)) gravity_list_free(vm, (gravity_list_t *)obj);
1272
else if (OBJECT_ISA_MAP(obj)) gravity_map_free(vm, (gravity_map_t *)obj);
1273
else if (OBJECT_ISA_FIBER(obj)) gravity_fiber_free(vm, (gravity_fiber_t *)obj);
1274
else if (OBJECT_ISA_RANGE(obj)) gravity_range_free(vm, (gravity_range_t *)obj);
1275
else if (OBJECT_ISA_MODULE(obj)) gravity_module_free(vm, (gravity_module_t *)obj);
1276
else if (OBJECT_ISA_STRING(obj)) gravity_string_free(vm, (gravity_string_t *)obj);
1277
else if (OBJECT_ISA_UPVALUE(obj)) gravity_upvalue_free(vm, (gravity_upvalue_t *)obj);
1278
else assert(0); // should never reach this point
1279
}
1280
1281
uint32_t gravity_object_size (gravity_vm *vm, gravity_object_t *obj) {
1282
if ((!obj) || (!OBJECT_IS_VALID(obj))) return 0;
1283
1284
if (OBJECT_ISA_CLASS(obj)) return gravity_class_size(vm, (gravity_class_t *)obj);
1285
else if (OBJECT_ISA_FUNCTION(obj)) return gravity_function_size(vm, (gravity_function_t *)obj);
1286
else if (OBJECT_ISA_CLOSURE(obj)) return gravity_closure_size(vm, (gravity_closure_t *)obj);
1287
else if (OBJECT_ISA_INSTANCE(obj)) return gravity_instance_size(vm, (gravity_instance_t *)obj);
1288
else if (OBJECT_ISA_LIST(obj)) return gravity_list_size(vm, (gravity_list_t *)obj);
1289
else if (OBJECT_ISA_MAP(obj)) return gravity_map_size(vm, (gravity_map_t *)obj);
1290
else if (OBJECT_ISA_FIBER(obj)) return gravity_fiber_size(vm, (gravity_fiber_t *)obj);
1291
else if (OBJECT_ISA_RANGE(obj)) return gravity_range_size(vm, (gravity_range_t *)obj);
1292
else if (OBJECT_ISA_MODULE(obj)) return gravity_module_size(vm, (gravity_module_t *)obj);
1293
else if (OBJECT_ISA_STRING(obj)) return gravity_string_size(vm, (gravity_string_t *)obj);
1294
else if (OBJECT_ISA_UPVALUE(obj)) return gravity_upvalue_size(vm, (gravity_upvalue_t *)obj);
1295
return 0;
1296
}
1297
1298
void gravity_object_blacken (gravity_vm *vm, gravity_object_t *obj) {
1299
if ((!obj) || (!OBJECT_IS_VALID(obj))) return;
1300
1301
if (OBJECT_ISA_CLASS(obj)) gravity_class_blacken(vm, (gravity_class_t *)obj);
1302
else if (OBJECT_ISA_FUNCTION(obj)) gravity_function_blacken(vm, (gravity_function_t *)obj);
1303
else if (OBJECT_ISA_CLOSURE(obj)) gravity_closure_blacken(vm, (gravity_closure_t *)obj);
1304
else if (OBJECT_ISA_INSTANCE(obj)) gravity_instance_blacken(vm, (gravity_instance_t *)obj);
1305
else if (OBJECT_ISA_LIST(obj)) gravity_list_blacken(vm, (gravity_list_t *)obj);
1306
else if (OBJECT_ISA_MAP(obj)) gravity_map_blacken(vm, (gravity_map_t *)obj);
1307
else if (OBJECT_ISA_FIBER(obj)) gravity_fiber_blacken(vm, (gravity_fiber_t *)obj);
1308
else if (OBJECT_ISA_RANGE(obj)) gravity_range_blacken(vm, (gravity_range_t *)obj);
1309
else if (OBJECT_ISA_MODULE(obj)) gravity_module_blacken(vm, (gravity_module_t *)obj);
1310
else if (OBJECT_ISA_STRING(obj)) gravity_string_blacken(vm, (gravity_string_t *)obj);
1311
else if (OBJECT_ISA_UPVALUE(obj)) gravity_upvalue_blacken(vm, (gravity_upvalue_t *)obj);
1312
else assert(0); // should never reach this point
1313
}
1314
1315
// MARK: -
1316
1317
gravity_instance_t *gravity_instance_new (gravity_vm *vm, gravity_class_t *c) {
1318
gravity_instance_t *instance = (gravity_instance_t *)mem_alloc(sizeof(gravity_instance_t) + (c->nivars * sizeof(gravity_value_t)));
1319
1320
instance->isa = gravity_class_instance;
1321
instance->objclass = c;
1322
for (uint32_t i=0; i<c->nivars; ++i) instance->ivars[i] = VALUE_FROM_NULL;
1323
1324
if (vm) gravity_vm_transfer(vm, (gravity_object_t*) instance);
1325
return instance;
1326
}
1327
1328
gravity_instance_t *gravity_instance_dup (gravity_vm *vm, gravity_instance_t *src) {
1329
gravity_class_t *c = src->objclass;
1330
1331
gravity_instance_t *instance = (gravity_instance_t *)mem_alloc(sizeof(gravity_instance_t) + (c->nivars * sizeof(gravity_value_t)));
1332
instance->objclass = c;
1333
for (uint32_t i=0; i<c->nivars; ++i) instance->ivars[i] = src->ivars[i];
1334
1335
if (vm) gravity_vm_transfer(vm, (gravity_object_t*) instance);
1336
return instance;
1337
}
1338
1339
void gravity_instance_setivar (gravity_instance_t *instance, uint32_t idx, gravity_value_t value) {
1340
if (idx < instance->objclass->nivars) instance->ivars[idx] = value;
1341
}
1342
1343
void gravity_instance_setxdata (gravity_instance_t *i, void *xdata) {
1344
i->xdata = xdata;
1345
}
1346
1347
void gravity_instance_free (gravity_vm *vm, gravity_instance_t *i) {
1348
DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)i));
1349
1350
// check if bridged data needs to be freed too
1351
if (i->xdata && vm) {
1352
gravity_delegate_t *delegate = gravity_vm_delegate(vm);
1353
if (delegate && delegate->bridge_free) delegate->bridge_free(vm, (gravity_object_t *)i);
1354
}
1355
1356
mem_free((void *)i);
1357
}
1358
1359
gravity_closure_t *gravity_instance_lookup_event (gravity_instance_t *i, const char *name) {
1360
// TODO: implemented as gravity_class_lookup but should be the exact opposite
1361
1362
STATICVALUE_FROM_STRING(key, name, strlen(name));
1363
gravity_class_t *c = i->objclass;
1364
while (c) {
1365
gravity_value_t *v = gravity_hash_lookup(c->htable, key);
1366
// NOTE: there could be events (like InitContainer) which are empty (bytecode NULL) should I handle them here?
1367
if ((v) && (OBJECT_ISA_CLOSURE(v->p))) return (gravity_closure_t *)v->p;
1368
c = c->superclass;
1369
}
1370
return NULL;
1371
}
1372
1373
uint32_t gravity_instance_size (gravity_vm *vm, gravity_instance_t *i) {
1374
uint32_t instance_size = sizeof(gravity_instance_t) + (i->objclass->nivars * sizeof(gravity_value_t));
1375
1376
gravity_delegate_t *delegate = gravity_vm_delegate(vm);
1377
if ((i->xdata) && (delegate) && (delegate->bridge_size))
1378
instance_size += delegate->bridge_size(vm, i->xdata);
1379
1380
return instance_size;
1381
}
1382
1383
void gravity_instance_blacken (gravity_vm *vm, gravity_instance_t *i) {
1384
gravity_vm_memupdate(vm, gravity_instance_size(vm, i));
1385
1386
// instance class
1387
gravity_gray_object(vm, (gravity_object_t *)i->objclass);
1388
1389
// ivars
1390
for (uint32_t j=0; j<i->objclass->nivars; ++j) {
1391
gravity_gray_value(vm, i->ivars[j]);
1392
}
1393
}
1394
1395
// MARK: -
1396
1397
bool gravity_value_equals (gravity_value_t v1, gravity_value_t v2) {
1398
1399
// check same class
1400
if (v1.isa != v2.isa) return false;
1401
1402
// check same value for value types
1403
if ((v1.isa == gravity_class_int) || (v1.isa == gravity_class_bool) || (v1.isa == gravity_class_null)) {
1404
return (v1.n == v2.n);
1405
} else if (v1.isa == gravity_class_float) {
1406
#if GRAVITY_ENABLE_DOUBLE
1407
return (fabs(v1.f - v2.f) < EPSILON);
1408
#else
1409
return (fabsf(v1.f - v2.f) < EPSILON);
1410
#endif
1411
} else if (v1.isa == gravity_class_string) {
1412
gravity_string_t *s1 = VALUE_AS_STRING(v1);
1413
gravity_string_t *s2 = VALUE_AS_STRING(v2);
1414
if (s1->hash != s2->hash) return false;
1415
if (s1->len != s2->len) return false;
1416
// same hash and same len so let's compare bytes
1417
return (memcmp(s1->s, s2->s, s1->len) == 0);
1418
}
1419
1420
// if here means that they are two heap allocated objects
1421
gravity_object_t *obj1 = VALUE_AS_OBJECT(v1);
1422
gravity_object_t *obj2 = VALUE_AS_OBJECT(v2);
1423
if (obj1->isa != obj2->isa) return false;
1424
1425
return (obj1 == obj2);
1426
}
1427
1428
uint32_t gravity_value_hash (gravity_value_t value) {
1429
if (value.isa == gravity_class_string)
1430
return VALUE_AS_STRING(value)->hash;
1431
1432
if ((value.isa == gravity_class_int) || (value.isa == gravity_class_bool) || (value.isa == gravity_class_null))
1433
return gravity_hash_compute_int(value.n);
1434
1435
if (value.isa == gravity_class_float)
1436
return gravity_hash_compute_float(value.f);
1437
1438
return gravity_hash_compute_buffer((const char *)value.p, sizeof(gravity_object_t*));
1439
}
1440
1441
inline gravity_class_t *gravity_value_getclass (gravity_value_t v) {
1442
if ((v.isa == gravity_class_class) && (v.p->objclass == gravity_class_object)) return (gravity_class_t *)v.p;
1443
if ((v.isa == gravity_class_instance) || (v.isa == gravity_class_class)) return v.p->objclass;
1444
return v.isa;
1445
}
1446
1447
inline gravity_class_t *gravity_value_getsuper (gravity_value_t v) {
1448
gravity_class_t *c = gravity_value_getclass(v);
1449
return (c->superclass) ? c->superclass : NULL;
1450
}
1451
1452
void gravity_value_free (gravity_vm *vm, gravity_value_t v) {
1453
if (v.isa == gravity_class_int) return;
1454
if (v.isa == gravity_class_float) return;
1455
if (v.isa == gravity_class_bool) return;
1456
if (v.isa == gravity_class_null) return;
1457
1458
gravity_object_free(vm, VALUE_AS_OBJECT(v));
1459
}
1460
1461
static void gravity_map_serialize_iterator (gravity_hash_t *hashtable, gravity_value_t key, gravity_value_t v, void *data) {
1462
#pragma unused(hashtable)
1463
assert(key.isa == gravity_class_string);
1464
1465
json_t *json = (json_t *)data;
1466
const char *key_value = VALUE_AS_STRING(key)->s;
1467
1468
// BOOL
1469
if (VALUE_ISA_BOOL(v)) {
1470
json_add_bool(json, key_value, (v.n == 0) ? false : true);
1471
return;
1472
}
1473
1474
// INT
1475
if (VALUE_ISA_INT(v)) {
1476
json_add_int(json, key_value, (int64_t)v.n);
1477
return;
1478
}
1479
1480
// FLOAT
1481
if (VALUE_ISA_FLOAT(v)) {
1482
json_add_double(json, key_value, (double)v.f);
1483
return;
1484
}
1485
1486
// STRING
1487
if (VALUE_ISA_STRING(v)) {
1488
gravity_string_t *value = VALUE_AS_STRING(v);
1489
json_add_string(json, key_value, value->s, value->len);
1490
return;
1491
}
1492
1493
// should never reach this point
1494
assert(0);
1495
}
1496
1497
void gravity_value_serialize (gravity_value_t v, json_t *json) {
1498
1499
// BOOL
1500
if (VALUE_ISA_BOOL(v)) {
1501
json_add_bool(json, NULL, (v.n == 0) ? false : true);
1502
return;
1503
}
1504
1505
// INT
1506
if (VALUE_ISA_INT(v)) {
1507
json_add_int(json, NULL, (int64_t)v.n);
1508
return;
1509
}
1510
1511
// FLOAT
1512
if (VALUE_ISA_FLOAT(v)) {
1513
json_add_double(json, NULL, (double)v.f);
1514
return;
1515
}
1516
1517
// FUNCTION
1518
if (VALUE_ISA_FUNCTION(v)) {
1519
gravity_function_serialize(VALUE_AS_FUNCTION(v), json);
1520
return;
1521
}
1522
1523
// CLASS
1524
if (VALUE_ISA_CLASS(v)) {
1525
gravity_class_serialize(VALUE_AS_CLASS(v), json);
1526
return;
1527
}
1528
1529
// STRING
1530
if (VALUE_ISA_STRING(v)) {
1531
gravity_string_t *value = VALUE_AS_STRING(v);
1532
json_add_string(json, NULL, value->s, value->len);
1533
return;
1534
}
1535
1536
// LIST (ARRAY)
1537
if (VALUE_ISA_LIST(v)) {
1538
gravity_list_t *value = VALUE_AS_LIST(v);
1539
json_begin_array(json, NULL);
1540
size_t count = marray_size(value->array);
1541
for (size_t j=0; j<count; j++) {
1542
gravity_value_t item = marray_get(value->array, j);
1543
// here I am sure that value is a literal value
1544
gravity_value_serialize(item, json);
1545
}
1546
json_end_array(json);
1547
return;
1548
}
1549
1550
// MAP (HASH)
1551
// a map is serialized only if it contains only literals, otherwise it is computed at runtime
1552
if (VALUE_ISA_MAP(v)) {
1553
gravity_map_t *value = VALUE_AS_MAP(v);
1554
json_begin_object(json, NULL);
1555
json_add_cstring(json, GRAVITY_JSON_LABELTYPE, GRAVITY_JSON_MAP);
1556
gravity_hash_iterate(value->hash, gravity_map_serialize_iterator, json);
1557
json_end_object(json);
1558
return;
1559
}
1560
1561
// should never reach this point
1562
assert(0);
1563
}
1564
1565
bool gravity_value_isobject (gravity_value_t v) {
1566
// was:
1567
// if (VALUE_ISA_NOTVALID(v)) return false;
1568
// if (VALUE_ISA_INT(v)) return false;
1569
// if (VALUE_ISA_FLOAT(v)) return false;
1570
// if (VALUE_ISA_BOOL(v)) return false;
1571
// if (VALUE_ISA_NULL(v)) return false;
1572
// if (VALUE_ISA_UNDEFINED(v)) return false;
1573
// return true;
1574
1575
if ((v.isa == NULL) || (v.isa == gravity_class_int) || (v.isa == gravity_class_float) ||
1576
(v.isa == gravity_class_bool) || (v.isa == gravity_class_null)) return false;
1577
return true;
1578
}
1579
1580
uint32_t gravity_value_size (gravity_vm *vm, gravity_value_t v) {
1581
return (gravity_value_isobject(v)) ? gravity_object_size(vm, (gravity_object_t*)v.p) : 0;
1582
}
1583
1584
void *gravity_value_xdata (gravity_value_t value) {
1585
if (VALUE_ISA_INSTANCE(value)) {
1586
gravity_instance_t *i = VALUE_AS_INSTANCE(value);
1587
return i->xdata;
1588
} else if (VALUE_ISA_CLASS(value)) {
1589
gravity_class_t *c = VALUE_AS_CLASS(value);
1590
return c->xdata;
1591
}
1592
return NULL;
1593
}
1594
1595
void gravity_value_dump (gravity_value_t v, char *buffer, uint16_t len) {
1596
const char *type = NULL;
1597
const char *value = NULL;
1598
char sbuffer[1024];
1599
1600
if (buffer == NULL) buffer = sbuffer;
1601
if (len == 0) len = sizeof(sbuffer);
1602
1603
if (v.isa == NULL) {
1604
type = "INVALID!";
1605
snprintf(buffer, len, "%s", type);
1606
value = buffer;
1607
} else if (v.isa == gravity_class_bool) {
1608
type = "BOOL";
1609
value = (v.n == 0) ? "false" : "true";
1610
snprintf(buffer, len, "(%s) %s", type, value);
1611
value = buffer;
1612
} else if (v.isa == gravity_class_null) {
1613
type = (v.n == 0) ? "NULL" : "UNDEFINED";
1614
snprintf(buffer, len, "%s", type);
1615
value = buffer;
1616
} else if (v.isa == gravity_class_int) {
1617
type = "INT";
1618
snprintf(buffer, len, "(%s) %lld", type, v.n);
1619
value = buffer;
1620
} else if (v.isa == gravity_class_float) {
1621
type = "FLOAT";
1622
snprintf(buffer, len, "(%s) %f", type, v.f);
1623
value = buffer;
1624
} else if (v.isa == gravity_class_function) {
1625
type = "FUNCTION";
1626
value = VALUE_AS_FUNCTION(v)->identifier;
1627
snprintf(buffer, len, "(%s) %s (%p)", type, value, VALUE_AS_FUNCTION(v));
1628
value = buffer;
1629
} else if (v.isa == gravity_class_class) {
1630
type = "CLASS";
1631
value = VALUE_AS_CLASS(v)->identifier;
1632
snprintf(buffer, len, "(%s) %s (%p)", type, value, VALUE_AS_CLASS(v));
1633
value = buffer;
1634
} else if (v.isa == gravity_class_string) {
1635
type = "STRING";
1636
gravity_string_t *s = VALUE_AS_STRING(v);
1637
snprintf(buffer, len, "(%s) %.*s (%p)", type, s->len, s->s, s);
1638
value = buffer;
1639
} else if (v.isa == gravity_class_instance) {
1640
type = "INSTANCE OF CLASS";
1641
gravity_instance_t *i = VALUE_AS_INSTANCE(v);
1642
gravity_class_t *c = i->objclass;
1643
value = c->identifier;
1644
snprintf(buffer, len, "(%s) %s (%p)", type, value, i);
1645
value = buffer;
1646
} else if (v.isa == gravity_class_list) {
1647
type = "LIST";
1648
value = "N/A";
1649
snprintf(buffer, len, "(%s) %s", type, value);
1650
value = buffer;
1651
} else if (v.isa == gravity_class_map) {
1652
type = "MAP";
1653
value = "N/A";
1654
snprintf(buffer, len, "(%s) %s", type, value);
1655
value = buffer;
1656
} else if (v.isa == gravity_class_range) {
1657
type = "RANGE";
1658
gravity_range_t *r = VALUE_AS_RANGE(v);
1659
snprintf(buffer, len, "(%s) from %lld to %lld", type, r->from, r->to);
1660
value = buffer;
1661
} else if (v.isa == gravity_class_object) {
1662
type = "OBJECT";
1663
value = "N/A";
1664
snprintf(buffer, len, "(%s) %s", type, value);
1665
value = buffer;
1666
} else if (v.isa == gravity_class_fiber) {
1667
type = "FIBER";
1668
snprintf(buffer, len, "(%s) %p", type, v.p);
1669
value = buffer;
1670
} else {
1671
type = "N/A";
1672
value = "N/A";
1673
snprintf(buffer, len, "(%s) %s", type, value);
1674
value = buffer;
1675
}
1676
1677
if (buffer == sbuffer) printf("%s\n", value);
1678
}
1679
1680
// MARK: -
1681
gravity_list_t *gravity_list_new (gravity_vm *vm, uint32_t n) {
1682
gravity_list_t *list = (gravity_list_t *)mem_alloc(sizeof(gravity_list_t));
1683
1684
list->isa = gravity_class_list;
1685
marray_init(list->array);
1686
marray_resize(gravity_value_t, list->array, n + MARRAY_DEFAULT_SIZE);
1687
1688
if (vm) gravity_vm_transfer(vm, (gravity_object_t*) list);
1689
return list;
1690
}
1691
1692
gravity_list_t *gravity_list_from_array (gravity_vm *vm, uint32_t n, gravity_value_t *p) {
1693
gravity_list_t *list = (gravity_list_t *)mem_alloc(sizeof(gravity_list_t));
1694
1695
list->isa = gravity_class_list;
1696
marray_init(list->array);
1697
// elements must be copied because for the compiler their registers are TEMP
1698
// and could be reused by other successive operations
1699
for (size_t i=0; i<n; ++i) marray_push(gravity_value_t, list->array, p[i]);
1700
1701
gravity_vm_transfer(vm, (gravity_object_t*) list);
1702
return list;
1703
}
1704
1705
void gravity_list_free (gravity_vm *vm, gravity_list_t *list) {
1706
#pragma unused(vm)
1707
1708
DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)list));
1709
marray_destroy(list->array);
1710
mem_free((void *)list);
1711
}
1712
1713
void gravity_list_append_list (gravity_vm *vm, gravity_list_t *list1, gravity_list_t *list2) {
1714
#pragma unused(vm)
1715
// append list2 to list1
1716
size_t count = marray_size(list2->array);
1717
for (size_t i=0; i<count; ++i) {
1718
marray_push(gravity_value_t, list1->array, marray_get(list2->array, i));
1719
}
1720
}
1721
1722
uint32_t gravity_list_size (gravity_vm *vm, gravity_list_t *list) {
1723
uint32_t internal_size = 0;
1724
size_t count = marray_size(list->array);
1725
for (size_t i=0; i<count; ++i) {
1726
internal_size += gravity_value_size(vm, marray_get(list->array, i));
1727
}
1728
return sizeof(gravity_list_t) + internal_size;
1729
}
1730
1731
void gravity_list_blacken (gravity_vm *vm, gravity_list_t *list) {
1732
gravity_vm_memupdate(vm, gravity_list_size(vm, list));
1733
1734
size_t count = marray_size(list->array);
1735
for (size_t i=0; i<count; ++i) {
1736
gravity_gray_value(vm, marray_get(list->array, i));
1737
}
1738
}
1739
1740
// MARK: -
1741
gravity_map_t *gravity_map_new (gravity_vm *vm, uint32_t n) {
1742
gravity_map_t *map = (gravity_map_t *)mem_alloc(sizeof(gravity_map_t));
1743
1744
map->isa = gravity_class_map;
1745
map->hash = gravity_hash_create(n, gravity_value_hash, gravity_value_equals, NULL, NULL);
1746
1747
gravity_vm_transfer(vm, (gravity_object_t*) map);
1748
return map;
1749
}
1750
1751
void gravity_map_free (gravity_vm *vm, gravity_map_t *map) {
1752
#pragma unused(vm)
1753
1754
DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)map));
1755
gravity_hash_free(map->hash);
1756
mem_free((void *)map);
1757
}
1758
1759
void gravity_map_append_map (gravity_vm *vm, gravity_map_t *map1, gravity_map_t *map2) {
1760
#pragma unused(vm)
1761
// append map2 to map1
1762
gravity_hash_append(map1->hash, map2->hash);
1763
}
1764
1765
void gravity_map_insert (gravity_vm *vm, gravity_map_t *map, gravity_value_t key, gravity_value_t value) {
1766
#pragma unused(vm)
1767
gravity_hash_insert(map->hash, key, value);
1768
}
1769
1770
static gravity_map_t *gravity_map_deserialize (gravity_vm *vm, json_value *json) {
1771
uint32_t n = json->u.object.length;
1772
gravity_map_t *map = gravity_map_new(vm, n);
1773
1774
DEBUG_DESERIALIZE("DESERIALIZE MAP: %p\n", map);
1775
1776
for (uint32_t i=1; i<n; ++i) { // from 1 to skip type
1777
const char *label = json->u.object.values[i].name;
1778
json_value *jsonv = json->u.object.values[i].value;
1779
1780
gravity_value_t key = VALUE_FROM_CSTRING(vm, label);
1781
gravity_value_t value;
1782
1783
switch (jsonv->type) {
1784
case json_integer: value = VALUE_FROM_INT((gravity_int_t)jsonv->u.integer); break;
1785
case json_double: value = VALUE_FROM_FLOAT((gravity_float_t)jsonv->u.dbl); break;
1786
case json_boolean: value = VALUE_FROM_BOOL(jsonv->u.boolean); break;
1787
case json_string: value = VALUE_FROM_STRING(vm, jsonv->u.string.ptr, jsonv->u.string.length); break;
1788
default:assert(0);
1789
}
1790
1791
gravity_map_insert(NULL, map, key, value);
1792
}
1793
1794
return map;
1795
}
1796
1797
uint32_t gravity_map_size (gravity_vm *vm, gravity_map_t *map) {
1798
uint32_t hash_size = 0;
1799
gravity_hash_iterate2(map->hash, gravity_hash_internalsize, (void *)&hash_size, (void *)vm);
1800
hash_size += gravity_hash_memsize(map->hash);
1801
return sizeof(gravity_map_t) + hash_size;
1802
}
1803
1804
void gravity_map_blacken (gravity_vm *vm, gravity_map_t *map) {
1805
gravity_vm_memupdate(vm, gravity_map_size(vm, map));
1806
gravity_hash_iterate(map->hash, gravity_hash_gray, (void *)vm);
1807
}
1808
1809
// MARK: -
1810
1811
gravity_range_t *gravity_range_new (gravity_vm *vm, gravity_int_t from_range, gravity_int_t to_range, bool inclusive) {
1812
gravity_range_t *range = mem_alloc(sizeof(gravity_range_t));
1813
1814
range->isa = gravity_class_range;
1815
range->from = from_range;
1816
range->to = (inclusive) ? to_range : --to_range;
1817
1818
gravity_vm_transfer(vm, (gravity_object_t*) range);
1819
return range;
1820
}
1821
1822
void gravity_range_free (gravity_vm *vm, gravity_range_t *range) {
1823
#pragma unused(vm)
1824
1825
DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)range));
1826
mem_free((void *)range);
1827
}
1828
1829
uint32_t gravity_range_size (gravity_vm *vm, gravity_range_t *range) {
1830
#pragma unused(vm, range)
1831
return sizeof(gravity_range_t);
1832
}
1833
1834
void gravity_range_blacken (gravity_vm *vm, gravity_range_t *range) {
1835
gravity_vm_memupdate(vm, gravity_range_size(vm, range));
1836
}
1837
1838
// MARK: -
1839
1840
inline gravity_value_t gravity_string_to_value (gravity_vm *vm, const char *s, uint32_t len) {
1841
gravity_string_t *obj = mem_alloc(sizeof(gravity_string_t));
1842
if (len == AUTOLENGTH) len = (uint32_t)strlen(s);
1843
1844
uint32_t alloc = MAXNUM(len+1, DEFAULT_MINSTRING_SIZE);
1845
char *ptr = mem_alloc(alloc);
1846
memcpy(ptr, s, len);
1847
1848
obj->isa = gravity_class_string;
1849
obj->s = ptr;
1850
obj->len = len;
1851
obj->alloc = alloc;
1852
obj->hash = gravity_hash_compute_buffer((const char *)ptr, len);
1853
1854
gravity_value_t value;
1855
value.isa = gravity_class_string;
1856
value.p = (gravity_object_t *)obj;
1857
1858
if (vm) gravity_vm_transfer(vm, (gravity_object_t*) obj);
1859
return value;
1860
}
1861
1862
inline gravity_string_t *gravity_string_new (gravity_vm *vm, char *s, uint32_t len, uint32_t alloc) {
1863
gravity_string_t *obj = mem_alloc(sizeof(gravity_string_t));
1864
if (len == AUTOLENGTH) len = (uint32_t)strlen(s);
1865
1866
obj->isa = gravity_class_string;
1867
obj->s = (char *)s;
1868
obj->len = len;
1869
obj->alloc = alloc;
1870
if (s && len) obj->hash = gravity_hash_compute_buffer((const char *)s, len);
1871
1872
if (vm) gravity_vm_transfer(vm, (gravity_object_t*) obj);
1873
return obj;
1874
}
1875
1876
inline void gravity_string_set (gravity_string_t *obj, char *s, uint32_t len) {
1877
obj->s = (char *)s;
1878
obj->len = len;
1879
obj->hash = gravity_hash_compute_buffer((const char *)s, len);
1880
}
1881
1882
inline void gravity_string_free (gravity_vm *vm, gravity_string_t *value) {
1883
#pragma unused(vm)
1884
DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)value));
1885
if (value->alloc) mem_free(value->s);
1886
mem_free(value);
1887
}
1888
1889
uint32_t gravity_string_size (gravity_vm *vm, gravity_string_t *string) {
1890
#pragma unused(vm)
1891
return (sizeof(gravity_string_t)) + string->alloc;
1892
}
1893
1894
void gravity_string_blacken (gravity_vm *vm, gravity_string_t *string) {
1895
gravity_vm_memupdate(vm, gravity_string_size(vm, string));
1896
}
1897
1898
1899