compute_llvm_code_range (MonoAotModule *amodule, guint8 **code_start, guint8 **code_end);
static gboolean
-init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass *init_class, MonoError *error);
+init_method (MonoAotModule *amodule, gpointer info, guint32 method_index, MonoMethod *method, MonoClass *init_class, MonoError *error);
static MonoJumpInfo*
decode_patches (MonoAotModule *amodule, MonoMemPool *mp, int n_patches, gboolean llvm, guint32 *got_offsets);
if (!(is_llvm_code (amodule, code) && (amodule->info.flags & MONO_AOT_FILE_FLAG_LLVM_ONLY)) ||
(mono_llvm_only && method && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)) {
- res = init_method (amodule, method_index, method, NULL, error);
- if (!res)
- goto cleanup;
+ /* offset == 0 means its llvm code */
+ if (mono_aot_get_offset (amodule->method_info_offsets, method_index) != 0) {
+ res = init_method (amodule, NULL, method_index, method, NULL, error);
+ if (!res)
+ goto cleanup;
+ }
}
if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
}
if (mono_llvm_only) {
- guint8 *info, *p;
-
- info = &amodule->blob [mono_aot_get_offset (amodule->method_info_offsets, method_index)];
- p = info;
- guint8 flags = decode_value (p, &p);
+ guint8 flags = amodule->info.method_flags_table [method_index];
/* The caller needs to looks this up, but its hard to do without constructing the full MonoJitInfo, so save it here */
if (flags & MONO_AOT_METHOD_FLAG_GSHAREDVT_VARIABLE) {
mono_aot_lock ();
}
static gboolean
-init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass *init_class, MonoError *error)
+init_method (MonoAotModule *amodule, gpointer info, guint32 method_index, MonoMethod *method, MonoClass *init_class, MonoError *error)
{
MonoDomain *domain = mono_domain_get ();
MonoMemPool *mp;
int pindex, n_patches;
guint8 *p;
MonoJitInfo *jinfo = NULL;
- guint8 *code, *info;
+ guint8 *code;
MonoGenericContext *context;
MonoGenericContext ctx;
error_init (error);
- code = (guint8 *)amodule->methods [method_index];
- info = &amodule->blob [mono_aot_get_offset (amodule->method_info_offsets, method_index)];
+ if (!info)
+ info = &amodule->blob [mono_aot_get_offset (amodule->method_info_offsets, method_index)];
- p = info;
+ p = (guint8*)info;
+
+ // FIXME: Is this aligned ?
+ guint32 encoded_method_index = *(guint32*)p;
+ if (method_index)
+ g_assert (method_index == encoded_method_index);
+ method_index = encoded_method_index;
+ p += 4;
+
+ code = (guint8 *)amodule->methods [method_index];
+ guint8 flags = amodule->info.method_flags_table [method_index];
- guint8 flags = decode_value (p, &p);
if (flags & MONO_AOT_METHOD_FLAG_HAS_CCTOR)
klass_to_run_ctor = decode_klass_ref (amodule, p, &p, error);
if (!is_ok (error))
}
/*
- * mono_aot_init_llvmonly_method:
+ * mono_aot_init_llvm_method:
*
- * Initialize the method identified by METHOD_INDEX in llvmonly mode.
+ * Initialize the LLVM method identified by METHOD_INFO.
*/
gboolean
-mono_aot_init_llvmonly_method (gpointer aot_module, guint32 method_index, MonoClass *init_class, MonoError *error)
+mono_aot_init_llvm_method (gpointer aot_module, gpointer method_info, MonoClass *init_class, MonoError *error)
{
MonoAotModule *amodule = (MonoAotModule*)aot_module;
- MonoMethod *method = NULL;
- return init_method (amodule, method_index, method, init_class, error);
+ return init_method (amodule, method_info, 0, NULL, init_class, error);
}
/*
}
/*
- * emit_init_icall_wrapper:
+ * emit_init_func:
*
- * Emit wrappers around the mini_llvm_init_method () JIT icall.
+ * Emit functions to initialize LLVM methods.
+ * These are wrappers around the mini_llvm_init_method () JIT icall.
* The wrappers handle adding the 'amodule' argument, loading the vtable from different locations, and they have
* a cold calling convention.
*/
static LLVMValueRef
-emit_init_icall_wrapper (MonoLLVMModule *module, MonoAotInitSubtype subtype)
+emit_init_func (MonoLLVMModule *module, MonoAotInitSubtype subtype)
{
LLVMModuleRef lmodule = module->lmodule;
- LLVMValueRef func, indexes [2], args [16], callee, inited_var, cmp;
+ LLVMValueRef func, indexes [2], args [16], callee, info_var, index_var, inited_var, cmp;
LLVMBasicBlockRef entry_bb, inited_bb, notinited_bb;
LLVMBuilderRef builder;
LLVMTypeRef icall_sig;
const char *wrapper_name = mono_marshal_get_aot_init_wrapper_name (subtype);
LLVMTypeRef func_type = NULL;
+ LLVMTypeRef arg_type = module->ptr_type;
char *name = g_strdup_printf ("%s_%s", module->global_prefix, wrapper_name);
switch (subtype) {
case AOT_INIT_METHOD:
- func_type = LLVMFunctionType1 (LLVMVoidType (), LLVMInt32Type (), FALSE);
+ func_type = LLVMFunctionType1 (LLVMVoidType (), arg_type, FALSE);
break;
case AOT_INIT_METHOD_GSHARED_MRGCTX:
- func_type = LLVMFunctionType2 (LLVMVoidType (), LLVMInt32Type (), IntPtrType (), FALSE);
- break;
case AOT_INIT_METHOD_GSHARED_VTABLE:
- func_type = LLVMFunctionType2 (LLVMVoidType (), LLVMInt32Type (), IntPtrType (), FALSE);
+ func_type = LLVMFunctionType2 (LLVMVoidType (), arg_type, IntPtrType (), FALSE);
break;
case AOT_INIT_METHOD_GSHARED_THIS:
- func_type = LLVMFunctionType2 (LLVMVoidType (), LLVMInt32Type (), ObjRefType (), FALSE);
+ func_type = LLVMFunctionType2 (LLVMVoidType (), arg_type, ObjRefType (), FALSE);
break;
default:
g_assert_not_reached ();
func = LLVMAddFunction (lmodule, name, func_type);
+ info_var = LLVMGetParam (func, 0);
+
LLVMSetLinkage (func, LLVMInternalLinkage);
mono_llvm_add_func_attr (func, LLVM_ATTR_NO_INLINE);
builder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (builder, entry_bb);
+ /* Load method_index which is emitted at the start of the method info */
+ indexes [0] = const_int32 (0);
+ indexes [1] = const_int32 (0);
+ // FIXME: Make sure its aligned
+ index_var = LLVMBuildLoad (builder, LLVMBuildGEP (builder, LLVMBuildBitCast (builder, info_var, LLVMPointerType (LLVMInt32Type (), 0), ""), indexes, 1, ""), "method_index");
+
/* Check for is_inited here as well, since this can be called from JITted code which might not check it */
- indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
- indexes [1] = LLVMGetParam (func, 0);
+ indexes [0] = const_int32 (0);
+ indexes [1] = index_var;
inited_var = LLVMBuildLoad (builder, LLVMBuildGEP (builder, module->inited_var, indexes, 2, ""), "is_inited");
cmp = LLVMBuildICmp (builder, LLVMIntEQ, inited_var, LLVMConstInt (LLVMTypeOf (inited_var), 0, FALSE), "");
args [0] = LLVMBuildPtrToInt (builder, module->info_var, IntPtrType (), "");
args [1] = LLVMBuildPtrToInt (builder, amodule_var, IntPtrType (), "");
- args [2] = LLVMGetParam (func, 0);
+ args [2] = info_var;
switch (subtype) {
case AOT_INIT_METHOD:
break;
}
- icall_sig = LLVMFunctionType4 (LLVMVoidType (), IntPtrType (), IntPtrType (), LLVMInt32Type (), IntPtrType (), FALSE);
+ /* Call the mini_llvm_init_method JIT icall */
+ icall_sig = LLVMFunctionType4 (LLVMVoidType (), IntPtrType (), IntPtrType (), arg_type, IntPtrType (), FALSE);
callee = get_aotconst_module (module, builder, MONO_PATCH_INFO_JIT_ICALL_ID, GINT_TO_POINTER (MONO_JIT_ICALL_mini_llvm_init_method), LLVMPointerType (icall_sig, 0), NULL, NULL);
LLVMBuildCall (builder, callee, args, LLVMCountParamTypes (icall_sig), "");
- // Set the inited flag
- indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
- indexes [1] = LLVMGetParam (func, 0);
+ /*
+ * Set the inited flag
+ * This is already done by the LLVM methods themselves, but its needed by JITted methods.
+ */
+ indexes [0] = const_int32 (0);
+ indexes [1] = index_var;
LLVMBuildStore (builder, LLVMConstInt (LLVMInt8Type (), 1, FALSE), LLVMBuildGEP (builder, module->inited_var, indexes, 2, ""));
LLVMBuildBr (builder, inited_bb);
LLVMPositionBuilderAtEnd (builder, inited_bb);
LLVMBuildRetVoid (builder);
- LLVMVerifyFunction(func, LLVMAbortProcessAction);
+ LLVMVerifyFunction (func, LLVMAbortProcessAction);
LLVMDisposeBuilder (builder);
g_free (name);
* cold calling convention.
*/
static void
-emit_init_icall_wrappers (MonoLLVMModule *module)
+emit_init_funcs (MonoLLVMModule *module)
{
- module->init_method = emit_init_icall_wrapper (module, AOT_INIT_METHOD);
- module->init_method_gshared_mrgctx = emit_init_icall_wrapper (module, AOT_INIT_METHOD_GSHARED_MRGCTX);
- module->init_method_gshared_this = emit_init_icall_wrapper (module, AOT_INIT_METHOD_GSHARED_THIS);
- module->init_method_gshared_vtable = emit_init_icall_wrapper (module, AOT_INIT_METHOD_GSHARED_VTABLE);
+ module->init_method = emit_init_func (module, AOT_INIT_METHOD);
+ module->init_method_gshared_mrgctx = emit_init_func (module, AOT_INIT_METHOD_GSHARED_MRGCTX);
+ module->init_method_gshared_this = emit_init_func (module, AOT_INIT_METHOD_GSHARED_THIS);
+ module->init_method_gshared_vtable = emit_init_func (module, AOT_INIT_METHOD_GSHARED_VTABLE);
}
static LLVMValueRef
-get_init_icall_wrapper (MonoLLVMModule *module, MonoAotInitSubtype subtype)
+get_init_func (MonoLLVMModule *module, MonoAotInitSubtype subtype)
{
switch (subtype) {
case AOT_INIT_METHOD:
}
/*
- * emit_init_method:
+ * emit_method_init:
*
* Emit code to initialize the GOT slots used by the method.
*/
static void
-emit_init_method (EmitContext *ctx)
+emit_method_init (EmitContext *ctx)
{
LLVMValueRef indexes [16], args [16], callee;
LLVMValueRef inited_var, cmp, call;
ctx->module->max_inited_idx = MAX (ctx->module->max_inited_idx, cfg->method_index);
- indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
- indexes [1] = LLVMConstInt (LLVMInt32Type (), cfg->method_index, FALSE);
+ indexes [0] = const_int32 (0);
+ indexes [1] = const_int32 (cfg->method_index);
inited_var = LLVMBuildLoad (builder, LLVMBuildGEP (builder, ctx->module->inited_var, indexes, 2, ""), "is_inited");
args [0] = inited_var;
builder = ctx->builder = create_builder (ctx);
LLVMPositionBuilderAtEnd (ctx->builder, notinited_bb);
+ LLVMTypeRef type = LLVMArrayType (LLVMInt8Type (), 0);
+ char *symbol = g_strdup_printf ("info_dummy_%s", cfg->llvm_method_name);
+ LLVMValueRef info_var = LLVMAddGlobal (ctx->lmodule, type, symbol);
+ g_free (symbol);
+ cfg->llvm_dummy_info_var = info_var;
+
+ args [0] = convert (ctx, info_var, ctx->module->ptr_type);
+
// FIXME: Cache
if (ctx->rgctx_arg && ((cfg->method->is_inflated && mono_method_get_context (cfg->method)->method_inst) ||
mini_method_is_default_method (cfg->method))) {
- args [0] = LLVMConstInt (LLVMInt32Type (), cfg->method_index, 0);
args [1] = convert (ctx, ctx->rgctx_arg, IntPtrType ());
callee = ctx->module->init_method_gshared_mrgctx;
call = LLVMBuildCall (builder, callee, args, 2, "");
} else if (ctx->rgctx_arg) {
/* A vtable is passed as the rgctx argument */
- args [0] = LLVMConstInt (LLVMInt32Type (), cfg->method_index, 0);
args [1] = convert (ctx, ctx->rgctx_arg, IntPtrType ());
callee = ctx->module->init_method_gshared_vtable;
call = LLVMBuildCall (builder, callee, args, 2, "");
} else if (cfg->gshared) {
- args [0] = LLVMConstInt (LLVMInt32Type (), cfg->method_index, 0);
args [1] = convert (ctx, ctx->this_arg, ObjRefType ());
callee = ctx->module->init_method_gshared_this;
call = LLVMBuildCall (builder, callee, args, 2, "");
} else {
- args [0] = LLVMConstInt (LLVMInt32Type (), cfg->method_index, 0);
callee = ctx->module->init_method;
call = LLVMBuildCall (builder, callee, args, 1, "");
}
*/
set_call_cold_cconv (call);
+ // Set the inited flag
+ indexes [0] = const_int32 (0);
+ indexes [1] = const_int32 (cfg->method_index);
+ LLVMBuildStore (builder, LLVMConstInt (LLVMInt8Type (), 1, FALSE), LLVMBuildGEP (builder, ctx->module->inited_var, indexes, 2, ""));
+
LLVMBuildBr (builder, inited_bb);
ctx->bblocks [cfg->bb_entry->block_num].end_bblock = inited_bb;
if (cfg->method->wrapper_type == MONO_WRAPPER_OTHER) {
WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
if (info->subtype == WRAPPER_SUBTYPE_AOT_INIT) {
- method = get_init_icall_wrapper (ctx->module, info->d.aot_init.subtype);
+ method = get_init_func (ctx->module, info->d.aot_init.subtype);
ctx->lmethod = method;
ctx->module->max_method_idx = MAX (ctx->module->max_method_idx, cfg->method_index);
if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
needs_init = FALSE;
if (needs_init)
- emit_init_method (ctx);
+ emit_method_init (ctx);
else
LLVMBuildBr (ctx->builder, ctx->inited_bb);
mono_llvm_add_func_attr (method, LLVM_ATTR_NO_INLINE);
after_codegen:
+ g_ptr_array_add (ctx->module->cfgs, cfg);
if (cfg->llvm_only) {
- g_ptr_array_add (ctx->module->cfgs, cfg);
-
/*
* Add the contents of ctx->callsite_list to module->callsite_list.
* We can't do this earlier, as it contains llvm instructions which can be
}
//LLVMDumpValue (ctx->lmethod);
- //int err = LLVMVerifyFunction(ctx->lmethod, LLVMPrintMessageAction);
+ //int err = LLVMVerifyFunction (ctx->lmethod, LLVMPrintMessageAction);
//g_assert (err == 0);
} else {
//LLVMVerifyFunction (method, 0);
module->cfgs = g_ptr_array_new ();
module->intrins_by_id = g_new0 (LLVMValueRef, INTRINS_NUM);
module->aotconst_vars = g_hash_table_new (NULL, NULL);
+ module->llvm_types = g_hash_table_new (NULL, NULL);
+ module->plt_entries = g_hash_table_new (g_str_hash, g_str_equal);
+ module->plt_entries_ji = g_hash_table_new (NULL, NULL);
+ module->direct_callables = g_hash_table_new (g_str_hash, g_str_equal);
+ module->idx_to_lmethod = g_hash_table_new (NULL, NULL);
+ module->method_to_lmethod = g_hash_table_new (NULL, NULL);
+ module->method_to_call_info = g_hash_table_new (NULL, NULL);
+ module->idx_to_unbox_tramp = g_hash_table_new (NULL, NULL);
+ module->no_method_table_lmethods = g_hash_table_new (NULL, NULL);
+ module->callsite_list = g_ptr_array_new ();
if (llvm_only)
/* clang ignores our debug info because it has an invalid version */
emit_llvm_code_start (module);
// Needs idx_to_lmethod
- emit_init_icall_wrappers (module);
+ emit_init_funcs (module);
/* Add a dummy personality function */
if (!use_mono_personality_debug) {
LLVMSetLinkage (module->sentinel_exception, LLVMExternalLinkage);
mono_llvm_set_is_constant (module->sentinel_exception);
}
-
- module->llvm_types = g_hash_table_new (NULL, NULL);
- module->plt_entries = g_hash_table_new (g_str_hash, g_str_equal);
- module->plt_entries_ji = g_hash_table_new (NULL, NULL);
- module->direct_callables = g_hash_table_new (g_str_hash, g_str_equal);
- module->idx_to_lmethod = g_hash_table_new (NULL, NULL);
- module->method_to_lmethod = g_hash_table_new (NULL, NULL);
- module->method_to_call_info = g_hash_table_new (NULL, NULL);
- module->idx_to_unbox_tramp = g_hash_table_new (NULL, NULL);
- module->no_method_table_lmethods = g_hash_table_new (NULL, NULL);
- module->callsite_list = g_ptr_array_new ();
}
void
* mono_llvm_emit_aot_data:
*
* Emit the binary data DATA pointed to by symbol SYMBOL.
+ * Return the LLVM variable for the data.
*/
-void
-mono_llvm_emit_aot_data (const char *symbol, guint8 *data, int data_len)
+gpointer
+mono_llvm_emit_aot_data_aligned (const char *symbol, guint8 *data, int data_len, int align)
{
MonoLLVMModule *module = &aot_module;
LLVMTypeRef type;
LLVMSetVisibility (d, LLVMHiddenVisibility);
LLVMSetLinkage (d, LLVMInternalLinkage);
LLVMSetInitializer (d, mono_llvm_create_constant_data_array (data, data_len));
- LLVMSetAlignment (d, 8);
+ if (align != 1)
+ LLVMSetAlignment (d, align);
mono_llvm_set_is_constant (d);
+ return d;
+}
+
+gpointer
+mono_llvm_emit_aot_data (const char *symbol, guint8 *data, int data_len)
+{
+ return mono_llvm_emit_aot_data_aligned (symbol, data, data_len, 8);
}
/* Add a reference to a global defined in JITted code */
fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "llvm_got_info_offsets");
fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "image_table");
fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "weak_field_indexes");
+ fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "method_flags_table");
}
/* Not needed (mem_end) */
fields [tindex ++] = LLVMConstNull (eltype);
mono_llvm_replace_uses_of (module->inited_var, real_inited);
LLVMDeleteGlobal (module->inited_var);
+ /* Replace the dummy info_ variables with the real ones */
+ for (int i = 0; i < module->cfgs->len; ++i) {
+ MonoCompile *cfg = (MonoCompile *)g_ptr_array_index (module->cfgs, i);
+
+ // FIXME: Eliminate unused vars
+
+ // FIXME: Speed this up
+ if (cfg->llvm_dummy_info_var) {
+ if (cfg->llvm_info_var) {
+ mono_llvm_replace_uses_of (cfg->llvm_dummy_info_var, cfg->llvm_info_var);
+ LLVMDeleteGlobal (cfg->llvm_dummy_info_var);
+ } else {
+ // FIXME: How can this happen ?
+ LLVMSetInitializer (cfg->llvm_dummy_info_var, mono_llvm_create_constant_data_array (NULL, 0));
+ }
+ }
+ }
+
if (module->llvm_only) {
emit_get_method (&aot_module);
emit_get_unbox_tramp (&aot_module);