GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class) { GDMonoClass *match = NULL; if (gdobject_class_cache_updated) { Map<StringName, GDMonoClass *>::Element *result = gdobject_class_cache.find(p_class); if (result) match = result->get(); } else { List<GDMonoClass *> nested_classes; int rows = mono_image_get_table_rows(image, MONO_TABLE_TYPEDEF); for (int i = 1; i < rows; i++) { MonoClass *mono_class = mono_class_get(image, (i + 1) | MONO_TOKEN_TYPE_DEF); if (!mono_class_is_assignable_from(CACHED_CLASS_RAW(GodotObject), mono_class)) continue; GDMonoClass *current = get_class(mono_class); if (!current) continue; nested_classes.push_back(current); if (!match && current->get_name() == p_class) match = current; while (!nested_classes.empty()) { GDMonoClass *current_nested = nested_classes.front()->get(); nested_classes.pop_back(); void *iter = NULL; while (true) { MonoClass *raw_nested = mono_class_get_nested_types(current_nested->get_raw(), &iter); if (!raw_nested) break; GDMonoClass *nested_class = get_class(raw_nested); if (nested_class) { gdobject_class_cache.insert(nested_class->get_name(), nested_class); nested_classes.push_back(nested_class); } } } gdobject_class_cache.insert(current->get_name(), current); } gdobject_class_cache_updated = true; } return match; }
bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const { return mono_class_is_assignable_from(mono_class, p_from->mono_class); }
/* * Used by the arch code to replace the exception handling * with a direct branch. This is safe to do if the * exception object isn't used, no rethrow statement and * no filter statement (verify). * */ MonoInst * mono_branch_optimize_exception_target (MonoCompile *cfg, MonoBasicBlock *bb, const char * exname) { MonoMethodHeader *header = cfg->header; MonoExceptionClause *clause; MonoClass *exclass; int i; if (!(cfg->opt & MONO_OPT_EXCEPTION)) return NULL; if (bb->region == -1 || !MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY)) return NULL; exclass = mono_class_from_name (mono_get_corlib (), "System", exname); /* search for the handler */ for (i = 0; i < header->num_clauses; ++i) { clause = &header->clauses [i]; if (MONO_OFFSET_IN_CLAUSE (clause, bb->real_offset)) { if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE && clause->data.catch_class && mono_class_is_assignable_from (clause->data.catch_class, exclass)) { MonoBasicBlock *tbb; /* get the basic block for the handler and * check if the exception object is used. * Flag is set during method_to_ir due to * pop-op is optmized away in codegen (burg). */ tbb = cfg->cil_offset_to_bb [clause->handler_offset]; if (tbb && tbb->flags & BB_EXCEPTION_DEAD_OBJ && !(tbb->flags & BB_EXCEPTION_UNSAFE)) { MonoBasicBlock *targetbb = tbb; gboolean unsafe = FALSE; /* Check if this catch clause is ok to optimize by * looking for the BB_EXCEPTION_UNSAFE in every BB that * belongs to the same region. * * UNSAFE flag is set during method_to_ir (OP_RETHROW) */ while (!unsafe && tbb->next_bb && tbb->region == tbb->next_bb->region) { if (tbb->next_bb->flags & BB_EXCEPTION_UNSAFE) { unsafe = TRUE; break; } tbb = tbb->next_bb; } if (!unsafe) { MonoInst *jump; /* Create dummy inst to allow easier integration in * arch dependent code (opcode ignored) */ MONO_INST_NEW (cfg, jump, OP_BR); /* Allocate memory for our branch target */ jump->inst_i1 = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst)); jump->inst_true_bb = targetbb; if (cfg->verbose_level > 2) g_print ("found exception to optimize - returning branch to BB%d (%s) (instead of throw) for method %s:%s\n", targetbb->block_num, clause->data.catch_class->name, cfg->method->klass->name, cfg->method->name); return jump; } return NULL; } else { /* Branching to an outer clause could skip inner clauses */ return NULL; } } else { /* Branching to an outer clause could skip inner clauses */ return NULL; } } } return NULL; }