Skip to content

Commit ed9f475

Browse files
kglewingradical
authored
[wasm] p/invoke and interop improvements (#94446)
Refactor logging in the wasm build tasks to use a LogAdapter helper class that can either write to stdout/stderr or via the msbuild logging APIs Refactor ManagedToNativeGenerator so that it can run in either in-process or out-of-process modes (but it still runs in-process right now). This will enable us to pivot to out-of-process later if necessary. Add support for function pointer types via reflection (so that we can still build and run on net4x for visual studio). If S.R.MLC is sufficiently new, function pointers will now work, but if it's old, they won't. Add basic support for structs as arguments Implement scalar struct behavior from the wasm C ABI (structs containing one scalar are passed by-value instead of by-reference) in various places in the build tasks, interpreter, and AOT compiler Remove a use of varargs pinvoke from SystemNative because it isn't compatible with the WASM C ABI (it's replaced with two non-varargs pinvokes) Generate more accurate C signatures for pinvokes Expand WBT test coverage for pinvokes --------- Co-authored-by: Larry Ewing <lewing@microsoft.com> Co-authored-by: Ankit Jain <radical@gmail.com>
1 parent 6441968 commit ed9f475

24 files changed

+616
-176
lines changed

eng/Version.Details.xml

+5
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,11 @@
340340
<Sha>205ef031e0fe5152dede0bd9f99d0f6f9e7f1e45</Sha>
341341
<SourceBuild RepoName="runtime" ManagedOnly="false" />
342342
</Dependency>
343+
<Dependency Name="System.Reflection.MetadataLoadContext" Version="8.0.0">
344+
<Uri>https://github.com/dotnet/runtime</Uri>
345+
<Sha>4dffd80c4d77c27e772a0be26e8036af77fbb26e</Sha>
346+
<SourceBuild RepoName="runtime" ManagedOnly="false" />
347+
</Dependency>
343348
<Dependency Name="Microsoft.DotNet.ILCompiler" Version="9.0.0-alpha.1.24072.1">
344349
<Uri>https://github.com/dotnet/runtime</Uri>
345350
<Sha>205ef031e0fe5152dede0bd9f99d0f6f9e7f1e45</Sha>

eng/Versions.props

+3-3
Original file line numberDiff line numberDiff line change
@@ -123,16 +123,16 @@
123123
<MicrosoftWin32RegistryVersion>5.0.0</MicrosoftWin32RegistryVersion>
124124
<StyleCopAnalyzersVersion>1.2.0-beta.507</StyleCopAnalyzersVersion>
125125
<SystemBuffersVersion>4.5.1</SystemBuffersVersion>
126-
<SystemCollectionsImmutableVersion>7.0.0</SystemCollectionsImmutableVersion>
126+
<SystemCollectionsImmutableVersion>8.0.0</SystemCollectionsImmutableVersion>
127127
<SystemComponentModelAnnotationsVersion>5.0.0</SystemComponentModelAnnotationsVersion>
128128
<SystemDataSqlClientVersion>4.8.6</SystemDataSqlClientVersion>
129129
<SystemDrawingCommonVersion>8.0.0</SystemDrawingCommonVersion>
130130
<SystemIOFileSystemAccessControlVersion>5.0.0</SystemIOFileSystemAccessControlVersion>
131131
<SystemMemoryVersion>4.5.5</SystemMemoryVersion>
132132
<SystemReflectionMetadataVersion>9.0.0-alpha.1.24072.1</SystemReflectionMetadataVersion>
133133
<!-- Keep toolset versions in sync with dotnet/msbuild and dotnet/sdk -->
134-
<SystemReflectionMetadataToolsetVersion>7.0.0</SystemReflectionMetadataToolsetVersion>
135-
<SystemReflectionMetadataLoadContextVersion>7.0.0</SystemReflectionMetadataLoadContextVersion>
134+
<SystemReflectionMetadataToolsetVersion>8.0.0</SystemReflectionMetadataToolsetVersion>
135+
<SystemReflectionMetadataLoadContextVersion>8.0.0</SystemReflectionMetadataLoadContextVersion>
136136
<SystemSecurityAccessControlVersion>6.0.0</SystemSecurityAccessControlVersion>
137137
<SystemSecurityCryptographyCngVersion>5.0.0</SystemSecurityCryptographyCngVersion>
138138
<SystemSecurityCryptographyOpenSslVersion>5.0.0</SystemSecurityCryptographyOpenSslVersion>

src/libraries/Common/src/Interop/Unix/System.Native/Interop.SNPrintF.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ internal static partial class Sys
2626
/// success; if the return value is equal to the size then the result may have been truncated.
2727
/// On failure, returns a negative value.
2828
/// </returns>
29-
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_SNPrintF", StringMarshalling = StringMarshalling.Utf8, SetLastError = true)]
29+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_SNPrintF_1S", StringMarshalling = StringMarshalling.Utf8, SetLastError = true)]
3030
internal static unsafe partial int SNPrintF(byte* str, int size, string format, string arg1);
3131

3232
/// <summary>
@@ -47,7 +47,7 @@ internal static partial class Sys
4747
/// success; if the return value is equal to the size then the result may have been truncated.
4848
/// On failure, returns a negative value.
4949
/// </returns>
50-
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_SNPrintF", StringMarshalling = StringMarshalling.Utf8, SetLastError = true)]
50+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_SNPrintF_1I", StringMarshalling = StringMarshalling.Utf8, SetLastError = true)]
5151
internal static unsafe partial int SNPrintF(byte* str, int size, string format, int arg1);
5252
}
5353
}

src/mono/mono/mini/aot-runtime-wasm.c

+8
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ type_to_c (MonoType *t)
5454
goto handle_enum;
5555
}
5656

57+
// https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md#function-signatures
58+
// Any struct or union that recursively (including through nested structs, unions, and arrays)
59+
// contains just a single scalar value and is not specified to have greater than natural alignment.
60+
// FIXME: Handle the scenario where there are fields of struct types that contain no members
61+
MonoType *scalar_vtype;
62+
if (mini_wasm_is_scalar_vtype (t, &scalar_vtype))
63+
return type_to_c (scalar_vtype);
64+
5765
return 'I';
5866
case MONO_TYPE_GENERICINST:
5967
if (m_class_is_valuetype (t->data.klass))

src/mono/mono/mini/interp/interp.c

+25-11
Original file line numberDiff line numberDiff line change
@@ -1345,10 +1345,22 @@ typedef enum {
13451345

13461346
typedef struct {
13471347
int ilen, flen;
1348-
PInvokeArgType ret_type;
1348+
MonoType *ret_mono_type;
1349+
PInvokeArgType ret_pinvoke_type;
13491350
PInvokeArgType *arg_types;
13501351
} BuildArgsFromSigInfo;
13511352

1353+
static MonoType *
1354+
filter_type_for_args_from_sig (MonoType *type) {
1355+
#if defined(HOST_WASM)
1356+
MonoType *etype;
1357+
if (MONO_TYPE_ISSTRUCT (type) && mini_wasm_is_scalar_vtype (type, &etype))
1358+
// FIXME: Does this need to be recursive?
1359+
return etype;
1360+
#endif
1361+
return type;
1362+
}
1363+
13521364
static BuildArgsFromSigInfo *
13531365
get_build_args_from_sig_info (MonoMemoryManager *mem_manager, MonoMethodSignature *sig)
13541366
{
@@ -1360,7 +1372,7 @@ get_build_args_from_sig_info (MonoMemoryManager *mem_manager, MonoMethodSignatur
13601372
g_assert (!sig->hasthis);
13611373

13621374
for (int i = 0; i < sig->param_count; i++) {
1363-
MonoType *type = sig->params [i];
1375+
MonoType *type = filter_type_for_args_from_sig (sig->params [i]);
13641376
guint32 ptype;
13651377

13661378
retry:
@@ -1442,7 +1454,9 @@ get_build_args_from_sig_info (MonoMemoryManager *mem_manager, MonoMethodSignatur
14421454
info->ilen = ilen;
14431455
info->flen = flen;
14441456

1445-
switch (sig->ret->type) {
1457+
info->ret_mono_type = filter_type_for_args_from_sig (sig->ret);
1458+
1459+
switch (info->ret_mono_type->type) {
14461460
case MONO_TYPE_BOOLEAN:
14471461
case MONO_TYPE_CHAR:
14481462
case MONO_TYPE_I1:
@@ -1463,17 +1477,17 @@ get_build_args_from_sig_info (MonoMemoryManager *mem_manager, MonoMethodSignatur
14631477
case MONO_TYPE_U8:
14641478
case MONO_TYPE_VALUETYPE:
14651479
case MONO_TYPE_GENERICINST:
1466-
info->ret_type = PINVOKE_ARG_INT;
1480+
info->ret_pinvoke_type = PINVOKE_ARG_INT;
14671481
break;
14681482
case MONO_TYPE_R4:
14691483
case MONO_TYPE_R8:
1470-
info->ret_type = PINVOKE_ARG_R8;
1484+
info->ret_pinvoke_type = PINVOKE_ARG_R8;
14711485
break;
14721486
case MONO_TYPE_VOID:
1473-
info->ret_type = PINVOKE_ARG_NONE;
1487+
info->ret_pinvoke_type = PINVOKE_ARG_NONE;
14741488
break;
14751489
default:
1476-
g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1490+
g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", info->ret_mono_type->type);
14771491
}
14781492

14791493
return info;
@@ -1563,7 +1577,7 @@ build_args_from_sig (InterpMethodArguments *margs, MonoMethodSignature *sig, Bui
15631577
}
15641578
}
15651579

1566-
switch (info->ret_type) {
1580+
switch (info->ret_pinvoke_type) {
15671581
case PINVOKE_ARG_INT:
15681582
margs->retval = (gpointer*)frame->retval;
15691583
margs->is_float_ret = 0;
@@ -1781,8 +1795,8 @@ ves_pinvoke_method (
17811795
g_free (ccontext.stack);
17821796
#else
17831797
// Only the vt address has been returned, we need to copy the entire content on interp stack
1784-
if (!context->has_resume_state && MONO_TYPE_ISSTRUCT (sig->ret))
1785-
stackval_from_data (sig->ret, frame.retval, (char*)frame.retval->data.p, sig->pinvoke && !sig->marshalling_disabled);
1798+
if (!context->has_resume_state && MONO_TYPE_ISSTRUCT (call_info->ret_mono_type))
1799+
stackval_from_data (call_info->ret_mono_type, frame.retval, (char*)frame.retval->data.p, sig->pinvoke && !sig->marshalling_disabled);
17861800

17871801
if (margs.iargs != margs.iargs_buf)
17881802
g_free (margs.iargs);
@@ -4252,7 +4266,7 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause
42524266
LOCAL_VAR (call_args_offset, gpointer) = unboxed;
42534267
}
42544268

4255-
jit_call:
4269+
jit_call:
42564270
{
42574271
InterpMethodCodeType code_type = cmethod->code_type;
42584272

src/mono/mono/mini/mini-llvm.c

+17-8
Original file line numberDiff line numberDiff line change
@@ -4192,6 +4192,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
41924192
case LLVMArgVtypeAddr:
41934193
case LLVMArgVtypeByRef:
41944194
case LLVMArgAsFpArgs:
4195+
case LLVMArgWasmVtypeAsScalar:
41954196
{
41964197
MonoClass *klass = mono_class_from_mono_type_internal (ainfo->type);
41974198
if (mini_class_is_simd (ctx->cfg, klass)) {
@@ -4968,6 +4969,8 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
49684969
if (!addresses [call->inst.dreg])
49694970
addresses [call->inst.dreg] = build_alloca_address (ctx, sig->ret);
49704971
emit_store (builder, lcall, convert_full (ctx, addresses [call->inst.dreg]->value, pointer_type (LLVMTypeOf (lcall)), FALSE), is_volatile);
4972+
load_name = "wasm_vtype_as_scalar";
4973+
should_promote_to_value = TRUE;
49714974
break;
49724975
}
49734976
default:
@@ -5421,6 +5424,7 @@ static LLVMValueRef
54215424
concatenate_vectors (EmitContext *ctx, LLVMValueRef xs, LLVMValueRef ys)
54225425
{
54235426
LLVMTypeRef t = LLVMTypeOf (xs);
5427+
g_assert (LLVMGetTypeKind (t) == LLVMVectorTypeKind);
54245428
unsigned int elems = LLVMGetVectorSize (t) * 2;
54255429
int mask [MAX_VECTOR_ELEMS] = { 0 };
54265430
for (guint i = 0; i < elems; ++i)
@@ -6175,8 +6179,13 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
61756179
}
61766180
break;
61776181
case LLVMArgWasmVtypeAsScalar:
6178-
g_assert (addresses [ins->sreg1]);
6179-
retval = LLVMBuildLoad2 (builder, ret_type, build_ptr_cast (builder, addresses [ins->sreg1]->value, pointer_type (ret_type)), "");
6182+
if (!addresses [ins->sreg1]) {
6183+
/* SIMD value */
6184+
g_assert (lhs);
6185+
retval = LLVMBuildBitCast (builder, lhs, ret_type, "");
6186+
} else {
6187+
retval = LLVMBuildLoad2 (builder, ret_type, build_ptr_cast (builder, addresses [ins->sreg1]->value, pointer_type (ret_type)), "");
6188+
}
61806189
break;
61816190
}
61826191
LLVMBuildRet (builder, retval);
@@ -6225,8 +6234,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
62256234

62266235
if (lhs) {
62276236
// Vector3: ret_type is Vector3, lhs is Vector3 represented as a Vector4 (three elements + zero). We need to extract only the first 3 elements from lhs.
6228-
int len = mono_class_value_size (klass, NULL) == 12 ? 3 : LLVMGetVectorSize (LLVMTypeOf (lhs));
6229-
6237+
int len = mono_class_value_size (klass, NULL) == 12 ? 3 : LLVMGetVectorSize (LLVMTypeOf (lhs));
6238+
62306239
for (int i = 0; i < len; i++) {
62316240
elem = LLVMBuildExtractElement (builder, lhs, const_int32 (i), "extract_elem");
62326241
retval = LLVMBuildInsertValue (builder, retval, elem, i, "insert_val_struct");
@@ -6841,7 +6850,7 @@ MONO_RESTORE_WARNING
68416850
// LLVM should fuse the individual Div and Rem instructions into one DIV/IDIV on x86
68426851
values [ins->dreg] = LLVMBuildTrunc (builder, LLVMBuildSDiv (builder, dividend, divisor, ""), part_type, "");
68436852
last_divrem = LLVMBuildTrunc (builder, LLVMBuildSRem (builder, dividend, divisor, ""), part_type, "");
6844-
break;
6853+
break;
68456854
}
68466855
case OP_X86_IDIVREMU:
68476856
case OP_X86_LDIVREMU: {
@@ -6856,7 +6865,7 @@ MONO_RESTORE_WARNING
68566865
LLVMValueRef divisor = LLVMBuildZExt (builder, convert (ctx, arg3, part_type), full_type, "");
68576866
values [ins->dreg] = LLVMBuildTrunc (builder, LLVMBuildUDiv (builder, dividend, divisor, ""), part_type, "");
68586867
last_divrem = LLVMBuildTrunc (builder, LLVMBuildURem (builder, dividend, divisor, ""), part_type, "");
6859-
break;
6868+
break;
68606869
}
68616870
case OP_X86_IDIVREM2:
68626871
case OP_X86_LDIVREM2: {
@@ -10671,7 +10680,7 @@ MONO_RESTORE_WARNING
1067110680

1067210681
// convert to 0/1
1067310682
result = LLVMBuildICmp (builder, LLVMIntEQ, first_elem, LLVMConstAllOnes (LLVMInt64Type ()), "");
10674-
10683+
1067510684
values [ins->dreg] = LLVMBuildZExt (builder, result, LLVMInt8Type (), "");
1067610685
break;
1067710686
}
@@ -12020,7 +12029,7 @@ MONO_RESTORE_WARNING
1202012029
gboolean scalar = ins->opcode == OP_NEGATION_SCALAR;
1202112030
gboolean is_float = (ins->inst_c1 == MONO_TYPE_R4 || ins->inst_c1 == MONO_TYPE_R8);
1202212031

12023-
LLVMValueRef result = lhs;
12032+
LLVMValueRef result = lhs;
1202412033
if (scalar)
1202512034
result = scalar_from_vector (ctx, result);
1202612035
if (is_float)

src/mono/mono/mini/mini-wasm.c

-2
Original file line numberDiff line numberDiff line change
@@ -774,8 +774,6 @@ mini_wasm_is_scalar_vtype (MonoType *type, MonoType **etype)
774774
return FALSE;
775775
} else if (!((MONO_TYPE_IS_PRIMITIVE (t) || MONO_TYPE_IS_REFERENCE (t) || MONO_TYPE_IS_POINTER (t)))) {
776776
return FALSE;
777-
} else if (size == 8 && t->type != MONO_TYPE_R8) {
778-
return FALSE;
779777
} else {
780778
if (etype)
781779
*etype = t;

0 commit comments

Comments
 (0)