#include #include #include #include #include struct string_cache_entry { unsigned long e_index; fx_namemap_entry e_entry; }; struct bshell_scriptblock_p { /* pool values referenced by the text */ FX_VECTOR_DECLARE(fx_value, b_pool); /* bytecode instructions */ FX_VECTOR_DECLARE(bshell_instruction, b_text); /* string value cache */ fx_namemap b_strings; }; static fx_status pool_destroy(void *p) { fx_value_unset(p); return FX_SUCCESS; } static fx_vector_ops pool_ops = { .v_destroy = pool_destroy, }; static void scriptblock_fini(fx_object *obj, void *priv) { struct bshell_scriptblock_p *block = priv; fx_vector_destroy(block->b_pool, &pool_ops); fx_vector_destroy(block->b_text, NULL); } static size_t scriptblock_push_instruction( struct bshell_scriptblock_p *block, enum bshell_opcode opcode, uint32_t arg) { size_t offset = block->b_text.count * sizeof(bshell_instruction); uint32_t instr = bshell_instruction_encode(opcode, arg); fx_vector_push_back(block->b_text, &instr, NULL); return offset; } static enum bshell_status scriptblock_read_instruction( struct bshell_scriptblock_p *block, size_t offset, enum bshell_opcode *out_opcode, uint32_t *out_arg) { offset /= sizeof(bshell_instruction); if (offset >= block->b_text.count) { return BSHELL_ERR_INVALID_ARGUMENT; } enum bshell_opcode opcode; uint32_t arg; bshell_instruction_decode(block->b_text.items[offset], &opcode, &arg); if (out_opcode) { *out_opcode = opcode; } if (out_arg) { *out_arg = arg; } return BSHELL_SUCCESS; } static void scriptblock_patch_instruction( struct bshell_scriptblock_p *block, size_t offset, enum bshell_opcode opcode, uint32_t arg) { offset /= sizeof(bshell_instruction); if (offset >= block->b_text.count) { return; } block->b_text.items[offset] = bshell_instruction_encode(opcode, arg); } static void scriptblock_clear_text(struct bshell_scriptblock_p *block) { block->b_text.count = 0; } static void scriptblock_get_text( const struct bshell_scriptblock_p *block, bshell_instruction **out_ptr, size_t *out_count) { if (out_ptr) { *out_ptr = block->b_text.items; } if (out_count) { *out_count = block->b_text.count; } } static void scriptblock_get_pool( const struct bshell_scriptblock_p *block, fx_value **out_ptr, size_t *out_count) { if (out_ptr) { *out_ptr = block->b_pool.items; } if (out_count) { *out_count = block->b_pool.count; } } static unsigned long scriptblock_add_pool_value( struct bshell_scriptblock_p *block, fx_value *value) { unsigned long id = block->b_pool.count; fx_value *slot = fx_vector_emplace_back(block->b_pool, &pool_ops); if (!slot) { return (unsigned long)-1; } fx_value_copy(slot, value); return id; } static fx_value *scriptblock_get_pool_value( const struct bshell_scriptblock_p *block, unsigned long index, fx_type_id expected_type) { if (index >= block->b_pool.count) { return NULL; } fx_value *value = &block->b_pool.items[index]; if (expected_type && fx_type_id_compare(value->v_type, expected_type) != 0) { return NULL; } return value; } static unsigned long scriptblock_get_string( struct bshell_scriptblock_p *block, const char *s) { struct string_cache_entry *cache_entry = NULL; fx_string *str = NULL; fx_namemap_entry *e = fx_namemap_get(&block->b_strings, s); if (e) { cache_entry = fx_unbox(struct string_cache_entry, e, e_entry); return cache_entry->e_index; } cache_entry = malloc(sizeof *cache_entry); if (!cache_entry) { goto cleanup; } str = fx_string_create_from_cstr(s); if (!str) { goto cleanup; } unsigned long index = block->b_pool.count; fx_value *slot = fx_vector_emplace_back(block->b_pool, &pool_ops); if (!slot) { goto cleanup; } *slot = FX_VALUE_OBJECT(str); cache_entry->e_index = index; fx_namemap_put( &block->b_strings, fx_string_get_cstr(str), &cache_entry->e_entry); return index; cleanup: if (str) { fx_string_unref(str); } if (cache_entry) { free(cache_entry); } return POOL_INDEX_INVALID; } static unsigned long scriptblock_get_double( struct bshell_scriptblock_p *block, double v) { fx_value value = FX_DOUBLE(v); return scriptblock_add_pool_value(block, &value); } size_t bshell_scriptblock_push_instruction( bshell_scriptblock *block, enum bshell_opcode opcode, uint32_t arg) { FX_CLASS_DISPATCH_STATIC( BSHELL_TYPE_SCRIPTBLOCK, scriptblock_push_instruction, block, opcode, arg); } enum bshell_status bshell_scriptblock_read_instruction( bshell_scriptblock *block, size_t offset, enum bshell_opcode *out_opcode, uint32_t *out_arg) { FX_CLASS_DISPATCH_STATIC( BSHELL_TYPE_SCRIPTBLOCK, scriptblock_read_instruction, block, offset, out_opcode, out_arg); } void bshell_scriptblock_patch_instruction( bshell_scriptblock *block, size_t offset, enum bshell_opcode opcode, uint32_t arg) { FX_CLASS_DISPATCH_STATIC_V( BSHELL_TYPE_SCRIPTBLOCK, scriptblock_patch_instruction, block, offset, opcode, arg); } void bshell_scriptblock_clear_text(bshell_scriptblock *block) { FX_CLASS_DISPATCH_STATIC_V0( BSHELL_TYPE_SCRIPTBLOCK, scriptblock_clear_text, block); } void bshell_scriptblock_get_text( const bshell_scriptblock *block, bshell_instruction **out_ptr, size_t *out_count) { FX_CLASS_DISPATCH_STATIC( BSHELL_TYPE_SCRIPTBLOCK, scriptblock_get_text, block, out_ptr, out_count); } void bshell_scriptblock_get_pool( const bshell_scriptblock *block, fx_value **out_ptr, size_t *out_count) { FX_CLASS_DISPATCH_STATIC( BSHELL_TYPE_SCRIPTBLOCK, scriptblock_get_pool, block, out_ptr, out_count); } unsigned long bshell_scriptblock_add_pool_value( bshell_scriptblock *block, fx_value *value) { FX_CLASS_DISPATCH_STATIC( BSHELL_TYPE_SCRIPTBLOCK, scriptblock_add_pool_value, block, value); } fx_value *bshell_scriptblock_get_pool_value( const bshell_scriptblock *block, unsigned long index, fx_type_id expected_type) { FX_CLASS_DISPATCH_STATIC( BSHELL_TYPE_SCRIPTBLOCK, scriptblock_get_pool_value, block, index, expected_type); } unsigned long bshell_scriptblock_get_string( bshell_scriptblock *block, const char *s) { FX_CLASS_DISPATCH_STATIC( BSHELL_TYPE_SCRIPTBLOCK, scriptblock_get_string, block, s); } unsigned long bshell_scriptblock_get_double(bshell_scriptblock *block, double v) { FX_CLASS_DISPATCH_STATIC( BSHELL_TYPE_SCRIPTBLOCK, scriptblock_get_double, block, v); } FX_TYPE_CLASS_BEGIN(bshell_scriptblock) FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT) FX_INTERFACE_ENTRY(to_string) = NULL; FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT) FX_TYPE_CONSTRUCTOR( "create", bshell_scriptblock_create, 0, FX_TYPE_VOID); FX_TYPE_CLASS_END(bshell_scriptblock) FX_TYPE_DEFINITION_BEGIN(bshell_scriptblock) FX_TYPE_ID(0x02b87313, 0x83f6, 0x4a57, 0xa573, 0x62cf492391ce); FX_TYPE_NAME("bshell.runtime.scriptblock"); FX_TYPE_CLASS(bshell_scriptblock_class); FX_TYPE_INSTANCE_PRIVATE(struct bshell_scriptblock_p); FX_TYPE_INSTANCE_FINI(scriptblock_fini); FX_TYPE_DEFINITION_END(bshell_scriptblock)