Skip to content

Commit

Permalink
[llvm] Use explicit null checks with LLVM. (#16954)
Browse files Browse the repository at this point in the history
* [llvm] Use explicit null checks with LLVM.

When the LLVM backend is used for a method, explicit null checks will
unconditionally be used at the mini IR level. We had previously used
implicit null checks at the mini IR level combined with llvm-volatile
loads and stores to avoid mis-optimization of the generated code.

During AOT compilation, LLVM's `ImplicitNullChecks` pass is enabled.
This conservatively elides these explicit null checks. This pass only
modifies branches tagged with `make.implicit` metadata.

Null check branches are now tagged with `make.implicit` metadata, with
three exceptions:

1. For platforms with backends that do not support zero page fault
handling, null check branches are not tagged with `make.implicit`.

2. This commit also adds a `MONO_DEBUG` option:
`llvm-disable-implicit-null-checks`. When it is enabled, null check
branches are not tagged with `make.implicit`.

3. This commit alters the behavior of the `explicit-null-checks`
`MONO_DEBUG` option. Enabling `explicit-null-checks` also implies
`llvm-disable-implicit-null-checks`, because this option is documented
(e.g. in https://www.mono-project.com/docs/debug+profile/debug/) to
completely disable signal/seh-based null checks.

* Add llvm-disable-implicit-null-checks to the MONO_DEBUG help string.

* Add llvm-disable-implicit-null-checks to mono.1.

* Don't tag null checks in EH regions with `make.implicit`.

This relocates the logic formerly used to guard individual LLVM-level
loads and stores with explicit null checks inside EH regions.

* Use atomic/volatile loads and stores for the terimation flag in thread-suspend-suspended.

LLVM was hoisting the load of and branch against `finished` out of
thread t1's loop, resulting in an infinite spin.

* Use ImplicitNullChecks with LLVM JIT.

* Suppress emission of the .llvm_faultmaps section.

Bump external/llvm to release_60
(7a8dc89adbe7e123220e070a527e096ee91e66d5).

* [ci] use LLVM built from repository
  • Loading branch information
imhameed authored and lewurm committed Nov 13, 2019
1 parent eaf895f commit fe0f824
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 56 deletions.
6 changes: 6 additions & 0 deletions man/mono.1
Original file line number Diff line number Diff line change
Expand Up @@ -1763,6 +1763,12 @@ Automatically generates sequence points where the
IL stack is empty. These are places where the debugger can set a
breakpoint.
.TP
\fBllvm-disable-implicit-null-checks\fR
Makes the LLVM backend use explicit NULL checks on variable dereferences
instead of depending on operating system support for signals or traps when
an invalid memory location is accessed. Unconditionally enabled by
explicit-null-checks.
.TP
\fBno-compact-seq-points\fR
Unless the option is used, the runtime generates sequence points data that
maps native offsets to IL offsets. Sequence point data is used to
Expand Down
1 change: 1 addition & 0 deletions mono/mini/aot-compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,7 @@ arch_init (MonoAotCompile *acfg)
/* NOP */
acfg->align_pad_value = 0x90;
#endif
g_string_append (acfg->llc_args, " -enable-implicit-null-checks -disable-fault-maps");

if (mono_use_fast_math) {
// same parameters are passed to opt and LLVM JIT
Expand Down
2 changes: 1 addition & 1 deletion mono/mini/llvm-jit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ class MonoLLVMJIT {
// FIXME: find optimal mono specific order of passes
// see https://llvm.org/docs/Frontend/PerformanceTips.html#pass-ordering
// the following order is based on a stripped version of "OPT -O2"
const char *default_opts = " -simplifycfg -sroa -lower-expect -instcombine -licm -simplifycfg -lcssa -indvars -loop-deletion -gvn -memcpyopt -sccp -bdce -instcombine -dse -simplifycfg";
const char *default_opts = " -simplifycfg -sroa -lower-expect -instcombine -licm -simplifycfg -lcssa -indvars -loop-deletion -gvn -memcpyopt -sccp -bdce -instcombine -dse -simplifycfg -enable-implicit-null-checks";
const char *opts = g_getenv ("MONO_LLVM_OPT");
if (opts == NULL)
opts = default_opts;
Expand Down
89 changes: 41 additions & 48 deletions mono/mini/mini-llvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ static void emit_dbg_loc (EmitContext *ctx, LLVMBuilderRef builder, const unsign
static void emit_default_dbg_loc (EmitContext *ctx, LLVMBuilderRef builder);
static LLVMValueRef emit_dbg_subprogram (EmitContext *ctx, MonoCompile *cfg, LLVMValueRef method, const char *name);
static void emit_dbg_info (MonoLLVMModule *module, const char *filename, const char *cu_name);
static void emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *exc_type, LLVMValueRef cmp);
static void emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *exc_type, LLVMValueRef cmp, gboolean force_explicit);
static LLVMValueRef get_intrins_by_name (EmitContext *ctx, const char *name);
static LLVMValueRef get_intrins (EmitContext *ctx, int id);
static LLVMValueRef get_intrins_from_module (LLVMModuleRef lmodule, int id);
Expand Down Expand Up @@ -2299,58 +2299,36 @@ emit_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, LL
}

static LLVMValueRef
emit_load (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef addr, LLVMValueRef base, const char *name, gboolean is_faulting, BarrierKind barrier)
emit_load (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef addr, LLVMValueRef base, const char *name, gboolean is_faulting, gboolean is_volatile, BarrierKind barrier)
{
LLVMValueRef res;

if (is_faulting && bb->region != -1 && !ctx->cfg->llvm_only) {
/* The llvm.mono.load/store intrinsics are not supported by this llvm version, emit an explicit null check instead */
LLVMValueRef cmp;

cmp = LLVMBuildICmp (*builder_ref, LLVMIntEQ, base, LLVMConstNull (LLVMTypeOf (base)), "");
emit_cond_system_exception (ctx, bb, "NullReferenceException", cmp);
*builder_ref = ctx->builder;
}

/*
* We emit volatile loads for loads which can fault, because otherwise
* LLVM will generate invalid code when encountering a load from a
* NULL address.
*/
if (barrier != LLVM_BARRIER_NONE)
res = mono_llvm_build_atomic_load (*builder_ref, addr, name, is_faulting, size, barrier);
res = mono_llvm_build_atomic_load (*builder_ref, addr, name, is_volatile, size, barrier);
else
res = mono_llvm_build_load (*builder_ref, addr, name, is_faulting);

/* Mark it with a custom metadata */
/*
if (is_faulting)
set_metadata_flag (res, "mono.faulting.load");
*/
res = mono_llvm_build_load (*builder_ref, addr, name, is_volatile);

return res;
}

static void
emit_store_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, LLVMValueRef base, gboolean is_faulting, BarrierKind barrier)
emit_store_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, LLVMValueRef base, gboolean is_faulting, gboolean is_volatile, BarrierKind barrier)
{
if (is_faulting && bb->region != -1 && !ctx->cfg->llvm_only) {
/* The llvm.mono.load/store intrinsics are not supported by this llvm version, emit an explicit null check instead */
LLVMValueRef cmp = LLVMBuildICmp (*builder_ref, LLVMIntEQ, base, LLVMConstNull (LLVMTypeOf (base)), "");
emit_cond_system_exception (ctx, bb, "NullReferenceException", cmp);
*builder_ref = ctx->builder;
}

if (barrier != LLVM_BARRIER_NONE)
mono_llvm_build_aligned_store (*builder_ref, value, addr, barrier, size);
else
mono_llvm_build_store (*builder_ref, value, addr, is_faulting, barrier);
mono_llvm_build_store (*builder_ref, value, addr, is_volatile, barrier);
}

static void
emit_store (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, LLVMValueRef base, gboolean is_faulting)
emit_store (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, LLVMValueRef base, gboolean is_faulting, gboolean is_volatile)
{
emit_store_general (ctx, bb, builder_ref, size, value, addr, base, is_faulting, LLVM_BARRIER_NONE);
emit_store_general (ctx, bb, builder_ref, size, value, addr, base, is_faulting, is_volatile, LLVM_BARRIER_NONE);
}

/*
Expand All @@ -2360,7 +2338,7 @@ emit_store (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, i
* Might set the ctx exception.
*/
static void
emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *exc_type, LLVMValueRef cmp)
emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *exc_type, LLVMValueRef cmp, gboolean force_explicit)
{
LLVMBasicBlockRef ex_bb, ex2_bb = NULL, noex_bb;
LLVMBuilderRef builder;
Expand All @@ -2384,7 +2362,10 @@ emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *ex
ex2_bb = gen_bb (ctx, "EX2_BB");
noex_bb = gen_bb (ctx, "NOEX_BB");

LLVMBuildCondBr (ctx->builder, cmp, ex_bb, noex_bb);
LLVMValueRef branch = LLVMBuildCondBr (ctx->builder, cmp, ex_bb, noex_bb);
if (exc_id == MONO_EXC_NULL_REF && !ctx->cfg->disable_llvm_implicit_null_checks && !force_explicit) {
mono_llvm_set_implicit_branch (ctx->builder, branch);
}

/* Emit exception throwing code */
ctx->builder = builder = create_builder (ctx);
Expand Down Expand Up @@ -3284,7 +3265,7 @@ emit_div_check (EmitContext *ctx, LLVMBuilderRef builder, MonoBasicBlock *bb, Mo
ins->opcode == OP_IDIV_IMM || ins->opcode == OP_LDIV_IMM || ins->opcode == OP_IREM_IMM || ins->opcode == OP_LREM_IMM);

cmp = LLVMBuildICmp (builder, LLVMIntEQ, rhs, LLVMConstInt (LLVMTypeOf (rhs), 0, FALSE), "");
emit_cond_system_exception (ctx, bb, "DivideByZeroException", cmp);
emit_cond_system_exception (ctx, bb, "DivideByZeroException", cmp, FALSE);
if (!ctx_ok (ctx))
break;
builder = ctx->builder;
Expand All @@ -3296,7 +3277,7 @@ emit_div_check (EmitContext *ctx, LLVMBuilderRef builder, MonoBasicBlock *bb, Mo
LLVMValueRef cond2 = LLVMBuildICmp (builder, LLVMIntEQ, lhs, c, "");

cmp = LLVMBuildICmp (builder, LLVMIntEQ, LLVMBuildAnd (builder, cond1, cond2, ""), LLVMConstInt (LLVMInt1Type (), 1, FALSE), "");
emit_cond_system_exception (ctx, bb, "OverflowException", cmp);
emit_cond_system_exception (ctx, bb, "OverflowException", cmp, FALSE);
if (!ctx_ok (ctx))
break;
builder = ctx->builder;
Expand Down Expand Up @@ -5211,7 +5192,14 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
/* Add stores for volatile variables */
emit_volatile_store (ctx, ins->next->dreg);
} else if (MONO_IS_COND_EXC (ins->next)) {
emit_cond_system_exception (ctx, bb, (const char*)ins->next->inst_p1, cmp);
gboolean force_explicit_branch = FALSE;
if (bb->region != -1) {
/* Don't tag null check branches in exception-handling
* regions with `make.implicit`.
*/
force_explicit_branch = TRUE;
}
emit_cond_system_exception (ctx, bb, (const char*)ins->next->inst_p1, cmp, force_explicit_branch);
if (!ctx_ok (ctx))
break;
builder = ctx->builder;
Expand Down Expand Up @@ -5758,7 +5746,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
LLVMValueRef base, index, addr;
LLVMTypeRef t;
gboolean sext = FALSE, zext = FALSE;
gboolean is_volatile = (ins->flags & (MONO_INST_FAULT | MONO_INST_VOLATILE)) != 0;
gboolean is_faulting = (ins->flags & MONO_INST_FAULT) != 0;
gboolean is_volatile = (ins->flags & MONO_INST_VOLATILE) != 0;

t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);

Expand Down Expand Up @@ -5786,9 +5775,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)

addr = convert (ctx, addr, LLVMPointerType (t, 0));

values [ins->dreg] = emit_load (ctx, bb, &builder, size, addr, base, dname, is_volatile, LLVM_BARRIER_NONE);
values [ins->dreg] = emit_load (ctx, bb, &builder, size, addr, base, dname, is_faulting, is_volatile, LLVM_BARRIER_NONE);

if (!is_volatile && (ins->flags & MONO_INST_INVARIANT_LOAD)) {
if (!(is_faulting || is_volatile) && (ins->flags & MONO_INST_INVARIANT_LOAD)) {
/*
* These will signal LLVM that these loads do not alias any stores, and
* they can't fail, allowing them to be hoisted out of loops.
Expand Down Expand Up @@ -5816,7 +5805,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
LLVMValueRef index, addr, base;
LLVMTypeRef t;
gboolean sext = FALSE, zext = FALSE;
gboolean is_volatile = (ins->flags & (MONO_INST_FAULT | MONO_INST_VOLATILE)) != 0;
gboolean is_faulting = (ins->flags & MONO_INST_FAULT) != 0;
gboolean is_volatile = (ins->flags & MONO_INST_VOLATILE) != 0;

if (!values [ins->inst_destbasereg]) {
set_failure (ctx, "inst_destbasereg");
Expand All @@ -5837,7 +5827,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
if (is_volatile && LLVMGetInstructionOpcode (base) == LLVMAlloca && !(ins->flags & MONO_INST_VOLATILE))
/* Storing to an alloca cannot fail */
is_volatile = FALSE;
emit_store (ctx, bb, &builder, size, convert (ctx, values [ins->sreg1], t), convert (ctx, addr, LLVMPointerType (t, 0)), base, is_volatile);
emit_store (ctx, bb, &builder, size, convert (ctx, values [ins->sreg1], t), convert (ctx, addr, LLVMPointerType (t, 0)), base, is_faulting, is_volatile);
break;
}

Expand All @@ -5850,7 +5840,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
LLVMValueRef index, addr, base;
LLVMTypeRef t;
gboolean sext = FALSE, zext = FALSE;
gboolean is_volatile = (ins->flags & (MONO_INST_FAULT | MONO_INST_VOLATILE)) != 0;
gboolean is_faulting = (ins->flags & MONO_INST_FAULT) != 0;
gboolean is_volatile = (ins->flags & MONO_INST_VOLATILE) != 0;

t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);

Expand All @@ -5863,12 +5854,12 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);
addr = LLVMBuildGEP (builder, convert (ctx, base, LLVMPointerType (t, 0)), &index, 1, "");
}
emit_store (ctx, bb, &builder, size, convert (ctx, LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), t), convert (ctx, addr, LLVMPointerType (t, 0)), base, is_volatile);
emit_store (ctx, bb, &builder, size, convert (ctx, LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), t), convert (ctx, addr, LLVMPointerType (t, 0)), base, is_faulting, is_volatile);
break;
}

case OP_CHECK_THIS:
emit_load (ctx, bb, &builder, TARGET_SIZEOF_VOID_P, convert (ctx, lhs, LLVMPointerType (IntPtrType (), 0)), lhs, "", TRUE, LLVM_BARRIER_NONE);
emit_load (ctx, bb, &builder, TARGET_SIZEOF_VOID_P, convert (ctx, lhs, LLVMPointerType (IntPtrType (), 0)), lhs, "", TRUE, FALSE, LLVM_BARRIER_NONE);
break;
case OP_OUTARG_VTRETADDR:
break;
Expand Down Expand Up @@ -6344,7 +6335,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
int size;
gboolean sext, zext;
LLVMTypeRef t;
gboolean is_volatile = (ins->flags & (MONO_INST_FAULT | MONO_INST_VOLATILE)) != 0;
gboolean is_faulting = (ins->flags & MONO_INST_FAULT) != 0;
gboolean is_volatile = (ins->flags & MONO_INST_VOLATILE) != 0;
BarrierKind barrier = (BarrierKind) ins->backend.memory_barrier_kind;
LLVMValueRef index, addr;

Expand All @@ -6363,7 +6355,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
addr = convert (ctx, addr, LLVMPointerType (t, 0));

ARM64_ATOMIC_FENCE_FIX;
values [ins->dreg] = emit_load (ctx, bb, &builder, size, addr, lhs, dname, is_volatile, barrier);
values [ins->dreg] = emit_load (ctx, bb, &builder, size, addr, lhs, dname, is_faulting, is_volatile, barrier);
ARM64_ATOMIC_FENCE_FIX;

if (sext)
Expand All @@ -6385,7 +6377,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
int size;
gboolean sext, zext;
LLVMTypeRef t;
gboolean is_volatile = (ins->flags & (MONO_INST_FAULT | MONO_INST_VOLATILE)) != 0;
gboolean is_faulting = (ins->flags & MONO_INST_FAULT) != 0;
gboolean is_volatile = (ins->flags & MONO_INST_VOLATILE) != 0;
BarrierKind barrier = (BarrierKind) ins->backend.memory_barrier_kind;
LLVMValueRef index, addr, value, base;

Expand All @@ -6402,7 +6395,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
value = convert (ctx, values [ins->sreg1], t);

ARM64_ATOMIC_FENCE_FIX;
emit_store_general (ctx, bb, &builder, size, value, addr, base, is_volatile, barrier);
emit_store_general (ctx, bb, &builder, size, value, addr, base, is_faulting, is_volatile, barrier);
ARM64_ATOMIC_FENCE_FIX;
break;
}
Expand Down Expand Up @@ -6520,7 +6513,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
val = LLVMBuildCall (builder, func, args, 2, "");
values [ins->dreg] = LLVMBuildExtractValue (builder, val, 0, dname);
ovf = LLVMBuildExtractValue (builder, val, 1, "");
emit_cond_system_exception (ctx, bb, "OverflowException", ovf);
emit_cond_system_exception (ctx, bb, "OverflowException", ovf, FALSE);
if (!ctx_ok (ctx))
break;
builder = ctx->builder;
Expand Down
4 changes: 3 additions & 1 deletion mono/mini/mini-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -3694,6 +3694,8 @@ mini_parse_debug_option (const char *option)
mini_debug_options.llvm_disable_self_init = TRUE;
else if (!strcmp (option, "llvm-disable-inlining"))
mini_debug_options.llvm_disable_inlining = TRUE;
else if (!strcmp (option, "llvm-disable-implicit-null-checks"))
mini_debug_options.llvm_disable_implicit_null_checks = TRUE;
else if (!strcmp (option, "explicit-null-checks"))
mini_debug_options.explicit_null_checks = TRUE;
else if (!strcmp (option, "gen-seq-points"))
Expand Down Expand Up @@ -3767,7 +3769,7 @@ mini_parse_debug_options (void)
// test-tailcall-require is also accepted but not documented.
// empty string is also accepted and ignored as a consequence
// of appending ",foo" without checking for empty.
fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-native-crash', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'no-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break', 'thread-dump-dir=DIR', 'no-verbose-gdb', 'llvm_disable_inlining', 'llvm-disable-self-init', 'weak-memory-model'.\n");
fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-native-crash', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'no-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break', 'thread-dump-dir=DIR', 'no-verbose-gdb', 'llvm_disable_inlining', 'llvm-disable-self-init', 'llvm-disable-implicit-null-checks', 'weak-memory-model'.\n");
exit (1);
}
}
Expand Down
1 change: 1 addition & 0 deletions mono/mini/mini-runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ typedef struct MonoDebugOptions {
* Prevent LLVM from inlining any methods
*/
gboolean llvm_disable_inlining;
gboolean llvm_disable_implicit_null_checks;
gboolean use_fallback_tls;
/*
* Whenever data such as next sequence points and flags is required.
Expand Down
9 changes: 7 additions & 2 deletions mono/mini/mini.c
Original file line number Diff line number Diff line change
Expand Up @@ -3173,11 +3173,13 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
/* coop requires loop detection to happen */
if (mini_safepoints_enabled ())
cfg->opt |= MONO_OPT_LOOP;
if (cfg->backend->explicit_null_checks) {
cfg->disable_llvm_implicit_null_checks = mini_debug_options.llvm_disable_implicit_null_checks;
if (cfg->backend->explicit_null_checks || mini_debug_options.explicit_null_checks) {
/* some platforms have null pages, so we can't SIGSEGV */
cfg->explicit_null_checks = TRUE;
cfg->disable_llvm_implicit_null_checks = TRUE;
} else {
cfg->explicit_null_checks = mini_debug_options.explicit_null_checks || (flags & JIT_FLAG_EXPLICIT_NULL_CHECKS);
cfg->explicit_null_checks = flags & JIT_FLAG_EXPLICIT_NULL_CHECKS;
}
cfg->soft_breakpoints = mini_debug_options.soft_breakpoints;
cfg->check_pinvoke_callconv = mini_debug_options.check_pinvoke_callconv;
Expand All @@ -3190,6 +3192,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
if (cfg->compile_aot)
cfg->method_index = aot_method_index;

if (cfg->compile_llvm)
cfg->explicit_null_checks = TRUE;

/*
if (!mono_debug_count ())
cfg->opt &= ~MONO_OPT_FLOAT32;
Expand Down
1 change: 1 addition & 0 deletions mono/mini/mini.h
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,7 @@ typedef struct {
guint ret_var_set : 1;
guint unverifiable : 1;
guint skip_visibility : 1;
guint disable_llvm_implicit_null_checks : 1;
guint disable_reuse_registers : 1;
guint disable_reuse_stack_slots : 1;
guint disable_reuse_ref_stack_slots : 1;
Expand Down
6 changes: 3 additions & 3 deletions mono/tests/thread-suspend-suspended.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ public static void Main ()
AutoResetEvent finished_gc = new AutoResetEvent (false);

Thread t1 = new Thread (() => {
while (!finished) {}
while (!Volatile.Read(ref finished)) {}
});

Thread t2 = new Thread (() => {
while (!finished) {
while (!Volatile.Read(ref finished)) {
if (start_gc.WaitOne (0)) {
GC.Collect ();
finished_gc.Set ();
Expand All @@ -44,7 +44,7 @@ public static void Main ()
Console.WriteLine ();
}

finished = true;
Volatile.Write(ref finished, true);

t1.Join ();
t2.Join ();
Expand Down
2 changes: 1 addition & 1 deletion scripts/ci/run-test-make-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ export PATH=$MONO_PREFIX/bin:$PATH
${TESTCMD} --label=check-prefix-mcs --timeout=1m mcs /out:${MONO_REPO_ROOT}/tmp/hello.exe ${MONO_REPO_ROOT}/tmp/hello.cs
${TESTCMD} --label=check-prefix-roslyn --timeout=1m csc /out:${MONO_REPO_ROOT}/tmp/hello.exe ${MONO_REPO_ROOT}/tmp/hello.cs
${TESTCMD} --label=check-prefix-aot --timeout=1m mono --aot ${MONO_REPO_ROOT}/tmp/hello.exe
${TESTCMD} --label=check-prefix-llvmaot --timeout=1m mono --aot=llvm,llvm-path=/usr/lib/mono/llvm/bin ${MONO_REPO_ROOT}/tmp/hello.exe
${TESTCMD} --label=check-prefix-llvmaot --timeout=1m mono --aot=llvm,llvm-path=${MONO_REPO_ROOT}/llvm/usr/bin ${MONO_REPO_ROOT}/tmp/hello.exe
${TESTCMD} --label=check-prefix-llvmjit --timeout=1m mono --llvm ${MONO_REPO_ROOT}/tmp/hello.exe

0 comments on commit fe0f824

Please sign in to comment.