@@ -24,6 +24,14 @@ public ExportedMemberBuilder (JniRuntime runtime)
2424 OnSetRuntime ( runtime ) ;
2525 }
2626
27+ public override LambdaExpression CreateMarshalToManagedExpression ( MethodInfo method )
28+ {
29+ if ( method == null )
30+ throw new ArgumentNullException ( nameof ( method ) ) ;
31+
32+ return CreateMarshalToManagedExpression ( method , null , method . DeclaringType ) ;
33+ }
34+
2735 public override IEnumerable < JniNativeMethodRegistration > GetExportedMemberRegistrations ( Type declaringType )
2836 {
2937 if ( declaringType == null )
@@ -38,33 +46,31 @@ IEnumerable<JniNativeMethodRegistration> CreateExportedMemberRegistrationIterato
3846 if ( exports == null || exports . Length == 0 )
3947 continue ;
4048 var export = exports [ 0 ] ;
41- yield return CreateMarshalFromJniMethodRegistration ( export , declaringType , method ) ;
49+ yield return CreateMarshalToManagedMethodRegistration ( export , method , declaringType ) ;
4250 }
4351 }
4452
45- public JniNativeMethodRegistration CreateMarshalFromJniMethodRegistration ( JavaCallableAttribute export , Type type , MethodInfo method )
53+ public JniNativeMethodRegistration CreateMarshalToManagedMethodRegistration ( JavaCallableAttribute export , MethodInfo method , Type type = null )
4654 {
4755 if ( export == null )
4856 throw new ArgumentNullException ( "export" ) ;
49- if ( type == null )
50- throw new ArgumentNullException ( "type" ) ;
5157 if ( method == null )
5258 throw new ArgumentNullException ( "method" ) ;
5359
5460 string signature = GetJniMethodSignature ( export , method ) ;
5561 return new JniNativeMethodRegistration ( ) {
5662 Name = GetJniMethodName ( export , method ) ,
5763 Signature = signature ,
58- Marshaler = CreateJniMethodMarshaler ( export , type , method ) ,
64+ Marshaler = CreateJniMethodMarshaler ( method , export , type ) ,
5965 } ;
6066 }
6167
62- protected virtual string GetJniMethodName ( JavaCallableAttribute export , MethodInfo method )
68+ string GetJniMethodName ( JavaCallableAttribute export , MethodInfo method )
6369 {
6470 return export . Name ?? "n_" + method . Name ;
6571 }
6672
67- public virtual string GetJniMethodSignature ( JavaCallableAttribute export , MethodInfo method )
73+ public string GetJniMethodSignature ( JavaCallableAttribute export , MethodInfo method )
6874 {
6975 if ( export == null )
7076 throw new ArgumentNullException ( "export" ) ;
@@ -75,7 +81,8 @@ public virtual string GetJniMethodSignature (JavaCallableAttribute export, Metho
7581 return export . Signature ;
7682
7783 var signature = new StringBuilder ( ) . Append ( "(" ) ;
78- foreach ( var p in method . GetParameters ( ) ) {
84+ var methodParameters = method . GetParameters ( ) ;
85+ foreach ( var p in IsDirectMethod ( methodParameters ) ? methodParameters . Skip ( 2 ) : methodParameters ) {
7986 signature . Append ( GetTypeSignature ( p ) ) ;
8087 }
8188 signature . Append ( ")" ) ;
@@ -97,28 +104,26 @@ string GetTypeSignature (ParameterInfo p)
97104 throw new NotSupportedException ( "Don't know how to determine JNI signature for parameter type: " + p . ParameterType . FullName + "." ) ;
98105 }
99106
100- Delegate CreateJniMethodMarshaler ( JavaCallableAttribute export , Type type , MethodInfo method )
107+ Delegate CreateJniMethodMarshaler ( MethodInfo method , JavaCallableAttribute export , Type type )
101108 {
102- var e = CreateMarshalFromJniMethodExpression ( export , type , method ) ;
109+ var e = CreateMarshalToManagedExpression ( method , export , type ) ;
103110 return e . Compile ( ) ;
104111 }
105112
106- // TODO: make internal, and add [InternalsVisibleTo] for Java.Interop.Export-Tests
107- public virtual LambdaExpression CreateMarshalFromJniMethodExpression ( JavaCallableAttribute export , Type type , MethodInfo method )
113+ public LambdaExpression CreateMarshalToManagedExpression ( MethodInfo method , JavaCallableAttribute callable , Type type = null )
108114 {
109- if ( export == null )
110- throw new ArgumentNullException ( "export" ) ;
111- if ( type == null )
112- throw new ArgumentNullException ( "type" ) ;
113115 if ( method == null )
114116 throw new ArgumentNullException ( "method" ) ;
117+ type = type ?? method . DeclaringType ;
115118
116119 var methodParameters = method . GetParameters ( ) ;
117120
118- CheckMarshalTypesMatch ( method , export . Signature , methodParameters ) ;
121+ CheckMarshalTypesMatch ( method , callable ? . Signature , methodParameters ) ;
119122
120- var jnienv = Expression . Parameter ( typeof ( IntPtr ) , "__jnienv" ) ;
121- var context = Expression . Parameter ( typeof ( IntPtr ) , method . IsStatic ? "__class" : "__this" ) ;
123+ bool direct = IsDirectMethod ( methodParameters ) ;
124+
125+ var jnienv = Expression . Parameter ( typeof ( IntPtr ) , direct ? methodParameters [ 0 ] . Name : "__jnienv" ) ;
126+ var context = Expression . Parameter ( typeof ( IntPtr ) , direct ? methodParameters [ 1 ] . Name : ( method . IsStatic ? "__class" : "__this" ) ) ;
122127
123128 var envp = Expression . Variable ( typeof ( JniTransition ) , "__envp" ) ;
124129 var jvm = Expression . Variable ( typeof ( JniRuntime ) , "__jvm" ) ;
@@ -146,7 +151,17 @@ public virtual LambdaExpression CreateMarshalFromJniMethodExpression (JavaCallab
146151 var invokeParameters = new List < Expression > ( methodParameters . Length ) ;
147152 for ( int i = 0 ; i < methodParameters . Length ; ++ i ) {
148153 var marshaler = GetValueMarshaler ( methodParameters [ i ] ) ;
149- var np = Expression . Parameter ( marshaler . MarshalType , methodParameters [ i ] . Name ) ;
154+ ParameterExpression np ;
155+ if ( i > 1 || ! direct )
156+ np = Expression . Parameter ( marshaler . MarshalType , methodParameters [ i ] . Name ) ;
157+ else {
158+ if ( i == 0 )
159+ np = jnienv ;
160+ else if ( i == 1 )
161+ np = context ;
162+ else
163+ throw new InvalidOperationException ( "Should not be reached." ) ;
164+ }
150165 var p = marshaler . CreateParameterToManagedExpression ( marshalerContext , np , methodParameters [ i ] . Attributes , methodParameters [ i ] . ParameterType ) ;
151166 marshalParameters . Add ( np ) ;
152167 invokeParameters . Add ( p ) ;
@@ -190,10 +205,14 @@ public virtual LambdaExpression CreateMarshalFromJniMethodExpression (JavaCallab
190205 envpBody . Add ( Expression . Label ( exit , Expression . Default ( jniRType ) ) ) ;
191206 }
192207
193- var funcTypeParams = new List < Type > ( ) {
194- typeof ( IntPtr ) ,
195- typeof ( IntPtr ) ,
196- } ;
208+ var funcTypeParams = new List < Type > ( ) ;
209+ var bodyParams = new List < ParameterExpression > ( ) ;
210+ if ( ! direct ) {
211+ funcTypeParams . Add ( typeof ( IntPtr ) ) ;
212+ funcTypeParams . Add ( typeof ( IntPtr ) ) ;
213+ bodyParams . Add ( jnienv ) ;
214+ bodyParams . Add ( context ) ;
215+ }
197216 foreach ( var p in marshalParameters )
198217 funcTypeParams . Add ( p . Type ) ;
199218 if ( ret != null )
@@ -202,14 +221,24 @@ public virtual LambdaExpression CreateMarshalFromJniMethodExpression (JavaCallab
202221 ? Expression . GetActionType ( funcTypeParams . ToArray ( ) )
203222 : Expression . GetFuncType ( funcTypeParams . ToArray ( ) ) ;
204223
205- var bodyParams = new List < ParameterExpression > { jnienv , context } ;
206224 bodyParams . AddRange ( marshalParameters ) ;
207225 var body = Expression . Block ( envpVars , envpBody ) ;
208226 return Expression . Lambda ( marshalerType , body , bodyParams ) ;
209227 }
210228
229+ // Heuristic: if first two parameters are IntPtr, this is a "direct" wrapper.
230+ static bool IsDirectMethod ( ParameterInfo [ ] methodParameters )
231+ {
232+ return methodParameters . Length >= 2 &&
233+ methodParameters [ 0 ] . ParameterType == typeof ( IntPtr ) &&
234+ methodParameters [ 1 ] . ParameterType == typeof ( IntPtr ) ;
235+ }
236+
211237 JniValueMarshaler GetValueMarshaler ( ParameterInfo parameter )
212238 {
239+ if ( parameter . ParameterType == typeof ( IntPtr ) )
240+ return IntPtrValueMarshaler . Instance ;
241+
213242 var attr = parameter . GetCustomAttribute < JniValueMarshalerAttribute > ( ) ;
214243 if ( attr != null ) {
215244 return ( JniValueMarshaler ) Activator . CreateInstance ( attr . MarshalerType ) ;
@@ -223,8 +252,14 @@ void CheckMarshalTypesMatch (MethodInfo method, string signature, ParameterInfo[
223252 return ;
224253
225254 var mptypes = JniSignature . GetMarshalParameterTypes ( signature ) . ToList ( ) ;
255+ int rpcount = methodParameters . Length ;
226256 int len = Math . Min ( methodParameters . Length , mptypes . Count ) ;
227- for ( int i = 0 ; i < len ; ++ i ) {
257+ int start = 0 ;
258+ if ( IsDirectMethod ( methodParameters ) ) {
259+ start += 2 ;
260+ rpcount -= 2 ;
261+ }
262+ for ( int i = start ; i < len ; ++ i ) {
228263 var vm = GetValueMarshaler ( methodParameters [ i ] ) ;
229264 var jni = vm . MarshalType ;
230265 if ( mptypes [ i ] != jni )
@@ -233,31 +268,32 @@ void CheckMarshalTypesMatch (MethodInfo method, string signature, ParameterInfo[
233268 "signature" ) ;
234269 }
235270
236- if ( mptypes . Count != methodParameters . Length )
271+ if ( mptypes . Count != rpcount )
237272 throw new ArgumentException (
238273 string . Format ( "JNI parametr count mismatch: signature contains {0} parameters, method contains {1}." ,
239274 mptypes . Count , methodParameters . Length ) ,
240- " signature" ) ;
275+ nameof ( signature ) ) ;
241276
242277 var jrinfo = JniSignature . GetMarshalReturnType ( signature ) ;
243278 var mrvm = GetValueMarshaler ( method . ReturnParameter ) ;
244279 var mrinfo = mrvm . MarshalType ;
245280 if ( mrinfo != jrinfo )
246281 throw new ArgumentException (
247282 string . Format ( "JNI return type mismatch. Type '{0}' != '{1}'." , jrinfo , mrinfo ) ,
248- " signature" ) ;
283+ nameof ( signature ) ) ;
249284 }
250285
286+ static ConstructorInfo JniTransitionConstructor =
287+ ( from c in typeof ( JniTransition ) . GetTypeInfo ( ) . DeclaredConstructors
288+ let p = c . GetParameters ( )
289+ where p . Length == 1 && p [ 0 ] . ParameterType == typeof ( IntPtr )
290+ select c )
291+ . First ( ) ;
292+
251293 static Expression CreateJniTransition ( ParameterExpression jnienv )
252294 {
253- var ctor =
254- ( from c in typeof ( JniTransition ) . GetTypeInfo ( ) . DeclaredConstructors
255- let p = c . GetParameters ( )
256- where p . Length == 1 && p [ 0 ] . ParameterType == typeof ( IntPtr )
257- select c )
258- . First ( ) ;
259295 return Expression . New (
260- ctor ,
296+ JniTransitionConstructor ,
261297 jnienv ) ;
262298 }
263299
@@ -364,5 +400,65 @@ static Type ExtractMarshalTypeFromSignature (string signature, ref int index)
364400 #endif
365401 }
366402 }
403+
404+ class IntPtrValueMarshaler : JniValueMarshaler < IntPtr > {
405+ internal static IntPtrValueMarshaler Instance = new IntPtrValueMarshaler ( ) ;
406+
407+ public override Expression CreateParameterFromManagedExpression ( JniValueMarshalerContext context , ParameterExpression sourceValue , ParameterAttributes synchronize )
408+ {
409+ return sourceValue ;
410+ }
411+
412+ public override Expression CreateParameterToManagedExpression ( JniValueMarshalerContext context , ParameterExpression sourceValue , ParameterAttributes synchronize , Type targetType )
413+ {
414+ return sourceValue ;
415+ }
416+
417+ public override Expression CreateReturnValueFromManagedExpression ( JniValueMarshalerContext context , ParameterExpression sourceValue )
418+ {
419+ return sourceValue ;
420+ }
421+
422+
423+ public override object CreateValue ( ref JniObjectReference reference , JniObjectReferenceOptions options , Type targetType )
424+ {
425+ throw new NotImplementedException ( ) ;
426+ }
427+
428+ public override IntPtr CreateGenericValue ( ref JniObjectReference reference , JniObjectReferenceOptions options , Type targetType )
429+ {
430+ throw new NotImplementedException ( ) ;
431+ }
432+
433+ public override JniValueMarshalerState CreateArgumentState ( object value , ParameterAttributes synchronize )
434+ {
435+ throw new NotSupportedException ( ) ;
436+ }
437+
438+ public override JniValueMarshalerState CreateGenericArgumentState ( IntPtr value , ParameterAttributes synchronize )
439+ {
440+ throw new NotSupportedException ( ) ;
441+ }
442+
443+ public override JniValueMarshalerState CreateObjectReferenceArgumentState ( object value , ParameterAttributes synchronize )
444+ {
445+ throw new NotImplementedException ( ) ;
446+ }
447+
448+ public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ( IntPtr value , ParameterAttributes synchronize )
449+ {
450+ throw new NotImplementedException ( ) ;
451+ }
452+
453+ public override void DestroyArgumentState ( object value , ref JniValueMarshalerState state , ParameterAttributes synchronize )
454+ {
455+ throw new NotImplementedException ( ) ;
456+ }
457+
458+ public override void DestroyGenericArgumentState ( IntPtr value , ref JniValueMarshalerState state , ParameterAttributes synchronize )
459+ {
460+ throw new NotImplementedException ( ) ;
461+ }
462+ }
367463}
368464
0 commit comments