Skip to content

Commit 0cfeee8

Browse files
committed
Add ABIOverride type for def field
Together with #54899, this PR is intending to replicate the functionality of #54373, which allowed particular specializations to have a different ABI signature than what would be suggested by the MethodInstance's `specTypes` field. This PR handles that by adding a special `ABIOverwrite` type, which, when placed in the `def` field of a `CodeInstance` instructs the system to use the given signature instead.
1 parent d3c26b7 commit 0cfeee8

28 files changed

+177
-100
lines changed

Compiler/src/Compiler.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ ccall(:jl_set_module_uuid, Cvoid, (Any, NTuple{2, UInt64}), Compiler,
4141

4242
using Core.Intrinsics, Core.IR
4343

44-
using Core: Builtin, CodeInstance, IntrinsicFunction, MethodInstance, MethodMatch,
44+
using Core: ABIOverride, Builtin, CodeInstance, IntrinsicFunction, MethodInstance, MethodMatch,
4545
MethodTable, PartialOpaque, SimpleVector, TypeofVararg,
4646
_apply_iterate, apply_type, compilerbarrier, donotdelete, memoryref_isassigned,
4747
memoryrefget, memoryrefnew, memoryrefoffset, memoryrefset!, print, println, show, svec,

Compiler/src/abstractinterpretation.jl

+15-3
Original file line numberDiff line numberDiff line change
@@ -2212,6 +2212,18 @@ function abstract_call_unionall(interp::AbstractInterpreter, argtypes::Vector{An
22122212
return CallMeta(ret, Any, Effects(EFFECTS_TOTAL; nothrow), call.info)
22132213
end
22142214

2215+
function ci_abi(ci::CodeInstance)
2216+
def = ci.def
2217+
isa(def, ABIOverride) && return def.abi
2218+
(def::MethodInstance).specTypes
2219+
end
2220+
2221+
function get_ci_mi(ci::CodeInstance)
2222+
def = ci.def
2223+
isa(def, ABIOverride) && return def.def
2224+
return def::MethodInstance
2225+
end
2226+
22152227
function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::StmtInfo, sv::AbsIntState)
22162228
argtypes = arginfo.argtypes
22172229
ft′ = argtype_by_index(argtypes, 2)
@@ -2223,12 +2235,12 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt
22232235
if isa(method_or_ci, CodeInstance)
22242236
our_world = sv.world.this
22252237
argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft))
2226-
specsig = method_or_ci.def.specTypes
2227-
defdef = method_or_ci.def.def
2238+
specsig = ci_abi(method_or_ci)
2239+
defdef = get_ci_mi(method_or_ci).def
22282240
exct = method_or_ci.exctype
22292241
if !hasintersect(argtype, specsig)
22302242
return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
2231-
elseif !(argtype <: specsig) || (isa(defdef, Method) && !(argtype <: defdef.sig))
2243+
elseif !(argtype <: specsig) || ((!isa(method_or_ci.def, ABIOverride) && isa(defdef, Method)) && !(argtype <: defdef.sig))
22322244
exct = Union{exct, TypeError}
22332245
end
22342246
callee_valid_range = WorldRange(method_or_ci.min_world, method_or_ci.max_world)

Compiler/src/ssair/show.jl

+7-1
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,17 @@ function print_stmt(io::IO, idx::Int, @nospecialize(stmt), code::Union{IRCode,Co
100100
if !(mi isa Core.MethodInstance)
101101
mi = (mi::Core.CodeInstance).def
102102
end
103+
if isa(mi, Core.ABIOverride)
104+
abi = mi.abi
105+
mi = mi.def
106+
else
107+
abi = mi.specTypes
108+
end
103109
show_unquoted(io, stmt.args[2], indent)
104110
print(io, "(")
105111
# XXX: this is wrong if `sig` is not a concretetype method
106112
# more correct would be to use `fieldtype(sig, i)`, but that would obscure / discard Varargs information in show
107-
sig = mi.specTypes == Tuple ? Core.svec() : Base.unwrap_unionall(mi.specTypes).parameters::Core.SimpleVector
113+
sig = abi == Tuple ? Core.svec() : Base.unwrap_unionall(abi).parameters::Core.SimpleVector
108114
print_arg(i) = sprint(; context=io) do io
109115
show_unquoted(io, stmt.args[i], indent)
110116
if (i - 1) <= length(sig)

Compiler/src/stmtinfo.jl

+4-4
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ function _add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo, mi_edge::Boo
7171
mi = specialize_method(m) # don't allow `Method`-edge for this optimized format
7272
edge = mi
7373
else
74-
mi = edge.def
74+
mi = edge.def::MethodInstance
7575
end
7676
if mi.specTypes === m.spec_types
7777
add_one_edge!(edges, edge)
@@ -103,7 +103,7 @@ function add_one_edge!(edges::Vector{Any}, edge::MethodInstance)
103103
while i <= length(edges)
104104
edgeᵢ = edges[i]
105105
edgeᵢ isa Int && (i += 2 + edgeᵢ; continue)
106-
edgeᵢ isa CodeInstance && (edgeᵢ = edgeᵢ.def)
106+
edgeᵢ isa CodeInstance && (edgeᵢ = get_ci_mi(edgeᵢ))
107107
edgeᵢ isa MethodInstance || (i += 1; continue)
108108
if edgeᵢ === edge && !(i > 1 && edges[i-1] isa Type)
109109
return # found existing covered edge
@@ -118,7 +118,7 @@ function add_one_edge!(edges::Vector{Any}, edge::CodeInstance)
118118
while i <= length(edges)
119119
edgeᵢ_orig = edgeᵢ = edges[i]
120120
edgeᵢ isa Int && (i += 2 + edgeᵢ; continue)
121-
edgeᵢ isa CodeInstance && (edgeᵢ = edgeᵢ.def)
121+
edgeᵢ isa CodeInstance && (edgeᵢ = get_ci_mi(edgeᵢ))
122122
edgeᵢ isa MethodInstance || (i += 1; continue)
123123
if edgeᵢ === edge.def && !(i > 1 && edges[i-1] isa Type)
124124
if edgeᵢ_orig isa MethodInstance
@@ -385,7 +385,7 @@ function add_inlining_edge!(edges::Vector{Any}, edge::CodeInstance)
385385
i += 1
386386
end
387387
# add_invoke_edge alone
388-
push!(edges, (edge.def.def::Method).sig)
388+
push!(edges, (get_ci_mi(edge).def::Method).sig)
389389
push!(edges, edge)
390390
nothing
391391
end

Compiler/src/typeinfer.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ function store_backedges(caller::CodeInstance, edges::SimpleVector)
528528
i += 2
529529
continue
530530
elseif isa(callee, CodeInstance)
531-
callee = callee.def
531+
callee = get_ci_mi(callee)
532532
end
533533
ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any, Any), callee, item, caller)
534534
i += 2

Compiler/test/inference.jl

+6-1
Original file line numberDiff line numberDiff line change
@@ -4110,7 +4110,12 @@ end == [Union{Some{Float64}, Some{Int}, Some{UInt8}}]
41104110
mi = codeinst
41114111
else
41124112
codeinst::Core.CodeInstance
4113-
mi = codeinst.def
4113+
def = codeinst.def
4114+
if isa(def, Core.ABIOverride)
4115+
mi = def.def
4116+
else
4117+
mi = def::Core.MethodInstance
4118+
end
41144119
end
41154120
return mi
41164121
end == Core.MethodInstance

base/arrayshow.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Accept keyword args `c` for alternate single character marker.
4141
"""
4242
function replace_with_centered_mark(s::AbstractString;c::AbstractChar = '')
4343
N = textwidth(ANSIIterator(s))
44-
return join(setindex!([" " for i=1:N],string(c),ceil(Int,N/2)))
44+
return N == 0 ? string(c) : join(setindex!([" " for i=1:N],string(c),ceil(Int,N/2)))
4545
end
4646

4747
const undef_ref_alignment = (3,3)

base/boot.jl

+7-1
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,12 @@ struct InitError <: WrappedException
465465
error
466466
end
467467

468+
struct ABIOverride
469+
abi::Type
470+
def::MethodInstance
471+
ABIOverride(@nospecialize(abi::Type), def::MethodInstance) = new(abi, def)
472+
end
473+
468474
struct PrecompilableError <: Exception end
469475

470476
String(s::String) = s # no constructor yet
@@ -552,7 +558,7 @@ end
552558

553559

554560
function CodeInstance(
555-
mi::MethodInstance, owner, @nospecialize(rettype), @nospecialize(exctype), @nospecialize(inferred_const),
561+
mi::Union{MethodInstance, ABIOverride}, owner, @nospecialize(rettype), @nospecialize(exctype), @nospecialize(inferred_const),
556562
@nospecialize(inferred), const_flags::Int32, min_world::UInt, max_world::UInt,
557563
effects::UInt32, @nospecialize(analysis_results),
558564
relocatability::UInt8, di::Union{DebugInfo,Nothing}, edges::SimpleVector)

base/show.jl

+7-1
Original file line numberDiff line numberDiff line change
@@ -1353,7 +1353,13 @@ end
13531353
show(io::IO, mi::Core.MethodInstance) = show_mi(io, mi)
13541354
function show(io::IO, codeinst::Core.CodeInstance)
13551355
print(io, "CodeInstance for ")
1356-
show_mi(io, codeinst.def)
1356+
def = codeinst.def
1357+
if isa(def, Core.ABIOverride)
1358+
show_mi(io, def.def)
1359+
print(io, " (ABI Overridden)")
1360+
else
1361+
show_mi(io, def::MethodInstance)
1362+
end
13571363
end
13581364

13591365
function show_mi(io::IO, mi::Core.MethodInstance, from_stackframe::Bool=false)

src/aotcompile.cpp

+8-8
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ jl_get_llvm_mis_impl(void *native_code, size_t *num_elements, jl_method_instance
105105
assert(*num_elements == map.size());
106106
size_t i = 0;
107107
for (auto &ci : map) {
108-
data[i++] = ci.first->def;
108+
data[i++] = jl_get_ci_mi(ci.first);
109109
}
110110
}
111111

@@ -455,14 +455,14 @@ static void compile_workqueue(jl_codegen_params_t &params, egal_set &method_root
455455
if ((policy != CompilationPolicy::Default || params.params->trim) &&
456456
jl_atomic_load_relaxed(&codeinst->inferred) == jl_nothing) {
457457
// XXX: SOURCE_MODE_FORCE_SOURCE is wrong here (neither sufficient nor necessary)
458-
codeinst = jl_type_infer(codeinst->def, jl_atomic_load_relaxed(&codeinst->max_world), SOURCE_MODE_FORCE_SOURCE);
458+
codeinst = jl_type_infer(jl_get_ci_mi(codeinst), jl_atomic_load_relaxed(&codeinst->max_world), SOURCE_MODE_FORCE_SOURCE);
459459
}
460460
if (codeinst) {
461461
orc::ThreadSafeModule result_m =
462-
jl_create_ts_module(name_from_method_instance(codeinst->def),
462+
jl_create_ts_module(name_from_method_instance(jl_get_ci_mi(codeinst)),
463463
params.tsctx, params.DL, params.TargetTriple);
464464
auto decls = jl_emit_codeinst(result_m, codeinst, NULL, params);
465-
record_method_roots(method_roots, codeinst->def);
465+
record_method_roots(method_roots, jl_get_ci_mi(codeinst));
466466
if (result_m)
467467
it = compiled_functions.insert(std::make_pair(codeinst, std::make_pair(std::move(result_m), std::move(decls)))).first;
468468
}
@@ -501,7 +501,7 @@ static void compile_workqueue(jl_codegen_params_t &params, egal_set &method_root
501501
proto.decl->setLinkage(GlobalVariable::InternalLinkage);
502502
//protodecl->setAlwaysInline();
503503
jl_init_function(proto.decl, params.TargetTriple);
504-
jl_method_instance_t *mi = codeinst->def;
504+
jl_method_instance_t *mi = jl_get_ci_mi(codeinst);
505505
size_t nrealargs = jl_nparams(mi->specTypes); // number of actual arguments being passed
506506
bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure;
507507
// TODO: maybe this can be cached in codeinst->specfptr?
@@ -641,12 +641,12 @@ void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvm
641641
data->jl_fvar_map[codeinst] = std::make_tuple((uint32_t)-3, (uint32_t)-3);
642642
}
643643
else {
644-
orc::ThreadSafeModule result_m = jl_create_ts_module(name_from_method_instance(codeinst->def),
644+
orc::ThreadSafeModule result_m = jl_create_ts_module(name_from_method_instance(jl_get_ci_mi(codeinst)),
645645
params.tsctx, clone.getModuleUnlocked()->getDataLayout(),
646646
Triple(clone.getModuleUnlocked()->getTargetTriple()));
647647
jl_llvm_functions_t decls = jl_emit_codeinst(result_m, codeinst, NULL, params);
648648
JL_GC_PROMISE_ROOTED(codeinst->def); // analyzer seems confused
649-
record_method_roots(method_roots, codeinst->def);
649+
record_method_roots(method_roots, jl_get_ci_mi(codeinst));
650650
if (result_m)
651651
compiled_functions[codeinst] = {std::move(result_m), std::move(decls)};
652652
else if (jl_options.trim != JL_TRIM_NO) {
@@ -2267,7 +2267,7 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, jl_
22672267
// To get correct names in the IR this needs to be at least 2
22682268
output.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0);
22692269
JL_GC_PUSH1(&output.temporary_roots);
2270-
auto decls = jl_emit_code(m, mi, src, output);
2270+
auto decls = jl_emit_code(m, mi, src, NULL, output);
22712271
output.temporary_roots = nullptr;
22722272
JL_GC_POP(); // GC the global_targets array contents now since reflection doesn't need it
22732273

src/builtins.c

+12-4
Original file line numberDiff line numberDiff line change
@@ -1589,11 +1589,19 @@ JL_CALLABLE(jl_f_invoke)
15891589
return jl_gf_invoke_by_method(m, args[0], &args[2], nargs - 1);
15901590
} else if (jl_is_code_instance(argtypes)) {
15911591
jl_code_instance_t *codeinst = (jl_code_instance_t*)args[1];
1592+
jl_method_instance_t *mi = jl_get_ci_mi(codeinst);
15921593
jl_callptr_t invoke = jl_atomic_load_acquire(&codeinst->invoke);
15931594
// N.B.: specTypes need not be a subtype of the method signature. We need to check both.
1594-
if (!jl_tuple1_isa(args[0], &args[2], nargs - 1, (jl_datatype_t*)codeinst->def->specTypes) ||
1595-
(jl_is_method(codeinst->def->def.value) && !jl_tuple1_isa(args[0], &args[2], nargs - 1, (jl_datatype_t*)codeinst->def->def.method->sig))) {
1596-
jl_type_error("invoke: argument type error", codeinst->def->specTypes, arg_tuple(args[0], &args[2], nargs - 1));
1595+
if (jl_is_abioverride(codeinst->def)) {
1596+
jl_datatype_t *abi = (jl_datatype_t*)((jl_abi_override_t*)(codeinst->def))->abi;
1597+
if (!jl_tuple1_isa(args[0], &args[2], nargs - 1, abi)) {
1598+
jl_type_error("invoke: argument type error (ABI overwrite)", (jl_value_t*)abi, arg_tuple(args[0], &args[2], nargs - 1));
1599+
}
1600+
} else {
1601+
if (!jl_tuple1_isa(args[0], &args[2], nargs - 1, (jl_datatype_t*)mi->specTypes) ||
1602+
(jl_is_method(mi->def.value) && !jl_tuple1_isa(args[0], &args[2], nargs - 1, (jl_datatype_t*)mi->def.method->sig))) {
1603+
jl_type_error("invoke: argument type error", mi->specTypes, arg_tuple(args[0], &args[2], nargs - 1));
1604+
}
15971605
}
15981606
if (jl_atomic_load_relaxed(&codeinst->min_world) > jl_current_task->world_age ||
15991607
jl_current_task->world_age > jl_atomic_load_relaxed(&codeinst->max_world)) {
@@ -1609,7 +1617,7 @@ JL_CALLABLE(jl_f_invoke)
16091617
if (codeinst->owner != jl_nothing) {
16101618
jl_error("Failed to invoke or compile external codeinst");
16111619
}
1612-
return jl_invoke(args[0], &args[2], nargs - 1, codeinst->def);
1620+
return jl_invoke(args[0], &args[2], nargs - 1, mi);
16131621
}
16141622
}
16151623
if (!jl_is_tuple_type(jl_unwrap_unionall(argtypes)))

src/clangsa/GCChecker.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,7 @@ bool GCChecker::isGCTrackedType(QualType QT) {
847847
Name.ends_with_insensitive("jl_vararg_t") ||
848848
Name.ends_with_insensitive("jl_opaque_closure_t") ||
849849
Name.ends_with_insensitive("jl_globalref_t") ||
850+
Name.ends_with_insensitive("jl_abi_override_t") ||
850851
// Probably not technically true for these, but let's allow it as a root
851852
Name.ends_with_insensitive("jl_ircode_state") ||
852853
Name.ends_with_insensitive("typemap_intersection_env") ||

0 commit comments

Comments
 (0)