1
1
using Biohazrd . CSharp . Metadata ;
2
2
using Biohazrd . CSharp . Trampolines ;
3
- using Biohazrd . OutputGeneration ;
4
3
using ClangSharp . Pathogen ;
5
4
using System ;
6
- using System . Collections . Immutable ;
7
5
using System . Diagnostics ;
8
6
using System . Runtime . CompilerServices ;
9
7
using System . Runtime . InteropServices ;
@@ -13,47 +11,19 @@ namespace Biohazrd.CSharp
13
11
{
14
12
partial class CSharpLibraryGenerator
15
13
{
16
- private struct ParameterEmitStrategy
17
- {
18
- public TranslatedParameter Declaration { get ; init ; }
19
- public ParameterOutputMode OutputMode { get ; init ; }
20
- public string FixedName => $ "__{ Declaration . Name } P";
21
- }
22
-
23
14
private ref struct EmitFunctionContext
24
15
{
25
16
public bool NeedsTrampoline { get ; }
26
17
public string DllImportName { get ; }
27
18
public TypeReference ? ThisType { get ; }
28
19
public string ThisParameterName => "this" ;
29
20
public string ReturnBufferParameterName => "__returnBuffer" ;
30
- public ImmutableArray < ParameterEmitStrategy > Parameters { get ; }
31
- public VisitorContext ParameterContext { get ; }
32
21
33
- public EmitFunctionContext ( VisitorContext context , TranslatedFunction declaration , CSharpGenerationOptions options )
22
+ public EmitFunctionContext ( VisitorContext context , TranslatedFunction declaration )
34
23
{
35
24
// We emit a trampoline for functions which are instance methods or return via reference to hide those ABI semantics
36
25
NeedsTrampoline = declaration . IsInstanceMethod || declaration . ReturnByReference ;
37
26
38
- // Determine how parameters will be written
39
- ImmutableArray < ParameterEmitStrategy > . Builder parameters = ImmutableArray . CreateBuilder < ParameterEmitStrategy > ( declaration . Parameters . Length ) ;
40
- foreach ( TranslatedParameter parameter in declaration . Parameters )
41
- {
42
- ParameterEmitStrategy strategy = new ( )
43
- {
44
- Declaration = parameter ,
45
- OutputMode = parameter . GetParameterOutputMode ( options . ReferenceTypeOutputBehavior )
46
- } ;
47
-
48
- // References emitted as anything other than pointers need a trampoline
49
- if ( strategy . OutputMode != ParameterOutputMode . Normal )
50
- { NeedsTrampoline = true ; }
51
-
52
- parameters . Add ( strategy ) ;
53
- }
54
- Parameters = parameters . MoveToImmutable ( ) ;
55
- ParameterContext = context . Add ( declaration ) ;
56
-
57
27
// When this function is uses a trampoline, we add a suffix to the P/Invoke method to ensure they don't conflict with other methods.
58
28
// (For instance, when there's a SomeClass::Method() method in addition to a SomeClass::Method(SomeClass*) method.)
59
29
DllImportName = NeedsTrampoline ? $ "{ declaration . Name } _PInvoke" : declaration . Name ;
@@ -100,7 +70,7 @@ protected override void VisitFunction(VisitorContext context, TranslatedFunction
100
70
return ;
101
71
}
102
72
103
- EmitFunctionContext emitContext = new ( context , declaration , Options ) ;
73
+ EmitFunctionContext emitContext = new ( context , declaration ) ;
104
74
105
75
// Emit the DllImport
106
76
if ( ! declaration . IsVirtual )
@@ -283,31 +253,20 @@ private void EmitFunctionTrampoline(VisitorContext context, EmitFunctionContext
283
253
// Emit the dispatch
284
254
using ( Writer . Block ( ) )
285
255
{
286
- bool hasFixedBlocks = false ;
287
-
288
- // Fix the this pointer if necessary
256
+ bool hasThis ;
289
257
if ( emitContext . ThisType is not null )
290
258
{
259
+ hasThis = true ;
291
260
Debug . Assert ( declaration . IsInstanceMethod ) ;
292
261
293
262
Writer . Write ( $ "fixed (") ;
294
263
WriteType ( context , declaration , emitContext . ThisType ! ) ;
295
264
Writer . WriteLine ( $ " { SanitizeIdentifier ( emitContext . ThisParameterName ) } = &this)") ;
296
- hasFixedBlocks = true ;
297
265
}
298
266
else
299
- { Debug . Assert ( ! declaration . IsInstanceMethod ) ; }
300
-
301
- // Fix the parameters if necessary
302
- foreach ( ParameterEmitStrategy parameter in emitContext . Parameters )
303
267
{
304
- if ( parameter . OutputMode != ParameterOutputMode . RefByRef && parameter . OutputMode != ParameterOutputMode . RefByReadonlyRef )
305
- { continue ; }
306
-
307
- Writer . Write ( "fixed (" ) ;
308
- WriteType ( emitContext . ParameterContext , parameter . Declaration , parameter . Declaration . Type ) ;
309
- Writer . WriteLine ( $ " { SanitizeIdentifier ( parameter . FixedName ) } = &{ SanitizeIdentifier ( parameter . Declaration . Name ) } )") ;
310
- hasFixedBlocks = true ;
268
+ hasThis = false ;
269
+ Debug . Assert ( ! declaration . IsInstanceMethod ) ;
311
270
}
312
271
313
272
bool hasReturnValue = declaration . ReturnType is not VoidTypeReference ;
@@ -326,7 +285,7 @@ void EmitFunctionBodyWithReturnByReference(EmitFunctionContext emitContext)
326
285
Writer . WriteLine ( $ "return { SanitizeIdentifier ( emitContext . ReturnBufferParameterName ) } ;") ;
327
286
}
328
287
329
- if ( hasFixedBlocks )
288
+ if ( hasThis )
330
289
{
331
290
// If we have a fixed statement for the this pointer, wrap the return buffer logic with a block
332
291
using ( Writer . Block ( ) )
@@ -338,7 +297,7 @@ void EmitFunctionBodyWithReturnByReference(EmitFunctionContext emitContext)
338
297
else
339
298
{
340
299
// If we have a fixed statement for the this pointer, write out the curly braces for it
341
- if ( hasFixedBlocks )
300
+ if ( hasThis )
342
301
{ Writer . Write ( "{ " ) ; }
343
302
344
303
if ( hasReturnValue )
@@ -348,7 +307,7 @@ void EmitFunctionBodyWithReturnByReference(EmitFunctionContext emitContext)
348
307
EmitFunctionParameterList ( context , emitContext , declaration , EmitParameterListMode . TrampolineArguments ) ;
349
308
Writer . Write ( ");" ) ;
350
309
351
- if ( hasFixedBlocks )
310
+ if ( hasThis )
352
311
{ Writer . WriteLine ( " }" ) ; }
353
312
}
354
313
}
@@ -411,6 +370,8 @@ private void EmitFunctionParameterList(VisitorContext context, EmitFunctionConte
411
370
_ => false
412
371
} ;
413
372
373
+ VisitorContext parameterContext = context . Add ( declaration ) ;
374
+
414
375
// Write out the this/retbuf parameters
415
376
if ( writeImplicitParameters )
416
377
{
@@ -466,80 +427,38 @@ void WriteOutReturnBuffer(EmitFunctionContext emitContext)
466
427
}
467
428
468
429
// Write out parameters
469
- foreach ( ParameterEmitStrategy strategy in emitContext . Parameters )
430
+ foreach ( TranslatedParameter parameter in declaration . Parameters )
470
431
{
471
- TranslatedParameter parameter = strategy . Declaration ;
472
-
473
432
if ( first )
474
433
{ first = false ; }
475
434
else
476
435
{ Writer . Write ( ", " ) ; }
477
436
478
437
if ( writeTypes )
479
438
{
480
- if ( mode == EmitParameterListMode . TrampolineParameters && strategy . OutputMode != ParameterOutputMode . Normal )
481
- {
482
- Debug . Assert ( writeNames ) ;
483
- Debug . Assert ( ! parameter . ImplicitlyPassedByReference ) ;
484
- PointerTypeReference ? pointerType = parameter . Type as PointerTypeReference ;
485
- Debug . Assert ( pointerType is not null ) ; // EffectiveReferenceTypeOutputBehavior should not return a byref mode when the type isn't a pointer
486
- Debug . Assert ( pointerType . WasReference ) ;
487
-
488
- switch ( strategy . OutputMode )
489
- {
490
- case ParameterOutputMode . RefByReadonlyRef :
491
- Writer . Write ( "in " ) ;
492
- break ;
493
- case ParameterOutputMode . RefByRef :
494
- Writer . Write ( "ref " ) ;
495
- break ;
496
- }
497
-
498
- WriteTypeForTrampoline ( emitContext . ParameterContext , parameter , pointerType . Inner ) ;
499
- }
500
- else if ( parameter . ImplicitlyPassedByReference )
501
- { WriteTypeAsReference ( emitContext . ParameterContext , parameter , parameter . Type ) ; }
439
+ if ( parameter . ImplicitlyPassedByReference )
440
+ { WriteTypeAsReference ( parameterContext , parameter , parameter . Type ) ; }
502
441
else
503
442
{
504
443
// Write MarshalAs for booleans at pinvoke boundaries
505
444
if ( mode == EmitParameterListMode . DllImportParameters && parameter . Type . IsCSharpType ( context . Library , CSharpBuiltinType . Bool ) )
506
445
{ Writer . Write ( "[MarshalAs(UnmanagedType.I1)] " ) ; }
507
446
508
447
if ( mode == EmitParameterListMode . TrampolineParameters )
509
- { WriteTypeForTrampoline ( emitContext . ParameterContext , parameter , parameter . Type ) ; }
448
+ { WriteTypeForTrampoline ( parameterContext , parameter , parameter . Type ) ; }
510
449
else
511
- { WriteType ( emitContext . ParameterContext , parameter , parameter . Type ) ; }
450
+ { WriteType ( parameterContext , parameter , parameter . Type ) ; }
512
451
}
513
452
514
453
if ( writeNames )
515
454
{ Writer . Write ( ' ' ) ; }
516
455
}
517
456
518
457
if ( writeNames )
519
- {
520
- if ( mode == EmitParameterListMode . TrampolineArguments && strategy . OutputMode != ParameterOutputMode . Normal )
521
- {
522
- switch ( strategy . OutputMode )
523
- {
524
- case ParameterOutputMode . RefByReadonlyRef :
525
- case ParameterOutputMode . RefByRef :
526
- Writer . WriteIdentifier ( strategy . FixedName ) ;
527
- break ;
528
- case ParameterOutputMode . RefByValue :
529
- Writer . Write ( '&' ) ;
530
- Writer . WriteIdentifier ( parameter . Name ) ;
531
- break ;
532
- default :
533
- FatalContext ( emitContext . ParameterContext , parameter , $ "Invalid parameter output mode '{ strategy . OutputMode } '") ;
534
- break ;
535
- }
536
- }
537
- else
538
- { Writer . WriteIdentifier ( parameter . Name ) ; }
539
- }
458
+ { Writer . WriteIdentifier ( parameter . Name ) ; }
540
459
541
460
if ( writeDefautValues && parameter . DefaultValue is not null )
542
- { Writer . Write ( $ " = { GetConstantAsString ( emitContext . ParameterContext , parameter , parameter . DefaultValue , parameter . Type ) } ") ; }
461
+ { Writer . Write ( $ " = { GetConstantAsString ( parameterContext , parameter , parameter . DefaultValue , parameter . Type ) } ") ; }
543
462
}
544
463
}
545
464
0 commit comments