• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kos-lang / kos / 6760698844

05 Nov 2023 09:32AM UTC coverage: 96.503% (+0.04%) from 96.465%
6760698844

push

github

cdragan
core: remove unused comparison

5 of 5 new or added lines in 1 file covered. (100.0%)

56 existing lines in 2 files now uncovered.

24343 of 25225 relevant lines covered (96.5%)

878464.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.89
/core/kos_instance.c
1
/* SPDX-License-Identifier: MIT
2
 * Copyright (c) 2014-2023 Chris Dragan
3
 */
4

5
#include "../inc/kos_instance.h"
6
#include "../inc/kos_array.h"
7
#include "../inc/kos_atomic.h"
8
#include "../inc/kos_constants.h"
9
#include "../inc/kos_error.h"
10
#include "../inc/kos_malloc.h"
11
#include "../inc/kos_memory.h"
12
#include "../inc/kos_module.h"
13
#include "../inc/kos_object.h"
14
#include "../inc/kos_string.h"
15
#include "../inc/kos_utils.h"
16
#include "kos_config.h"
17
#include "kos_debug.h"
18
#include "kos_heap.h"
19
#include "kos_math.h"
20
#include "kos_misc.h"
21
#include "kos_object_internal.h"
22
#include "kos_perf.h"
23
#include "kos_system_internal.h"
24
#include "kos_threads_internal.h"
25
#include "kos_try.h"
26
#include <assert.h>
27
#include <errno.h>
28
#define __STDC_FORMAT_MACROS
29
#include <inttypes.h>
30
#include <signal.h>
31
#include <stdarg.h>
32
#include <stdio.h>
33
#include <string.h>
34

35
static const char str_format_exception[]        = "Exception: ";
36
static const char str_format_hash[]             = "  #";
37
static const char str_format_line[]             = ":";
38
static const char str_format_function[]         = " in '";
39
static const char str_format_module[]           = "' in ";
40
static const char str_format_offset[]           = "  ";
41
static const char str_format_question_marks[]   = "???";
42

43
KOS_DECLARE_STATIC_CONST_STRING(str_description,               "description");
44
KOS_DECLARE_STATIC_CONST_STRING(str_err_ctrl_c,                "user pressed Ctrl-C");
45
KOS_DECLARE_STATIC_CONST_STRING(str_err_ctrl_c_already_hooked, "Ctrl-C already hooked");
46
KOS_DECLARE_STATIC_CONST_STRING(str_err_generator_end,         "end of generator");
47
KOS_DECLARE_STATIC_CONST_STRING(str_err_not_array,             "object is not an array");
48
KOS_DECLARE_STATIC_CONST_STRING(str_err_panic,                 "detected bytecode corruption");
49
KOS_DECLARE_STATIC_CONST_STRING(str_err_thread_registered,     "thread already registered");
50

51
struct KOS_LIB_LIST_S {
52
    uint32_t       num_libs;
53
    uint32_t       capacity;
54
    KOS_SHARED_LIB libs[1];
55
};
56

57
#ifdef CONFIG_PERF
58
struct KOS_PERF_S kos_perf = {
59
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0, 0, 0, 0 },
60
    0, 0,
61
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
62
    0, 0, 0, 0, 0, 0, 0, 0, 0,
63
    { 0, 0, 0, 0 },
64
    { 0, 0, 0, 0 },
65
    0
66
};
67
#endif
68

69
#if defined(CONFIG_SEQFAIL) || defined(CONFIG_FUZZ)
70
static int                  kos_seq_init      = 0;
71
static KOS_ATOMIC(uint32_t) kos_seq;
72
static uint32_t             kos_seq_threshold = ~0U;
73

74
int kos_seq_fail(void)
31,858,100✔
75
{
76
    if ( ! kos_seq_init) {
31,858,100✔
77

78
        KOS_VECTOR cstr;
79
        int64_t    value = -1;
7,571✔
80

81
        KOS_vector_init(&cstr);
7,571✔
82

83
        if (KOS_get_env("KOSSEQFAIL", &cstr) == KOS_SUCCESS
7,571✔
84
                && cstr.size > 0
7,295✔
85
                && kos_parse_int(cstr.buffer, cstr.buffer + cstr.size - 1, &value) == KOS_SUCCESS)
7,295✔
86
            kos_seq_threshold = (uint32_t)value;
7,295✔
87

88
        KOS_vector_destroy(&cstr);
7,571✔
89

90
        KOS_atomic_write_relaxed_u32(kos_seq, 0);
7,571✔
91

92
        kos_seq_init = 1;
7,571✔
93
    }
94

95
    if ((uint32_t)KOS_atomic_add_i32(kos_seq, 1) >= kos_seq_threshold)
31,858,100✔
96
        return KOS_ERROR_INTERNAL;
20,351✔
97

98
    return KOS_SUCCESS;
31,837,800✔
99
}
100

UNCOV
101
void kos_set_seq_point(int seq_point)
×
102
{
103
    kos_seq_init = seq_point;
×
UNCOV
104
}
×
105
#endif
106

107
static void init_context(KOS_CONTEXT ctx, KOS_INSTANCE *inst)
24,443✔
108
{
109
    ctx->next        = KOS_NULL;
24,443✔
110
    ctx->prev        = KOS_NULL;
24,443✔
111
    ctx->inst        = inst;
24,443✔
112
    ctx->cur_page    = KOS_NULL;
24,443✔
113
    ctx->thread_obj  = KOS_BADPTR;
24,443✔
114
    ctx->exception   = KOS_BADPTR;
24,443✔
115
    ctx->stack       = KOS_BADPTR;
24,443✔
116
    ctx->regs_idx    = 0;
24,443✔
117
    ctx->stack_depth = 0;
24,443✔
118
    ctx->local_list  = KOS_NULL;
24,443✔
119
    ctx->ulocal_list = KOS_NULL;
24,443✔
120
    ctx->gc_state    = GC_SUSPENDED;
24,443✔
121
    ctx->event_flags = 0;
24,443✔
122
}
24,443✔
123

124
static int register_thread(KOS_INSTANCE *inst,
15,846✔
125
                           KOS_CONTEXT   ctx)
126
{
127
    int error = KOS_SUCCESS;
15,846✔
128

129
    if (kos_tls_get(inst->threads.thread_key)) {
15,846✔
130
        TRY(KOS_resume_context(ctx));
×
UNCOV
131
        RAISE_EXCEPTION_STR(str_err_thread_registered);
×
132
    }
133

134
    assert( ! kos_tls_get(inst->threads.thread_key));
15,845✔
135

136
    kos_tls_set(inst->threads.thread_key, ctx);
15,845✔
137

138
    TRY(KOS_resume_context(ctx));
15,846✔
139

140
cleanup:
15,846✔
141
    if (error)
15,846✔
UNCOV
142
        kos_heap_release_thread_page(ctx);
×
143

144
    return error;
15,846✔
145
}
146

147
static void unregister_thread(KOS_INSTANCE *inst,
7,192✔
148
                              KOS_CONTEXT   ctx)
149
{
150
    assert(ctx != &inst->threads.main_thread);
7,192✔
151

152
    KOS_suspend_context(ctx);
7,192✔
153

154
    kos_tls_set(inst->threads.thread_key, KOS_NULL);
7,224✔
155

156
    kos_lock_mutex(inst->threads.ctx_mutex);
7,224✔
157

158
    if (ctx->prev)
7,224✔
159
        ctx->prev->next = ctx->next;
7,224✔
160

161
    if (ctx->next)
7,224✔
162
        ctx->next->prev = ctx->prev;
2,819✔
163

164
    kos_unlock_mutex(inst->threads.ctx_mutex);
7,224✔
165
}
7,223✔
166

167
int KOS_instance_register_thread(KOS_INSTANCE *inst,
7,219✔
168
                                 KOS_CONTEXT   ctx)
169
{
170
    int error;
171

172
    init_context(ctx, inst);
7,219✔
173

174
#if defined(CONFIG_THREADS) && (CONFIG_THREADS == 0)
175
    {
176
        KOS_DECLARE_STATIC_CONST_STRING(str_no_threads, "Kos was compiled without supports for threads");
177

178
        KOS_raise_exception(ctx, KOS_CONST_ID(str_no_threads));
179
    }
180
    error = KOS_ERROR_EXCEPTION;
181
#else
182

183
    kos_lock_mutex(inst->threads.ctx_mutex);
7,210✔
184

185
    ctx->prev                      = &inst->threads.main_thread;
7,224✔
186
    ctx->next                      = inst->threads.main_thread.next;
7,224✔
187
    inst->threads.main_thread.next = ctx;
7,224✔
188
    if (ctx->next)
7,224✔
189
        ctx->next->prev            = ctx;
4,832✔
190

191
    KOS_atomic_write_relaxed_u32(ctx->event_flags,
7,224✔
192
            KOS_atomic_read_relaxed_u32(inst->threads.main_thread.event_flags));
193

194
    kos_unlock_mutex(inst->threads.ctx_mutex);
7,224✔
195

196
    error = register_thread(inst, ctx);
7,224✔
197

198
    if (error)
7,224✔
UNCOV
199
        unregister_thread(inst, ctx);
×
200
#endif
201

202
    return error;
7,224✔
203
}
204

205
void KOS_instance_unregister_thread(KOS_INSTANCE *inst,
7,198✔
206
                                    KOS_CONTEXT   ctx)
207
{
208
    assert((KOS_CONTEXT)kos_tls_get(inst->threads.thread_key) == ctx);
7,198✔
209

210
    unregister_thread(inst, ctx);
7,194✔
211
}
7,222✔
212

213
static int add_multiple_paths(KOS_CONTEXT ctx, KOS_VECTOR *cpaths)
18✔
214
{
215
    int   error = KOS_SUCCESS;
18✔
216
    char *buf   = cpaths->buffer;
18✔
217

218
    while ( ! error) {
18✔
219
        char *end = strchr(buf, KOS_PATH_LIST_SEPARATOR);
18✔
220

221
        if (end)
18✔
UNCOV
222
            *end = '\0';
×
223

224
        error = KOS_instance_add_path(ctx, buf);
18✔
225

226
        if (end)
18✔
UNCOV
227
            buf = end + 1;
×
228
        else
229
            break;
18✔
230
    }
231

232
    return error;
18✔
233
}
234

235
static int init_search_paths(KOS_CONTEXT ctx)
8,593✔
236
{
237
#ifdef CONFIG_DISABLE_KOSPATH
238
    return KOS_SUCCESS;
239
#else
240
    int        error = KOS_SUCCESS;
8,593✔
241
    KOS_VECTOR cpaths;
242

243
    KOS_vector_init(&cpaths);
8,593✔
244

245
    if (KOS_get_env("KOSPATH", &cpaths) == KOS_SUCCESS)
8,593✔
246
        error = add_multiple_paths(ctx, &cpaths);
18✔
247

248
    KOS_vector_destroy(&cpaths);
8,593✔
249

250
    return error;
8,593✔
251
#endif
252
}
253

254
static void setup_init_module(KOS_MODULE *init_module)
25,826✔
255
{
256
    KOS_DECLARE_STATIC_CONST_STRING(str_init, "init");
257

258
    assert(kos_get_object_type(init_module->header) == OBJ_MODULE);
25,826✔
259

260
    init_module->name           = KOS_CONST_ID(str_init);
25,826✔
261
    init_module->path           = KOS_STR_EMPTY;
25,826✔
262
    init_module->inst           = KOS_NULL;
25,826✔
263
    init_module->constants      = KOS_BADPTR;
25,826✔
264
    init_module->global_names   = KOS_BADPTR;
25,826✔
265
    init_module->globals        = KOS_BADPTR;
25,826✔
266
    init_module->module_names   = KOS_BADPTR;
25,826✔
267
    init_module->priv           = KOS_BADPTR;
25,826✔
268
    init_module->finalize       = KOS_NULL;
25,826✔
269
}
25,826✔
270

271
struct KOS_CONST_MODULE_S {
272
    struct KOS_CONST_OBJECT_ALIGNMENT_S align;
273
    KOS_MODULE                          object;
274
};
275

276
static KOS_OBJ_ID get_init_module(void)
17,230✔
277
{
278
    KOS_DECLARE_ALIGNED(32, static struct KOS_CONST_MODULE_S) init_module;
279

280
    kos_set_object_type_size(init_module.object.header, OBJ_MODULE, 0);
17,230✔
281

282
    setup_init_module(&init_module.object);
17,230✔
283

284
    assert( ! kos_is_heap_object(KOS_CONST_ID(init_module)));
17,230✔
285

286
    return KOS_CONST_ID(init_module);
17,230✔
287
}
288

289
static void clear_instance(KOS_INSTANCE *inst)
17,230✔
290
{
291
    /* Disable GC during early init */
292
    inst->flags = KOS_INST_MANUAL_GC;
17,230✔
293

294
    inst->args                           = KOS_BADPTR;
17,230✔
295
    inst->prototypes.object_proto        = KOS_BADPTR;
17,230✔
296
    inst->prototypes.number_proto        = KOS_BADPTR;
17,230✔
297
    inst->prototypes.integer_proto       = KOS_BADPTR;
17,230✔
298
    inst->prototypes.float_proto         = KOS_BADPTR;
17,230✔
299
    inst->prototypes.string_proto        = KOS_BADPTR;
17,230✔
300
    inst->prototypes.boolean_proto       = KOS_BADPTR;
17,230✔
301
    inst->prototypes.array_proto         = KOS_BADPTR;
17,230✔
302
    inst->prototypes.buffer_proto        = KOS_BADPTR;
17,230✔
303
    inst->prototypes.function_proto      = KOS_BADPTR;
17,230✔
304
    inst->prototypes.class_proto         = KOS_BADPTR;
17,230✔
305
    inst->prototypes.generator_proto     = KOS_BADPTR;
17,230✔
306
    inst->prototypes.exception_proto     = KOS_BADPTR;
17,230✔
307
    inst->prototypes.generator_end_proto = KOS_BADPTR;
17,230✔
308
    inst->prototypes.panic_proto         = KOS_BADPTR;
17,230✔
309
    inst->prototypes.ctrl_c_proto        = KOS_BADPTR;
17,230✔
310
    inst->prototypes.thread_proto        = KOS_BADPTR;
17,230✔
311
    inst->prototypes.module_proto        = KOS_BADPTR;
17,230✔
312
    inst->modules.search_paths           = KOS_BADPTR;
17,230✔
313
    inst->modules.module_names           = KOS_BADPTR;
17,230✔
314
    inst->modules.modules                = KOS_BADPTR;
17,230✔
315
    inst->modules.init_module            = get_init_module();
17,230✔
316
    inst->modules.module_inits           = KOS_BADPTR;
17,230✔
317
    inst->modules.libs                   = KOS_NULL;
17,230✔
318
    inst->modules.load_chain             = KOS_NULL;
17,230✔
319
    inst->threads.threads                = KOS_NULL;
17,230✔
320
    inst->threads.can_create             = 0;
17,230✔
321
    inst->threads.num_threads            = 0;
17,230✔
322
    inst->threads.max_threads            = KOS_MAX_THREADS;
17,230✔
323

324
    init_context(&inst->threads.main_thread, inst);
17,230✔
325
}
17,230✔
326

327
static int init_prototypes(KOS_CONTEXT ctx, struct KOS_PROTOTYPES_S *prototypes)
8,622✔
328
{
329
    int error = KOS_SUCCESS;
8,622✔
330

331
    TRY_OBJID(prototypes->object_proto        = KOS_new_object_with_prototype(ctx, KOS_VOID));
8,622✔
332
    TRY_OBJID(prototypes->number_proto        = KOS_new_object(ctx));
8,619✔
333
    TRY_OBJID(prototypes->integer_proto       = KOS_new_object_with_prototype(ctx, prototypes->number_proto));
8,618✔
334
    TRY_OBJID(prototypes->float_proto         = KOS_new_object_with_prototype(ctx, prototypes->number_proto));
8,617✔
335
    TRY_OBJID(prototypes->string_proto        = KOS_new_object(ctx));
8,616✔
336
    TRY_OBJID(prototypes->boolean_proto       = KOS_new_object(ctx));
8,615✔
337
    TRY_OBJID(prototypes->array_proto         = KOS_new_object(ctx));
8,614✔
338
    TRY_OBJID(prototypes->buffer_proto        = KOS_new_object(ctx));
8,613✔
339
    TRY_OBJID(prototypes->function_proto      = KOS_new_object(ctx));
8,612✔
340
    TRY_OBJID(prototypes->class_proto         = KOS_new_object_with_prototype(ctx, prototypes->function_proto));
8,611✔
341
    TRY_OBJID(prototypes->generator_proto     = KOS_new_object_with_prototype(ctx, prototypes->function_proto));
8,610✔
342
    TRY_OBJID(prototypes->exception_proto     = KOS_new_object(ctx));
8,609✔
343
    TRY_OBJID(prototypes->generator_end_proto = KOS_new_object(ctx));
8,608✔
344
    TRY_OBJID(prototypes->panic_proto         = KOS_new_object(ctx));
8,607✔
345
    TRY_OBJID(prototypes->ctrl_c_proto        = KOS_new_object(ctx));
8,606✔
346
    TRY_OBJID(prototypes->thread_proto        = KOS_new_object(ctx));
8,605✔
347
    TRY_OBJID(prototypes->module_proto        = KOS_new_object(ctx));
8,604✔
348

349
cleanup:
8,603✔
350
    return error;
8,622✔
351
}
352

353
#ifdef CONFIG_FUZZ
354
KOS_ATOMIC(uint32_t) kos_fuzz_instructions;
355
#endif
356

357
int KOS_instance_init(KOS_INSTANCE *inst,
8,641✔
358
                      uint32_t      flags,
359
                      KOS_CONTEXT  *out_ctx)
360
{
361
    int         error;
362
    int         heap_ok   = 0;
8,641✔
363
    int         thread_ok = 0;
8,641✔
364
    KOS_MODULE *init_module;
365
    KOS_CONTEXT ctx;
366

367
    assert(!kos_is_heap_object(KOS_VOID));
8,641✔
368
    assert(!kos_is_heap_object(KOS_FALSE));
8,641✔
369
    assert(!kos_is_heap_object(KOS_TRUE));
8,641✔
370
    assert(!kos_is_heap_object(KOS_STR_EMPTY));
8,641✔
371
    assert(KOS_get_string_length(KOS_STR_EMPTY) == 0);
8,641✔
372
    assert(!kos_is_heap_object(KOS_STR_OUT_OF_MEMORY));
8,641✔
373
    assert(KOS_get_string_length(KOS_STR_OUT_OF_MEMORY) == 13);
8,641✔
374
    assert(!kos_is_heap_object(KOS_EMPTY_ARRAY));
8,641✔
375
    assert(GET_OBJ_TYPE(KOS_EMPTY_ARRAY) == OBJ_ARRAY);
8,641✔
376
    assert(KOS_get_array_size(KOS_EMPTY_ARRAY) == 0);
8,641✔
377

378
#ifdef CONFIG_FUZZ
379
    KOS_atomic_write_relaxed_u32(kos_fuzz_instructions, 0U);
380
#endif
381

382
    clear_instance(inst);
8,641✔
383

384
    TRY(kos_tls_create(&inst->threads.thread_key));
8,641✔
385
    error = kos_create_mutex(&inst->threads.ctx_mutex);
8,639✔
386
    if (error) {
8,639✔
387
        kos_tls_destroy(inst->threads.thread_key);
2✔
388
        goto cleanup;
2✔
389
    }
390
    error = kos_create_mutex(&inst->threads.new_mutex);
8,637✔
391
    if (error) {
8,637✔
392
        kos_destroy_mutex(&inst->threads.ctx_mutex);
2✔
393
        kos_tls_destroy(inst->threads.thread_key);
2✔
394
        goto cleanup;
2✔
395
    }
396
    thread_ok = 1;
8,635✔
397

398
    TRY(kos_heap_init(inst));
8,635✔
399
    heap_ok = 1;
8,623✔
400

401
    inst->threads.threads = (KOS_ATOMIC(KOS_THREAD *) *)
8,623✔
402
        KOS_malloc(sizeof(KOS_THREAD *) * inst->threads.max_threads);
8,623✔
403
    if ( ! inst->threads.threads)
8,623✔
404
        RAISE_ERROR(KOS_ERROR_OUT_OF_MEMORY);
1✔
405
    memset((void *)inst->threads.threads, 0, sizeof(KOS_THREAD *) * inst->threads.max_threads);
8,622✔
406

407
    TRY(register_thread(inst, &inst->threads.main_thread));
8,622✔
408

409
    ctx = &inst->threads.main_thread;
8,622✔
410

411
    TRY(init_prototypes(ctx, &inst->prototypes));
8,622✔
412

413
    TRY_OBJID(inst->modules.module_names           = KOS_new_object(ctx));
8,603✔
414
    TRY_OBJID(inst->modules.modules                = KOS_new_array(ctx, 0));
8,602✔
415
    TRY_OBJID(inst->modules.search_paths           = KOS_new_array(ctx, 0));
8,601✔
416
    TRY_OBJID(inst->modules.module_inits           = KOS_new_object(ctx));
8,600✔
417
    TRY_OBJID(inst->args                           = KOS_new_array(ctx, 0));
8,599✔
418

419
    init_module = (KOS_MODULE *)kos_alloc_object(ctx, KOS_ALLOC_IMMOVABLE, OBJ_MODULE, sizeof(KOS_MODULE));
8,598✔
420
    if ( ! init_module)
8,598✔
421
        RAISE_ERROR(KOS_ERROR_OUT_OF_MEMORY);
2✔
422
    setup_init_module(init_module);
8,596✔
423

424
    init_module->inst                    = inst;
8,596✔
425
    TRY_OBJID(init_module->globals       = KOS_new_array(ctx, 0));
8,596✔
426
    TRY_OBJID(init_module->global_names  = KOS_new_object(ctx));
8,595✔
427
    TRY_OBJID(init_module->module_names  = KOS_new_object(ctx));
8,594✔
428

429
    inst->modules.init_module = OBJID(MODULE, init_module);
8,593✔
430

431
    TRY(init_search_paths(ctx));
8,593✔
432

433
    TRY(KOS_set_property(ctx, inst->prototypes.generator_end_proto, KOS_CONST_ID(str_description),
8,593✔
434
                         KOS_CONST_ID(str_err_generator_end)));
435
    TRY(KOS_set_property(ctx, inst->prototypes.panic_proto, KOS_CONST_ID(str_description),
8,592✔
436
                         KOS_CONST_ID(str_err_panic)));
437
    TRY(KOS_set_property(ctx, inst->prototypes.ctrl_c_proto, KOS_CONST_ID(str_description),
8,591✔
438
                         KOS_CONST_ID(str_err_ctrl_c)));
439

440
    *out_ctx = ctx;
8,590✔
441

442
    /* Set user flags.
443
     * Also, enable automatic GC unless disabled by user */
444
    inst->flags = flags;
8,590✔
445

446
    /* Enable creation of new threads */
447
    inst->threads.can_create = 1U;
8,590✔
448

449
cleanup:
8,641✔
450
    if (error) {
8,641✔
451
        if (heap_ok)
51✔
452
            kos_heap_destroy(inst);
33✔
453

454
        if (thread_ok) {
51✔
455
            kos_tls_destroy(inst->threads.thread_key);
45✔
456
            kos_destroy_mutex(&inst->threads.new_mutex);
45✔
457
            kos_destroy_mutex(&inst->threads.ctx_mutex);
45✔
458
        }
459

460
        if (inst->threads.threads)
51✔
461
            KOS_free((void *)inst->threads.threads);
32✔
462
    }
463

464
    return error;
8,641✔
465
}
466

467
void KOS_instance_destroy(KOS_INSTANCE *inst)
8,589✔
468
{
469
    int         error;
470
    uint32_t    i;
471
    uint32_t    num_modules = KOS_get_array_size(inst->modules.modules);
8,589✔
472
    KOS_CONTEXT ctx         = &inst->threads.main_thread;
8,589✔
473
    KOS_VECTOR  finalizers;
474

475
    kos_validate_context(ctx);
8,589✔
476

477
    error = kos_join_finished_threads(ctx, KOS_JOIN_ALL);
8,589✔
478

479
    if (error == KOS_ERROR_EXCEPTION)
8,589✔
480
        KOS_print_exception(ctx, KOS_STDERR);
1✔
481
    else if (error) {
8,588✔
482
        assert(error == KOS_ERROR_OUT_OF_MEMORY);
×
UNCOV
483
        fprintf(stderr, "Out of memory\n");
×
484
    }
485

486
    KOS_vector_init(&finalizers);
8,589✔
487

488
    for (i = 0; i < num_modules; i++) {
20,579✔
489
        KOS_OBJ_ID module_obj = KOS_array_read(ctx, inst->modules.modules, (int)i);
11,990✔
490
        if (IS_BAD_PTR(module_obj))
11,990✔
491
            KOS_clear_exception(ctx);
11,463✔
492
        else if (GET_OBJ_TYPE(module_obj) == OBJ_MODULE) {
527✔
493

494
            /* Copy away module finalizers and run them after heap is destroyed
495
             * in case objects created by the module have private data which
496
             * depends on module initialization. */
497
            if (OBJPTR(MODULE, module_obj)->finalize) {
395✔
498
                const size_t old_size = finalizers.size;
4✔
499
                const size_t new_size = old_size + sizeof(KOS_MODULE_FINALIZE);
4✔
500
                if ( ! KOS_vector_resize(&finalizers, new_size)) {
4✔
501
                    memcpy(&finalizers.buffer[old_size], &OBJPTR(MODULE, module_obj)->finalize, sizeof(KOS_MODULE_FINALIZE));
4✔
502
                    memset(&OBJPTR(MODULE, module_obj)->finalize, 0, sizeof(KOS_MODULE_FINALIZE));
4✔
503
                }
504
            }
505
        }
506
        else {
507
            /* failed e.g. during compilation */
508
            assert(GET_OBJ_TYPE(module_obj) == OBJ_VOID);
132✔
509
        }
510
    }
511

512
    kos_heap_destroy(inst);
8,589✔
513

514
    if (finalizers.size) {
8,589✔
515
        KOS_MODULE_FINALIZE       *finalize = (KOS_MODULE_FINALIZE *)finalizers.buffer;
4✔
516
        KOS_MODULE_FINALIZE *const end      = (KOS_MODULE_FINALIZE *)(finalizers.buffer + finalizers.size);
4✔
517

518
        for ( ; finalize < end; ++finalize)
8✔
519
            (*finalize)();
4✔
520
    }
521

522
    KOS_vector_destroy(&finalizers);
8,589✔
523

524
    if (inst->modules.libs) {
8,589✔
525
        uint32_t      idx;
526
        KOS_LIB_LIST *libs = inst->modules.libs;
1,345✔
527

528
        for (idx = libs->num_libs; idx > 0; ) {
2,695✔
529
            const KOS_SHARED_LIB lib = libs->libs[--idx];
1,350✔
530

531
            assert(lib);
1,350✔
532
            KOS_unload_library(lib);
1,350✔
533
        }
534

535
        KOS_free((void *)libs);
1,345✔
536
    }
537

538
    kos_tls_destroy(inst->threads.thread_key);
8,589✔
539

540
    kos_destroy_mutex(&inst->threads.new_mutex);
8,589✔
541
    kos_destroy_mutex(&inst->threads.ctx_mutex);
8,589✔
542

543
    KOS_free((void *)inst->threads.threads);
8,589✔
544

545
    clear_instance(inst);
8,589✔
546

547
#ifdef CONFIG_PERF
548
#   define PERF_RATIO(a) do {                                                      \
549
        const uint64_t va = KOS_atomic_read_relaxed_u64(kos_perf.a##_success);     \
550
        const uint64_t vb = KOS_atomic_read_relaxed_u64(kos_perf.a##_fail);        \
551
        uint64_t       total = va + vb;                                            \
552
        if (total == 0) total = 1;                                                 \
553
        fprintf(stderr, "    " #a "\t%" PRIu64 " / %" PRIu64 " (%" PRIu64 "%%)\n", \
554
                va, total, va * 100 / total);                                      \
555
    } while (0)
556
#   define PERF_VALUE_NAME(name, a) do {                             \
557
        const uint64_t va = KOS_atomic_read_relaxed_u64(kos_perf.a); \
558
        fprintf(stderr, "    " #name "\t%" PRIu64 " \n", va);        \
559
    } while (0)
560
#   define PERF_VALUE(a) PERF_VALUE_NAME(a, a)
561
    fprintf(stderr, "Performance stats:\n");
562
    PERF_VALUE(object_key_diff_hash);
563
    PERF_RATIO(object_key_compare);
564
    PERF_RATIO(object_get);
565
    PERF_RATIO(object_set);
566
    PERF_RATIO(object_delete);
567
    PERF_RATIO(object_resize);
568
    PERF_RATIO(object_salvage);
569
    PERF_VALUE(object_collision[0]);
570
    PERF_VALUE(object_collision[1]);
571
    PERF_VALUE(object_collision[2]);
572
    PERF_VALUE(object_collision[3]);
573
    PERF_RATIO(array_salvage);
574
    PERF_VALUE(alloc_object);
575
    PERF_VALUE_NAME(new_object_integer,        new_object[0]);
576
    PERF_VALUE_NAME(new_object_float,          new_object[1]);
577
    PERF_VALUE_NAME(new_object_void,           new_object[2]);
578
    PERF_VALUE_NAME(new_object_boolean,        new_object[3]);
579
    PERF_VALUE_NAME(new_object_string,         new_object[4]);
580
    PERF_VALUE_NAME(new_object_object,         new_object[5]);
581
    PERF_VALUE_NAME(new_object_array,          new_object[6]);
582
    PERF_VALUE_NAME(new_object_buffer,         new_object[7]);
583
    PERF_VALUE_NAME(new_object_function,       new_object[8]);
584
    PERF_VALUE_NAME(new_object_class,          new_object[9]);
585
    PERF_VALUE_NAME(new_object_module,         new_object[10]);
586
    PERF_VALUE_NAME(new_object_opaque,         new_object[11]);
587
    PERF_VALUE_NAME(new_object_huge_tracker,   new_object[12]);
588
    PERF_VALUE_NAME(new_object_object_storage, new_object[13]);
589
    PERF_VALUE_NAME(new_object_array_storage,  new_object[14]);
590
    PERF_VALUE_NAME(new_object_buffer_storage, new_object[15]);
591
    PERF_VALUE_NAME(new_object_dynamic_prop,   new_object[16]);
592
    PERF_VALUE_NAME(new_object_iterator,       new_object[17]);
593
    PERF_VALUE_NAME(new_object_stack,          new_object[18]);
594
    PERF_VALUE_NAME(alloc_object_32,        alloc_object_size[0]);
595
    PERF_VALUE_NAME(alloc_object_64_128,    alloc_object_size[1]);
596
    PERF_VALUE_NAME(alloc_object_160_256,   alloc_object_size[2]);
597
    PERF_VALUE_NAME(alloc_object_288_512,   alloc_object_size[3]);
598
    PERF_VALUE(alloc_huge_object);
599
    PERF_VALUE(non_full_seek);
600
    PERF_VALUE(non_full_seek_max);
601
    PERF_VALUE(alloc_new_page);
602
    PERF_VALUE(alloc_free_page);
603
    PERF_VALUE(gc_cycles);
604
    PERF_VALUE(mark_groups_alloc);
605
    PERF_VALUE(mark_groups_sched);
606
    PERF_VALUE_NAME(evac_object_32,         evac_object_size[0]);
607
    PERF_VALUE_NAME(evac_object_64_128,     evac_object_size[1]);
608
    PERF_VALUE_NAME(evac_object_160_256,    evac_object_size[2]);
609
    PERF_VALUE_NAME(evac_object_288_512,    evac_object_size[3]);
610
    PERF_VALUE(instructions);
611
#endif
612
}
8,589✔
613

614
int KOS_instance_add_path(KOS_CONTEXT ctx, const char *module_search_path)
7,459✔
615
{
616
    int           error;
617
    KOS_OBJ_ID    path_str;
618
    KOS_INSTANCE *inst = ctx->inst;
7,459✔
619

620
    path_str = KOS_new_cstring(ctx, module_search_path);
7,459✔
621
    TRY_OBJID(path_str);
7,459✔
622

623
    TRY(KOS_array_push(ctx, inst->modules.search_paths, path_str, KOS_NULL));
7,457✔
624

625
cleanup:
7,456✔
626
    return error;
7,459✔
627
}
628

629
#ifndef CONFIG_MODULE_PATH
630
#   ifdef _WIN32
631
#       define CONFIG_MODULE_PATH "modules"
632
#   else
633
#       define CONFIG_MODULE_PATH "../share/kos/modules"
634
#   endif
635
#endif
636

637
int KOS_instance_add_default_path(KOS_CONTEXT ctx, const char *argv0)
7,459✔
638
{
639
    int               error      = KOS_ERROR_NOT_FOUND;
7,459✔
640
    KOS_VECTOR        cstr;
641
    KOS_VECTOR        cpath;
642
    size_t            pos;
643
    static const char rel_path[] = CONFIG_MODULE_PATH;
644

645
    KOS_vector_init(&cstr);
7,459✔
646
    KOS_vector_init(&cpath);
7,459✔
647

648
    if (argv0) {
7,459✔
649

650
        size_t len = strlen(argv0);
18✔
651

652
        if ( ! len)
18✔
653
            goto cleanup;
1✔
654

655
        /* Absolute or relative path */
656
        if (strchr(argv0, KOS_PATH_SEPARATOR)) {
17✔
657

658
            if ( ! KOS_does_file_exist(argv0))
12✔
659
                RAISE_ERROR(KOS_ERROR_NOT_FOUND);
10✔
660

661
            len += 1;
2✔
662
            TRY(KOS_vector_resize(&cstr, len));
2✔
663

664
            memcpy(cstr.buffer, argv0, len);
2✔
665
        }
666
        /* Just executable name, scan PATH */
667
        else {
668

669
            char *buf;
670

671
            TRY(KOS_get_env("PATH", &cpath));
5✔
672

673
            buf = cpath.buffer;
5✔
674

675
            TRY(KOS_vector_reserve(&cstr, cpath.size + len + 1));
5✔
676

677
            cstr.size = 0;
5✔
678

679
            while ((size_t)(buf - cpath.buffer + 1) < cpath.size) {
9✔
680

681
                char  *end = strchr(buf, KOS_PATH_LIST_SEPARATOR);
7✔
682
                size_t base_len;
683

684
                if ( ! end)
7✔
685
                    end = cpath.buffer + cpath.size - 1;
3✔
686

687
                base_len = end - buf;
7✔
688

689
                TRY(KOS_vector_resize(&cstr, base_len + 1 + len + 1));
7✔
690

691
                memcpy(cstr.buffer, buf, base_len);
7✔
692
                cstr.buffer[base_len] = KOS_PATH_SEPARATOR;
7✔
693
                memcpy(&cstr.buffer[base_len + 1], argv0, len);
7✔
694
                cstr.buffer[base_len + 1 + len] = 0;
7✔
695

696
                if (KOS_does_file_exist(cstr.buffer))
7✔
697
                    break;
3✔
698

699
                cstr.size = 0;
4✔
700

701
                buf = end + 1;
4✔
702
            }
703

704
            if (cstr.size == 0)
5✔
705
                RAISE_ERROR(KOS_ERROR_NOT_FOUND);
2✔
706
        }
707
    }
708
    else {
709
        if (kos_seq_fail())
7,441✔
710
            RAISE_ERROR(KOS_ERROR_NOT_FOUND);
1✔
711

712
        TRY(kos_executable_path(&cstr));
7,440✔
713
    }
714

715
    TRY(KOS_get_absolute_path(&cstr));
7,441✔
716

717
    assert(cstr.size > 0);
7,441✔
718

719
    for (pos = cstr.size - 1; pos > 0 && cstr.buffer[pos] != KOS_PATH_SEPARATOR; --pos);
37,250✔
720

721
    if ( ! pos)
7,441✔
UNCOV
722
        RAISE_ERROR(KOS_ERROR_NOT_FOUND);
×
723

724
    TRY(KOS_vector_resize(&cstr, pos + 1 + sizeof(rel_path)));
7,441✔
725

726
    memcpy(&cstr.buffer[pos + 1], rel_path, sizeof(rel_path));
7,441✔
727

728
    TRY(KOS_instance_add_path(ctx, cstr.buffer));
7,441✔
729

730
cleanup:
7,438✔
731
    KOS_vector_destroy(&cpath);
7,459✔
732
    KOS_vector_destroy(&cstr);
7,459✔
733

734
    return error;
7,459✔
735
}
736

737
int KOS_instance_set_args(KOS_CONTEXT  ctx,
7,452✔
738
                          int          argc,
739
                          const char **argv)
740
{
741
    int           error;
742
    int           i;
743
    KOS_INSTANCE *inst = ctx->inst;
7,452✔
744

745
    assert(argc >= 0);
7,452✔
746

747
    if (argc <= 0)
7,452✔
UNCOV
748
        return KOS_SUCCESS;
×
749

750
    TRY(KOS_array_resize(ctx, inst->args, (uint32_t)argc));
7,452✔
751

752
    for (i = 0; i < argc; i++) {
36,601✔
753
        KOS_OBJ_ID arg_str = KOS_new_cstring(ctx, argv[i]);
29,155✔
754
        TRY_OBJID(arg_str);
29,155✔
755

756
        TRY(KOS_array_write(ctx, inst->args, i, arg_str));
29,150✔
757
    }
758

759
cleanup:
7,446✔
760
    return error;
7,452✔
761
}
762

763
static int save_module_lib(KOS_CONTEXT ctx, KOS_SHARED_LIB lib)
53,475✔
764
{
765
    KOS_LIB_LIST *libs;
766

767
    if ( ! lib)
53,475✔
768
        return KOS_SUCCESS;
52,122✔
769

770
    libs = ctx->inst->modules.libs;
1,353✔
771

772
    if ( ! libs) {
1,353✔
773
        libs = (KOS_LIB_LIST *)KOS_malloc(sizeof(KOS_LIB_LIST) + 7 * sizeof(KOS_SHARED_LIB));
1,347✔
774

775
        if ( ! libs)
1,347✔
776
            return KOS_ERROR_OUT_OF_MEMORY;
1✔
777

778
        libs->num_libs = 0;
1,346✔
779
        libs->capacity = 8;
1,346✔
780

781
        ctx->inst->modules.libs = libs;
1,346✔
782
    }
783

784
    if (libs->num_libs >= libs->capacity) {
1,352✔
UNCOV
785
        const uint32_t new_capacity = libs->capacity + 8;
×
UNCOV
786
        KOS_LIB_LIST  *new_libs     = (KOS_LIB_LIST *)KOS_realloc(libs,
×
UNCOV
787
                sizeof(KOS_LIB_LIST) + (new_capacity - 1) * sizeof(KOS_SHARED_LIB));
×
788

UNCOV
789
        if ( ! new_libs)
×
UNCOV
790
            return KOS_ERROR_OUT_OF_MEMORY;
×
791

UNCOV
792
        libs                    = new_libs;
×
UNCOV
793
        libs->capacity          = new_capacity;
×
UNCOV
794
        ctx->inst->modules.libs = libs;
×
795
    }
796

797
    libs->libs[libs->num_libs++] = lib;
1,352✔
798

799
    return KOS_SUCCESS;
1,352✔
800
}
801

802
KOS_OBJ_ID kos_register_module_init(KOS_CONTEXT      ctx,
53,486✔
803
                                    KOS_OBJ_ID       module_name_obj,
804
                                    KOS_SHARED_LIB   lib,
805
                                    KOS_BUILTIN_INIT init,
806
                                    unsigned         flags)
807
{
808
    struct KOS_MODULE_INIT_S *mod_init_ptr;
809
    KOS_INSTANCE       *const inst  = ctx->inst;
53,486✔
810
    KOS_LOCAL                 module_name;
811
    KOS_LOCAL                 mod_init;
812

813
#ifdef CONFIG_FUZZ
814
    flags &= ~KOS_MODULE_NEEDS_KOS_SOURCE;
815
#endif
816

817
    KOS_init_local(     ctx, &mod_init);
53,486✔
818
    KOS_init_local_with(ctx, &module_name, module_name_obj);
53,486✔
819

820
    mod_init_ptr = (struct KOS_MODULE_INIT_S *)kos_alloc_object(ctx,
53,486✔
821
                                                                KOS_ALLOC_MOVABLE,
822
                                                                OBJ_OPAQUE,
823
                                                                sizeof(struct KOS_MODULE_INIT_S));
824

825
    if ( ! mod_init_ptr)
53,486✔
826
        goto cleanup;
8✔
827

828
    mod_init_ptr->lib   = lib;
53,478✔
829
    mod_init_ptr->init  = init;
53,478✔
830
    mod_init_ptr->flags = flags;
53,478✔
831

832
    mod_init.o = OBJID(OPAQUE, (KOS_OPAQUE *)mod_init_ptr);
53,478✔
833

834
    if (KOS_set_property(ctx,
53,478✔
835
                         inst->modules.module_inits,
836
                         module_name.o,
837
                         mod_init.o) == KOS_SUCCESS) {
838

839
        if (save_module_lib(ctx, lib) != KOS_SUCCESS) {
53,475✔
840
            assert( ! KOS_is_exception_pending(ctx));
1✔
841

842
            mod_init_ptr = (struct KOS_MODULE_INIT_S *)OBJPTR(OPAQUE, mod_init.o);
1✔
843
            mod_init_ptr->lib  = KOS_NULL;
1✔
844
            mod_init_ptr->init = KOS_NULL;
1✔
845

846
            mod_init.o = KOS_BADPTR;
1✔
847

848
            KOS_raise_exception(ctx, KOS_STR_OUT_OF_MEMORY);
1✔
849
        }
850
    }
851
    else
852
        mod_init.o = KOS_BADPTR;
3✔
853

854
cleanup:
53,486✔
855
    if (IS_BAD_PTR(mod_init.o) && lib)
53,486✔
856
        KOS_unload_library(lib);
2✔
857

858
    return KOS_destroy_top_locals(ctx, &module_name, &mod_init);
53,486✔
859
}
860

861
int KOS_instance_register_builtin(KOS_CONTEXT      ctx,
52,139✔
862
                                  const char      *module,
863
                                  KOS_BUILTIN_INIT init,
864
                                  unsigned         flags)
865
{
866
    const KOS_OBJ_ID module_name = KOS_new_cstring(ctx, module);
52,139✔
867

868
    if (IS_BAD_PTR(module_name))
52,139✔
869
        return KOS_ERROR_EXCEPTION;
7✔
870

871
    return IS_BAD_PTR(kos_register_module_init(ctx, module_name, KOS_NULL, init, flags))
52,132✔
872
           ? KOS_ERROR_EXCEPTION : KOS_SUCCESS;
52,132✔
873
}
874

875
#ifndef NDEBUG
876
void kos_validate_context(KOS_CONTEXT ctx)
7,989,760✔
877
{
878
    KOS_INSTANCE *inst = ctx->inst;
7,989,760✔
879
    KOS_CONTEXT   thread_ctx;
880

881
    assert(inst);
7,989,760✔
882

883
    thread_ctx = (KOS_CONTEXT)kos_tls_get(inst->threads.thread_key);
7,989,760✔
884

885
    assert(thread_ctx);
7,997,590✔
886
    assert(thread_ctx == ctx);
7,997,040✔
887
}
7,997,040✔
888
#endif
889

890
void KOS_raise_exception(KOS_CONTEXT ctx,
636,048✔
891
                         KOS_OBJ_ID  exception_obj)
892
{
893
    /* Nested exceptions are not allowed. */
894
    /* This can only happen if there is a bug and an exception has been ignored. */
895
    assert(IS_BAD_PTR(ctx->exception));
636,048✔
896

897
    assert(GET_OBJ_TYPE_GC_SAFE(exception_obj) <= OBJ_LAST_TYPE ||
636,048✔
898
           GET_OBJ_TYPE_GC_SAFE(exception_obj) == OBJ_DYNAMIC_PROP);
899

900
#ifdef CONFIG_MAD_GC
901
    if ( ! kos_gc_active(ctx)) {
902
        KOS_LOCAL saved_exception;
903

904
        KOS_init_local_with(ctx, &saved_exception, exception_obj);
905
        (void)kos_trigger_mad_gc(ctx);
906
        exception_obj = KOS_destroy_top_local(ctx, &saved_exception);
907
    }
908
#endif
909

910
    if (IS_BAD_PTR(ctx->exception))
637,185✔
911
        ctx->exception = exception_obj;
637,257✔
912
}
637,185✔
913

914
void KOS_raise_exception_cstring(KOS_CONTEXT ctx,
62✔
915
                                 const char *cstr)
916
{
917
    const KOS_OBJ_ID str = KOS_new_const_ascii_cstring(ctx, cstr);
62✔
918

919
    if ( ! IS_BAD_PTR(str))
62✔
920
        KOS_raise_exception(ctx, str);
62✔
921

922
    assert( ! IS_BAD_PTR(ctx->exception));
62✔
923
}
62✔
924

925
KOS_OBJ_ID KOS_format_exception(KOS_CONTEXT ctx,
655✔
926
                                KOS_OBJ_ID  exception)
927
{
928
    int        error;
929
    unsigned   i;
930
    unsigned   depth;
931
    KOS_LOCAL  value;
932
    KOS_LOCAL  backtrace;
933
    KOS_LOCAL  frame_desc;
934
    KOS_LOCAL  array;
935
    KOS_OBJ_ID str;
936
    KOS_VECTOR cstr;
937

938
    KOS_vector_init(&cstr);
655✔
939

940
    KOS_init_locals(ctx, &value, &backtrace, &frame_desc, &array, kos_end_locals);
655✔
941

942
    value.o = KOS_get_property(ctx, exception, KOS_STR_VALUE);
655✔
943
    TRY_OBJID(value.o);
655✔
944

945
    backtrace.o = KOS_get_property(ctx, exception, KOS_STR_BACKTRACE);
655✔
946
    TRY_OBJID(backtrace.o);
655✔
947

948
    if (GET_OBJ_TYPE(backtrace.o) != OBJ_ARRAY)
655✔
UNCOV
949
        RAISE_EXCEPTION_STR(str_err_not_array);
×
950

951
    depth   = KOS_get_array_size(backtrace.o);
655✔
952
    array.o = KOS_new_array(ctx, 1 + depth);
655✔
953
    TRY_OBJID(array.o);
655✔
954

955
    if (GET_OBJ_TYPE(value.o) == OBJ_OBJECT) {
653✔
956
        str = KOS_get_property(ctx, value.o, KOS_CONST_ID(str_description));
293✔
957

958
        if (IS_BAD_PTR(str))
293✔
959
            KOS_clear_exception(ctx);
293✔
960
        else
UNCOV
961
            value.o = str;
×
962
    }
963

964
    if (KOS_vector_reserve(&cstr, 80) != KOS_SUCCESS) {
653✔
965
        KOS_raise_exception(ctx, KOS_STR_OUT_OF_MEMORY);
4✔
966
        RAISE_ERROR(KOS_ERROR_EXCEPTION);
4✔
967
    }
968
    TRY(KOS_append_cstr(ctx, &cstr, str_format_exception, sizeof(str_format_exception) - 1));
649✔
969
    TRY(KOS_object_to_string_or_cstr_vec(ctx, value.o, KOS_DONT_QUOTE, KOS_NULL, &cstr));
649✔
970

971
    str = KOS_new_string(ctx, cstr.buffer, (unsigned)(cstr.size - 1));
647✔
972
    TRY_OBJID(str);
647✔
973

974
    TRY(KOS_array_write(ctx, array.o, 0, str));
645✔
975

976
    for (i = 0; i < depth; i++) {
4,764✔
977

978
        char     cbuf[19];
979
        unsigned len;
980

981
        frame_desc.o = KOS_array_read(ctx, backtrace.o, (int)i);
4,129✔
982
        TRY_OBJID(frame_desc.o);
4,137✔
983

984
        cstr.size = 0;
4,127✔
985

986
        TRY(KOS_append_cstr(ctx, &cstr, str_format_hash,
4,127✔
987
                            sizeof(str_format_hash) - 1));
988

989
        len = (unsigned)snprintf(cbuf, sizeof(cbuf), "%u", i);
4,127✔
990
        TRY(KOS_append_cstr(ctx, &cstr, cbuf, KOS_min(len, (unsigned)(sizeof(cbuf) - 1))));
4,127✔
991

992
        TRY(KOS_append_cstr(ctx, &cstr, str_format_offset,
4,127✔
993
                            sizeof(str_format_offset) - 1));
994

995
        str = KOS_get_property(ctx, frame_desc.o, KOS_STR_OFFSET);
4,127✔
996
        TRY_OBJID(str);
4,127✔
997
        if (IS_NUMERIC_OBJ(str)) {
8,254✔
998
            int64_t int_value;
999

1000
            TRY(KOS_get_integer(ctx, str, &int_value));
4,127✔
1001
            len = (unsigned)snprintf(cbuf, sizeof(cbuf), "0x%" PRIX64, int_value);
4,127✔
1002
            TRY(KOS_append_cstr(ctx, &cstr, cbuf, KOS_min(len, (unsigned)(sizeof(cbuf) - 1))));
4,127✔
1003
        }
1004
        else
UNCOV
1005
            TRY(KOS_append_cstr(ctx, &cstr, str_format_question_marks,
×
1006
                                sizeof(str_format_question_marks) - 1));
1007

1008
        TRY(KOS_append_cstr(ctx, &cstr, str_format_function,
4,127✔
1009
                            sizeof(str_format_function) - 1));
1010

1011
        str = KOS_get_property(ctx, frame_desc.o, KOS_STR_FUNCTION);
4,127✔
1012
        TRY_OBJID(str);
4,127✔
1013
        TRY(KOS_object_to_string_or_cstr_vec(ctx, str, KOS_DONT_QUOTE, KOS_NULL, &cstr));
4,127✔
1014

1015
        TRY(KOS_append_cstr(ctx, &cstr, str_format_module,
4,127✔
1016
                            sizeof(str_format_module) - 1));
1017

1018
        str = KOS_get_property(ctx, frame_desc.o, KOS_STR_FILE);
4,127✔
1019
        TRY_OBJID(str);
4,127✔
1020
        str = KOS_get_file_name(ctx, str);
4,127✔
1021
        TRY_OBJID(str);
4,127✔
1022
        TRY(KOS_object_to_string_or_cstr_vec(ctx, str, KOS_DONT_QUOTE, KOS_NULL, &cstr));
4,125✔
1023

1024
        TRY(KOS_append_cstr(ctx, &cstr, str_format_line,
4,125✔
1025
                            sizeof(str_format_line) - 1));
1026

1027
        str = KOS_get_property(ctx, frame_desc.o, KOS_STR_LINE);
4,125✔
1028
        TRY_OBJID(str);
4,125✔
1029
        TRY(KOS_object_to_string_or_cstr_vec(ctx, str, KOS_DONT_QUOTE, KOS_NULL, &cstr));
4,125✔
1030

1031
        str = KOS_new_string(ctx, cstr.buffer, (unsigned)(cstr.size - 1));
4,123✔
1032
        TRY_OBJID(str);
4,123✔
1033

1034
        TRY(KOS_array_write(ctx, array.o, 1+(int)i, str));
4,119✔
1035
    }
1036

1037
cleanup:
635✔
1038
    array.o = KOS_destroy_top_locals(ctx, &value, &array);
655✔
1039

1040
    KOS_vector_destroy(&cstr);
655✔
1041

1042
    return error ? KOS_BADPTR : array.o;
655✔
1043
}
1044

1045
static void raise_internal_exception(KOS_CONTEXT ctx, KOS_OBJ_ID base)
104✔
1046
{
1047
    const KOS_OBJ_ID exception = KOS_new_object_with_prototype(ctx, base);
104✔
1048

1049
    if ( ! IS_BAD_PTR(exception))
104✔
1050
        KOS_raise_exception(ctx, exception);
104✔
1051
}
104✔
1052

1053
void KOS_raise_generator_end(KOS_CONTEXT ctx)
104✔
1054
{
1055
    raise_internal_exception(ctx, ctx->inst->prototypes.generator_end_proto);
104✔
1056
}
104✔
1057

UNCOV
1058
void kos_raise_panic(KOS_CONTEXT ctx)
×
1059
{
UNCOV
1060
    raise_internal_exception(ctx, ctx->inst->prototypes.panic_proto);
×
UNCOV
1061
}
×
1062

1063
#ifdef NDEBUG
1064
#define check_local_list(ctx, local) ((void)0)
1065
#else
1066
static void check_local_list(KOS_LOCAL *list, KOS_LOCAL *local)
32,035,600✔
1067
{
1068
    while (list) {
383,444,000✔
1069
        assert(list != local);
351,409,000✔
1070
        list = list->next;
351,409,000✔
1071
    }
1072
}
32,035,600✔
1073
#endif
1074

1075
void KOS_init_local_with(KOS_CONTEXT ctx, KOS_LOCAL *local, KOS_OBJ_ID obj_id)
25,886,700✔
1076
{
1077
    KOS_LOCAL *next = ctx->local_list;
25,886,700✔
1078

1079
    check_local_list(next, local);
25,886,700✔
1080

1081
    local->next     = next;
26,290,100✔
1082
    local->o        = obj_id;
26,290,100✔
1083
    ctx->local_list = local;
26,290,100✔
1084
}
26,290,100✔
1085

1086
void KOS_init_ulocal(KOS_CONTEXT ctx, KOS_ULOCAL *local)
1,061✔
1087
{
1088
    KOS_ULOCAL *next = ctx->ulocal_list;
1,061✔
1089

1090
    check_local_list((KOS_LOCAL *)next, (KOS_LOCAL *)local);
1,061✔
1091

1092
    local->next      = next;
1,061✔
1093
    local->prev      = KOS_NULL;
1,061✔
1094
    local->o         = KOS_BADPTR;
1,061✔
1095
    ctx->ulocal_list = local;
1,061✔
1096
    if (next)
1,061✔
1097
        next->prev   = local;
1,020✔
1098
}
1,061✔
1099

1100
void KOS_init_locals(KOS_CONTEXT ctx, ...)
762,641✔
1101
{
1102
    va_list     args;
1103
    KOS_LOCAL  *head     = KOS_NULL;
762,641✔
1104
    KOS_LOCAL **tail_ptr = &head;
762,641✔
1105

1106
    va_start(args, ctx);
762,641✔
1107

1108
    for (;;) {
3,097,020✔
1109
        KOS_LOCAL *local = (KOS_LOCAL *)va_arg(args, KOS_LOCAL *);
3,859,660✔
1110

1111
        if ( ! local)
3,859,300✔
1112
            break;
762,644✔
1113

1114
        check_local_list(head, local);
3,096,650✔
1115
        check_local_list(ctx->local_list, local);
3,096,940✔
1116

1117
        *tail_ptr = local;
3,097,020✔
1118
        tail_ptr  = &local->next;
3,097,020✔
1119

1120
        local->o = KOS_BADPTR;
3,097,020✔
1121
#ifndef NDEBUG
1122
        local->next = KOS_NULL;
3,097,020✔
1123
#endif
1124
    }
1125

1126
    *tail_ptr       = ctx->local_list;
762,644✔
1127
    ctx->local_list = head;
762,644✔
1128

1129
    va_end(args);
762,644✔
1130
}
762,644✔
1131

1132
KOS_OBJ_ID KOS_destroy_ulocal(KOS_CONTEXT ctx, KOS_ULOCAL *local)
1,084✔
1133
{
1134
    KOS_OBJ_ID ret = KOS_BADPTR;
1,084✔
1135

1136
    if (ctx) {
1,084✔
1137
        KOS_ULOCAL *prev = local->prev;
1,061✔
1138
        KOS_ULOCAL *next = local->next;
1,061✔
1139

1140
        KOS_ULOCAL **prev_hookup = prev ? &prev->next : &ctx->ulocal_list;
1,061✔
1141

1142
        assert(ctx->ulocal_list);
1,061✔
1143
        if (prev) {
1,061✔
1144
            assert(ctx->ulocal_list != local);
553✔
1145
        }
1146
        else {
1147
            assert(ctx->ulocal_list == local);
508✔
1148
        }
1149

1150
        *prev_hookup = next;
1,061✔
1151
        if (next)
1,061✔
1152
            next->prev = prev;
1,007✔
1153

1154
        ret = local->o;
1,061✔
1155

1156
#ifndef NDEBUG
1157
        local->next = KOS_NULL;
1,061✔
1158
        local->prev = KOS_NULL;
1,061✔
1159
        local->o    = KOS_BADPTR;
1,061✔
1160
#endif
1161
    }
1162

1163
    return ret;
1,084✔
1164
}
1165

1166
KOS_OBJ_ID KOS_destroy_top_local(KOS_CONTEXT ctx, KOS_LOCAL *local)
6,302,220✔
1167
{
1168
    KOS_OBJ_ID ret = KOS_BADPTR;
6,302,220✔
1169

1170
    assert(ctx->local_list == local);
6,302,220✔
1171

1172
    ctx->local_list = local->next;
6,302,220✔
1173

1174
    ret = local->o;
6,302,220✔
1175

1176
#ifndef NDEBUG
1177
    local->next = KOS_NULL;
6,302,220✔
1178
    local->o    = KOS_BADPTR;
6,302,220✔
1179
#endif
1180

1181
    return ret;
6,302,220✔
1182
}
1183

1184
KOS_OBJ_ID KOS_destroy_top_locals(KOS_CONTEXT ctx, KOS_LOCAL *first, KOS_LOCAL *last)
8,350,720✔
1185
{
1186
    KOS_LOCAL **hookup = &ctx->local_list;
8,350,720✔
1187
    KOS_OBJ_ID  ret    = last->o;
8,350,720✔
1188

1189
    assert(ctx->local_list == first);
8,350,720✔
1190

1191
    *hookup = last->next;
8,350,720✔
1192

1193
#ifndef NDEBUG
1194
    for (;;) {
14,987,600✔
1195
        KOS_LOCAL *next = first->next;
23,338,300✔
1196

1197
        first->next = KOS_NULL;
23,338,300✔
1198
        first->o    = KOS_BADPTR;
23,338,300✔
1199

1200
        if (first == last)
23,338,300✔
1201
            break;
8,350,720✔
1202

1203
        first = next;
14,987,600✔
1204
    }
1205
#endif
1206

1207
    return ret;
8,350,720✔
1208
}
1209

1210
void kos_set_global_event(KOS_CONTEXT ctx, enum KOS_GLOBAL_EVENT_E event)
3,689✔
1211
{
1212
    KOS_INSTANCE* const inst = ctx->inst;
3,689✔
1213
    KOS_CONTEXT         walk_ctx;
1214

1215
    kos_lock_mutex(inst->threads.ctx_mutex);
3,689✔
1216

1217
    walk_ctx = &inst->threads.main_thread;
3,689✔
1218

1219
    for ( ; walk_ctx; walk_ctx = walk_ctx->next) {
11,546✔
1220
        uint32_t flags;
1221

1222
        do {
1223
            flags = KOS_atomic_read_relaxed_u32(walk_ctx->event_flags);
7,857✔
1224
        } while ( ! KOS_atomic_cas_weak_u32(walk_ctx->event_flags, flags, flags | event));
7,857✔
1225
    }
1226

1227
    kos_unlock_mutex(inst->threads.ctx_mutex);
3,689✔
1228
}
3,689✔
1229

1230
void kos_clear_global_event(KOS_CONTEXT ctx, enum KOS_GLOBAL_EVENT_E event)
3,761✔
1231
{
1232
    KOS_INSTANCE* const inst = ctx->inst;
3,761✔
1233
    KOS_CONTEXT         walk_ctx;
1234

1235
    kos_lock_mutex(inst->threads.ctx_mutex);
3,761✔
1236

1237
    walk_ctx = &inst->threads.main_thread;
3,761✔
1238

1239
    for ( ; walk_ctx; walk_ctx = walk_ctx->next) {
12,629✔
1240
        uint32_t flags;
1241

1242
        do {
1243
            flags = KOS_atomic_read_relaxed_u32(walk_ctx->event_flags);
8,868✔
1244
        } while ( ! KOS_atomic_cas_weak_u32(walk_ctx->event_flags, flags, flags & ~event));
8,868✔
1245
    }
1246

1247
    kos_unlock_mutex(inst->threads.ctx_mutex);
3,761✔
1248
}
3,761✔
1249

1250
int KOS_handle_global_event(KOS_CONTEXT ctx)
1,565,010✔
1251
{
1252
    uint32_t event;
1253

1254
    kos_validate_context(ctx);
1,565,010✔
1255

1256
    event = KOS_atomic_read_relaxed_u32(ctx->event_flags);
1,564,920✔
1257

1258
    if ( ! event)
1,564,920✔
1259
        return KOS_SUCCESS;
1,564,910✔
1260

1261
    if (event & KOS_EVENT_PANIC) {
15✔
UNCOV
1262
        kos_raise_panic(ctx);
×
UNCOV
1263
        return KOS_ERROR_EXCEPTION;
×
1264
    }
1265

1266
    if (event & KOS_EVENT_CTRL_C) {
15✔
UNCOV
1267
        raise_internal_exception(ctx, ctx->inst->prototypes.ctrl_c_proto);
×
1268

UNCOV
1269
        return KOS_ERROR_EXCEPTION;
×
1270
    }
1271

1272
    if (event & KOS_EVENT_GC)
15✔
1273
        kos_help_gc(ctx);
55✔
1274

1275
    return KOS_SUCCESS;
55✔
1276
}
1277

1278
#ifdef _WIN32
1279
typedef void (* signal_handler)(int);
1280

1281
static int set_signal(int sig, void (* handler)(int), signal_handler *old_action)
1282
{
1283
    errno = 0;
1284

1285
    return (kos_seq_fail() || ((*old_action = signal(sig, handler)) == SIG_ERR)) ? KOS_ERROR_ERRNO : KOS_SUCCESS;
1286
}
1287

1288
static void restore_signal(int sig, signal_handler *old_action)
1289
{
1290
    signal(sig, *old_action);
1291
}
1292
#else
1293
typedef struct sigaction signal_handler;
1294

1295
static int set_signal(int sig, void (* handler)(int), signal_handler *old_action)
7,518✔
1296
{
1297
    signal_handler sa;
1298

1299
    memset(&sa, 0, sizeof(sa));
7,518✔
1300
    sa.sa_handler = handler;
7,518✔
1301
    sigemptyset(&sa.sa_mask);
7,518✔
1302

1303
    errno = 0;
7,518✔
1304

1305
    return (kos_seq_fail() || sigaction(sig, &sa, old_action) != 0) ? KOS_ERROR_ERRNO : KOS_SUCCESS;
7,518✔
1306
}
1307

1308
static void restore_signal(int sig, signal_handler *old_action)
72✔
1309
{
1310
    signal_handler prev_handler;
1311

1312
    sigaction(sig, old_action, &prev_handler);
72✔
1313
}
72✔
1314
#endif
1315

1316
struct KOS_CTRL_C {
1317
    KOS_ATOMIC(KOS_INSTANCE *) instance;
1318
    signal_handler             old_handler;
1319
};
1320

1321
static struct KOS_CTRL_C ctrl_c;
1322

UNCOV
1323
static void instance_ctrlc_signal_handler(int sig)
×
1324
{
UNCOV
1325
    KOS_INSTANCE *const instance = (KOS_INSTANCE *)KOS_atomic_read_relaxed_ptr(ctrl_c.instance);
×
1326

UNCOV
1327
    kos_set_global_event(&instance->threads.main_thread, KOS_EVENT_CTRL_C);
×
UNCOV
1328
}
×
1329

1330
int KOS_hook_ctrl_c(KOS_CONTEXT ctx)
7,518✔
1331
{
1332
    if ( ! KOS_atomic_cas_strong_ptr(ctrl_c.instance, (KOS_INSTANCE *)KOS_NULL, ctx->inst)) {
7,518✔
UNCOV
1333
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_ctrl_c_already_hooked));
×
UNCOV
1334
        return KOS_ERROR_EXCEPTION;
×
1335
    }
1336

1337
    if (set_signal(SIGINT, instance_ctrlc_signal_handler, &ctrl_c.old_handler)) {
7,518✔
1338
        KOS_raise_errno(ctx, "signal");
1✔
1339
        return KOS_ERROR_EXCEPTION;
1✔
1340
    }
1341

1342
    return KOS_SUCCESS;
7,517✔
1343
}
1344

1345
int KOS_unhook_ctrl_c(KOS_CONTEXT ctx)
72✔
1346
{
1347
    if (KOS_atomic_read_acquire_ptr(ctrl_c.instance) == ctx->inst) {
72✔
1348

1349
        restore_signal(SIGINT, &ctrl_c.old_handler);
72✔
1350
        memset(&ctrl_c.old_handler, 0, sizeof(ctrl_c.old_handler));
72✔
1351

1352
        kos_clear_global_event(ctx, KOS_EVENT_CTRL_C);
72✔
1353

1354
        KOS_atomic_write_release_ptr(ctrl_c.instance, (KOS_INSTANCE *)KOS_NULL);
72✔
1355
    }
1356

1357
    return KOS_SUCCESS;
72✔
1358
}
1359

1360
void KOS_clear_ctrl_c_event(KOS_CONTEXT ctx)
1,787✔
1361
{
1362
    KOS_LOCAL exception;
1363
    int       clear_flag = 0;
1,787✔
1364

1365
    KOS_init_local_with(ctx, &exception, KOS_get_exception(ctx));
1,787✔
1366

1367
    if ( ! IS_BAD_PTR(exception.o)) {
1,787✔
1368

1369
        KOS_OBJ_ID value;
1370

1371
        KOS_clear_exception(ctx);
1,787✔
1372

1373
        value = KOS_get_property(ctx, exception.o, KOS_STR_VALUE);
1,787✔
1374

1375
        if ( ! IS_BAD_PTR(value)) {
1,787✔
1376
            if (KOS_has_prototype(ctx, value, ctx->inst->prototypes.ctrl_c_proto))
1,769✔
UNCOV
1377
                clear_flag = 1;
×
1378
        }
1379
        else
1380
            KOS_clear_exception(ctx);
18✔
1381

1382
        KOS_raise_exception(ctx, exception.o);
1,787✔
1383
    }
1384

1385
    KOS_destroy_top_local(ctx, &exception);
1,787✔
1386

1387
    if (clear_flag)
1,787✔
UNCOV
1388
        kos_clear_global_event(ctx, KOS_EVENT_CTRL_C);
×
1389
}
1,787✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc