#include "moar.h" int MVM_ext_load(MVMThreadContext *tc, MVMString *lib, MVMString *ext) { MVMString *colon, *prefix, *name; MVMDLLSym *sym; void (*init)(MVMThreadContext *); MVMROOT2(tc, lib, ext, { colon = MVM_string_ascii_decode_nt( tc, tc->instance->VMString, ":"); prefix = MVM_string_concatenate(tc, lib, colon); name = MVM_string_concatenate(tc, prefix, ext); }); uv_mutex_lock(&tc->instance->mutex_ext_registry); /* MVM_string_concatenate returns a concrete MVMString, will always pass the * MVM_str_hash_key_is_valid check. */ MVMExtRegistry *entry = MVM_fixkey_hash_fetch_nocheck(tc, &tc->instance->ext_registry, name); /* Extension already loaded. */ if (entry) { uv_mutex_unlock(&tc->instance->mutex_ext_registry); return 0; } MVMROOT(tc, name, { sym = (MVMDLLSym *)MVM_dll_find_symbol(tc, lib, ext); }); if (!sym) { char *c_name = MVM_string_utf8_encode_C_string(tc, name); char *waste[] = { c_name, NULL }; uv_mutex_unlock(&tc->instance->mutex_ext_registry); MVM_exception_throw_adhoc_free(tc, waste, "extension symbol (%s) not found", c_name); } entry = MVM_fixkey_hash_insert_nocheck(tc, &tc->instance->ext_registry, name); entry->sym = sym; MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&entry->hash_key, "Extension name hash key"); uv_mutex_unlock(&tc->instance->mutex_ext_registry); /* Call extension's initializer */ init = (void (*)(MVMThreadContext *))sym->body.address; init(tc); return 1; } int MVM_ext_register_extop(MVMThreadContext *tc, const char *cname, MVMExtOpFunc func, MVMuint8 num_operands, MVMuint8 operands[], MVMExtOpSpesh *spesh, MVMExtOpFactDiscover *discover, MVMuint32 flags) { /* This MVMString ends up being permarooted, so if we create it in gen2 we * save some GC work */ MVM_gc_allocate_gen2_default_set(tc); MVMString *name = MVM_string_ascii_decode_nt( tc, tc->instance->VMString, cname); MVM_gc_allocate_gen2_default_clear(tc); uv_mutex_lock(&tc->instance->mutex_extop_registry); struct MVMExtOpRegistry *entry = MVM_fixkey_hash_fetch_nocheck(tc, &tc->instance->extop_registry, name); /* Op already registered, so just verify its signature. */ if (entry) { uv_mutex_unlock(&tc->instance->mutex_extop_registry); if (num_operands != entry->info.num_operands || memcmp(operands, entry->info.operands, num_operands) != 0) MVM_exception_throw_adhoc(tc, "signature mismatch when re-registering extension op %s", cname); return 0; } /* Sanity-check signature. */ if (num_operands > MVM_MAX_OPERANDS) { uv_mutex_unlock(&tc->instance->mutex_extop_registry); MVM_exception_throw_adhoc(tc, "cannot register extension op with more than %u operands", MVM_MAX_OPERANDS); } { MVMuint8 i = 0; for(; i < num_operands; i++) { MVMuint8 flags = operands[i]; switch (flags & MVM_operand_rw_mask) { case MVM_operand_literal: goto check_literal; case MVM_operand_read_reg: case MVM_operand_write_reg: case MVM_operand_read_lex: case MVM_operand_write_lex: goto check_reg; default: goto fail; } check_literal: switch (flags & MVM_operand_type_mask) { case MVM_operand_int8: case MVM_operand_int16: case MVM_operand_int32: case MVM_operand_int64: case MVM_operand_num32: case MVM_operand_num64: case MVM_operand_str: case MVM_operand_coderef: continue; case MVM_operand_ins: case MVM_operand_callsite: default: goto fail; } check_reg: switch (flags & MVM_operand_type_mask) { case MVM_operand_int8: case MVM_operand_int16: case MVM_operand_int32: case MVM_operand_int64: case MVM_operand_num32: case MVM_operand_num64: case MVM_operand_str: case MVM_operand_obj: case MVM_operand_type_var: case MVM_operand_uint8: case MVM_operand_uint16: case MVM_operand_uint32: case MVM_operand_uint64: continue; default: goto fail; } fail: uv_mutex_unlock(&tc->instance->mutex_extop_registry); MVM_exception_throw_adhoc(tc, "extension op %s has illegal signature", cname); } } entry = MVM_fixkey_hash_insert_nocheck(tc, &tc->instance->extop_registry, name); entry->func = func; entry->info.name = cname; entry->info.opcode = (MVMuint16)-1; entry->info.num_operands = num_operands; entry->info.pure = flags & MVM_EXTOP_PURE; entry->info.deopt_point = 0; entry->info.logged = 0; entry->info.post_logged = 0; entry->info.no_inline = flags & MVM_EXTOP_NOINLINE; entry->info.jittivity = (flags & MVM_EXTOP_INVOKISH) ? MVM_JIT_INFO_INVOKISH : 0; entry->info.uses_hll = 0; entry->info.uses_cache = 0; entry->info.may_cause_deopt = 0; entry->info.specializable = spesh ? 1 : 0; memcpy(entry->info.operands, operands, num_operands); memset(entry->info.operands + num_operands, 0, MVM_MAX_OPERANDS - num_operands); entry->spesh = spesh; entry->discover = discover; entry->no_jit = flags & MVM_EXTOP_NO_JIT; entry->allocating = flags & MVM_EXTOP_ALLOCATING; MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&entry->hash_key, "Extension op name hash key"); uv_mutex_unlock(&tc->instance->mutex_extop_registry); return 1; } const MVMOpInfo * MVM_ext_resolve_extop_record(MVMThreadContext *tc, MVMExtOpRecord *record) { /* Already resolved. */ if (record->info) return record->info; if (!MVM_str_hash_key_is_valid(tc, record->name)) { MVM_str_hash_key_throw_invalid(tc, record->name); } uv_mutex_lock(&tc->instance->mutex_extop_registry); MVMExtOpRegistry *entry = MVM_fixkey_hash_fetch_nocheck(tc, &tc->instance->extop_registry, record->name); if (!entry) { uv_mutex_unlock(&tc->instance->mutex_extop_registry); return NULL; } /* Resolve record. */ record->info = &entry->info; record->func = entry->func; record->spesh = entry->spesh; record->discover = entry->discover; record->no_jit = entry->no_jit; record->allocating = entry->allocating; uv_mutex_unlock(&tc->instance->mutex_extop_registry); return record->info; } const MVMOpInfo * MVM_ext_resolve_extop_record_in_cu(MVMThreadContext *tc, MVMCompUnit *cu, MVMuint16 opcode) { MVMuint16 index = opcode - MVM_OP_EXT_BASE; MVMExtOpRecord *record = &cu->body.extops[index]; return MVM_ext_resolve_extop_record(tc, record); }