public static void EmitAddFrame(ILEmitter/*!*/ il, IPlace/*!*/ scriptContextPlace, int typeArgCount, int argCount, Action<ILEmitter, int> typeArgEmitter, Action<ILEmitter, int>/*!*/ argEmitter) { Debug.Assert(typeArgCount == 0 || typeArgEmitter != null); // type args: if (typeArgCount > 0) { scriptContextPlace.EmitLoad(il); il.Emit(OpCodes.Ldfld, Fields.ScriptContext_Stack); il.EmitOverloadedArgs(Types.DTypeDesc[0], typeArgCount, Methods.PhpStack.AddTypeFrame.ExplicitOverloads, typeArgEmitter); } // args: scriptContextPlace.EmitLoad(il); il.Emit(OpCodes.Ldfld, Fields.ScriptContext_Stack); il.EmitOverloadedArgs(Types.Object[0], argCount, Methods.PhpStack.AddFrame.ExplicitOverloads, argEmitter); il.Emit(OpCodes.Call, Methods.PhpStack.AddFrame.Overload(argCount)); // AddFrame adds empty type frame by default, so if there are no type parameters, we can skip AddTypeFrame call: if (typeArgCount > 0) il.Emit(OpCodes.Call, Methods.PhpStack.AddTypeFrame.Overload(typeArgCount)); }
public ClrStubBuilder(ILEmitter/*!*/ il, IPlace/*!*/ scriptContextPlace, int paramCount, int paramOffset) { this.il = il; this.scriptContextPlace = scriptContextPlace; this.paramOffset = paramOffset; this.referenceLocals = new LocalBuilder[paramCount]; }
/// <summary> /// Emits code that loads current <see cref="PHP.Core.ScriptContext"/> by calling /// <see cref="PHP.Core.ScriptContext.CurrentContext"/> and remembers it in a local. /// </summary> /// <param name="il"></param> public void EmitLoad(ILEmitter il) { if (localBuilder == null) { localBuilder = il.DeclareLocal(typeof(ScriptContext)); il.EmitCall(OpCodes.Call, Methods.ScriptContext.GetCurrentContext, null); il.Stloc(localBuilder); } il.Ldloc(localBuilder); }
/// <summary> /// Initializes a new empty instance of the <see cref="Chain"/>. /// </summary> /// <param name="il">An IL emitter.</param> public Chain(ILEmitter il) { isChainMember = false; isArrayItem = false; IsLastChainMember = false; length = 0; errorLabelHasValue = false; this.il = il; this.QuietRead = false; }
public static void EmitArgFullPostCall(ILEmitter/*!*/ il, IPlace/*!*/ stack, LocalBuilder locArgsCount) { // args-aware: if (locArgsCount != null) { // CALL stack.RemoveArgsAwareFrame(count); stack.EmitLoad(il); il.Ldloc(locArgsCount); il.Emit(OpCodes.Call, Methods.PhpStack.RemoveArgsAwareFrame); } }
/// <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); } }
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); } }
public void DefineContextType() { linqContextBuilder = cg.IL.TypeBuilder.DefineNestedType(ContextTypeName + cg.IL.GetNextUniqueIndex(), TypeAttributes.Class | TypeAttributes.NestedPrivate | TypeAttributes.Sealed, typeof(PHP.Core.LinqContext), null); // .ctor: ConstructorBuilder ctor = linqContextBuilder.DefineConstructor(MethodAttributes.Assembly, CallingConventions.HasThis, Types.LinqContextArgs); ILEmitter il = new ILEmitter(ctor); il.Ldarg(0); il.Ldarg(1); il.Ldarg(2); il.Ldarg(3); il.Ldarg(4); il.Emit(OpCodes.Call, Constructors.LinqContext); il.Emit(OpCodes.Ret); linqContextCtor = ctor; }
/// <summary> /// Emit LOAD <paramref name="instance"/>. /// </summary>ILEmiter /// <param name="il"><see cref="ILEmitter"/> object instance.</param> /// <param name="instance">The place where to load the instance from.</param> /// <param name="declaringType">The type of resulting instance.</param> /// <remarks>Instance of value types are wrapped in <see cref="ClrValue<T>"/> object instance.</remarks> internal static void EmitLoadInstance(ILEmitter/*!*/il, IPlace/*!*/instance, Type/*!*/declaringType) { Debug.Assert(il != null && instance != null && declaringType != null, "ClrOverloadBuilder.EmitLoadInstance() null argument!"); // LOAD <instance> instance.EmitLoad(il); if (declaringType.IsValueType) { var clrValueType = ClrObject.valueTypesCache.Get(declaringType).Item1; Debug.Assert(clrValueType != null, "Specific ClrValue<T> not found!"); // CAST (ClrValue<T>) il.Emit(OpCodes.Castclass, clrValueType); // LOAD .realValue var realValueField = clrValueType.GetField("realValue"); Debug.Assert(realValueField != null, "ClrValue<T>.realValue field not found!"); il.Emit(OpCodes.Ldflda, clrValueType.GetField("realValue")); } else { // CAST (T) il.Emit(OpCodes.Castclass, declaringType); } }
/// <summary> /// Converts a value of the given CLR type to PHP value. /// </summary> internal static PhpTypeCode EmitConvertToPhp(ILEmitter/*!*/ il, Type/*!*/ type) { // box generic parameter if (type.IsGenericParameter) { il.Emit(OpCodes.Box, type); type = Types.Object[0]; } switch (Type.GetTypeCode(type)) { // primitives: case TypeCode.Boolean: return PhpTypeCode.Boolean; case TypeCode.Int32: return PhpTypeCode.Integer; case TypeCode.Int64: return PhpTypeCode.LongInteger; case TypeCode.Double: return PhpTypeCode.Double; case TypeCode.String: return PhpTypeCode.String; // coercion: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Byte: case TypeCode.UInt16: { il.Emit(OpCodes.Conv_I4); return PhpTypeCode.Integer; } case TypeCode.UInt32: EmitConstrainedCoercion(il, typeof(int), typeof(long), Int32.MaxValue); return PhpTypeCode.Object; case TypeCode.UInt64: EmitConstrainedCoercion(il, typeof(int), typeof(long), Int32.MaxValue); return PhpTypeCode.Object; case TypeCode.Single: il.Emit(OpCodes.Conv_R8); return PhpTypeCode.Double; case TypeCode.Char: il.Emit(OpCodes.Box, type); il.Emit(OpCodes.Callvirt, Methods.Object_ToString); return PhpTypeCode.String; case TypeCode.DBNull: { il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ldnull); return PhpTypeCode.Object; } case TypeCode.Decimal: // TODO: what to do with this guy? case TypeCode.DateTime: { il.Emit(OpCodes.Box, type); il.Emit(OpCodes.Call, Methods.ClrObject_Wrap); return PhpTypeCode.DObject; } case TypeCode.Object: { if (!typeof(IPhpVariable).IsAssignableFrom(type)) { if (type.IsValueType) il.Emit(OpCodes.Box, type); il.Emit(OpCodes.Call, Methods.ClrObject_WrapDynamic); return PhpTypeCode.Object; } else return PhpTypeCodeEnum.FromType(type); } default: { Debug.Fail(); return PhpTypeCode.Invalid; } } }
internal static void EmitConstrainedCoercion(ILEmitter/*!*/ il, Type/*!*/ narrow, Type/*!*/ wide, object threshold) { Label else_label = il.DefineLabel(); Label endif_label = il.DefineLabel(); il.Emit(OpCodes.Dup); // IF (STACK <= threshold) THEN il.LoadLiteral(threshold); il.Emit(OpCodes.Bgt_S, else_label); // LOAD (narrow)STACK il.Conv(narrow, false); il.Emit(OpCodes.Box, narrow); il.Emit(OpCodes.Br_S, endif_label); // ELSE il.MarkLabel(else_label); // LOAD (wide)STACK il.Conv(wide, false); il.Emit(OpCodes.Box, wide); // ENDIF il.MarkLabel(endif_label); }
/// <summary> /// Converts object to CLR type /// </summary> private static bool EmitConvertObjectToClr(ILEmitter il, PhpTypeCode typeCode, Type formalType, LocalBuilder strictnessLocal) { MethodInfo convert_method = null; switch (Type.GetTypeCode(formalType)) { case TypeCode.Boolean: if (typeCode != PhpTypeCode.Boolean) convert_method = Methods.ConvertToClr.TryObjectToBoolean; break; case TypeCode.Int32: if (typeCode != PhpTypeCode.Integer) convert_method = Methods.ConvertToClr.TryObjectToInt32; break; case TypeCode.Int64: if (typeCode != PhpTypeCode.LongInteger) convert_method = Methods.ConvertToClr.TryObjectToInt64; break; case TypeCode.Double: if (typeCode != PhpTypeCode.Double) convert_method = Methods.ConvertToClr.TryObjectToDouble; break; case TypeCode.String: if (typeCode != PhpTypeCode.String) convert_method = Methods.ConvertToClr.TryObjectToString; break; case TypeCode.SByte: convert_method = Methods.ConvertToClr.TryObjectToInt8; break; case TypeCode.Int16: convert_method = Methods.ConvertToClr.TryObjectToInt16; break; case TypeCode.Byte: convert_method = Methods.ConvertToClr.TryObjectToUInt8; break; case TypeCode.UInt16: convert_method = Methods.ConvertToClr.TryObjectToUInt16; break; case TypeCode.UInt32: convert_method = Methods.ConvertToClr.TryObjectToUInt32; break; case TypeCode.UInt64: convert_method = Methods.ConvertToClr.TryObjectToUInt64; break; case TypeCode.Single: convert_method = Methods.ConvertToClr.TryObjectToSingle; break; case TypeCode.Decimal: convert_method = Methods.ConvertToClr.TryObjectToDecimal; break; case TypeCode.Char: convert_method = Methods.ConvertToClr.TryObjectToChar; break; case TypeCode.DateTime: convert_method = Methods.ConvertToClr.TryObjectToDateTime; break; case TypeCode.DBNull: convert_method = Methods.ConvertToClr.TryObjectToDBNull; break; case TypeCode.Object: { if (formalType.IsValueType) { if (formalType.IsGenericType && NullableType == formalType.GetGenericTypeDefinition()) { // This is an ugly corner case (using generic TryObjectToStruct wouldn't work, because // for nullables .IsValueType returns true, but it doesn't match "T : struct" constraint)! // We have to try converting object to Nullable<T> first and then to T // (which requires a new call to 'EmitConvertObjectToClr') Type nullableArg = formalType.GetGenericArguments()[0]; Type nullableType = NullableType.MakeGenericType(nullableArg); LocalBuilder tmpVar = il.DeclareLocal(typeof(object)); // This succeeds only for exact match il.Emit(OpCodes.Call, Methods.ConvertToClr.UnwrapNullable); il.Emit(OpCodes.Dup); il.Stloc(tmpVar); // <stack_0> = tmpVar = UnwrapNullable(...) // if (<stack_0> != null) Label lblNull = il.DefineLabel(), lblDone = il.DefineLabel(); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Beq, lblNull); // { // Convert tmpVar to T and wrap it into Nullable<T> il.Ldloc(tmpVar); bool ret = EmitConvertObjectToClr(il, typeCode, nullableArg, strictnessLocal); // TODO: use reflection cache? il.Emit(OpCodes.Newobj, nullableType.GetConstructors()[0]); il.Emit(OpCodes.Br, lblDone); // } else /* == null */ { il.MarkLabel(lblNull); // return (T?)null; LocalBuilder tmpNull = il.DeclareLocal(nullableType); il.Ldloca(tmpNull); il.Emit(OpCodes.Initobj, nullableType); il.Ldloc(tmpNull); // } il.MarkLabel(lblDone); return ret; } else convert_method = Methods.ConvertToClr.TryObjectToStruct.MakeGenericMethod(formalType); } else { if (formalType.IsArray) convert_method = Methods.ConvertToClr.TryObjectToArray.MakeGenericMethod(formalType.GetElementType()); else if (typeof(Delegate).IsAssignableFrom(formalType)) convert_method = Methods.ConvertToClr.TryObjectToDelegate.MakeGenericMethod(formalType); else convert_method = Methods.ConvertToClr.TryObjectToClass.MakeGenericMethod(formalType); } break; } default: Debug.Fail(); return true; } if (convert_method != null) { il.Ldloca(strictnessLocal); il.Emit(OpCodes.Call, convert_method); return false; } else return true; }
public ClrOverloadBuilder(ILEmitter/*!*/ il, ClrMethod/*!*/ method, ConstructedType constructedType, IPlace/*!*/ stack, IPlace/*!*/ instance, bool emitParentCtorCall, ParameterLoader/*!*/ loadValueArg, ParameterLoader/*!*/ loadReferenceArg) { this.il = il; this.method = method; this.constructedType = constructedType; this.stack = stack; this.instance = instance; this.loadValueArg = loadValueArg; this.loadReferenceArg = loadReferenceArg; this.emitParentCtorCall = emitParentCtorCall; this.overloads = new List<Overload>(method.Overloads); SortOverloads(this.overloads); }
/// <summary> /// Converts a PHP value to the given CLR type (the caller is not interested in the success of the conversion). /// </summary> public static void EmitConvertToClr(ILEmitter/*!*/ il, PhpTypeCode typeCode, Type/*!*/ formalType) { EmitConvertToClr(il, typeCode, formalType, il.GetTemporaryLocal(typeof(ConversionStrictness), true)); }
/// <summary> /// Converts a PHP value to the given CLR type (the caller passes a <paramref name="strictnessLocal"/> that will /// receive one of the <see cref="PHP.Core.ConvertToClr.ConversionStrictness"/> enumeration values that /// describe the conversion result (the Failed value indicates that conversion was not successful). /// </summary> /// <returns><B>True</B> if it the conversion will surely succeed.</returns> internal static bool EmitConvertToClr(ILEmitter/*!*/ il, PhpTypeCode typeCode, Type/*!*/ formalType, LocalBuilder/*!*/ strictnessLocal) { Debug.Assert(strictnessLocal.LocalType == typeof(ConversionStrictness)); // preprocess the value according to the PHP type code switch (typeCode) { case PhpTypeCode.PhpReference: { // dereference il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value); typeCode = PhpTypeCode.Object; break; } case PhpTypeCode.ObjectAddress: { // dereference il.Emit(OpCodes.Ldind_Ref); typeCode = PhpTypeCode.Object; break; } case PhpTypeCode.LinqSource: case PhpTypeCode.PhpRuntimeChain: { Debug.Fail(); return true; } } // special treatment for generic parameters if (formalType.IsGenericParameter) { EmitConvertToClrGeneric(il, formalType, strictnessLocal); return false; } // convert CLR type return EmitConvertObjectToClr(il, typeCode, formalType, strictnessLocal); }
/// <summary> /// Emit publically accessible stub that just calls argfull of <paramref name="function"/>. /// </summary> /// <returns><see cref="MethodInfo"/> of newly created function stub.</returns> private MethodInfo/*!*/EmitPhpFunctionPublicStub(ref TypeBuilder publicsContainer, PhpFunction/*!*/function) { Debug.Assert(function != null); Debug.Assert(function.ArgFullInfo != null, "!function.ArgFullInfo"); if (publicsContainer == null) { publicsContainer = PureAssemblyBuilder.RealModuleBuilder.DefineType( string.Format("{1}<{0}>", StringUtils.ToClsCompliantIdentifier(Path.ChangeExtension(PureAssemblyBuilder.FileName, "")), QualifiedName.Global.ToString()), TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class | TypeAttributes.SpecialName); } Type returnType; var parameterTypes = function.Signature.ToArgfullSignature(1, out returnType); parameterTypes[0] = Types.ScriptContext[0]; var mi = publicsContainer.DefineMethod(function.GetFullName(), MethodAttributes.Public | MethodAttributes.Static, returnType, parameterTypes); var il = new ILEmitter(mi); // load arguments for (int i = 0; i < parameterTypes.Length; i++) { if (function.Builder != null) mi.DefineParameter(i + 1, ParameterAttributes.None, function.Builder.ParameterBuilders[i].Name); il.Ldarg(i); } // call function.ArgFullInfo il.Emit(OpCodes.Call, function.ArgFullInfo); // .ret il.Emit(OpCodes.Ret); // return mi; }
internal static void EmitGetterStub(ILEmitter/*!*/ il, PropertyInfo/*!*/ propertyInfo, Type/*!*/ declaringType) { var getter = propertyInfo.GetGetMethod(/*false*/); if (getter == null) { il.Emit(OpCodes.Ldstr, declaringType.Name); il.Emit(OpCodes.Ldstr, "get_" + propertyInfo.Name); il.Emit(OpCodes.Call, Methods.PhpException.UndefinedMethodCalled); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ret); return; } if (getter.IsStatic) { // [ return getter() ] il.Emit(OpCodes.Call, getter); } else { // [ return ((self)<instance>).getter() ] il.Ldarg(0); il.Emit(OpCodes.Castclass, declaringType); il.Emit(OpCodes.Call, getter); } // box il.EmitBoxing(PhpTypeCodeEnum.FromType(getter.ReturnType)); // il.Emit(OpCodes.Ret); }
/// <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(); }
public void EmitStore(ILEmitter/*!*/ il) { throw new InvalidOperationException(); }
protected virtual SetterDelegate/*!*/ GenerateSetterStub() { if (Member is ClrEvent) return new SetterDelegate(EventSetter); #if SILVERLIGHT DynamicMethod stub = new DynamicMethod("<^SetterStub>", Types.Void, Types.Object_Object); /*DynamicMethod stub = new DynamicMethod("<^SetterStub>", PhpFunctionUtils.DynamicStubAttributes, CallingConventions.Standard, Types.Void, Types.Object_Object, this.declaringType.RealType, true);*/ #else DynamicMethod stub = new DynamicMethod("<^SetterStub>", PhpFunctionUtils.DynamicStubAttributes, CallingConventions.Standard, Types.Void, Types.Object_Object, this.declaringType.RealType, true); #endif #if DEBUG_DYNAMIC_STUBS // Debugging - save the generated stub to TEMP AssemblyName name = new AssemblyName("SetterStub_" + Property.FullName.ToString().Replace(':', '_')); AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Save, "C:\\Temp"); ModuleBuilder mb = ab.DefineDynamicModule(name.Name, name.Name + ".dll"); TypeBuilder tb = mb.DefineType("Stub"); MethodBuilder meb = tb.DefineMethod(DeclaringType.ToString() + "::" + Property.FullName, MethodAttributes.PrivateScope | MethodAttributes.Static, Types.Void, Types.Object_Object); ILEmitter il_dbg = new ILEmitter(meb); IndexedPlace instance2 = new IndexedPlace(PlaceHolder.Argument, 0); IndexedPlace stack = new IndexedPlace(PlaceHolder.Argument, 1); ClrProperty clr_property_dbg = Member as ClrProperty; if (clr_property_dbg != null && clr_property_dbg.HasSetter) { if (!clr_property_dbg.Setter.IsStatic) { il_dbg.Emit(OpCodes.Ldarg_0); if (declaringType.RealType.IsValueType) il_dbg.Emit(OpCodes.Unbox, declaringType.RealType); #if EMIT_VERIFIABLE_STUBS else il_dbg.Emit(OpCodes.Castclass, declaringType.RealType); #endif } il_dbg.Emit(OpCodes.Ldarg_1); EmitSetConversion(il_dbg, PhpTypeCode.Object, clr_property_dbg.Setter.GetParameters()[0].ParameterType); il_dbg.Emit(OpCodes.Call, clr_property_dbg.Setter); } il_dbg.Emit(OpCodes.Ret); tb.CreateType(); ab.Save("SetterStub_" + Property.FullName.ToString().Replace(':', '_') + ".dll"); #endif ILEmitter il = new ILEmitter(stub); ClrProperty clr_property = Member as ClrProperty; Type arg_type; if (clr_property != null) { // return error-throwing setter if the property is read-only if (!clr_property.HasSetter) return new SetterDelegate(MissingSetter); if (!clr_property.Setter.IsStatic) { ClrOverloadBuilder.EmitLoadInstance(il, IndexedPlace.ThisArg, declaringType.RealType); // il.Emit(OpCodes.Ldarg_0); // if (declaringType.RealType.IsValueType) // il.Emit(OpCodes.Unbox, declaringType.RealType); //#if EMIT_VERIFIABLE_STUBS // else // il.Emit(OpCodes.Castclass, declaringType.RealType); //#endif } il.Emit(OpCodes.Ldarg_1); arg_type = clr_property.Setter.GetParameters()[0].ParameterType; EmitSetConversion(il, PhpTypeCode.Object, arg_type); il.Emit(OpCodes.Call, clr_property.Setter); } else { ClrField clr_field = ClrField; // return error-throwing setter if the field is initonly if (clr_field.FieldInfo.IsInitOnly) return new SetterDelegate(MissingSetter); if (!clr_field.FieldInfo.IsStatic) { ClrOverloadBuilder.EmitLoadInstance(il, IndexedPlace.ThisArg, declaringType.RealType); //il.Emit(OpCodes.Ldarg_0); ////il.Emit(OpCodes.Castclass, this.declaringType.RealType); //if (declaringType.RealType.IsValueType) il.Emit(OpCodes.Unbox, declaringType.RealType); } il.Emit(OpCodes.Ldarg_1); arg_type = clr_field.FieldInfo.FieldType; EmitSetConversion(il, PhpTypeCode.Object, arg_type); il.Emit((clr_field.FieldInfo.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld), clr_field.FieldInfo); } il.Emit(OpCodes.Ret); return (SetterDelegate)stub.CreateDelegate(typeof(SetterDelegate)); }
private void EmitLoadAccessorDelegate(ILEmitter/*!*/ il, ConstructorInfo/*!*/ delegateCtor, IPlace instance, bool dynamicStub, MethodInfo accessor) { if (accessor != null) { if (instance != null) instance.EmitLoad(il); else il.Emit(OpCodes.Ldnull); if (!dynamicStub && accessor.IsVirtual) { instance.EmitLoad(il); il.Emit(OpCodes.Ldvirtftn, accessor); } else il.Emit(OpCodes.Ldftn, accessor); il.Emit(OpCodes.Newobj, delegateCtor); } else il.Emit(OpCodes.Ldnull); }
internal void EmitGetEventObject(ILEmitter/*!*/ il, IPlace/*!*/ contextPlace, IPlace instance, bool dynamicStub) { // [ ClrEventObject<handlerType>.Wrap(<SC>, <event name>, <addMethod>, <removeMethod>) ] contextPlace.EmitLoad(il); il.Emit(OpCodes.Ldstr, FullName); ConstructorInfo hook_ctor = typeof(Library.EventClass<>.HookDelegate).MakeGenericType(HandlerType). GetConstructor(Types.DelegateCtorArgs); // create delegates to the add and remove methods EmitLoadAccessorDelegate(il, hook_ctor, instance, dynamicStub, AddMethod); EmitLoadAccessorDelegate(il, hook_ctor, instance, dynamicStub, RemoveMethod); MethodInfo wrap_method = typeof(Library.EventClass<>).MakeGenericType(HandlerType).GetMethod("Wrap"); il.Emit(OpCodes.Call, wrap_method); }
/// <summary> /// Emit (stack_top dup).IsAliased = true; /// </summary> /// <param name="il"></param> private void EmitIsAliased(ILEmitter/*!*/il) { // set IsAliased to true il.Emit(OpCodes.Dup); il.Emit(OpCodes.Ldc_I4_1); il.EmitCall(OpCodes.Callvirt, Properties.PhpReference_IsAliased.GetSetMethod(), null); }
internal static void EmitSetterStub(ILEmitter/*!*/ il, PropertyInfo/*!*/ propertyInfo, Type/*!*/ declaringType) { var setter = propertyInfo.GetSetMethod(/*false*/); if (setter == null) { il.Emit(OpCodes.Ldstr, declaringType.Name); il.Emit(OpCodes.Ldstr, "set_" + propertyInfo.Name); il.Emit(OpCodes.Call, Methods.PhpException.UndefinedMethodCalled); // CoreResources.readonly_property_written il.Emit(OpCodes.Ret); return; } var parameters = setter.GetParameters(); Debug.Assert(parameters.Length == 1 /*&& parameters[0].ParameterType == Types.PhpReference[0]*/); if (!setter.IsStatic) { // [ ((self)<instance>). ] il.Ldarg(0); il.Emit(OpCodes.Castclass, declaringType); } // [ setter((object)value) ] il.Ldarg(1); il.Emit(OpCodes.Castclass, parameters[0].ParameterType); il.Emit(OpCodes.Call, setter); // il.Emit(OpCodes.Ret); }
internal void EmitHelpers() { CompilationUnit unit = this.CompilationUnit; ILEmitter il = new ILEmitter(DeclareHelperBuilder); IndexedPlace script_context_place = new IndexedPlace(PlaceHolder.Argument, 0); foreach (PhpFunction function in unit.GetDeclaredFunctions()) { if (function.IsDefinite) { CodeGenerator.EmitDeclareFunction(il, script_context_place, function); } } foreach (PhpType type in unit.GetDeclaredTypes()) { if (type.IsDefinite) { // CALL <context>.DeclareType(<type desc>, <name>); type.EmitAutoDeclareOnScriptContext(il, script_context_place); } else if (!type.IsComplete) { if (type.IncompleteClassDeclareMethodInfo != null) { // check whether base class is known at this point of execution, // if so, declare this incomplete class immediately. As PHP does. type.EmitDeclareIncompleteOnScriptContext(il, script_context_place); } } } foreach (GlobalConstant constant in unit.GetDeclaredConstants()) { if (constant.IsDefinite) { var field = constant.RealField; Debug.Assert(field != null); Debug.Assert(field.IsStatic); // CALL <context>.DeclareConstant(<name>, <value>); script_context_place.EmitLoad(il); il.Emit(OpCodes.Ldstr, constant.FullName); il.LoadLiteralBox(constant.Value); //il.Emit(OpCodes.Ldsfld, field); // const field cannot be referenced in IL il.Emit(OpCodes.Call, Methods.ScriptContext.DeclareConstant); } } il.Emit(OpCodes.Ret); }
/// <summary> /// Converts a PHP value to the given CLR type that is a generic parameter. /// </summary> private static void EmitConvertToClrGeneric(ILEmitter/*!*/ il, Type/*!*/ formalType, LocalBuilder/*!*/ strictnessLocal) { Debug.Assert(formalType.IsGenericParameter); // f...ing GenericTypeParameterBuilder will not allow us to read its attributes and constraints :( if (!(formalType is GenericTypeParameterBuilder)) { GenericParameterAttributes attrs = formalType.GenericParameterAttributes; if (Reflection.Enums.GenericParameterAttrTest(attrs, GenericParameterAttributes.NotNullableValueTypeConstraint)) { // we know that we are converting to a value type il.Ldloca(strictnessLocal); il.Emit(OpCodes.Call, Methods.ConvertToClr.TryObjectToStruct.MakeGenericMethod(formalType)); return; } Type[] constraints = formalType.GetGenericParameterConstraints(); for (int i = 0; i < constraints.Length; i++) { if (constraints[i].IsClass) { if (!constraints[i].IsArray && !typeof(Delegate).IsAssignableFrom(constraints[i])) { // we know that we are converting to a class that is not an array nor a delegate il.Ldloca(strictnessLocal); il.Emit(OpCodes.Call, Methods.ConvertToClr.TryObjectToClass.MakeGenericMethod(formalType)); return; } else break; } } } // postpone the conversion to runtime il.Ldloca(strictnessLocal); il.Emit(OpCodes.Call, Methods.Convert.TryObjectToType.MakeGenericMethod(formalType)); }
public void EmitLoad(ILEmitter/*!*/ il) { Debug.Assert(ReferenceEquals(il, codeGenerator.IL)); typeCode = expression.Emit(codeGenerator); }
protected override void EmitEntryPoint(MethodBuilder/*!*/ builder) { PureCompilationUnit unit = PureModuleBuilder.PureCompilationUnit; Debug.Assert(unit.EntryPoint != null); ILEmitter il = new ILEmitter(builder); // LOAD new RoutineDelegate(<main PHP method>); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ldftn, unit.EntryPoint.ArgLessInfo); il.Emit(OpCodes.Newobj, Constructors.RoutineDelegate); // ScriptContext.RunApplication(<main helper delegate>, null, null); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Call, Methods.ScriptContext.RunApplication); // RETURN; il.Emit(OpCodes.Ret); }
public void EmitLoadAddress(ILEmitter/*!*/ il) { throw new InvalidOperationException(); }
protected override void EmitEntryPoint(MethodBuilder/*!*/ methodBuilder) { ScriptBuilder script_builder = GetEntryScriptBuilder(); Debug.Assert(script_builder.CompilationUnit is ScriptCompilationUnit); if (script_builder == null) throw new InvalidOperationException(CoreResources.GetString("entrypoint_not_specified")); PhpSourceFile entry_file = ((ScriptCompilationUnit)script_builder.CompilationUnit).SourceUnit.SourceFile; ILEmitter il = new ILEmitter(methodBuilder); // LOAD new PhpScript.MainHelperDelegate(Default.Main); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ldftn, script_builder.MainHelper); il.Emit(OpCodes.Newobj, Constructors.MainHelperDelegate); // LOAD <source name> il.Emit(OpCodes.Ldstr, entry_file.RelativePath.ToString()); // LOAD Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) il.Emit(OpCodes.Call, Methods.Assembly.GetEntryAssembly); il.Emit(OpCodes.Callvirt, Properties.Assembly_Location.GetGetMethod()); il.Emit(OpCodes.Call, Methods.Path.GetDirectoryName); // ScriptContext.RunApplication(<main helper delegate>, <source name>, <entry assembly directory> ); il.Emit(OpCodes.Call, Methods.ScriptContext.RunApplication); // RETURN; il.Emit(OpCodes.Ret); }