1717using System . Linq . Expressions ;
1818using System . Reflection ;
1919using System . Reflection . Emit ;
20+ using System . Runtime . CompilerServices ;
21+ using static clojure . lang . CljCompiler . Context . DynInitHelper ;
2022
2123namespace clojure . lang . CljCompiler . Ast
2224{
@@ -164,31 +166,6 @@ public static void CacheDelegate(int key, Delegate d)
164166
165167 private void EmitComplexCall ( ObjExpr objx , CljILGen ilg )
166168 {
167- // TODO: We have gotten rid of light-compile. Simplify this.
168- // This is made more complex than I'd like by light-compiling.
169- // Without light-compile, we could just:
170- // Emit the target expression
171- // Emit the arguments (and build up the parameter list for the lambda)
172- // Create the lambda, compile to a methodbuilder, and call it.
173- // Light-compile forces us to
174- // create a lambda at the beginning because we must
175- // compile it to a delegate, to get the type
176- // write code to grab the delegate from a cache
177- // Then emit the target expression
178- // emit the arguments (but note we need already to have built the parameter list)
179- // Call the delegate
180- // Combined, this becomes
181- // Build the parameter list
182- // Build the dynamic call and lambda (slightly different for light-compile vs full)
183- // if light-compile
184- // build the delegate
185- // cache it
186- // emit code to retrieve and cast it
187- // emit the target expression
188- // emit the args
189- // emit the call (slightly different for light compile vs full)
190- //
191-
192169 // Build the parameter list
193170
194171 List < ParameterExpression > paramExprs = new List < ParameterExpression > ( _args . Count + 1 ) ;
@@ -260,7 +237,7 @@ private void EmitComplexCall(ObjExpr objx, CljILGen ilg)
260237 Type dynType = dih . MakeDelegateType ( "__interop__" , callsiteParamTypes . ToArray ( ) , returnType ) ;
261238
262239 DynamicExpression dyn = Expression . MakeDynamic ( dynType , binder , paramExprs ) ;
263- EmitDynamicCallPreamble ( dyn , _spanMap , "__interop_" + _methodName + RT . nextID ( ) , returnType , paramExprs , paramTypes . ToArray ( ) , ilg , out LambdaExpression lambda , out Type delType , out MethodBuilder mbLambda ) ;
240+ EmitDynamicCallPreamble ( dyn , _spanMap , "__interop_" + _methodName + RT . nextID ( ) , returnType , paramExprs , paramTypes . ToArray ( ) , ilg , out Type delType , out MethodBuilder mbLambda ) ;
264241
265242 // Emit target + args
266243
@@ -295,7 +272,7 @@ private void EmitComplexCall(ObjExpr objx, CljILGen ilg)
295272 }
296273 }
297274
298- EmitDynamicCallPostlude ( lambda , delType , mbLambda , ilg ) ;
275+ EmitDynamicCallPostlude ( mbLambda , ilg ) ;
299276 }
300277 [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Style" , "IDE0060:Remove unused parameter" , Justification = "Standard API" ) ]
301278 public static void EmitByRefArg ( HostArg ha , ObjExpr objx , CljILGen ilg )
@@ -308,116 +285,71 @@ public static void EmitByRefArg(HostArg ha, ObjExpr objx, CljILGen ilg)
308285 ilg . Emit ( OpCodes . Ldloca , ha . LocalBinding . LocalVar ) ;
309286 }
310287
311- static public void EmitDynamicCallPreamble ( DynamicExpression dyn , IPersistentMap spanMap , string methodName , Type returnType , IList < ParameterExpression > paramExprs , Type [ ] paramTypes , CljILGen ilg , out LambdaExpression lambda , out Type delType , out MethodBuilder mbLambda )
288+ static readonly FieldInfo FI_CallSite_Target = typeof ( CallSite < > ) . GetField ( "Target" , BindingFlags . Instance | BindingFlags . Public ) ;
289+ static FieldInfo GetCallSiteTarget ( Type siteType )
312290 {
313- GenContext context = Compiler . CompilerContextVar . deref ( ) as GenContext ;
314- DynInitHelper . SiteInfo siteInfo ;
315- Expression call ;
316- if ( context != null && context . DynInitHelper != null )
317- call = context . DynInitHelper . ReduceDyn ( dyn , out siteInfo ) ;
291+ if ( siteType is TypeBuilder || siteType . GetGenericArguments ( ) [ 0 ] is TypeBuilder )
292+ return TypeBuilder . GetField ( siteType , FI_CallSite_Target ) ;
318293 else
319- throw new InvalidOperationException ( "Don't know how to handle callsite in this case" ) ;
294+ return siteType . GetField ( "Target" , BindingFlags . Instance | BindingFlags . Public ) ;
295+ }
320296
321- if ( returnType == typeof ( void ) )
322- {
323- call = Expression . Block ( call , Expression . Default ( typeof ( object ) ) ) ;
324- returnType = typeof ( object ) ;
325- }
326- else if ( returnType != call . Type )
327- {
328- call = Expression . Convert ( call , returnType ) ;
329- }
330297
331- call = GenContext . AddDebugInfo ( call , spanMap ) ;
298+ static public void EmitDynamicCallPreamble ( DynamicExpression dyn , IPersistentMap spanMap , string methodName , Type returnType , IList < ParameterExpression > paramExprs , Type [ ] paramTypes , CljILGen ilg , out Type delType , out MethodBuilder mbLambda )
299+ {
300+ GenContext context = Compiler . CompilerContextVar . deref ( ) as GenContext ;
301+
302+ if ( context is null || context . DynInitHelper is null )
303+ throw new InvalidOperationException ( "Don't know how to handle callsite in this case" ) ;
332304
305+ DynInitHelper . SiteInfo siteInfo = context . DynInitHelper . ComputeSiteInfo ( dyn ) ;
333306
334307 // PLAN9 : seeing if we can replace this
335308 // delType = Microsoft.Scripting.Generation.Snippets.Shared.DefineDelegate("__interop__", returnType, paramTypes);
336309 delType = context . DynInitHelper . MakeDelegateType ( "__interop__" , paramTypes , returnType ) ;
337310
338- lambda = null ;
339- mbLambda = null ;
340-
341- if ( context == null )
311+ mbLambda = context . TB . DefineMethod ( methodName , MethodAttributes . Static | MethodAttributes . Public , CallingConventions . Standard , returnType , paramTypes ) ;
312+ //lambda.CompileToMethod(mbLambda);
313+ // Now we get to do all this code create by hand.
314+ // the primary code is
315+ // (loc1 = fb).Target.Invoke(loc1,*args);
316+ // if return type if void, pop the value and push a null
317+ // if return type does not match the call site, add a conversion
318+ CljILGen ilg2 = new CljILGen ( mbLambda . GetILGenerator ( ) ) ;
319+ ilg2 . EmitFieldGet ( siteInfo . FieldBuilder ) ;
320+ ilg2 . Emit ( OpCodes . Dup ) ;
321+ LocalBuilder siteVar = ilg2 . DeclareLocal ( siteInfo . SiteType ) ;
322+ ilg2 . Emit ( OpCodes . Stloc , siteVar ) ;
323+
324+ var targetFI = GetCallSiteTarget ( siteInfo . SiteType ) ; // siteInfo.SiteType.GetField("Target");
325+
326+ ilg2 . EmitFieldGet ( targetFI ) ;
327+
328+ ilg2 . Emit ( OpCodes . Ldloc , siteVar ) ;
329+ for ( int i = 0 ; i < paramExprs . Count ; i ++ )
330+ ilg2 . EmitLoadArg ( i ) ;
331+
332+ var invokeMethod = siteInfo . DelegateType . GetMethod ( "Invoke" ) ;
333+ ilg2 . EmitCall ( invokeMethod ) ;
334+ if ( returnType == typeof ( void ) )
342335 {
343- // light compile
344-
345- lambda = Expression . Lambda ( delType , call , paramExprs ) ;
346-
347- Delegate d = lambda . Compile ( ) ;
348- int key = RT . nextID ( ) ;
349- CacheDelegate ( key , d ) ;
350-
351- ilg . EmitInt ( key ) ;
352- ilg . Emit ( OpCodes . Call , Method_MethodExpr_GetDelegate ) ;
353- ilg . Emit ( OpCodes . Castclass , delType ) ;
336+ ilg2 . Emit ( OpCodes . Pop ) ;
337+ ilg2 . EmitNull ( ) ;
354338 }
355- else
339+ else if ( returnType != invokeMethod . ReturnType )
356340 {
357- mbLambda = context . TB . DefineMethod ( methodName , MethodAttributes . Static | MethodAttributes . Public , CallingConventions . Standard , returnType , paramTypes ) ;
358- //lambda.CompileToMethod(mbLambda);
359- // Now we get to do all this code create by hand.
360- // the primary code is
361- // (loc1 = fb).Target.Invoke(loc1,*args);
362- // if return type if void, pop the value and push a null
363- // if return type does not match the call site, add a conversion
364- CljILGen ilg2 = new CljILGen ( mbLambda . GetILGenerator ( ) ) ;
365- ilg2 . EmitFieldGet ( siteInfo . FieldBuilder ) ;
366- ilg2 . Emit ( OpCodes . Dup ) ;
367- LocalBuilder siteVar = ilg2 . DeclareLocal ( siteInfo . SiteType ) ;
368- ilg2 . Emit ( OpCodes . Stloc , siteVar ) ;
369- ilg2 . EmitFieldGet ( siteInfo . SiteType . GetField ( "Target" ) ) ;
370- ilg2 . Emit ( OpCodes . Ldloc , siteVar ) ;
371- for ( int i = 0 ; i < paramExprs . Count ; i ++ )
372- ilg2 . EmitLoadArg ( i ) ;
373-
374- var invokeMethod = siteInfo . DelegateType . GetMethod ( "Invoke" ) ;
375- ilg2 . EmitCall ( invokeMethod ) ;
376- if ( returnType == typeof ( void ) )
377- {
378- ilg2 . Emit ( OpCodes . Pop ) ;
379- ilg2 . EmitNull ( ) ;
380- }
381- else if ( returnType != invokeMethod . ReturnType )
382- {
383- EmitConvertToType ( ilg2 , invokeMethod . ReturnType , returnType , false ) ;
384- }
385-
386- ilg2 . Emit ( OpCodes . Ret ) ;
387-
388-
389- /*
390- * return Expression.Block(
391- new[] { site },
392- Expression.Call(
393- Expression.Field(
394- Expression.Assign(site, access),
395- cs.GetType().GetField("Target")
396- ),
397- node.DelegateType.GetMethod("Invoke"),
398- ClrExtensions.ArrayInsert(site, node.Arguments)
399- )
400- */
401-
402-
341+ EmitConvertToType ( ilg2 , invokeMethod . ReturnType , returnType , false ) ;
403342 }
343+
344+ ilg2 . Emit ( OpCodes . Ret ) ;
404345 }
405346
406347 [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Style" , "IDE0060:Remove unused parameter" , Justification = "Standard API" ) ]
407- static public void EmitDynamicCallPostlude ( LambdaExpression lambda , Type delType , MethodBuilder mbLambda , CljILGen ilg )
348+ static public void EmitDynamicCallPostlude ( MethodBuilder mbLambda , CljILGen ilg )
408349 {
409- if ( ! ( Compiler . CompilerContextVar . deref ( ) is GenContext ) )
410- {
411- // light compile
412-
413- MethodInfo mi = delType . GetMethod ( "Invoke" ) ;
414- ilg . Emit ( OpCodes . Callvirt , mi ) ;
415- }
416- else
417- {
418- ilg . Emit ( OpCodes . Call , mbLambda ) ;
419- }
350+ ilg . Emit ( OpCodes . Call , mbLambda ) ;
420351 }
352+
421353
422354 internal static void EmitArgsAsArray ( IPersistentVector args , ObjExpr objx , CljILGen ilg )
423355 {
0 commit comments