public static void EmitArgFullPreCall(ILEmitter/*!*/ il, IPlace/*!*/ stack, bool argsAware, int formalParamCount, int formalTypeParamCount, out LocalBuilder locArgsCount) { if (argsAware) { locArgsCount = il.DeclareLocal(typeof(int)); // locArgsCount = stack.MakeArgsAware(<formal tpye param count | formal param count>); stack.EmitLoad(il); il.LdcI4((formalTypeParamCount << 16) | formalParamCount); il.Emit(OpCodes.Call, Methods.PhpStack.MakeArgsAware); il.Stloc(locArgsCount); } else { locArgsCount = null; // CALL stack.RemoveFrame(); stack.EmitLoad(il); il.Emit(OpCodes.Call, Methods.PhpStack.RemoveFrame); } }
/// <summary> /// Emits helper declaring all single-declared functions and classes in the script being built. /// </summary> /// <remarks> /// For each function and class emits a call to <see cref="ApplicationContext.DeclareFunction"/> and /// <see cref="ApplicationContext.DeclareType"/>, respectively, which declares it. /// The helper is called as the first instruction of Main helper. /// </remarks> private void EmitDeclareHelper() { PureCompilationUnit unit = this.PureCompilationUnit; ILEmitter il = new ILEmitter(declareHelperBuilder); IndexedPlace app_context_place = new IndexedPlace(PlaceHolder.Argument, 0); TypeBuilder publicsContainer = null; // container type for public stubs of global declarations (which are inaccessible from other assemblies) foreach (PhpFunction function in unit.GetDeclaredFunctions()) { if (function.IsDefinite) { app_context_place.EmitLoad(il); // NEW RoutineDelegate(<static method>); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ldftn, function.ArgLessInfo); il.Emit(OpCodes.Newobj, Constructors.RoutineDelegate); // LOAD <full name>; il.Emit(OpCodes.Ldstr, function.FullName); // LOAD <attributes>; il.LdcI4((int)function.MemberDesc.MemberAttributes); // LOAD <argfull> if (function.ArgFullInfo != null) CodeGenerator.EmitLoadMethodInfo( il, (function.ArgFullInfo.DeclaringType != null) ? function.ArgFullInfo : EmitPhpFunctionPublicStub(ref publicsContainer, function) // function.ArgFullInfo is real global method not accessible from other assemblies, must be wrapped /*, AssemblyBuilder.DelegateBuilder*/); else il.Emit(OpCodes.Ldnull); // CALL <application context>.DeclareFunction(<stub>, <name>, <member attributes>, <argfull>) il.Emit(OpCodes.Call, Methods.ApplicationContext.DeclareFunction); } } foreach (PhpType type in unit.GetDeclaredTypes()) { if (type.IsDefinite) { // CALL <application context>.DeclareType(<type desc>, <name>); type.EmitAutoDeclareOnApplicationContext(il, app_context_place); } } foreach (GlobalConstant constant in unit.GetDeclaredConstants()) { if (constant.IsDefinite) { app_context_place.EmitLoad(il); // CALL <application context>.DeclareConstant(<name>, <value>); il.Emit(OpCodes.Ldstr, constant.FullName); //il.Emit(OpCodes.Ldsfld, constant.RealField); //if (constant.RealField.FieldType.IsValueType) il.Emit(OpCodes.Box, constant.RealField.FieldType); il.LoadLiteralBox(constant.Value); il.Emit(OpCodes.Call, Methods.ApplicationContext.DeclareConstant); } } il.Emit(OpCodes.Ret); // complete the publicsContainer type, if created: if (publicsContainer != null) publicsContainer.CreateType(); }
/// <summary> /// Emit <see cref="PhpVariable.Copy"/> if needed. It means <see cref="Expression.Access"/> has to be <see cref="AccessType.Read"/> and <paramref name="returnType"/> has to be copiable. /// </summary> /// <param name="il">The <see cref="ILEmitter"/>.</param> /// <param name="returnType"><see cref="PhpTypeCode"/> of function call return value.</param> protected void EmitReturnValueCopy(ILEmitter/*!*/il, PhpTypeCode returnType) { Debug.Assert(il != null); // copy only if we are reading the return value && // only if return type is copiable: if (access != AccessType.None && // reading, not literals: PhpTypeCodeEnum.IsDeeplyCopied(returnType) && returnType != PhpTypeCode.PhpReference) // PhpSmartReference can be an issue if method returns an object field (but this is handled by binders) { il.LdcI4((int)CopyReason.ReturnedByCopy); il.Emit(OpCodes.Call, Methods.PhpVariable.Copy); } }
internal void EmitSetConversion(ILEmitter/*!*/ il, PhpTypeCode sourceTypeCode, Type/*!*/ targetType) { LocalBuilder strictness = il.GetTemporaryLocal(typeof(PHP.Core.ConvertToClr.ConversionStrictness)); if (!ClrOverloadBuilder.EmitConvertToClr(il, sourceTypeCode, targetType, strictness)) { Label label_ok = il.DefineLabel(); il.Ldloc(strictness); il.LdcI4((int)PHP.Core.ConvertToClr.ConversionStrictness.Failed); il.Emit(OpCodes.Ceq); il.Emit(OpCodes.Brfalse, label_ok); il.Emit(OpCodes.Ldstr, Property.DeclaringType.FullName); il.Emit(OpCodes.Ldstr, Property.FullName); il.Emit(OpCodes.Call, Methods.PhpException.PropertyTypeMismatch); il.MarkLabel(label_ok, true); } il.ReturnTemporaryLocal(strictness); }
/// <summary> /// Emits call to <see cref="ScriptContext.DeclareFunction"/>. /// </summary> internal static void EmitDeclareFunction(ILEmitter/*!*/il, IPlace/*!*/scriptContextPlace, PhpFunction/*!*/ function) { Label lbl_fieldinitialized = il.DefineLabel(); // private static PhpRoutine <routine>'function = null; var attrs = FieldAttributes.Static | FieldAttributes.Private; var field = il.TypeBuilder.DefineField(string.Format("<routine>'{0}", function.FullName), typeof(PhpRoutineDesc), attrs); // if (<field> == null) il.Emit(OpCodes.Ldsfld, field); il.Emit(OpCodes.Brtrue, lbl_fieldinitialized); { // <field> = new PhpRoutineDesc(<attributes>, new RoutineDelegate(null, <delegate>)) // LOAD <attributes>; il.LdcI4((int)function.MemberDesc.MemberAttributes); // new RoutineDelegate(null, <delegate>, true) il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ldftn, function.ArgLessInfo); il.Emit(OpCodes.Newobj, Constructors.RoutineDelegate); il.LoadBool(true); // new PhpRoutineDesc: il.Emit(OpCodes.Newobj, Constructors.PhpRoutineDesc_Attr_Delegate_Bool); // <field> = <STACK> il.Emit(OpCodes.Stsfld, field); // new PurePhpFunction(<field>, fullName, argfull); // writes desc.Member il.Emit(OpCodes.Ldsfld, field); il.Emit(OpCodes.Ldstr, function.FullName); CodeGenerator.EmitLoadMethodInfo(il, function.ArgFullInfo/*, AssemblyBuilder.DelegateBuilder*/); il.Emit(OpCodes.Newobj, Constructors.PurePhpFunction); il.Emit(OpCodes.Pop); } il.MarkLabel(lbl_fieldinitialized); // CALL ScriptContent.DeclareFunction(<field>, <name>); scriptContextPlace.EmitLoad(il); // LOAD <field> il.Emit(OpCodes.Ldsfld, field); // LOAD <fullName> il.Emit(OpCodes.Ldstr, function.FullName); // il.Emit(OpCodes.Call, Methods.ScriptContext.DeclareFunction); }
/// <summary> /// Emits code which pops argument from the <see cref="PhpStack"/> and pushes it on the evaluation stack. /// </summary> private void EmitPeekArgument(ILEmitter/*!*/ il, int index) { bool optional = index >= signature.MandatoryParamCount; int stack_offset = index + 1; if (signature.IsAlias(index)) { // LOAD stack.PeekReference[Optional](<stack_offset>, [default_value]); arglessStackPlace.EmitLoad(il); // stack il.LdcI4(stack_offset); // offset on stack if (optional) il.Emit(OpCodes.Call, Methods.PhpStack.PeekReferenceOptional); else il.Emit(OpCodes.Call, Methods.PhpStack.PeekReference); } else { // LOAD stack.PeekValue[Optional](<stack_offset>); arglessStackPlace.EmitLoad(il); // stack il.LdcI4(stack_offset); // offset on stack if (optional) il.Emit(OpCodes.Call, Methods.PhpStack.PeekValueOptional); else il.Emit(OpCodes.Call, Methods.PhpStack.PeekValue); } }
private void EmitPeekPseudoGenericArgument(ILEmitter/*!*/ il, int index) { bool optional = index >= signature.MandatoryGenericParamCount; int stack_offset = index + 1; // LOAD stack.PeekType[Optional](<stack_offset>, [default_value]); arglessStackPlace.EmitLoad(il); // stack il.LdcI4(stack_offset); // offset on stack if (optional) il.Emit(OpCodes.Call, Methods.PhpStack.PeekTypeOptional); else il.Emit(OpCodes.Call, Methods.PhpStack.PeekType); }
/// <summary> /// Emits code that loads the value from this storage place. /// </summary> /// <param name="il">The <see cref="ILEmitter"/> to emit the code to.</param> public void EmitLoad(ILEmitter il) { switch (holder) { case PlaceHolder.Local: il.Ldloc(index); break; case PlaceHolder.Argument: il.Ldarg(index); break; case PlaceHolder.None: il.LdcI4(index); break; } }
/// <summary> /// Emits load of default value assuming given method fails. /// </summary> /// <param name="il">ILEmitter.</param> /// <param name="method">Method which default return value have to be loaded.</param> /// <returns></returns> public static PhpTypeCode EmitLoadDefault(ILEmitter/*!*/il, MethodInfo/*!*/method) { if (method.ReturnType == Types.Bool[0] || method.ReturnTypeCustomAttributes.IsDefined(typeof(CastToFalseAttribute), false)) { il.LoadBool(false); return PhpTypeCode.Boolean; } if (method.ReturnType == Types.Int[0]) { il.LdcI4(0); return PhpTypeCode.Integer; } return PhpTypeCode.Void; }
public static object EmitReferencePeekUnchecked(ILEmitter/*!*/ il, int index, object/*!*/ stackPlace) { Debug.Assert(il != null && stackPlace != null); // LOAD stack.PeekReferenceUnchecked(<index+1>); ((IPlace)stackPlace).EmitLoad(il); il.LdcI4(index); il.Emit(OpCodes.Call, Methods.PhpStack.PeekReferenceUnchecked); return typeof(PhpReference); }
public static object EmitValuePeek(ILEmitter/*!*/ il, int index, object/*!*/ stackPlace) { Debug.Assert(il != null && stackPlace != null); // CALL stack.PeekValue(<index+1>); ((IPlace)stackPlace).EmitLoad(il); il.LdcI4(index + 1); il.Emit(OpCodes.Call, Methods.PhpStack.PeekValue); return typeof(object); }