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 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)); } }
/// <summary>Loads copied parameter value.</summary> public TypeSymbol EmitLoad(CodeGenerator cg) { if (_isparams) { // converts params -> PhpArray Debug.Assert(_place.TypeOpt.IsSZArray()); return(cg.ArrayToPhpArray(_place, deepcopy: true)); } else { // load parameter & dereference PhpValue TypeSymbol t; if (_place.TypeOpt == cg.CoreTypes.PhpValue) { // p.GetValue() : PhpValue _place.EmitLoadAddress(cg.Builder); t = cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.GetValue); } else { // p t = _place.EmitLoad(cg.Builder); } // make copy of given value return(cg.EmitDeepCopy(t, nullcheck: !_notNull)); } }
public TypeSymbol EmitLoad(CodeGenerator cg) { if (_isparams) { // PhpArray( {varargs[index..] ) return(cg.ArrayToPhpArray(_varargsplace, startindex: _index, deepcopy: true)); } else { var il = cg.Builder; var lbl_default = new object(); var lbl_end = new object(); var element_type = ((ArrayTypeSymbol)_varargsplace.TypeOpt).ElementType; // Template: _index < {vargags}.Length ? {varargs[_index]} : DEFAULT // _index < {varargs}.Length il.EmitIntConstant(_index); _varargsplace.EmitLoad(il); cg.EmitArrayLength(); il.EmitBranch(ILOpCode.Bge, lbl_default); // LOAD varargs[index] _varargsplace.EmitLoad(il); il.EmitIntConstant(_index); il.EmitOpCode(ILOpCode.Ldelem); cg.EmitSymbolToken(element_type, null); cg.EmitConvertToPhpValue(cg.EmitDeepCopy(element_type, nullcheck: false), 0); il.EmitBranch(ILOpCode.Br, lbl_end); // DEFAULT il.MarkLabel(lbl_default); if (_p.Initializer != null) { using (var tmpcg = new CodeGenerator(cg, _p.Routine)) { tmpcg.EmitConvertToPhpValue(_p.Initializer); } } else { cg.Emit_PhpValue_Null(); } // il.MarkLabel(lbl_end); // return(cg.CoreTypes.PhpValue); } }
/// <summary>Loads copied parameter value.</summary> public TypeSymbol EmitLoad(CodeGenerator cg) { if (_isparams) { // converts params -> PhpArray Debug.Assert(_place.TypeOpt.IsSZArray()); return(cg.ArrayToPhpArray(_place, deepcopy: true)); } else { // make copy of given value return(cg.EmitDeepCopy(_place.EmitLoad(cg.Builder), nullcheck: !_notNull)); } }
public TypeSymbol EmitLoad(ILBuilder il) { _operand.EmitLoad(il); il.EmitOpCode(ILOpCode.Call, _operator.GetCallStackBehavior()); il.EmitToken(_operator, null, DiagnosticBag.GetInstance()); return(Type); }
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); } }
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); } }
//public static MethodCallPlace/*!*/ MakePeekValuePlace(IPlace/*!*/ stack, IPlace/*!*/ index) //{ // Debug.Assert(stack != null && index != null); // return new MethodCallPlace(Methods.PhpStack.PeekValue, false, stack, index); //} //public static MethodCallPlace/*!*/ MakeValuePeekUncheckedPlace(IPlace/*!*/ stack, IPlace/*!*/ index) //{ // Debug.Assert(stack != null && index != null); // return new MethodCallPlace(Methods.PhpStack.PeekValueUnchecked, false, stack, index); //} //public static MethodCallPlace/*!*/ MakeReferencePeekPlace(IPlace/*!*/ stack, IPlace/*!*/ index) //{ // Debug.Assert(stack != null && index != null); // return new MethodCallPlace(Methods.PhpStack.PeekReference, false, stack, index); //} //public static MethodCallPlace/*!*/ MakeReferencePeekUncheckedPlace(IPlace/*!*/ stack, IPlace/*!*/ index) //{ // Debug.Assert(stack != null && index != null); // return new MethodCallPlace(Methods.PhpStack.PeekReferenceUnchecked, false, stack, index); //} public static object EmitValuePeek(ILEmitter /*!*/ il, IPlace /*!*/ stack, IPlace /*!*/ index) { Debug.Assert(il != null && stack != null && index != null); // CALL stack.PeekValue(<index+1>); stack.EmitLoad(il); index.EmitLoad(il); il.Emit(OpCodes.Call, Methods.PhpStack.PeekValue); return(typeof(object)); }
public static object EmitReferencePeekUnchecked(ILEmitter /*!*/ il, IPlace /*!*/ stack, IPlace /*!*/ index) { Debug.Assert(il != null && stack != null && index != null); // LOAD stack.PeekReferenceUnchecked(<index+1>); stack.EmitLoad(il); index.EmitLoad(il); il.Emit(OpCodes.Call, Methods.PhpStack.PeekReferenceUnchecked); return(typeof(PhpReference)); }
public TypeSymbol EmitLoad(ILBuilder il) { //if (_property.Getter == null) // throw new InvalidOperationException(); var stack = +1; var getter = _property.GetMethod; if (_holder != null) { Debug.Assert(!getter.IsStatic); _holder.EmitLoad(il); // {holder} stack -= 1; } il.EmitOpCode(getter.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call, stack); il.EmitToken(getter, null, DiagnosticBag.GetInstance()); // return(getter.ReturnType); }
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 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); } }
override protected void EmitHolder(ILBuilder il) { Debug.Assert(_field.IsStatic == (_holder == null)); if (_holder != null) { if (_holder.Type != null && _holder.Type.IsValueType) { Debug.Assert(_holder.HasAddress); _holder.EmitLoadAddress(il); } else { _holder.EmitLoad(il); } } }
internal override PhpTypeCode EmitGet(CodeGenerator/*!*/ codeGenerator, IPlace instance, bool wantRef, ConstructedType constructedType, bool runtimeVisibilityCheck) { Debug.Assert(IsStatic == (instance == null)); ILEmitter il = codeGenerator.IL; if (IsStatic) { if (runtimeVisibilityCheck) { // let the operator to check the visibility: return codeGenerator.EmitGetStaticPropertyOperator(DeclaringType, this.FullName, null, wantRef); } il.Emit(OpCodes.Ldsfld, fieldInfo); } else { instance.EmitLoad(il); il.Emit(OpCodes.Ldfld, fieldInfo); } PhpTypeCode result = ClrOverloadBuilder.EmitConvertToPhp(il, fieldInfo.FieldType/*, codeGenerator.ScriptContextPlace*/); codeGenerator.EmitReferenceDereference(ref result, wantRef); return result; }
internal override AssignmentCallback EmitSet(CodeGenerator/*!*/ codeGenerator, IPlace instance, bool isRef, ConstructedType constructedType, bool runtimeVisibilityCheck) { Debug.Assert(IsStatic == (instance == null)); //Debug.Assert(hasSetter, "TODO"); if (!hasSetter) { throw new CompilerException( new ErrorInfo( 0, "readonly_property_written", ErrorSeverity.Error), new string[]{DeclaringType.FullName, this.Name.Value} ); } // if (IsStatic) { // check the visibility at runtime by the operator: if (runtimeVisibilityCheck) return codeGenerator.EmitSetStaticPropertyOperator(DeclaringType, this.FullName, null, isRef); } else { // load target instance: instance.EmitLoad(codeGenerator.IL); } return delegate(CodeGenerator codeGen, PhpTypeCode stackTypeCode) { MethodInfo setter = this.Setter; // TODO: can we get different PhpTypeCode? ILEmitter il = codeGen.IL; PropertyDesc.EmitSetConversion(il, stackTypeCode, setter.GetParameters()[0].ParameterType); il.Emit(setter.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, setter); }; }
/// <summary> /// Emits call to specified overload. /// </summary> /// <param name="method">The overload implementor.</param> /// <param name="ps">Formal parameters of the <paramref name="method"/>.</param> /// <param name="phpParamCount">The number of PHP arguments of the overload.</param> /// <param name="scriptContext">A place where current script context should be loaded from.</param> /// <param name="rtVariables">A place where run-time variables table should be loaded from.</param> /// <param name="namingContext">A place where the naming can be load from.</param> /// <param name="classContext">A place where the class context can be load from.</param> /// <param name="optArgs">A place where the number of optional arguments should be loaded from.</param> /// <param name="selfRef">A place where reference to 'self' ($this) can be loaded from.</param> /// <param name="ignoringReturnValue">True if the return value of the function call is not used then.</param> /// <returns>A type of value stored on the top of the evaluation stack. In case of value type, it is NOT boxed.</returns> public Type EmitOverloadCall( MethodInfo method, ParameterInfo[] ps, int phpParamCount, IPlace scriptContext, IPlace rtVariables, IPlace namingContext, IPlace classContext, IPlace optArgs, IPlace selfRef, bool ignoringReturnValue) { pushedArgsCount = 0; Label overloadCallEndLabel = il.DefineLabel(); Type/*!*/return_type = method.ReturnType; // the routine used to skip the method call in case of invalid parameter cast overloadCallSkipEmitter = (ile) => { if (return_type != Types.Void) { // emit the value; because the method call was skipped, value must be loaded here if (return_type.IsValueType) ile.LoadLiteral(Activator.CreateInstance(return_type), false); // value is not boxed else ile.Emit(OpCodes.Ldnull); } // goto the end label il.Emit(OpCodes.Br, overloadCallEndLabel); }; if (scriptContext != null) { // LOAD(<context>); scriptContext.EmitLoad(il); pushedArgsCount++; } if (selfRef != null) { // LOAD(<this>); selfRef.EmitLoad(il); pushedArgsCount++; } if (rtVariables != null) { // LOAD(<defined variables>); rtVariables.EmitLoad(il); pushedArgsCount++; } if (namingContext != null) { // LOAD(<naming context>); namingContext.EmitLoad(il); pushedArgsCount++; } if (classContext != null) { // LOAD(<class_context>) classContext.EmitLoad(il); pushedArgsCount++; } // loads mandatory arguments: for (int i = 0; i < phpParamCount; i++) { EmitMandatoryArgumentLoad(i, ps[pushedArgsCount]); pushedArgsCount++; } // loads optional arguments: if (optArgs != null) { loadOptParams(this, phpParamCount, ps[ps.Length - 1], optArgs); pushedArgsCount++; } Debug.Assert(pushedArgsCount == ps.Length); // all class library functions are args-unaware => remove frame if using stack: if (stack != null) { stack.EmitLoad(il); il.Emit(OpCodes.Call, Methods.PhpStack.RemoveFrame); } // CALL STATIC <overload>(items on STACK); il.Emit(OpCodes.Call, method); // the result value is on the top of the evaluation stack //IPlace return_value = null; // stores return value an tmp. variable: //if (method.ReturnType != Types.Void) //{ // LocalBuilder loc = il.DeclareLocal(method.ReturnType); // return_value = new Place(loc); // // stores the result of a call to local: // il.Stloc(loc); //} // updates arguments passed by reference: EmitReferencesLoad(); // An argument loader can jump here if method call should be skipped. // In such a case return_value local will have default value (since locals are initialized). il.MarkLabel(overloadCallEndLabel); // [CastToFalse] or [PhpDeepCopy] if (!ignoringReturnValue) { // converts return value (deep copy, cast to false): EmitReturnValueConversion(method, ref return_type); } // free the skip emitter, to not be used incidentally again overloadCallSkipEmitter = null; return return_type; }
/// <summary> /// Emits call to specified overload. /// </summary> /// <param name="method">The overload implementor.</param> /// <param name="ps">Formal parameters of the <paramref name="method"/>.</param> /// <param name="phpParamCount">The number of PHP arguments of the overload.</param> /// <param name="scriptContext">A place where current script context should be loaded from.</param> /// <param name="rtVariables">A place where run-time variables table should be loaded from.</param> /// <param name="namingContext">A place where the naming can be load from.</param> /// <param name="classContext">A place where the class context can be load from.</param> /// <param name="optArgs">A place where the number of optional arguments should be loaded from.</param> /// <param name="selfRef">A place where reference to 'self' ($this) can be loaded from.</param> /// <param name="ignoringReturnValue">True if the return value of the function call is not used then.</param> /// <returns>A type of value stored on the top of the evaluation stack. In case of value type, it is NOT boxed.</returns> public Type EmitOverloadCall( MethodInfo method, ParameterInfo[] ps, int phpParamCount, IPlace scriptContext, IPlace rtVariables, IPlace namingContext, IPlace classContext, IPlace optArgs, IPlace selfRef, bool ignoringReturnValue) { pushedArgsCount = 0; Label overloadCallEndLabel = il.DefineLabel(); Type /*!*/ return_type = method.ReturnType; // the routine used to skip the method call in case of invalid parameter cast overloadCallSkipEmitter = (ile) => { if (return_type != Types.Void) { // emit the value; because the method call was skipped, value must be loaded here if (return_type.IsValueType) { ile.LoadLiteral(Activator.CreateInstance(return_type), false); // value is not boxed } else { ile.Emit(OpCodes.Ldnull); } } // goto the end label il.Emit(OpCodes.Br, overloadCallEndLabel); }; if (scriptContext != null) { // LOAD(<context>); scriptContext.EmitLoad(il); pushedArgsCount++; } if (selfRef != null) { // LOAD(<this>); selfRef.EmitLoad(il); pushedArgsCount++; } if (rtVariables != null) { // LOAD(<defined variables>); rtVariables.EmitLoad(il); pushedArgsCount++; } if (namingContext != null) { // LOAD(<naming context>); namingContext.EmitLoad(il); pushedArgsCount++; } if (classContext != null) { // LOAD(<class_context>) classContext.EmitLoad(il); pushedArgsCount++; } // loads mandatory arguments: for (int i = 0; i < phpParamCount; i++) { EmitMandatoryArgumentLoad(i, ps[pushedArgsCount]); pushedArgsCount++; } // loads optional arguments: if (optArgs != null) { loadOptParams(this, phpParamCount, ps[ps.Length - 1], optArgs); pushedArgsCount++; } Debug.Assert(pushedArgsCount == ps.Length); // all class library functions are args-unaware => remove frame if using stack: if (stack != null) { stack.EmitLoad(il); il.Emit(OpCodes.Call, Methods.PhpStack.RemoveFrame); } // CALL STATIC <overload>(items on STACK); il.Emit(OpCodes.Call, method); // the result value is on the top of the evaluation stack //IPlace return_value = null; // stores return value an tmp. variable: //if (method.ReturnType != Types.Void) //{ // LocalBuilder loc = il.DeclareLocal(method.ReturnType); // return_value = new Place(loc); // // stores the result of a call to local: // il.Stloc(loc); //} // updates arguments passed by reference: EmitReferencesLoad(); // An argument loader can jump here if method call should be skipped. // In such a case return_value local will have default value (since locals are initialized). il.MarkLabel(overloadCallEndLabel); // [CastToFalse] or [PhpDeepCopy] if (!ignoringReturnValue) { // converts return value (deep copy, cast to false): EmitReturnValueConversion(method, ref return_type); } // free the skip emitter, to not be used incidentally again overloadCallSkipEmitter = null; return(return_type); }
//public static MethodCallPlace/*!*/ MakePeekValuePlace(IPlace/*!*/ stack, IPlace/*!*/ index) //{ // Debug.Assert(stack != null && index != null); // return new MethodCallPlace(Methods.PhpStack.PeekValue, false, stack, index); //} //public static MethodCallPlace/*!*/ MakeValuePeekUncheckedPlace(IPlace/*!*/ stack, IPlace/*!*/ index) //{ // Debug.Assert(stack != null && index != null); // return new MethodCallPlace(Methods.PhpStack.PeekValueUnchecked, false, stack, index); //} //public static MethodCallPlace/*!*/ MakeReferencePeekPlace(IPlace/*!*/ stack, IPlace/*!*/ index) //{ // Debug.Assert(stack != null && index != null); // return new MethodCallPlace(Methods.PhpStack.PeekReference, false, stack, index); //} //public static MethodCallPlace/*!*/ MakeReferencePeekUncheckedPlace(IPlace/*!*/ stack, IPlace/*!*/ index) //{ // Debug.Assert(stack != null && index != null); // return new MethodCallPlace(Methods.PhpStack.PeekReferenceUnchecked, false, stack, index); //} public static object EmitValuePeek(ILEmitter/*!*/ il, IPlace/*!*/ stack, IPlace/*!*/ index) { Debug.Assert(il != null && stack != null && index != null); // CALL stack.PeekValue(<index+1>); stack.EmitLoad(il); index.EmitLoad(il); il.Emit(OpCodes.Call, Methods.PhpStack.PeekValue); return typeof(object); }
/// <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); }
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); }
/// <summary> /// Emits stub for one overridden/implemented/exported CLR overload. /// </summary> /// <param name="il"></param> /// <param name="scriptContextPlace"></param> /// <param name="stubParameters">The overload parameters.</param> /// <param name="stubTypeParameters">The overload type parameters.</param> /// <param name="stubReturnType">The overload return type.</param> /// <param name="target">The overriding/implementing/exporting method.</param> /// <param name="targetType">The type (perhaps constructed) that declared <paramref name="target"/>.</param> public static void EmitMethodStubBody(ILEmitter/*!*/ il, IPlace/*!*/ scriptContextPlace, ParameterInfo[]/*!*/ stubParameters, Type[]/*!*/ stubTypeParameters, Type/*!*/ stubReturnType, PhpMethod/*!*/ target, DType/*!*/ targetType) { bool stub_is_static = il.MethodBase.IsStatic; ClrStubBuilder stub_builder = new ClrStubBuilder(il, scriptContextPlace, stubParameters.Length, (stub_is_static ? 0 : 1)); if (stubParameters.Length >= target.Signature.MandatoryParamCount && stubTypeParameters.Length >= target.Signature.MandatoryGenericParamCount && (target.Properties & RoutineProperties.IsArgsAware) == 0) { // we can directly call the target argful if (!stub_is_static) il.Ldarg(FunctionBuilder.ArgThis); scriptContextPlace.EmitLoad(il); stub_builder.EmitLoadArgfullParameters(stubParameters, stubTypeParameters, target); // invoke the target (virtually if it's not static) il.Emit(stub_is_static ? OpCodes.Call : OpCodes.Callvirt, DType.MakeConstructed(target.ArgFullInfo, targetType as ConstructedType)); } else { // we have to take the argless way stub_builder.EmitLoadArglessParameters(stubParameters, stubTypeParameters, target); // invoke the target's argless // TODO: this is not behaving 100% correct, because we're losing virtual dispatch here if (stub_is_static) il.Emit(OpCodes.Ldnull); else il.Ldarg(FunctionBuilder.ArgThis); scriptContextPlace.EmitLoad(il); il.Emit(OpCodes.Ldfld, Fields.ScriptContext_Stack); il.Emit(OpCodes.Call, DType.MakeConstructed(target.ArgLessInfo, targetType as ConstructedType)); } // do not keep it on stack needlessly if (stubReturnType == Types.Void) il.Emit(OpCodes.Pop); // convert ref/out parameters back to CLR type for (int i = 0; i < stubParameters.Length; i++) { stub_builder.EmitStoreClrParameter(stubParameters[i]); } if (stubReturnType != Types.Void) { // convert the return parameter back to CLR type stub_builder.EmitConvertReturnValue( stubReturnType, target.Signature.AliasReturn ? PhpTypeCode.PhpReference : PhpTypeCode.Object); } il.Emit(OpCodes.Ret); }
/// <summary> /// Emits stub for one overridden/implemented/exported CLR overload. /// </summary> /// <param name="il"></param> /// <param name="scriptContextPlace"></param> /// <param name="stubParameters">The overload parameters.</param> /// <param name="stubTypeParameters">The overload type parameters.</param> /// <param name="stubReturnType">The overload return type.</param> /// <param name="target">The overriding/implementing/exporting method.</param> /// <param name="targetType">The type (perhaps constructed) that declared <paramref name="target"/>.</param> public static void EmitMethodStubBody(ILEmitter /*!*/ il, IPlace /*!*/ scriptContextPlace, ParameterInfo[] /*!*/ stubParameters, Type[] /*!*/ stubTypeParameters, Type /*!*/ stubReturnType, PhpMethod /*!*/ target, DType /*!*/ targetType) { bool stub_is_static = il.MethodBase.IsStatic; ClrStubBuilder stub_builder = new ClrStubBuilder(il, scriptContextPlace, stubParameters.Length, (stub_is_static ? 0 : 1)); if (stubParameters.Length >= target.Signature.MandatoryParamCount && stubTypeParameters.Length >= target.Signature.MandatoryGenericParamCount && (target.Properties & RoutineProperties.IsArgsAware) == 0) { // we can directly call the target argful if (!stub_is_static) { il.Ldarg(FunctionBuilder.ArgThis); } scriptContextPlace.EmitLoad(il); stub_builder.EmitLoadArgfullParameters(stubParameters, stubTypeParameters, target); // invoke the target (virtually if it's not static) il.Emit(stub_is_static ? OpCodes.Call : OpCodes.Callvirt, DType.MakeConstructed(target.ArgFullInfo, targetType as ConstructedType)); } else { // we have to take the argless way stub_builder.EmitLoadArglessParameters(stubParameters, stubTypeParameters, target); // invoke the target's argless // TODO: this is not behaving 100% correct, because we're losing virtual dispatch here if (stub_is_static) { il.Emit(OpCodes.Ldnull); } else { il.Ldarg(FunctionBuilder.ArgThis); } scriptContextPlace.EmitLoad(il); il.Emit(OpCodes.Ldfld, Fields.ScriptContext_Stack); il.Emit(OpCodes.Call, DType.MakeConstructed(target.ArgLessInfo, targetType as ConstructedType)); } // do not keep it on stack needlessly if (stubReturnType == Types.Void) { il.Emit(OpCodes.Pop); } // convert ref/out parameters back to CLR type for (int i = 0; i < stubParameters.Length; i++) { stub_builder.EmitStoreClrParameter(stubParameters[i]); } if (stubReturnType != Types.Void) { // convert the return parameter back to CLR type stub_builder.EmitConvertReturnValue( stubReturnType, target.Signature.AliasReturn ? PhpTypeCode.PhpReference : PhpTypeCode.Object); } il.Emit(OpCodes.Ret); }
/// <summary> /// Create and call <see cref="CallSite"/> for getting property. /// </summary> /// <param name="cg"><see cref="CodeGenerator"/>.</param> /// <param name="wantRef">Wheter <see cref="PhpReference"/> is expected as the result.</param> /// <param name="targetExpr">The expression representing the target (object).</param> /// <param name="targetObjectPlace">The place representing the target (<see cref="DObject"/>) iff <paramref name="targetExpr"/> is not provided.</param> /// <param name="targetPlace">The place representing the target (object) iff <paramref name="targetExpr"/> and <paramref name="targetObjectPlace"/> are not provided.</param> /// <param name="targetType">Type of target iff we are getting property statically.</param> /// <param name="fieldName">The name of the field. Can be null if the name is not known at compile time (indirect).</param> /// <param name="fieldNameExpr">The expression used to get field name in run time (iff <paramref name="fieldName"/> is <c>null</c>.</param> /// <param name="issetSemantics">Wheter we are only checking if the property exists. If true, no warnings are thrown during run time.</param> /// <returns>Type code of the value that is pushed onto the top of the evaluation stack.</returns> public PhpTypeCode EmitGetProperty( PHP.Core.CodeGenerator /*!*/ cg, bool wantRef, Expression targetExpr, IPlace targetObjectPlace, IPlace targetPlace, DType targetType, string fieldName, Expression fieldNameExpr, bool issetSemantics) { Debug.Assert(fieldName != null ^ fieldNameExpr != null); Debug.Assert(targetExpr != null || targetObjectPlace != null || targetPlace != null || targetType != null); // bool staticCall = (targetExpr == null && targetObjectPlace == null && targetPlace == null); // we are going to access static property bool fieldNameIsKnown = (fieldName != null); bool classContextIsKnown = (this.classContextPlace != null); // // binder flags: // Type returnType = wantRef ? Types.PhpReference[0] : Types.Object[0]; // // define the call site: // // List <Type> additionalArgs = new List <Type>(); if (!classContextIsKnown) { additionalArgs.Add(Types.DTypeDesc[0]); } if (!fieldNameIsKnown) { additionalArgs.Add(Types.String[0]); } var delegateTypeArgs = GetPropertyDelegateTypeArgs( staticCall ? Types.DTypeDesc[0] : ((targetObjectPlace != null) ? Types.DObject[0] : Types.Object[0]), // DTypeDesc of static field's declaring type || DObject if field called on DObject known at compile time || otherwise object additionalArgs.ToArray(), returnType); var delegateType = /*System.Linq.Expressions.Expression.*/ delegateBuilder.GetDelegateType(delegateTypeArgs, callSitesCount); // (J) do not create dynamic delegates in dynamic modules, so they can be referenced from non-transient assemblies // var field = DefineCallSite(cg.IL, string.Format("get{0}_{1}", wantRef ? "ref" : string.Empty, fieldName ?? "$"), delegateType, (il) => { // <LOAD> Binder.{GetProperty|GetStaticProperty}( fieldName, classContext, issetSemantics, <returnType> ) if (fieldName != null) { il.Emit(OpCodes.Ldstr, fieldName); } else { il.Emit(OpCodes.Ldnull); } if (this.classContextPlace != null) { this.classContextPlace.EmitLoad(il); } else { il.Emit(OpCodes.Ldsfld, Fields.UnknownTypeDesc.Singleton); } il.LoadBool(issetSemantics); il.Emit(OpCodes.Ldtoken, returnType); il.Emit(OpCodes.Call, Methods.GetTypeFromHandle); il.Emit(OpCodes.Call, staticCall ? Methods.Binder.StaticGetProperty : Methods.Binder.GetProperty); }); // // call the CallSite: // // <field>.Target( <field>, <targetExpr|targetType>, (classContext)?, <methodNameExpr>? ): cg.IL.Emit(OpCodes.Ldsfld, field); cg.IL.Emit(OpCodes.Ldfld, field.FieldType.GetField("Target")); cg.IL.Emit(OpCodes.Ldsfld, field); if (staticCall) { targetType.EmitLoadTypeDesc(cg, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors); } else if (targetExpr != null) { cg.ChainBuilder.Lengthen(); // for hop over -> cg.EmitBoxing(targetExpr.Emit(cg)); // prepare for operator invocation } else if (targetObjectPlace != null) { targetObjectPlace.EmitLoad(cg.IL); } else if (targetPlace != null) { targetPlace.EmitLoad(cg.IL); } else { Debug.Fail(); } if (!classContextIsKnown) { cg.EmitLoadClassContext(); } if (!fieldNameIsKnown) { cg.EmitName(fieldName /*null*/, fieldNameExpr, true, PhpTypeCode.String); } cg.MarkTransientSequencePoint(); cg.IL.Emit(OpCodes.Callvirt, delegateType.GetMethod("Invoke")); cg.MarkTransientSequencePoint(); // return(PhpTypeCodeEnum.FromType(returnType)); }
/// <summary> /// Create and call <see cref="CallSite"/> for getting property. /// </summary> /// <param name="cg"><see cref="CodeGenerator"/>.</param> /// <param name="wantRef">Wheter <see cref="PhpReference"/> is expected as the result.</param> /// <param name="targetExpr">The expression representing the target (object).</param> /// <param name="targetObjectPlace">The place representing the target (<see cref="DObject"/>) iff <paramref name="targetExpr"/> is not provided.</param> /// <param name="targetPlace">The place representing the target (object) iff <paramref name="targetExpr"/> and <paramref name="targetObjectPlace"/> are not provided.</param> /// <param name="targetType">Type of target iff we are getting property statically.</param> /// <param name="fieldName">The name of the field. Can be null if the name is not known at compile time (indirect).</param> /// <param name="fieldNameExpr">The expression used to get field name in run time (iff <paramref name="fieldName"/> is <c>null</c>.</param> /// <param name="issetSemantics">Wheter we are only checking if the property exists. If true, no warnings are thrown during run time.</param> /// <returns>Type code of the value that is pushed onto the top of the evaluation stack.</returns> public PhpTypeCode EmitGetProperty( PHP.Core.CodeGenerator/*!*/cg, bool wantRef, Expression targetExpr, IPlace targetObjectPlace, IPlace targetPlace, DType targetType, string fieldName, Expression fieldNameExpr, bool issetSemantics) { Debug.Assert(fieldName != null ^ fieldNameExpr != null); Debug.Assert(targetExpr != null || targetObjectPlace != null || targetPlace != null || targetType != null); // bool staticCall = (targetExpr == null && targetObjectPlace == null && targetPlace == null); // we are going to access static property bool fieldNameIsKnown = (fieldName != null); bool classContextIsKnown = (this.classContextPlace != null); // // binder flags: // Type returnType = wantRef ? Types.PhpReference[0] : Types.Object[0]; // // define the call site: // // List<Type> additionalArgs = new List<Type>(); if (!classContextIsKnown) additionalArgs.Add(Types.DTypeDesc[0]); if (!fieldNameIsKnown) additionalArgs.Add(Types.String[0]); var delegateTypeArgs = GetPropertyDelegateTypeArgs( staticCall ? Types.DTypeDesc[0] : ((targetObjectPlace != null) ? Types.DObject[0] : Types.Object[0]), // DTypeDesc of static field's declaring type || DObject if field called on DObject known at compile time || otherwise object additionalArgs.ToArray(), returnType); var delegateType = /*System.Linq.Expressions.Expression.*/delegateBuilder.GetDelegateType(delegateTypeArgs, callSitesCount); // (J) do not create dynamic delegates in dynamic modules, so they can be referenced from non-transient assemblies // var field = DefineCallSite(cg.IL, string.Format("get{0}_{1}", wantRef ? "ref" : string.Empty, fieldName ?? "$"), delegateType, (il) => { // <LOAD> Binder.{GetProperty|GetStaticProperty}( fieldName, classContext, issetSemantics, <returnType> ) if (fieldName != null) il.Emit(OpCodes.Ldstr, fieldName); else il.Emit(OpCodes.Ldnull); if (this.classContextPlace != null) this.classContextPlace.EmitLoad(il); else il.Emit(OpCodes.Ldsfld, Fields.UnknownTypeDesc.Singleton); il.LoadBool(issetSemantics); il.Emit(OpCodes.Ldtoken, returnType); il.Emit(OpCodes.Call, Methods.GetTypeFromHandle); il.Emit(OpCodes.Call, staticCall ? Methods.Binder.StaticGetProperty : Methods.Binder.GetProperty); }); // // call the CallSite: // // <field>.Target( <field>, <targetExpr|targetType>, (classContext)?, <methodNameExpr>? ): cg.IL.Emit(OpCodes.Ldsfld, field); cg.IL.Emit(OpCodes.Ldfld, field.FieldType.GetField("Target")); cg.IL.Emit(OpCodes.Ldsfld, field); if (staticCall) targetType.EmitLoadTypeDesc(cg, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors); else if (targetExpr != null) { cg.ChainBuilder.Lengthen(); // for hop over -> cg.EmitBoxing(targetExpr.Emit(cg)); // prepare for operator invocation } else if (targetObjectPlace != null) targetObjectPlace.EmitLoad(cg.IL); else if (targetPlace != null) targetPlace.EmitLoad(cg.IL); else Debug.Fail(); if (!classContextIsKnown) cg.EmitLoadClassContext(); if (!fieldNameIsKnown) cg.EmitName(fieldName/*null*/, fieldNameExpr, true, PhpTypeCode.String); cg.MarkTransientSequencePoint(); cg.IL.Emit(OpCodes.Callvirt, delegateType.GetMethod("Invoke")); cg.MarkTransientSequencePoint(); // return PhpTypeCodeEnum.FromType(returnType); }
/// <summary> /// Emit load <paramref name="instance"/> in top of the evaluation stack. Unwraps the value if <proxy> is used instead of <c>this</c>. /// </summary> /// <param name="codeGenerator"></param> /// <param name="instance"></param> private static void EmitLoadInstanceUnwrapped(CodeGenerator/*!*/ codeGenerator, IPlace instance) { if (instance != null) { // just detect DirectVarUse holding $this in context of Type with <proxy> property: var targetExpression = ExpressionPlace.GetExpression(instance); // pass RealObject instead of DObject when using <proxy>: // J: ASP.NET code behind fix // ArgLesses expect RealObject too if (targetExpression != null && codeGenerator.LocationStack.InMethodDecl && codeGenerator.LocationStack.PeekMethodDecl().Type.ProxyFieldInfo != null && // current type has "<proxy>" property targetExpression is DirectVarUse && ((DirectVarUse)targetExpression).VarName.IsThisVariableName && ((DirectVarUse)targetExpression).IsMemberOf == null) // we are accessing "this" instance = IndexedPlace.ThisArg; // "this" instead of "this.<proxy>" // instance.EmitLoad(codeGenerator.IL); } }
internal override AssignmentCallback EmitSet(CodeGenerator/*!*/ codeGenerator, IPlace instance, bool isRef, ConstructedType constructedType, bool runtimeVisibilityCheck) { Debug.Assert(IsStatic == (instance == null)); if (IsStatic) { // check the visibility at runtime by the operator: if (runtimeVisibilityCheck) return codeGenerator.EmitSetStaticPropertyOperator(DeclaringType, this.FullName, null, isRef); } else { // load target instance: instance.EmitLoad(codeGenerator.IL); } return delegate(CodeGenerator codeGen, PhpTypeCode stackTypeCode) { // TODO: can we get different PhpTypeCode? ILEmitter il = codeGen.IL; PropertyDesc.EmitSetConversion(il, stackTypeCode, fieldInfo.FieldType); il.Emit(IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fieldInfo); }; }
public override ITypeSymbol EmitLoadTypeInfo(CodeGenerator cg, bool throwOnError = false) { return(_place .EmitLoad(cg.Builder) .Expect(cg.CoreTypes.PhpTypeInfo)); }
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> /// Emits <c>place != null</c> expression. /// </summary> public void EmitNotNull(IPlace place) { Debug.Assert(place != null); Debug.Assert(place.TypeOpt.IsReferenceType); // {place} != null : boolean place.EmitLoad(_il); _il.EmitNullConstant(); _il.EmitOpCode(ILOpCode.Cgt_un); }
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); }
internal override PhpTypeCode EmitGet(CodeGenerator/*!*/ codeGenerator, IPlace instance, bool wantRef, ConstructedType constructedType, bool runtimeVisibilityCheck) { Debug.Assert(IsStatic == (instance == null)); ILEmitter il = codeGenerator.IL; var getter = RealProperty.GetGetMethod(); if (getter == null) throw new MissingMethodException(string.Format("'{0}.get_{1}' not implemented!", RealProperty.DeclaringType.Name, RealProperty.Name)); // <this>. if (!IsStatic) instance.EmitLoad(il); // getter() il.Emit(OpCodes.Call, getter); // handle references if (wantRef) { // make reference if (Types.PhpReference[0].IsAssignableFrom(getter.ReturnType)) { EmitIsAliased(il); } else { throw new NotImplementedException(); } // return PhpTypeCode.PhpReference; } else { // dereference if (Types.PhpReference[0].IsAssignableFrom(getter.ReturnType)) { EmitIsAliased(il); il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value); } else { il.EmitBoxing(PhpTypeCodeEnum.FromType(getter.ReturnType)); } // return PhpTypeCode.Object; } }
public static object EmitReferencePeekUnchecked(ILEmitter/*!*/ il, IPlace/*!*/ stack, IPlace/*!*/ index) { Debug.Assert(il != null && stack != null && index != null); // LOAD stack.PeekReferenceUnchecked(<index+1>); stack.EmitLoad(il); index.EmitLoad(il); il.Emit(OpCodes.Call, Methods.PhpStack.PeekReferenceUnchecked); return typeof(PhpReference); }
internal override AssignmentCallback EmitSet(CodeGenerator/*!*/ codeGenerator, IPlace instance, bool isRef, ConstructedType constructedType, bool runtimeVisibilityCheck) { ILEmitter il = codeGenerator.IL; var setter = RealProperty.GetSetMethod(); if (setter == null) throw new MissingMethodException(string.Format("'{0}.set_{1}' not implemented!", RealProperty.DeclaringType.Name, RealProperty.Name)); // <this>. if (!IsStatic) instance.EmitLoad(il); // setter() return delegate(CodeGenerator codeGen, PhpTypeCode stackTypeCode) { var parameters = setter.GetParameters(); if (isRef && parameters[0].ParameterType != Types.PhpReference[0]) { // .setter(<stack>.Value) codeGen.IL.Emit(OpCodes.Ldfld, Fields.PhpReference_Value); codeGen.IL.Emit(OpCodes.Call, setter); } else if (!isRef && parameters[0].ParameterType == Types.PhpReference[0]) { // .getter().Value = <stack> codeGen.IL.Emit(OpCodes.Call, RealProperty.GetGetMethod()); codeGen.IL.Emit(OpCodes.Stfld, Fields.PhpReference_Value); } else { // .setter(<stack>) codeGen.IL.Emit(OpCodes.Call, setter); } }; }
/// <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); }
internal override PhpTypeCode EmitGet(CodeGenerator/*!*/ codeGenerator, IPlace instance, bool wantRef, ConstructedType constructedType, bool runtimeVisibilityCheck) { Debug.Assert(IsStatic == (instance == null)); Debug.Assert(hasGetter, "TODO"); ILEmitter il = codeGenerator.IL; if (IsStatic) { if (runtimeVisibilityCheck) { // let the operator to check the visibility: return codeGenerator.EmitGetStaticPropertyOperator(DeclaringType, this.FullName, null, wantRef); } } else { instance.EmitLoad(il); } MethodInfo getter = this.Getter; il.Emit(getter.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, getter); PhpTypeCode result = ClrOverloadBuilder.EmitConvertToPhp(il, getter.ReturnType/*, codeGenerator.ScriptContextPlace*/); codeGenerator.EmitReferenceDereference(ref result, wantRef); return result; }
/// <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); }
public TypeSymbol EmitLoad(ILBuilder il) => _place.EmitLoad(il);
private PhpTypeCode EmitGetInternal(CodeGenerator/*!*/ codeGenerator, IPlace instance, bool wantRef, ConstructedType constructedType, bool runtimeVisibilityCheck, bool setAliasedFlag) { ILEmitter il = codeGenerator.IL; if (IsStatic) { if (runtimeVisibilityCheck || UpgradesVisibility) { // let the operator to check the visibility: return codeGenerator.EmitGetStaticPropertyOperator(DeclaringType, this.FullName, null, wantRef); } if (!IsAppStatic) Implementor.EmitThreadStaticInit(codeGenerator, constructedType); // retrieve field value il.Emit(OpCodes.Ldsfld, DType.MakeConstructed(RealField, constructedType)); if (wantRef) { if (setAliasedFlag) { // set IsAliased to true il.Emit(OpCodes.Dup); il.Emit(OpCodes.Ldc_I4_1); il.EmitCall(OpCodes.Callvirt, Properties.PhpReference_IsAliased.GetSetMethod(), null); } return PhpTypeCode.PhpReference; } else { il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value); return PhpTypeCode.Object; } } else { // LOAD Operators.GetObjectFieldDirect[Ref](this,this.<field>,<name>,<type desc>,[<quiet>]); codeGenerator.EmitLoadSelf(); instance.EmitLoad(il); il.Emit(OpCodes.Ldfld, DType.MakeConstructed(RealField, constructedType)); il.Emit(OpCodes.Ldstr, Name.ToString()); codeGenerator.EmitLoadClassContext(); if (wantRef) { il.Emit(OpCodes.Call, Methods.Operators.GetObjectFieldDirectRef); return PhpTypeCode.PhpReference; } else { il.LoadBool(codeGenerator.ChainBuilder.QuietRead); il.Emit(OpCodes.Call, Methods.Operators.GetObjectFieldDirect); return PhpTypeCode.Object; } } }
internal override AssignmentCallback EmitSet(CodeGenerator/*!*/ codeGenerator, IPlace instance, bool isRef, ConstructedType constructedType, bool runtimeVisibilityCheck) { Debug.Assert(IsStatic == (instance == null)); AdjustConstructedType(ref constructedType); if (IsStatic) { // check the visibility at runtime by the operator: if (runtimeVisibilityCheck || UpgradesVisibility) return codeGenerator.EmitSetStaticPropertyOperator(DeclaringType, this.FullName, null, isRef); if (isRef) { if (!IsAppStatic) Implementor.EmitThreadStaticInit(codeGenerator, constructedType); // just write the PhpReference to the field upon assignment return delegate(CodeGenerator codeGen, PhpTypeCode stackTypeCode) { codeGen.IL.Emit(OpCodes.Stsfld, DType.MakeConstructed(RealField, constructedType)); }; } else { // read the PhpReference stored in the field EmitGetInternal(codeGenerator, null, true, constructedType, false, false); // finish the assignment by writing to its Value field return delegate(CodeGenerator codeGen, PhpTypeCode stackTypeCode) { codeGen.IL.Emit(OpCodes.Stfld, Fields.PhpReference_Value); }; } } else { // direct access is possible, however, we have to be prepared for actually calling // the operator if the field proves to have been unset return delegate(CodeGenerator codeGen, PhpTypeCode stackTypeCode) { ILEmitter il = codeGen.IL; codeGen.EmitLoadSelf(); instance.EmitLoad(il); il.Emit(isRef ? OpCodes.Ldflda : OpCodes.Ldfld, DType.MakeConstructed(RealField, constructedType)); il.Emit(OpCodes.Ldstr, Name.ToString()); codeGen.EmitLoadClassContext(); if (isRef) { // CALL Operators.SetObjectFieldDirectRef(STACK,<target>,ref <field>,<field name>,<type desc>) il.Emit(OpCodes.Call, Methods.Operators.SetObjectFieldDirectRef); } else { // CALL Operators.SetObjectFieldDirect(STACK,<target>,<field>,<field name>,<type desc>) il.Emit(OpCodes.Call, Methods.Operators.SetObjectFieldDirect); } }; } }
/// <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); } }
internal override void EmitUnset(CodeGenerator/*!*/ codeGenerator, IPlace/*!*/ instance, ConstructedType constructedType, bool runtimeVisibilityCheck) { ILEmitter il = codeGenerator.IL; if (IsStatic) { // emit error (whether or not the property is visible): il.Emit(OpCodes.Ldstr, DeclaringType.FullName); il.Emit(OpCodes.Ldstr, this.FullName); codeGenerator.EmitPhpException(Methods.PhpException.StaticPropertyUnset); return; } // replace the field with a new PhpSmartReference with IsSet false instance.EmitLoad(il); il.Emit(OpCodes.Newobj, Constructors.PhpSmartReference.Void); il.Emit(OpCodes.Dup); il.LoadBool(false); il.Emit(OpCodes.Callvirt, Properties.PhpReference_IsSet.GetSetMethod()); il.Emit(OpCodes.Stfld, DType.MakeConstructed(RealField, constructedType)); }
/// <summary> /// Loads a value from a specified place on the evaluation stack and boxes it if it is of a value type. /// </summary> /// <param name="place">The place where to load a value from.</param> public void LoadBoxed(IPlace/*!*/ place) { Type type = place.PlaceType; place.EmitLoad(this); if (type.IsValueType) il.Emit(OpCodes.Box, type); }
internal TypeSymbol EmitGetProperty(IPlace holder, PropertySymbol prop) { Debug.Assert(prop.IsStatic || holder != null); Debug.Assert(prop.GetMethod != null); Debug.Assert(prop.GetMethod.ParameterCount == 0); var getter = prop.GetMethod; if (holder != null && !getter.IsStatic) { Debug.Assert(holder.TypeOpt != null); if (holder.TypeOpt.IsValueType) { holder.EmitLoadAddress(_il); } else { holder.EmitLoad(_il); } } return EmitCall(getter.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call, getter); }