3
3
using System ;
4
4
using System . Diagnostics ;
5
5
using System . Runtime . CompilerServices ;
6
+ using System . Runtime . InteropServices ;
6
7
using static Biohazrd . CSharp . CSharpCodeWriter ;
7
8
8
9
namespace Biohazrd . CSharp
@@ -127,7 +128,6 @@ private void EmitFunctionTrampoline(VisitorContext context, EmitFunctionContext
127
128
// (We do this first so we can change our emit if the method is broken.)
128
129
string ? methodAccess = null ;
129
130
string ? methodAccessFailure = null ;
130
- TypeReference ? thisTypeCast = null ;
131
131
132
132
if ( ! declaration . IsVirtual )
133
133
{ methodAccess = SanitizeIdentifier ( emitContext . DllImportName ) ; }
@@ -140,13 +140,15 @@ private void EmitFunctionTrampoline(VisitorContext context, EmitFunctionContext
140
140
{ methodAccessFailure = "Class has no vTable pointer." ; }
141
141
else if ( record . VTable is null )
142
142
{ methodAccessFailure = "Class has no virtual method table." ; }
143
+ else if ( declaration . Declaration is null )
144
+ { methodAccessFailure = "Virtual method has no associated Clang declaration." ; }
143
145
else
144
146
{
145
147
TranslatedVTableEntry ? vTableEntry = null ;
146
148
147
149
foreach ( TranslatedVTableEntry entry in record . VTable . Entries )
148
150
{
149
- if ( entry . MethodDeclaration == declaration . Declaration )
151
+ if ( entry . Info . MethodDeclaration == declaration . Declaration . Handle )
150
152
{
151
153
vTableEntry = entry ;
152
154
break ;
@@ -156,17 +158,7 @@ private void EmitFunctionTrampoline(VisitorContext context, EmitFunctionContext
156
158
if ( vTableEntry is null )
157
159
{ methodAccessFailure = "Could not find entry in virtual method table." ; }
158
160
else
159
- {
160
- methodAccess = $ "{ SanitizeIdentifier ( record . VTableField . Name ) } ->{ SanitizeIdentifier ( vTableEntry . Name ) } ";
161
-
162
- // Determine if we need to cast the this pointer
163
- // (This happens if a virtual method is lifted from a base type to a child.)
164
- if ( vTableEntry . Type is FunctionPointerTypeReference vTableFunctionPointer
165
- && vTableFunctionPointer . ParameterTypes . Length > 0
166
- && vTableFunctionPointer . ParameterTypes [ 0 ] is PointerTypeReference { Inner : TypeReference vTableThis } vTableThisPointer
167
- && ( vTableThis is not TranslatedTypeReference vTableThisTranslated || ! ReferenceEquals ( vTableThisTranslated . TryResolve ( context . Library ) , context . ParentDeclaration ) ) )
168
- { thisTypeCast = vTableThisPointer ; }
169
- }
161
+ { methodAccess = $ "{ SanitizeIdentifier ( record . VTableField . Name ) } ->{ SanitizeIdentifier ( vTableEntry . Name ) } "; }
170
162
}
171
163
}
172
164
@@ -243,7 +235,7 @@ void EmitFunctionBodyWithReturnByReference(EmitFunctionContext emitContext)
243
235
Writer . WriteLine ( $ " { SanitizeIdentifier ( emitContext . ReturnBufferParameterName ) } ;") ;
244
236
245
237
Writer . Write ( $ "{ methodAccess } (") ;
246
- EmitFunctionParameterList ( context , emitContext , declaration , EmitParameterListMode . TrampolineArguments , thisTypeCast ) ;
238
+ EmitFunctionParameterList ( context , emitContext , declaration , EmitParameterListMode . TrampolineArguments ) ;
247
239
Writer . WriteLine ( ");" ) ;
248
240
249
241
Writer . WriteLine ( $ "return { SanitizeIdentifier ( emitContext . ReturnBufferParameterName ) } ;") ;
@@ -268,7 +260,7 @@ void EmitFunctionBodyWithReturnByReference(EmitFunctionContext emitContext)
268
260
{ Writer . Write ( "return " ) ; }
269
261
270
262
Writer . Write ( $ "{ methodAccess } (") ;
271
- EmitFunctionParameterList ( context , emitContext , declaration , EmitParameterListMode . TrampolineArguments , thisTypeCast ) ;
263
+ EmitFunctionParameterList ( context , emitContext , declaration , EmitParameterListMode . TrampolineArguments ) ;
272
264
Writer . Write ( ");" ) ;
273
265
274
266
if ( hasThis )
@@ -277,25 +269,56 @@ void EmitFunctionBodyWithReturnByReference(EmitFunctionContext emitContext)
277
269
}
278
270
}
279
271
272
+ private void EmitFunctionPointerForVTable ( VisitorContext context , EmitFunctionContext emitContext , TranslatedFunction declaration )
273
+ {
274
+ string ? callingConventionString = declaration . CallingConvention switch
275
+ {
276
+ CallingConvention . Cdecl => "unmanaged[Cdecl]" ,
277
+ CallingConvention . StdCall => "unmanaged[Stdcall]" ,
278
+ CallingConvention . ThisCall => "unmanaged[Thiscall]" ,
279
+ CallingConvention . FastCall => "unmanaged[Fastcall]" ,
280
+ _ => null
281
+ } ;
282
+
283
+ if ( callingConventionString is null )
284
+ {
285
+ Fatal ( context , declaration , $ "The { declaration . CallingConvention } convention is not supported.") ;
286
+ Writer . Write ( "void*" ) ;
287
+ return ;
288
+ }
289
+
290
+ Writer . Write ( $ "delegate* { callingConventionString } <") ;
291
+
292
+ EmitFunctionParameterList ( context , emitContext , declaration , EmitParameterListMode . VTableFunctionPointerParameters ) ;
293
+
294
+ Writer . Write ( ", " ) ;
295
+
296
+ if ( declaration . ReturnByReference )
297
+ { WriteTypeAsReference ( context , declaration , declaration . ReturnType ) ; }
298
+ else
299
+ { WriteType ( context , declaration , declaration . ReturnType ) ; }
300
+
301
+ Writer . Write ( '>' ) ;
302
+ }
303
+
280
304
private enum EmitParameterListMode
281
305
{
282
306
DllImportParameters ,
283
307
TrampolineParameters ,
284
308
TrampolineArguments ,
309
+ VTableFunctionPointerParameters ,
285
310
}
286
311
287
- private void EmitFunctionParameterList ( VisitorContext context , EmitFunctionContext emitContext , TranslatedFunction declaration , EmitParameterListMode mode , TypeReference ? thisCastType = null )
312
+ private void EmitFunctionParameterList ( VisitorContext context , EmitFunctionContext emitContext , TranslatedFunction declaration , EmitParameterListMode mode )
288
313
{
289
- if ( thisCastType is not null && mode != EmitParameterListMode . TrampolineArguments )
290
- { throw new ArgumentException ( "Emitting a this cast is only possible for trampoline arguments." , nameof ( thisCastType ) ) ; }
291
-
292
314
if ( declaration . FunctionAbi is null )
293
315
{ throw new ArgumentException ( "Cannot emit a parameter list for an uncallable function since they lack ABI information." , nameof ( declaration ) ) ; }
294
316
295
317
bool first = true ;
296
318
297
- bool writeImplicitParameters = mode == EmitParameterListMode . DllImportParameters || mode == EmitParameterListMode . TrampolineArguments ;
298
- bool writeTypes = mode == EmitParameterListMode . DllImportParameters || mode == EmitParameterListMode . TrampolineParameters ;
319
+ bool writeImplicitParameters = mode is EmitParameterListMode . DllImportParameters or EmitParameterListMode . TrampolineArguments or EmitParameterListMode . VTableFunctionPointerParameters ;
320
+ bool writeTypes = mode is EmitParameterListMode . DllImportParameters or EmitParameterListMode . TrampolineParameters or EmitParameterListMode . VTableFunctionPointerParameters ;
321
+ bool writeNames = mode is EmitParameterListMode . DllImportParameters or EmitParameterListMode . TrampolineArguments or EmitParameterListMode . TrampolineParameters ;
299
322
bool writeDefautValues = mode switch
300
323
{
301
324
EmitParameterListMode . DllImportParameters => ! declaration . IsInstanceMethod , // We only emit the defaults on the trampoline.
@@ -321,10 +344,18 @@ void WriteOutReturnBuffer(EmitFunctionContext emitContext)
321
344
if ( writeTypes )
322
345
{
323
346
WriteType ( context , declaration , declaration . ReturnType ) ;
324
- Writer . Write ( ' ' ) ;
347
+
348
+ //TODO: When fixing https://github.com/InfectedLibraries/Biohazrd/issues/196, use WriteTypeAsReference instead.
349
+ if ( mode == EmitParameterListMode . VTableFunctionPointerParameters )
350
+ { Writer . Write ( '*' ) ; }
351
+
352
+ if ( writeNames )
353
+ { Writer . Write ( ' ' ) ; }
325
354
}
326
355
327
- Writer . WriteIdentifier ( emitContext . ReturnBufferParameterName ) ;
356
+ if ( writeNames )
357
+ { Writer . WriteIdentifier ( emitContext . ReturnBufferParameterName ) ; }
358
+
328
359
first = false ;
329
360
}
330
361
@@ -341,16 +372,14 @@ void WriteOutReturnBuffer(EmitFunctionContext emitContext)
341
372
if ( writeTypes )
342
373
{
343
374
WriteType ( context , declaration , emitContext . ThisType ) ;
344
- Writer . Write ( ' ' ) ;
345
- }
346
- else if ( thisCastType is not null )
347
- {
348
- Writer . Write ( '(' ) ;
349
- WriteType ( context , declaration , thisCastType ) ;
350
- Writer . Write ( ')' ) ;
375
+
376
+ if ( writeNames )
377
+ { Writer . Write ( ' ' ) ; }
351
378
}
352
379
353
- Writer . WriteIdentifier ( emitContext . ThisParameterName ) ;
380
+ if ( writeNames )
381
+ { Writer . WriteIdentifier ( emitContext . ThisParameterName ) ; }
382
+
354
383
first = false ;
355
384
}
356
385
@@ -380,10 +409,12 @@ void WriteOutReturnBuffer(EmitFunctionContext emitContext)
380
409
WriteType ( parameterContext , parameter , parameter . Type ) ;
381
410
}
382
411
383
- Writer . Write ( ' ' ) ;
412
+ if ( writeNames )
413
+ { Writer . Write ( ' ' ) ; }
384
414
}
385
415
386
- Writer . WriteIdentifier ( parameter . Name ) ;
416
+ if ( writeNames )
417
+ { Writer . WriteIdentifier ( parameter . Name ) ; }
387
418
388
419
if ( writeDefautValues && parameter . DefaultValue is not null )
389
420
{ Writer . Write ( $ " = { GetConstantAsString ( parameterContext , parameter , parameter . DefaultValue , parameter . Type ) } ") ; }
0 commit comments