Earlier I reported a mysterious ReadOnlyMemoryError() in 0.6.2 under linux only. Someone else recently posted another problem with ReadOnlyMemoryError(), I decided to dig a bit deeper into my example, and the Julia behavior I uncovered is mysterious.
My code is in five modules, each of which is one file, say A.jl, B.jl, C.jl, D.jl, E.jl. Both D and E have using
statements referring to A, B, C. So I should include them in the order A, B, C, D, E from the Repl. I discovered that if I include D first, then of course I get an error immediately about an undefined module. But after this error, if I then include them in the right order, the ReadOnlyMemory() goes away! In other words, if I include them in the correct order A, B, C, D, E, then the code fails with ReadOnlyMemoryError, but if I include them in the order D, A, B, C, D, E, then it works. (The first inclusion of D yields an immediate error.)
So I decided to check whether different assembly is being emitted for my code in the two scenarios (two different include
orders) . The code_lowered’s are the same, but the LLVMs are different. Most of the differences appear to be variation in lengthy integers, which I presume are absolute memory addresses. However, there are some differences in the order of statements as well. I included one such difference below. Can someone who understands LLVM explain this? Note: I am not claiming that the LLVM below actually emits the ReadOnlyMemoryError; instead, I am just showing that the same code unexpectedly compiled into two different LLVMs.
This is the scenario when I included A, B, C, D, E:
L282: ; preds = %L275
%619 = load i64, i64* inttoptr (i64 139879721017720 to i64*), align 8
store i64 %619, i64* %88, align 8
store i8** inttoptr (i64 139879659292584 to i8**), i8*** %79, align 8
%620 = call i8** @jl_f_getfield(i8** null, i8*** %37, i32 2)
store i8** %620, i8*** %38, align 8
store i8** inttoptr (i64 139879659297368 to i8**), i8*** %77, align 8
%621 = call i8** @jl_f_getfield(i8** null, i8*** %38, i32 2)
store i8** %621, i8*** %19, align 8
store i8** inttoptr (i64 139874949373776 to i8**), i8*** %78, align 8
%622 = call i8** @jl_apply_generic(i8*** %19, i32 2)
store i8** %622, i8*** %356, align 8
call void @jl_throw(i8** %622)
unreachable
This is the scenario when I included D, A, B, C, D, E:
%619 = load i64, i64* inttoptr (i64 139989567349112 to i64*), align 8
%620 = bitcast i8*** %38 to i64*
store i64 %619, i64* %620, align 8
store i8** inttoptr (i64 139989505628072 to i8**), i8*** %77, align 8
%621 = call i8** @jl_f_getfield(i8** null, i8*** %38, i32 2)
store i8** %621, i8*** %37, align 8
store i8** inttoptr (i64 139989505632856 to i8**), i8*** %79, align 8
%622 = call i8** @jl_f_getfield(i8** null, i8*** %37, i32 2)
store i8** %622, i8*** %19, align 8
store i8** inttoptr (i64 139984803236368 to i8**), i8*** %78, align 8
%623 = call i8** @jl_apply_generic(i8*** %19, i32 2)
store i8** %623, i8*** %356, align 8
call void @jl_throw(i8** %623)
unreachable