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);
        }
Example #2
0
        /// <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);
        }
Example #3
0
            /// <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>
            }
Example #4
0
 public static void EmitLibraryLoadOptArguments(this CallSignature/*!*/node, OverloadsBuilder/*!*/ builder, int start, ParameterInfo/*!*/ param, IPlace optArgCount)
 {
     node.NodeCompiler<ICallSignatureCompiler>().EmitLibraryLoadOptArguments(node, builder, start, param, optArgCount);
 }
Example #5
0
		/// <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);
		}
Example #6
0
        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
        }
Example #7
0
        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;
            }
		}
Example #8
0
        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
		}
Example #9
0
		/// <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);
		}