private BoundValueType EmitMethodArgumentsAndGenerics(MethodInfo method, ReadOnlyArray<BoundCallArgument> arguments, ReadOnlyArray<BoundExpression> generics) { bool needWriteBack = arguments.Any(p => p.IsRef && p.Expression.IsAssignable()); // Load the arguments array. LocalBuilder arrayLocal = null; if (arguments.Count > 0 || generics.Count > 0) { int count = arguments.Count; if (generics.Count > 0) count++; // Create the array to hold the arguments. IL.EmitConstant(count); IL.Emit(OpCodes.Newarr, typeof(object)); // Emit store for the elements. EmitArrayElementsStore(arguments.Select(p => p.Expression)); // We smuggle the generic arguments into the last entry of the // arguments array. If we have generic arguments, create a // JsGenericArguments object to hold them and put it at the end // of the array. if (generics.Count > 0) { // Dup the array reference for the Stelem. We're going to leave // the array reference on the stack. IL.Emit(OpCodes.Dup); // Emit the index the item is at. IL.EmitConstant(count - 1); // Emit the array to hold the generic arguments. IL.EmitConstant(generics.Count); IL.Emit(OpCodes.Newarr, typeof(object)); // Store the generic arguments. EmitArrayElementsStore(generics); // Emit the JsGenericArguments object. IL.Emit(OpCodes.Newobj, _genericArgumentsConstructor); // Store the generic arguments in the array. IL.Emit(OpCodes.Stelem_Ref); } // If we're doing a write back, we need to hold on to a reference // to the array, so dup the stack element here and store it in // a local. if (needWriteBack) { arrayLocal = IL.DeclareLocal(typeof(object[])); IL.Emit(OpCodes.Dup); IL.Emit(OpCodes.Stloc, arrayLocal); } } else { IL.Emit(OpCodes.Ldsfld, _emptyObjectArray); } // And execute the method. IL.EmitCall(method); // The result is now on the stack, which we leave there as the result // of this emit. if (needWriteBack) { // We need to read the arguments back for when the ExecuteFunction // has out parameters for native calls. for (int i = 0; i < arguments.Count; i++) { var argument = arguments[i]; if (!argument.IsRef || !argument.Expression.IsAssignable()) continue; var valueExpression = new BoundEmitExpression( BoundValueType.Unknown, () => { // Load the argument from the array. IL.Emit(OpCodes.Ldloc, arrayLocal); IL.EmitConstant(i); IL.Emit(OpCodes.Ldelem_Ref); } ); if (argument.Expression.Kind == BoundKind.GetMember) { var getMember = (BoundGetMember)argument.Expression; EmitSetMember(getMember.Expression, getMember.Index, valueExpression); } else { var getVariable = (BoundGetVariable)argument.Expression; EmitSetVariable((IBoundWritable)getVariable.Variable, valueExpression); } } } return BoundValueType.Object; }
private BoundValueType EmitEmit(BoundEmitExpression node) { node.Emit(); return node.ValueType; }