private ArrayList refReferences = new ArrayList(3); // GENERICS: <LocalBuilder> #endregion #region Call Switch Emitter /// <summary> /// Emits calls to specified overloads and a switch statement which calls appropriate overload /// according to the current value of <see cref="PhpStack.ArgCount"/> field of the current stack. /// </summary> /// <param name="thisRef">Reference to self.</param> /// <param name="script_context">Current script context.</param> /// <param name="rtVariables"> /// Place where a run-time variables table can be loaded from. /// </param> /// <param name="namingContext">Naming context load-from place.</param> /// <param name="classContext">Class context load.</param> /// <param name="overloads">The overload list.</param> /// <remarks> /// Example: given overloads (2,5,7,9+), i.e. there are four overloads having 2, 5, 7 and 9 PHP parameters, /// respectively, and the last overload is marked as vararg, /// the method emits the following code: /// <code> /// switch(ArgCount - 2) // 2 = minimum { arg count of overload } /// { /// case 0: return call #2; // call to the 2nd overload with appropriate arg. and return value handling /// case 1: goto case error; /// case 2: goto case error; /// case 3: return call #5; /// case 4: goto case error; /// case 5: return call #7; /// case 6: goto case error; /// /// #if vararg /// case 7: goto default; /// default: return call #vararg (9 mandatory args,optional args);break; /// #elif /// case 7: return call #9; /// default: goto case error; /// #endif /// /// case error: PhpException.InvalidArgumentCount(null, functionName); break; /// } /// </code> /// </remarks> public void EmitCallSwitch(IPlace /*!*/ thisRef, IPlace /*!*/ script_context, IPlace /*!*/ rtVariables, IPlace /*!*/ namingContext, IPlace /*!*/ classContext, List <PhpLibraryFunction.Overload> /*!!*/ overloads) { Debug.AssertAllNonNull(overloads); int last = overloads.Count - 1; int min = overloads[0].ParamCount; int max = overloads[last].ParamCount; var flags = overloads[last].Flags; // if function is not supported, just throw the warning: if ((flags & PhpLibraryFunction.OverloadFlags.NotSupported) != 0) { // stack.RemoveFrame(); if (stack != null) { stack.EmitLoad(il); il.Emit(OpCodes.Call, Methods.PhpStack.RemoveFrame); } // PhpException.FunctionNotSupported( <FullName> ); il.Emit(OpCodes.Ldstr, FunctionName.Value); il.Emit(OpCodes.Call, Methods.PhpException.FunctionNotSupported_String); if (debug) { il.Emit(OpCodes.Nop); } // load methods default value il.EmitBoxing(OverloadsBuilder.EmitLoadDefault(il, overloads[last].Method)); return; } bool is_vararg = (flags & PhpLibraryFunction.OverloadFlags.IsVararg) != 0; if ((flags & PhpLibraryFunction.OverloadFlags.NeedsScriptContext) == 0) { script_context = null; } if ((flags & PhpLibraryFunction.OverloadFlags.NeedsThisReference) == 0) { thisRef = null; } if ((flags & PhpLibraryFunction.OverloadFlags.NeedsVariables) == 0) { rtVariables = null; } if ((flags & PhpLibraryFunction.OverloadFlags.NeedsNamingContext) == 0) { namingContext = null; } if ((flags & (PhpLibraryFunction.OverloadFlags.NeedsClassContext | PhpLibraryFunction.OverloadFlags.NeedsLateStaticBind)) == 0) { classContext = null; } Label end_label = il.DefineLabel(); Label error_label = il.DefineLabel(); Label[] cases = new Label[max - min + 1]; MethodInfo method; // fills cases with "goto case error": for (int i = 0; i < cases.Length; i++) { cases[i] = error_label; } // define labels for valid cases: for (int i = 0; i < overloads.Count; i++) { int count = overloads[i].ParamCount; cases[count - min] = il.DefineLabel(); } // LOAD(stack.ArgCount - min); stack.EmitLoad(il); il.Emit(OpCodes.Ldfld, Fields.PhpStack_ArgCount); il.LdcI4(min); il.Emit(OpCodes.Sub); // SWITCH(tmp) il.Emit(OpCodes.Switch, cases); // CASE >=N or <0 (underflows); // if the last overload is vararg: if (is_vararg) { LocalBuilder opt_arg_count_local = il.DeclareLocal(typeof(int)); // CASE N: il.MarkLabel(cases[cases.Length - 1]); // opt_arg_count = stack.ArgCount - max; stack.EmitLoad(il); il.Emit(OpCodes.Ldfld, Fields.PhpStack_ArgCount); il.LdcI4(max); il.Emit(OpCodes.Sub); il.Stloc(opt_arg_count_local); // IF(tmp<0) GOTO CASE error; il.Ldloc(opt_arg_count_local); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Blt, error_label); // emits argument loading, stack frame removal, method call, return value conversion: method = overloads[last].Method; Type return_type = EmitOverloadCall(method, overloads[last].RealParameters, max, script_context, rtVariables, namingContext, classContext, new Place(opt_arg_count_local), thisRef, false); // loads boxed return value: if (return_type != Types.Void) { //il.LoadBoxed(return_value); if (return_type.IsValueType) { il.Emit(OpCodes.Box, return_type); } } else { il.Emit(OpCodes.Ldnull); } // RETURN; il.Emit(OpCodes.Ret); //bug in Reflector: il.Emit(OpCodes.Br,end_label); } else { // GOTO CASE error; il.Emit(OpCodes.Br, error_label); } // emits all valid cases which are not vararg: int j = 0; for (int i = min; i <= max - (is_vararg ? 1 : 0); i++) { if (overloads[j].ParamCount == i) { // CASE <i>; il.MarkLabel(cases[i - min]); // emits argument loading, stack frame removal, method call, return value conversion: method = overloads[j].Method; Type return_type = EmitOverloadCall(method, overloads[j].RealParameters, i, script_context, rtVariables, namingContext, classContext, null, thisRef, false); // loads boxed return value: if (return_type != Types.Void) { //il.LoadBoxed(return_value); if (return_type.IsValueType) { il.Emit(OpCodes.Box, return_type); } } else { il.Emit(OpCodes.Ldnull); } // RETURN; il.Emit(OpCodes.Ret); //bug in Reflector: il.Emit(OpCodes.Br,end_label); j++; } } Debug.Assert(j + (is_vararg ? 1 : 0) == overloads.Count); // ERROR: il.MarkLabel(error_label); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ldstr, this.functionName.ToString()); il.Emit(OpCodes.Call, Methods.PhpException.InvalidArgumentCount); if (debug) { il.Emit(OpCodes.Nop); } // RETURN null: il.Emit(OpCodes.Ldnull); il.MarkLabel(end_label); }
/// <summary> /// Emits load of an array where all optional arguments are stored. /// Each optional argument is peeked from the PHP stack and converted before stored to the array. /// The resulting array is pushed on evaluation stack so it can be later passed as an argument to a method. /// </summary> /// <param name="builder">The builder.</param> /// <param name="start">The index of the first argument to be loaded.</param> /// <param name="param">The last parameter of the overload (should be an array).</param> /// <param name="optArgCount">The place where the number of optional arguments is stored.</param> /// <remarks>Assumes that the non-negative number of optional arguments has been stored to /// <paramref name="optArgCount"/> place.</remarks> public static void EmitPeekAllArguments(OverloadsBuilder /*!*/ builder, int start, ParameterInfo param, IPlace optArgCount) { Debug.Assert(start >= 0 && optArgCount != null && param != null); ILEmitter il = builder.IL; Type elem_type = param.ParameterType.GetElementType(); Type array_type = Type.GetType(elem_type.FullName + "[]", true); Type actual_type; // declares aux. variables: LocalBuilder loc_array = il.DeclareLocal(array_type); LocalBuilder loc_i = il.DeclareLocal(typeof(int)); LocalBuilder loc_elem = il.DeclareLocal(elem_type); // creates an array for the arguments // array = new <elem_type>[opt_arg_count]: optArgCount.EmitLoad(il); il.Emit(OpCodes.Newarr, elem_type); il.Stloc(loc_array); Label for_end_label = il.DefineLabel(); Label condition_label = il.DefineLabel(); // i = 0; il.Emit(OpCodes.Ldc_I4_0); il.Stloc(loc_i); // FOR (i = 0; i < opt_arg_count; i++) if (true) { il.MarkLabel(condition_label); // condition (i < opt_arg_count): il.Ldloc(loc_i); optArgCount.EmitLoad(il); il.Emit(OpCodes.Bge, for_end_label); // LOAD stack, i + start+1>: builder.Stack.EmitLoad(il); il.Ldloc(loc_i); il.LdcI4(start + 1); il.Emit(OpCodes.Add); if (elem_type == typeof(PhpReference)) { // CALL stack.PeekReferenceUnchecked(STACK); il.Emit(OpCodes.Call, Methods.PhpStack.PeekReferenceUnchecked); actual_type = typeof(PhpReference); } else { // CALL stack.PeekValueUnchecked(STACK); il.Emit(OpCodes.Call, Methods.PhpStack.PeekValueUnchecked); actual_type = typeof(object); } // emits a conversion stuff (loads result into "elem" local variable): builder.EmitArgumentConversion(elem_type, actual_type, false, param); il.Stloc(loc_elem); // array[i] = elem; il.Ldloc(loc_array); il.Ldloc(loc_i); il.Ldloc(loc_elem); il.Stelem(elem_type); // i = i + 1; il.Ldloc(loc_i); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Stloc(loc_i); // GOTO condition; il.Emit(OpCodes.Br, condition_label); } // END FOR il.MarkLabel(for_end_label); // loads array to stack - consumed by the method call: il.Ldloc(loc_array); }
/// <summary> /// Emits load of optional parameters array on the evaluation stack. /// </summary> /// <param name="node">Instance.</param> /// <param name="builder">An overloads builder.</param> /// <param name="start">An index of the first optional parameter to be loaded into the array (indices start from 0).</param> /// <param name="param"> /// A <see cref="ParameterInfo"/> of the formal parameter of the target method where the array will be passed. /// This information influences conversions all optional parameters. /// </param> /// <param name="optArgCount">Optional argument count (unused).</param> public void EmitLibraryLoadOptArguments(CallSignature/*!*/node, OverloadsBuilder/*!*/ builder, int start, ParameterInfo/*!*/ param, IPlace optArgCount) { Debug.Assert(start >= 0 && builder != null && param != null && builder.Aux is CodeGenerator); ILEmitter il = builder.IL; Type elem_type = param.ParameterType.GetElementType(); Type array_type = elem_type.MakeArrayType(); // NEW <alem_type>[<parameters count - start>] il.LdcI4(node.Parameters.Count - start); il.Emit(OpCodes.Newarr, elem_type); // loads each optional parameter into the appropriate bucket of the array: for (int i = start; i < node.Parameters.Count; i++) { // <arr>[i - start] il.Emit(OpCodes.Dup); il.LdcI4(i - start); // <parameter value> object type_or_value = EmitLibraryLoadArgument(node, il, i, builder.Aux, param); builder.EmitArgumentConversion(elem_type, type_or_value, false, param, 3); // <arr>[i - start] = <parameter value>; il.Stelem(elem_type); } // <arr> }
public static void EmitLibraryLoadOptArguments(this CallSignature/*!*/node, OverloadsBuilder/*!*/ builder, int start, ParameterInfo/*!*/ param, IPlace optArgCount) { node.NodeCompiler<ICallSignatureCompiler>().EmitLibraryLoadOptArguments(node, builder, start, param, optArgCount); }
/// <summary> /// Emits load of optional parameters array on the evaluation stack. /// </summary> /// <param name="builder">An overloads builder.</param> /// <param name="start">An index of the first optional parameter to be loaded into the array (indices start from 0).</param> /// <param name="param"> /// A <see cref="ParameterInfo"/> of the formal parameter of the target method where the array will be passed. /// This information influences conversions all optional parameters. /// </param> /// <param name="optArgCount">Optional argument count (unused).</param> internal void EmitLibraryLoadOptArguments(OverloadsBuilder/*!*/ builder, int start, ParameterInfo/*!*/ param, IPlace optArgCount) { Debug.Assert(start >= 0 && builder != null && param != null && builder.Aux is CodeGenerator); ILEmitter il = builder.IL; Type elem_type = param.ParameterType.GetElementType(); Type array_type = elem_type.MakeArrayType(); LocalBuilder loc_array = il.DeclareLocal(array_type); LocalBuilder loc_item = il.DeclareLocal(elem_type); // NEW <alem_type>[<parameters count - start>] il.LdcI4(parameters.Count - start); il.Emit(OpCodes.Newarr, elem_type); il.Stloc(loc_array); // loads each optional parameter into the appropriate bucket of the array: for (int i = start; i < parameters.Count; i++) { // item = <parameter value>; object type_or_value = EmitLibraryLoadArgument(il, i, builder.Aux); builder.EmitArgumentConversion(elem_type, type_or_value, false, param); il.Stloc(loc_item); // array[<i-start>] = item; il.Ldloc(loc_array); il.LdcI4(i - start); il.Ldloc(loc_item); il.Stelem(elem_type); } // loads the array: il.Ldloc(loc_array); }
private static string CreateDynamicWrapperInternal(Type /*!*/ attr, Assembly /*!*/ assembly, string directory, string filename) #endif { string assembly_base_name; AssemblyBuilder assembly_builder; ModuleBuilder module_builder; TypeBuilder type_builder; MethodBuilder method_builder; IndexedPlace stack_place = new IndexedPlace(PlaceHolder.Argument, 1); // TODO: if function requires this reference, we need to pass it somehow IPlace self_ref = LiteralPlace.Null; IPlace script_context = new Place(stack_place, Fields.PhpStack_Context); IPlace rt_variables = new Place(stack_place, Fields.PhpStack_Variables); IPlace naming_context = new Place(stack_place, Fields.PhpStack_NamingContext); IPlace class_context = new Place(null, Fields.UnknownTypeDesc.Singleton); #if !SILVERLIGHT if (directory == null) { directory = Configuration.GetPathsNoLoad().DynamicWrappers; } Directory.CreateDirectory(directory); #endif Dictionary <string, List <PhpLibraryFunction.Overload> > functions = GetLibraryFunctions(attr, assembly); OverloadsBuilder overloads_builder = new OverloadsBuilder( false, stack_place, new OverloadsBuilder.ParameterLoader(PhpStackBuilder.EmitValuePeekUnchecked), new OverloadsBuilder.ParameterLoader(PhpStackBuilder.EmitReferencePeekUnchecked), new OverloadsBuilder.ParametersLoader(PhpStackBuilder.EmitPeekAllArguments)); #if SILVERLIGHT int commaIdx = assembly.FullName.IndexOf(','); assembly_base_name = commaIdx == -1 ? assembly.FullName : assembly.FullName.Substring(0, commaIdx); #else // securitycritical assembly_base_name = assembly.GetName().Name; #endif // appends assembly name with the suffix: AssemblyName name = new AssemblyName(); #if !SILVERLIGHT name.Version = assembly.GetName().Version; #endif name.Name = assembly_base_name + PhpLibraryModule.DynamicAssemblySuffix; #if SILVERLIGHT // defines assembly with storage in the dynamic code path: assembly_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); // defines a module: module_builder = assembly_builder.DefineDynamicModule(PhpLibraryModule.DynamicWrapperModuleName); #else // defines assembly with storage in the dynamic code path: assembly_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Save, directory); // defines a module: module_builder = assembly_builder.DefineDynamicModule(PhpLibraryModule.DynamicWrapperModuleName, filename); #endif // defines type which will contain all mathods: type_builder = module_builder.DefineType(Namespaces.LibraryStubs + Type.Delimiter + assembly_base_name, DynamicTypeAttributes); try { foreach (KeyValuePair <string, List <PhpLibraryFunction.Overload> > function in functions) { // defines method: method_builder = type_builder.DefineMethod(function.Key, MethodAttributes.Public | MethodAttributes.Static, Types.Object[0], Types.Object_PhpStack); ILEmitter il = new ILEmitter(method_builder); overloads_builder.IL = il; overloads_builder.Aux = stack_place; overloads_builder.FunctionName = new Name(function.Key); // if run-time variables are needed by the overload sets a place where they are stored up: overloads_builder.EmitCallSwitch(self_ref, script_context, rt_variables, naming_context, class_context, function.Value); // RETURN: il.Emit(OpCodes.Ret); } } catch (Exception e) { Debug.WriteLine("A", e.ToString()); } type_builder.CreateType(); #if SILVERLIGHT return(assembly_builder); #else assembly_builder.Save(filename); return(Path.Combine(directory, filename)); #endif }
internal override PhpTypeCode EmitCall(CodeGenerator/*!*/ codeGenerator, string fallbackQualifiedName, CallSignature callSignature, IPlace instance, bool runtimeVisibilityCheck, int overloadIndex, DType type, Position position, AccessType access, bool callVirt) { Overload overload = overloads[overloadIndex]; Statistics.AST.AddLibraryFunctionCall(FullName, overload.ParamCount); if ((overload.Flags & OverloadFlags.NotSupported) != 0) { codeGenerator.IL.Emit(OpCodes.Ldstr, FullName); codeGenerator.IL.Emit(OpCodes.Call, Methods.PhpException.FunctionNotSupported_String); if (codeGenerator.Context.Config.Compiler.Debug) codeGenerator.IL.Emit(OpCodes.Nop); return OverloadsBuilder.EmitLoadDefault(codeGenerator.IL, overload.Method); } //IPlace return_value; IPlace script_context = null; IPlace opt_arg_count = null; IPlace self_ref = null; IPlace rt_variables = null; IPlace naming_context = null; IPlace class_context = null; // // captures eval info: if ((options & FunctionImplOptions.CaptureEvalInfo) != 0) { codeGenerator.EmitEvalInfoCapture(position.FirstLine, position.FirstColumn, false); } // current ScriptContext: if ((overload.Flags & OverloadFlags.NeedsScriptContext) != 0) { script_context = codeGenerator.ScriptContextPlace; } // number of optional arguments passed to a function (empty or a literal place): if ((overload.Flags & OverloadFlags.IsVararg) != 0) { opt_arg_count = new IndexedPlace(PlaceHolder.None, callSignature.Parameters.Count - overload.ParamCount); } // this reference? if ((options & FunctionImplOptions.NeedsThisReference) != 0) { self_ref = codeGenerator.SelfPlace; } // run-time variables table: if ((options & FunctionImplOptions.NeedsVariables) != 0) { rt_variables = codeGenerator.RTVariablesTablePlace; } // naming context if ((options & FunctionImplOptions.NeedsNamingContext) != 0) { naming_context = (codeGenerator.SourceUnit.NamingContextFieldBuilder != null) ? (IPlace)new Place(null, codeGenerator.SourceUnit.NamingContextFieldBuilder) : (IPlace)LiteralPlace.Null; } // call context if ((options & FunctionImplOptions.NeedsClassContext) != 0) { class_context = codeGenerator.TypeContextPlace; } OverloadsBuilder.ParameterLoader param_loader = new OverloadsBuilder.ParameterLoader(callSignature.EmitLibraryLoadArgument); OverloadsBuilder.ParametersLoader opt_param_loader = new OverloadsBuilder.ParametersLoader(callSignature.EmitLibraryLoadOptArguments); OverloadsBuilder builder = new OverloadsBuilder( codeGenerator.Context.Config.Compiler.Debug, null, // PHP stack is not used param_loader, // value parameter loader param_loader, // reference parameter loader opt_param_loader); // optional parameter array loader // setups builder: builder.Aux = codeGenerator; builder.IL = codeGenerator.IL; builder.FunctionName = name; // emits overload call: Type/*!*/return_type = builder.EmitOverloadCall(overload.Method, overload.RealParameters, overload.ParamCount, script_context, rt_variables, naming_context, class_context, opt_arg_count, self_ref, access == AccessType.None); //if (return_value != null) //{ // // loads value on the stack: // return_value.EmitLoad(codeGenerator.IL); // return PhpTypeCodeEnum.FromType(return_value.PlaceType); //} if (return_type != Types.Void) { return PhpTypeCodeEnum.FromType(return_type); } else { if (codeGenerator.Context.Config.Compiler.Debug) { codeGenerator.IL.Emit(OpCodes.Nop); } return PhpTypeCode.Void; } }
private static string CreateDynamicWrapperInternal(Type/*!*/ attr, Assembly/*!*/ assembly, string directory, string filename) #endif { string assembly_base_name; AssemblyBuilder assembly_builder; ModuleBuilder module_builder; TypeBuilder type_builder; MethodBuilder method_builder; IndexedPlace stack_place = new IndexedPlace(PlaceHolder.Argument, 1); // TODO: if function requires this reference, we need to pass it somehow IPlace self_ref = LiteralPlace.Null; IPlace script_context = new Place(stack_place, Fields.PhpStack_Context); IPlace rt_variables = new Place(stack_place, Fields.PhpStack_Variables); IPlace naming_context = new Place(stack_place, Fields.PhpStack_NamingContext); IPlace class_context = new Place(null, Fields.UnknownTypeDesc.Singleton); #if !SILVERLIGHT if (directory == null) directory = Configuration.GetPathsNoLoad().DynamicWrappers; Directory.CreateDirectory(directory); #endif Dictionary<string, List<PhpLibraryFunction.Overload>> functions = GetLibraryFunctions(attr, assembly); OverloadsBuilder overloads_builder = new OverloadsBuilder( false, stack_place, new OverloadsBuilder.ParameterLoader(PhpStackBuilder.EmitValuePeekUnchecked), new OverloadsBuilder.ParameterLoader(PhpStackBuilder.EmitReferencePeekUnchecked), new OverloadsBuilder.ParametersLoader(PhpStackBuilder.EmitPeekAllArguments)); #if SILVERLIGHT int commaIdx = assembly.FullName.IndexOf(','); assembly_base_name = commaIdx == -1 ? assembly.FullName : assembly.FullName.Substring(0, commaIdx); #else // securitycritical assembly_base_name = assembly.GetName().Name; #endif // appends assembly name with the suffix: AssemblyName name = new AssemblyName(); #if !SILVERLIGHT name.Version = assembly.GetName().Version; #endif name.Name = assembly_base_name + PhpLibraryModule.DynamicAssemblySuffix; #if SILVERLIGHT // defines assembly with storage in the dynamic code path: assembly_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); // defines a module: module_builder = assembly_builder.DefineDynamicModule(PhpLibraryModule.DynamicWrapperModuleName); #else // defines assembly with storage in the dynamic code path: assembly_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Save, directory); // defines a module: module_builder = assembly_builder.DefineDynamicModule(PhpLibraryModule.DynamicWrapperModuleName, filename); #endif // defines type which will contain all mathods: type_builder = module_builder.DefineType(Namespaces.LibraryStubs + Type.Delimiter + assembly_base_name, DynamicTypeAttributes); try { foreach (KeyValuePair<string, List<PhpLibraryFunction.Overload>> function in functions) { // defines method: method_builder = type_builder.DefineMethod(function.Key, MethodAttributes.Public | MethodAttributes.Static, Types.Object[0], Types.Object_PhpStack); ILEmitter il = new ILEmitter(method_builder); overloads_builder.IL = il; overloads_builder.Aux = stack_place; overloads_builder.FunctionName = new Name(function.Key); // if run-time variables are needed by the overload sets a place where they are stored up: overloads_builder.EmitCallSwitch(self_ref, script_context, rt_variables, naming_context, class_context, function.Value); // RETURN: il.Emit(OpCodes.Ret); } } catch (Exception e) { Debug.WriteLine("A", e.ToString()); } type_builder.CreateType(); #if SILVERLIGHT return assembly_builder; #else assembly_builder.Save(filename); return Path.Combine(directory, filename); #endif }
/// <summary> /// Emits load of an array where all optional arguments are stored. /// Each optional argument is peeked from the PHP stack and converted before stored to the array. /// The resulting array is pushed on evaluation stack so it can be later passed as an argument to a method. /// </summary> /// <param name="builder">The builder.</param> /// <param name="start">The index of the first argument to be loaded.</param> /// <param name="param">The last parameter of the overload (should be an array).</param> /// <param name="optArgCount">The place where the number of optional arguments is stored.</param> /// <remarks>Assumes that the non-negative number of optional arguments has been stored to /// <paramref name="optArgCount"/> place.</remarks> public static void EmitPeekAllArguments(OverloadsBuilder/*!*/ builder, int start, ParameterInfo param, IPlace optArgCount) { Debug.Assert(start >= 0 && optArgCount != null && param != null); ILEmitter il = builder.IL; Type elem_type = param.ParameterType.GetElementType(); Type array_type = Type.GetType(elem_type.FullName + "[]", true); Type actual_type; // declares aux. variables: LocalBuilder loc_array = il.DeclareLocal(array_type); LocalBuilder loc_i = il.DeclareLocal(typeof(int)); LocalBuilder loc_elem = il.DeclareLocal(elem_type); // creates an array for the arguments // array = new <elem_type>[opt_arg_count]: optArgCount.EmitLoad(il); il.Emit(OpCodes.Newarr, elem_type); il.Stloc(loc_array); Label for_end_label = il.DefineLabel(); Label condition_label = il.DefineLabel(); // i = 0; il.Emit(OpCodes.Ldc_I4_0); il.Stloc(loc_i); // FOR (i = 0; i < opt_arg_count; i++) if (true) { il.MarkLabel(condition_label); // condition (i < opt_arg_count): il.Ldloc(loc_i); optArgCount.EmitLoad(il); il.Emit(OpCodes.Bge, for_end_label); // LOAD stack, i + start+1>: builder.Stack.EmitLoad(il); il.Ldloc(loc_i); il.LdcI4(start + 1); il.Emit(OpCodes.Add); if (elem_type == typeof(PhpReference)) { // CALL stack.PeekReferenceUnchecked(STACK); il.Emit(OpCodes.Call, Methods.PhpStack.PeekReferenceUnchecked); actual_type = typeof(PhpReference); } else { // CALL stack.PeekValueUnchecked(STACK); il.Emit(OpCodes.Call, Methods.PhpStack.PeekValueUnchecked); actual_type = typeof(object); } // emits a conversion stuff (loads result into "elem" local variable): builder.EmitArgumentConversion(elem_type, actual_type, false, param); il.Stloc(loc_elem); // array[i] = elem; il.Ldloc(loc_array); il.Ldloc(loc_i); il.Ldloc(loc_elem); il.Stelem(elem_type); // i = i + 1; il.Ldloc(loc_i); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Stloc(loc_i); // GOTO condition; il.Emit(OpCodes.Br, condition_label); } // END FOR il.MarkLabel(for_end_label); // loads array to stack - consumed by the method call: il.Ldloc(loc_array); }