示例#1
0
        void IPhpPropertySymbol.EmitInit(CodeGenerator cg)
        {
            // this.{FIELD} = {ORIGINAL_FIELD}

            var fldplace = new FieldPlace(IsStatic ? null : new ArgPlace(ContainingType, 0), this, cg.Module);

            fldplace.EmitStorePrepare(cg.Builder);
            cg.EmitConvert(EmitLoadSourceValue(cg), 0, this.Type);
            fldplace.EmitStore(cg.Builder);
        }
        void EmitTraitImplementations(Emit.PEModuleBuilder module)
        {
            foreach (var t in TraitUses)
            {
                foreach (var m in t.GetMembers().OfType <SynthesizedMethodSymbol>())
                {
                    Debug.Assert(m.ForwardedCall != null);

                    module.SetMethodBody(m, MethodGenerator.GenerateMethodBody(module, m, il =>
                    {
                        IPlace thisPlace          = null;
                        IPlace traitInstancePlace = null;
                        IPlace ctxPlace;

                        if (m.IsStatic)
                        {
                            // Template: return TRAIT.method(...)
                            Debug.Assert(SpecialParameterSymbol.IsContextParameter(m.Parameters[0]));
                            ctxPlace = new ParamPlace(m.Parameters[0]);
                        }
                        else
                        {
                            // Template: return this.<>trait.method(...)
                            thisPlace          = new ArgPlace(this, 0);                                   // this
                            ctxPlace           = new FieldPlace(thisPlace, this.ContextStore, module);    // this.<ctx>
                            traitInstancePlace = new FieldPlace(thisPlace, t.TraitInstanceField, module); // this.<>trait
                        }

                        using (var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace)
                        {
                            CallerType = this,
                        })
                        {
                            var forwarded_type = cg.EmitForwardCall(m.ForwardedCall, m, thisPlaceExplicit: traitInstancePlace);
                            var target_type    = m.ReturnType;

                            cg.EmitConvert(forwarded_type, 0, target_type); // always (forwarded_type === target_type)
                            cg.EmitRet(target_type);
                        }
                    }, null, DiagnosticBag.GetInstance(), false));
                    module.SynthesizedManager.AddMethod(this, m);

                    // ghost stubs: // TODO: resolve this already in SourceTypeSymbol.GetMembers(), now it does not get overloaded properly
                    var ps = m.Parameters;
                    for (int i = 0; i < ps.Length; i++)
                    {
                        if (ps[i].HasUnmappedDefaultValue)  // => ConstantValue couldn't be resolved for optional parameter
                        {
                            // create ghost stub foo(p0, .. pi-1) => foo(p0, .. , pN)
                            GhostMethodBuilder.CreateGhostOverload(m, module, DiagnosticBag.GetInstance(), i);
                        }
                    }
                }
            }
        }
        static void EmitTraitCtorInit(CodeGenerator cg, SynthesizedPhpTraitCtorSymbol tctor)
        {
            var il = cg.Builder;

            // this.<>this = @this
            var thisFieldPlace = new FieldPlace(cg.ThisPlaceOpt, tctor.ContainingType.RealThisField, module: cg.Module);

            thisFieldPlace.EmitStorePrepare(il);
            tctor.ThisParameter.EmitLoad(il);
            thisFieldPlace.EmitStore(il);
        }
示例#4
0
        //public FieldPlace InsideFieldPlace(int pos) {
        //    return FieldPlaces.FirstOrDefault(fld => fld.OutPutTextStart <= pos && pos <= fld.OutPutTextEnd);
        //}

        public void InsideFieldPlace2(int pos, out FieldPlace fp, out int fldInd, out int fldsInd)
        {
            fp = FieldPlaces.FirstOrDefault(fp1 => fp1.OutPutTextStart <= pos && pos <= fp1.OutPutTextEnd);
            if (fp == null)
            {
                fldInd = -1; fldsInd = -1; return;
            }
            fldsInd = FieldPlaces.IndexOf(fp);
            var fn = fp.FldName;

            fldInd = FieldPlaces.Where(fp1 => fp1.FldName == fn).ToList().IndexOf(fp);
        }
示例#5
0
        /// <summary>
        /// Emit body of enumeration of app-wide global constants.
        /// </summary>
        internal void CreateEnumerateConstantsSymbol(DiagnosticBag diagnostic)
        {
            var method = this.ScriptType.EnumerateConstantsSymbol;
            var consts = this.Compilation.GlobalSemantics.GetExportedConstants().Cast <FieldSymbol>();   // TODO: PropertySymbol

            // void (Action<string, RuntimeMethodHandle> callback)
            var body = MethodGenerator.GenerateMethodBody(this, method,
                                                          (il) =>
            {
                var cg = new CodeGenerator(il, this, diagnostic, this.Compilation.Options.OptimizationLevel, false, this.ScriptType, null, null);

                var action_string_method = method.Parameters[0].Type;
                Debug.Assert(action_string_method.Name == "Action");
                var invoke = action_string_method.DelegateInvokeMethod();
                Debug.Assert(invoke != null);

                foreach (var c in consts)
                {
                    Debug.Assert(c.IsConst || (c.IsStatic && c.IsReadOnly));

                    // callback.Invoke(c.Name, c.Value, c.IgnoreCase)
                    il.EmitLoadArgumentOpcode(0);

                    // string : name
                    il.EmitStringConstant(c.MetadataName);

                    // PhpValue : value
                    TypeSymbol consttype;
                    var constvalue = c.GetConstantValue(false);
                    if (constvalue != null)
                    {
                        consttype = cg.EmitLoadConstant(constvalue.Value, cg.CoreTypes.PhpValue);
                    }
                    else
                    {
                        consttype = new FieldPlace(null, c, this).EmitLoad(il);
                    }
                    cg.EmitConvertToPhpValue(consttype, 0);

                    // bool : ignore case
                    il.EmitBoolConstant(false);

                    // Invoke(...)
                    il.EmitCall(this, diagnostic, ILOpCode.Callvirt, invoke);
                }

                //
                il.EmitRet(true);
            },
                                                          null, diagnostic, false);

            SetMethodBody(method, body);
        }
示例#6
0
        void EmitPhpCtors(ImmutableArray <MethodSymbol> instancectors, Emit.PEModuleBuilder module, DiagnosticBag diagnostics)
        {
            foreach (SynthesizedPhpCtorSymbol ctor in instancectors)
            {
                module.SetMethodBody(ctor, MethodGenerator.GenerateMethodBody(module, ctor, il =>
                {
                    Debug.Assert(SpecialParameterSymbol.IsContextParameter(ctor.Parameters[0]));

                    var cg = new CodeGenerator(il, module, diagnostics, OptimizationLevel.Release, false, this, new ParamPlace(ctor.Parameters[0]), new ArgPlace(this, 0));

                    Debug.Assert(ctor.BaseCtor != null);

                    // base..ctor or this..ctor
                    cg.EmitPop(cg.EmitThisCall(ctor.BaseCtor, ctor));

                    if (ctor.PhpConstructor == null)
                    {
                        // initialize <ctx> field, if field is declared within this type
                        var ctxField = this.ContextStore;
                        if (ctxField != null && object.ReferenceEquals((object)ctxField.ContainingType, this))
                        {
                            var ctxFieldPlace = new FieldPlace(cg.ThisPlaceOpt, ctxField);

                            // Debug.Assert(<ctx> != null)
                            cg.EmitDebugAssertNotNull(cg.ContextPlaceOpt, "Context cannot be null.");

                            // <this>.<ctx> = <ctx>
                            ctxFieldPlace.EmitStorePrepare(il);
                            cg.EmitLoadContext();
                            ctxFieldPlace.EmitStore(il);
                        }

                        // initialize class fields
                        foreach (var fld in this.EnsureMembers().OfType <SourceFieldSymbol>().Where(fld => !fld.RequiresHolder && !fld.IsStatic && !fld.IsConst))
                        {
                            fld.EmitInit(cg);
                        }
                    }
                    else
                    {
                        Debug.Assert(ctor.BaseCtor.ContainingType == this);

                        // this.__construct
                        cg.EmitPop(cg.EmitThisCall(ctor.PhpConstructor, ctor));
                    }

                    // ret
                    Debug.Assert(ctor.ReturnsVoid);
                    cg.EmitRet(ctor.ReturnType);
                }, null, diagnostics, false));
            }
        }
示例#7
0
        internal void EmitInit(Emit.PEModuleBuilder module)
        {
            var cctor = module.GetStaticCtorBuilder(_file);
            var field = new FieldPlace(null, this.EnsureRoutineInfoField(module));

            // {RoutineInfoField} = RoutineInfo.CreateUserRoutine(name, handle)
            field.EmitStorePrepare(cctor);

            cctor.EmitStringConstant(this.QualifiedName.ToString());
            cctor.EmitLoadToken(module, DiagnosticBag.GetInstance(), this, null);
            cctor.EmitCall(module, DiagnosticBag.GetInstance(), System.Reflection.Metadata.ILOpCode.Call, module.Compilation.CoreMethods.Reflection.CreateUserRoutine_string_RuntimeMethodHandle);

            field.EmitStore(cctor);
        }
        internal void EmitInit(PEModuleBuilder module)
        {
            var cctor = module.GetStaticCtorBuilder(_container);
            var field = new FieldPlace(null, this.EnsureRoutineInfoField(module), module);

            var ct = module.Compilation.CoreTypes;

            // {RoutineInfoField} = new PhpAnonymousRoutineInfo(name, handle)
            field.EmitStorePrepare(cctor);

            cctor.EmitStringConstant(this.MetadataName);
            cctor.EmitLoadToken(module, DiagnosticBag.GetInstance(), this, null);
            cctor.EmitCall(module, DiagnosticBag.GetInstance(), ILOpCode.Call, ct.Operators.Method("AnonymousRoutine", ct.String, ct.RuntimeMethodHandle));

            field.EmitStore(cctor);
        }
示例#9
0
        internal void EmitInit(CodeGenerator cg)
        {
            var fldplace = new FieldPlace(IsStatic ? null : new ArgPlace(ContainingType, 0), this);

            if (this.Initializer != null)
            {
                // fld = <initializer>
                fldplace.EmitStorePrepare(cg.Builder);
                cg.EmitConvert(this.Initializer, this.Type);
                fldplace.EmitStore(cg.Builder);
            }
            else
            {
                // fld = default(type)
                cg.EmitInitializePlace(fldplace);
            }
        }
示例#10
0
        private void Process(FieldPlace fp, int selStart, int selLen, char keyChar, string text)
        {
            int    fldPos = selStart - fp.OutPutTextStart;
            string value  = (string)fp.FldValue.Clone();

            value = value.Remove(fldPos, selLen);
            if (keyChar == '\b')
            {
            }                        // nothing to do
            else
            {
                value = value.Insert(fldPos, keyChar.ToString());
            }
            var fld = Fields.FirstOrDefault(f => f.Name == fp.FldName);

            fld.Value = value;
            FieldPlaces.Where(fpl => fpl.FldName == fld.Name).ToList().ForEach(fpl => fpl.FldValue = value);
        }
示例#11
0
        void EmitPhpNew(SynthesizedPhpNewMethodSymbol phpnew, Emit.PEModuleBuilder module)
        {
            if (phpnew == null)
            {
                return;                 // static class
            }
            module.SetMethodBody(phpnew, MethodGenerator.GenerateMethodBody(module, phpnew, il =>
            {
                Debug.Assert(SpecialParameterSymbol.IsContextParameter(phpnew.Parameters[0]));

                var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), OptimizationLevel.Release, false, this, new ParamPlace(phpnew.Parameters[0]), new ArgPlace(this, 0));

                // initialize <ctx> field,
                // if field is declared within this type
                var ctxField = this.ContextField;
                if (ctxField != null && object.ReferenceEquals(ctxField.ContainingType, this))
                {
                    var ctxFieldPlace = new FieldPlace(cg.ThisPlaceOpt, ctxField);

                    // Debug.Assert(<ctx> != null)
                    cg.EmitDebugAssertNotNull(cg.ContextPlaceOpt, "Context cannot be null.");

                    // <this>.<ctx> = <ctx>
                    ctxFieldPlace.EmitStorePrepare(il);
                    cg.EmitLoadContext();
                    ctxFieldPlace.EmitStore(il);
                }

                // initialize class fields,
                // default(PhpValue) is not a valid value, its TypeTable must not be null
                foreach (var fld in this.GetFieldsToEmit().OfType <SourceFieldSymbol>().Where(fld => !fld.IsStatic && !fld.IsConst))
                {
                    fld.EmitInit(cg);
                }

                // base..phpnew ?? base..ctor
                var basenew = phpnew.BasePhpNew;
                Debug.Assert(basenew != null);
                cg.EmitPop(cg.EmitThisCall(basenew, phpnew));

                Debug.Assert(phpnew.ReturnsVoid);
                cg.EmitRet(true);
            }, null, DiagnosticBag.GetInstance(), false));
        }
示例#12
0
        void IPhpPropertySymbol.EmitInit(CodeGenerator cg)
        {
            // skip initialization if we can use default
            if (this.Initializer == null &&
                this.OverridenDefinition == null &&
                !this.Type.Is_PhpAlias())
            {
                // does not have to be explicitly initialized
                // default is ok
                return;
            }

            //
            cg.TypeRefContext = EnsureTypeRefContext();

            //
            var fldplace = new FieldPlace(IsStatic ? null : new ArgPlace(ContainingType, 0), this, cg.Module);

            // fld = <initializer>
            fldplace.EmitStorePrepare(cg.Builder);

            if (this.Initializer != null)
            {
                cg.EmitSequencePoint(this.Initializer.PhpSyntax);

                // INITIALIZER
                cg.EmitConvert(this.Initializer, fldplace.Type);

                if (cg.EmitPdbSequencePoints)
                {
                    cg.Builder.EmitOpCode(ILOpCode.Nop);
                }
            }
            else
            {
                // default
                cg.EmitLoadDefault(fldplace.Type);
            }

            fldplace.EmitStore(cg.Builder);

            //
            cg.TypeRefContext = null;
        }
示例#13
0
        void EmitTraitImplementations(Emit.PEModuleBuilder module)
        {
            foreach (var t in TraitUses)
            {
                foreach (var m in t.GetMembers().OfType <SynthesizedMethodSymbol>())
                {
                    Debug.Assert(m.ForwardedCall != null);

                    module.SetMethodBody(m, MethodGenerator.GenerateMethodBody(module, m, il =>
                    {
                        IPlace thisPlace          = null;
                        IPlace traitInstancePlace = null;
                        IPlace ctxPlace;

                        if (m.IsStatic)
                        {
                            // Template: return TRAIT.method(...)
                            Debug.Assert(SpecialParameterSymbol.IsContextParameter(m.Parameters[0]));
                            ctxPlace = new ParamPlace(m.Parameters[0]);
                        }
                        else
                        {
                            // Template: return this.<>trait.method(...)
                            thisPlace          = new ArgPlace(this, 0);                                   // this
                            ctxPlace           = new FieldPlace(thisPlace, this.ContextStore, module);    // this.<ctx>
                            traitInstancePlace = new FieldPlace(thisPlace, t.TraitInstanceField, module); // this.<>trait
                        }

                        using (var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace)
                        {
                            CallerType = this,
                        })
                        {
                            var forwarded_type = cg.EmitForwardCall(m.ForwardedCall, m, thisPlaceExplicit: traitInstancePlace);
                            var target_type    = m.ReturnType;

                            cg.EmitConvert(forwarded_type, 0, target_type); // always (forwarded_type === target_type)
                            cg.EmitRet(target_type);
                        }
                    }, null, DiagnosticBag.GetInstance(), false));
                    module.SynthesizedManager.AddMethod(this, m);
                }
            }
        }
示例#14
0
        internal override void EmitInit(CodeGenerator cg)
        {
            // variable holder class
            _holder = cg.Factory.DeclareStaticLocalHolder(this.Name, (TypeSymbol)this.Variable.Type);

            // local with its instance
            var symbol = new SynthesizedLocalSymbol(cg.Routine, this.Name, _holder);
            var loc    = cg.Builder.LocalSlotManager.DeclareLocal(_holder, symbol, symbol.Name, SynthesizedLocalKind.OptimizerTemp, LocalDebugId.None, 0, LocalSlotConstraints.None, false, default(ImmutableArray <TypedConstant>), false);

            _holderPlace = new LocalPlace(loc);

            // place = holder.value
            _place = new FieldPlace(_holderPlace, _holder.ValueField);

            if (cg.HasUnoptimizedLocals)
            {
                // TODO reference to <locals>
            }
        }
        void IPhpPropertySymbol.EmitInit(CodeGenerator cg)
        {
            cg.TypeRefContext = EnsureTypeRefContext();

            //

            var fldplace = new FieldPlace(IsStatic ? null : new ArgPlace(ContainingType, 0), this, cg.Module);

            if (this.Initializer != null)
            {
                // fld = <initializer>
                fldplace.EmitStorePrepare(cg.Builder);
                cg.EmitConvert(this.Initializer, this.Type);
                fldplace.EmitStore(cg.Builder);
            }
            else
            {
                // fld = default(type)
                cg.EmitInitializePlace(fldplace);
            }

            //
            cg.TypeRefContext = null;
        }
示例#16
0
        public void SelectionInsideFieldPlace(int start, int selLength, out FieldPlace fp, out int fldInd, out int fldsInd)
        {
            // check start and end points are both inside fieldplace
            int end = start + selLength;

            FieldPlace fp1; int fldInd1; int fldsInd1;
            FieldPlace fp2; int fldInd2; int fldsInd2;

            InsideFieldPlace2(start, out fp1, out fldInd1, out fldsInd1);
            InsideFieldPlace2(start, out fp2, out fldInd2, out fldsInd2);

            if (Object.ReferenceEquals(fp1, fp2))
            {
                fp      = fp1;
                fldInd  = fldInd1;
                fldsInd = fldsInd1;
            }
            else
            {
                fp      = null;
                fldInd  = -1;
                fldsInd = -1;
            }
        }
示例#17
0
        void EmitInit(Emit.PEModuleBuilder module, DiagnosticBag diagnostic, PhpCompilation compilation, SynthesizedStaticLocHolder holder, BoundExpression initializer)
        {
            var requiresContext = initializer != null && initializer.RequiresContext;

            if (requiresContext)
            {
                // emit Init only if it needs Context

                holder.EmitInit(module, (il) =>
                {
                    var cg = new CodeGenerator(il, module, diagnostic, compilation.Options.OptimizationLevel, false,
                                               holder.ContainingType, new ArgPlace(compilation.CoreTypes.Context, 1), new ArgPlace(holder, 0));

                    var valuePlace = new FieldPlace(cg.ThisPlaceOpt, holder.ValueField, module);

                    // Template: this.value = <initilizer>;

                    valuePlace.EmitStorePrepare(il);
                    cg.EmitConvert(initializer, valuePlace.TypeOpt);
                    valuePlace.EmitStore(il);

                    //
                    il.EmitRet(true);
                });
            }

            // default .ctor
            holder.EmitCtor(module, (il) =>
            {
                // base..ctor()
                var ctor = holder.BaseType.InstanceConstructors.Single();
                il.EmitLoadArgumentOpcode(0);                         // this
                il.EmitCall(module, diagnostic, ILOpCode.Call, ctor); // .ctor()

                if (!requiresContext)
                {
                    // emit default value only if it won't be initialized by Init above

                    var cg = new CodeGenerator(il, module, diagnostic, compilation.Options.OptimizationLevel, false,
                                               holder.ContainingType, null, new ArgPlace(holder, 0));

                    var valuePlace = new FieldPlace(cg.ThisPlaceOpt, holder.ValueField, module);

                    // Template: this.value = default(T);

                    valuePlace.EmitStorePrepare(il);
                    if (initializer != null)
                    {
                        cg.EmitConvert(initializer, valuePlace.TypeOpt);
                    }
                    else
                    {
                        cg.EmitLoadDefault(valuePlace.TypeOpt, 0);
                    }
                    valuePlace.EmitStore(il);
                }

                //
                il.EmitRet(true);
            });
        }
示例#18
0
        internal void EmitGetCurrent(CodeGenerator cg, BoundReferenceExpression valueVar, BoundReferenceExpression keyVar)
        {
            Debug.Assert(_enumeratorLoc.IsValid);

            // NOTE: PHP writes first to {valueVar} then to {keyVar}

            if (_currentValue != null && _currentKey != null)
            {
                // special PhpArray enumerator

                cg.EmitSequencePoint(valueVar.PhpSyntax);
                var valueTarget = valueVar.BindPlace(cg);
                valueTarget.EmitStorePrepare(cg);
                valueTarget.EmitStore(cg, cg.EmitGetProperty(_enumeratorLoc, _currentValue));

                if (keyVar != null)
                {
                    cg.EmitSequencePoint(keyVar.PhpSyntax);
                    var keyTarget = keyVar.BindPlace(cg);
                    keyTarget.EmitStorePrepare(cg);
                    keyTarget.EmitStore(cg, cg.EmitGetProperty(_enumeratorLoc, _currentKey));
                }
            }
            else
            {
                Debug.Assert(_current != null);
                Debug.Assert(_current.GetMethod != null);

                var valuetype = _current.GetMethod.ReturnType;

                // ValueTuple (key, value)
                // TODO: KeyValuePair<key, value> // the same
                if (valuetype.Name == "ValueTuple" && valuetype.IsValueType && ((NamedTypeSymbol)valuetype).Arity == 2)
                {
                    // tmp = current;
                    var tmp = cg.GetTemporaryLocal(valuetype);
                    cg.EmitGetProperty(_enumeratorLoc, _current);
                    cg.Builder.EmitLocalStore(tmp);

                    // TODO: ValueTuple Helper
                    var item1 = valuetype.GetMembers("Item1").Single() as FieldSymbol;
                    var item2 = valuetype.GetMembers("Item2").Single() as FieldSymbol;

                    var item1place = new FieldPlace(new LocalPlace(tmp), item1, cg.Module);
                    var item2place = new FieldPlace(new LocalPlace(tmp), item2, cg.Module);

                    // value = tmp.Item2;
                    cg.EmitSequencePoint(valueVar.PhpSyntax);
                    var valueTarget = valueVar.BindPlace(cg);
                    valueTarget.EmitStorePrepare(cg);
                    valueTarget.EmitStore(cg, item2place.EmitLoad(cg.Builder));

                    // key = tmp.Item1;
                    if (keyVar != null)
                    {
                        cg.EmitSequencePoint(keyVar.PhpSyntax);
                        var keyTarget = keyVar.BindPlace(cg);
                        keyTarget.EmitStorePrepare(cg);
                        keyTarget.EmitStore(cg, item1place.EmitLoad(cg.Builder));
                    }

                    //
                    cg.ReturnTemporaryLocal(tmp);
                }
                // just a value
                else
                {
                    cg.EmitSequencePoint(valueVar.PhpSyntax);
                    var valueTarget = valueVar.BindPlace(cg);
                    valueTarget.EmitStorePrepare(cg);
                    var t = cg.EmitGetProperty(_enumeratorLoc, _current);  // TOOD: PhpValue.FromClr
                    valueTarget.EmitStore(cg, t);

                    if (keyVar != null)
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
        }
        /// <summary>
        /// Emits initializers of all parameter's non-standard default values (such as PhpArray)
        /// within the type's static .cctor
        /// </summary>
        private void EmitParametersDefaultValue(PEModuleBuilder module, DiagnosticBag diagnostics)
        {
            foreach (var p in this.SourceParameters)
            {
                var field = p.DefaultValueField;
                if (field is SynthesizedFieldSymbol)
                {
                    Debug.Assert(p.Initializer != null);

                    module.SynthesizedManager.AddField(field.ContainingType, field);

                    // .cctor() {

                    var cctor = module.GetStaticCtorBuilder(field.ContainingType);
                    lock (cctor)
                    {
                        SynthesizedMethodSymbol func = null;

                        if (field.Type.Is_Func_Context_PhpValue())  // Func<Context, PhpValue>
                        {
                            // private static PhpValue func(Context) => INITIALIZER()
                            func = new SynthesizedMethodSymbol(field.ContainingType, field.Name + "Func", isstatic: true, isvirtual: false, DeclaringCompilation.CoreTypes.PhpValue, isfinal: true);
                            func.SetParameters(new SynthesizedParameterSymbol(func, DeclaringCompilation.CoreTypes.Context, 0, RefKind.None, name: SpecialParameterSymbol.ContextName));

                            //
                            module.SetMethodBody(func, MethodGenerator.GenerateMethodBody(module, func, il =>
                            {
                                var ctxPlace = new ArgPlace(DeclaringCompilation.CoreTypes.Context, 0);
                                var cg       = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, field.ContainingType, ctxPlace, null)
                                {
                                    CallerType                = ContainingType,
                                    ContainingFile            = ContainingFile,
                                    IsInCachedArrayExpression = true,   // do not cache array initializers twice
                                };

                                // return {Initializer}
                                cg.EmitConvert(p.Initializer, func.ReturnType);
                                cg.EmitRet(func.ReturnType);
                            }, null, diagnostics, false));

                            module.SynthesizedManager.AddMethod(func.ContainingType, func);
                        }

                        using (var cg = new CodeGenerator(cctor, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, field.ContainingType,
                                                          contextPlace: null,
                                                          thisPlace: null)
                        {
                            CallerType = ContainingType,
                            ContainingFile = ContainingFile,
                            IsInCachedArrayExpression = true,   // do not cache array initializers twice
                        })
                        {
                            var fldplace = new FieldPlace(null, field, module);
                            fldplace.EmitStorePrepare(cg.Builder);
                            if (func == null)
                            {
                                // {field} = {Initializer};
                                cg.EmitConvert(p.Initializer, field.Type);
                            }
                            else
                            {
                                MethodSymbol funcsymbol = func;

                                // bind func in case it is generic
                                if (func.ContainingType is SourceTraitTypeSymbol st)
                                {
                                    funcsymbol = func.AsMember(st.Construct(st.TypeArguments));
                                }

                                // Func<,>(object @object, IntPtr method)
                                var func_ctor = ((NamedTypeSymbol)field.Type).InstanceConstructors.Single(m =>
                                                                                                          m.ParameterCount == 2 &&
                                                                                                          m.Parameters[0].Type.SpecialType == SpecialType.System_Object &&
                                                                                                          m.Parameters[1].Type.SpecialType == SpecialType.System_IntPtr
                                                                                                          );

                                // {field} = new Func<Context, PhpValue>( {func} )
                                cg.Builder.EmitNullConstant();                                                                         // null
                                cg.EmitOpCode(ILOpCode.Ldftn);                                                                         // method
                                cg.Builder.EmitToken(module.Translate(funcsymbol, null, cg.Diagnostics, false), null, cg.Diagnostics); // !! needDeclaration: false
                                cg.EmitCall(ILOpCode.Newobj, func_ctor);
                            }
                            fldplace.EmitStore(cg.Builder);
                        }
                    }
                }
            }
        }
        internal void EmitGetCurrent(CodeGenerator cg, BoundReferenceExpression valueVar, BoundReferenceExpression keyVar)
        {
            Debug.Assert(_enumeratorLoc.IsValid);

            // NOTE: PHP writes first to {valueVar} then to {keyVar}

            if (_currentValue != null && _currentKey != null)
            {
                // PhpArray enumerator or Iterator

                cg.EmitSequencePoint(valueVar.PhpSyntax);
                valueVar.BindPlace(cg).EmitStore(cg, () => EmitGetCurrentHelper(cg), valueVar.Access);

                if (keyVar != null)
                {
                    cg.EmitSequencePoint(keyVar.PhpSyntax);
                    keyVar.BindPlace(cg).EmitStore(cg, () => VariableReferenceExtensions.EmitLoadValue(cg, _currentKey, _enumeratorLoc), keyVar.Access);
                }
            }
            else
            {
                Debug.Assert(_current != null);

                var valuetype = _current.ReturnType;

                // ValueTuple (key, value)
                // TODO: KeyValuePair<key, value> // the same
                if (valuetype.Name == "ValueTuple" && valuetype.IsValueType && ((NamedTypeSymbol)valuetype).Arity == 2)
                {
                    // tmp = current;
                    var tmp = cg.GetTemporaryLocal(valuetype);
                    VariableReferenceExtensions.EmitLoadValue(cg, _current, _enumeratorLoc);
                    cg.Builder.EmitLocalStore(tmp);

                    // TODO: ValueTuple Helper
                    var item1 = valuetype.GetMembers("Item1").Single() as FieldSymbol;
                    var item2 = valuetype.GetMembers("Item2").Single() as FieldSymbol;

                    var item1place = new FieldPlace(new LocalPlace(tmp), item1, cg.Module);
                    var item2place = new FieldPlace(new LocalPlace(tmp), item2, cg.Module);

                    // value = tmp.Item2;
                    cg.EmitSequencePoint(valueVar.PhpSyntax);
                    valueVar.BindPlace(cg).EmitStore(cg, item2place, valueVar.Access);

                    // key = tmp.Item1;
                    if (keyVar != null)
                    {
                        cg.EmitSequencePoint(keyVar.PhpSyntax);
                        keyVar.BindPlace(cg).EmitStore(cg, item1place, keyVar.Access);
                    }

                    //
                    cg.ReturnTemporaryLocal(tmp);
                }
                // just a value
                else
                {
                    cg.EmitSequencePoint(valueVar.PhpSyntax);
                    valueVar.BindPlace(cg).EmitStore(cg, () => EmitGetCurrentHelper(cg), valueVar.Access);

                    if (keyVar != null)
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
        }
        void EmitDisposable(Emit.PEModuleBuilder module, DiagnosticBag diagnostics)
        {
            var __destruct = TryGetDestruct();

            if (__destruct == null ||
                IsAlreadyImplemented(__destruct) ||
                IsAlreadyImplemented(DeclaringCompilation.GetSpecialType(SpecialType.System_IDisposable)))
            {
                // already implemented in a base class
                return;
            }

            //
            // IDisposable.Dispose()
            //
            var dispose = new SynthesizedMethodSymbol(this, "IDisposable.Dispose", false, true, DeclaringCompilation.GetSpecialType(SpecialType.System_Void), isfinal: true)
            {
                ExplicitOverride = (MethodSymbol)DeclaringCompilation.GetSpecialTypeMember(SpecialMember.System_IDisposable__Dispose),
                ForwardedCall    = __destruct,
            };

            module.SetMethodBody(dispose, MethodGenerator.GenerateMethodBody(module, dispose, il =>
            {
                var thisPlace = new ArgPlace(this, 0);
                var ctxPlace  = new FieldPlace(thisPlace, this.ContextStore, module);
                var cg        = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace)
                {
                    CallerType = this,
                };

                // private bool <>b_disposed;
                var disposedField = cg.Module.SynthesizedManager.GetOrCreateSynthesizedField(this, DeclaringCompilation.CoreTypes.Boolean, WellKnownPchpNames.SynthesizedDisposedFieldName, Accessibility.Private, false, false, false);
                var disposedPlace = new FieldPlace(thisPlace, disposedField, cg.Module);

                // if (<>b_disposed) return;
                var lblContinue = new object();
                disposedPlace.EmitLoad(cg.Builder);
                cg.Builder.EmitBranch(ILOpCode.Brfalse, lblContinue);
                cg.EmitRet(DeclaringCompilation.CoreTypes.Void);
                cg.Builder.MarkLabel(lblContinue);

                // <>b_disposed = true;
                disposedPlace.EmitStorePrepare(cg.Builder);
                cg.Builder.EmitBoolConstant(true);
                disposedPlace.EmitStore(cg.Builder);

                // __destruct()
                cg.EmitPop(cg.EmitForwardCall(__destruct, dispose, callvirt: true));

                // .ret
                cg.EmitRet(DeclaringCompilation.GetSpecialType(SpecialType.System_Void));
            }, null, diagnostics, false));

            module.SynthesizedManager.AddMethod(this, dispose);

            ////
            //// Finalize()
            ////
            //var finalize = new SynthesizedFinalizeSymbol(this)
            //{
            //    ForwardedCall = dispose,
            //};

            //Debug.Assert(finalize.OverriddenMethod != null);

            //module.SetMethodBody(finalize, MethodGenerator.GenerateMethodBody(module, finalize, il =>
            //{
            //    var thisPlace = new ArgPlace(this, 0);
            //    var ctxPlace = new FieldPlace(thisPlace, this.ContextStore, module);
            //    var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace)
            //    {
            //        CallerType = this,
            //    };

            //    //
            //    cg.Builder.OpenLocalScope(ScopeType.TryCatchFinally);
            //    // try {
            //    cg.Builder.OpenLocalScope(ScopeType.Try);

            //    // Dispose()
            //    cg.EmitPop(cg.EmitForwardCall(dispose, finalize, callvirt: false));
            //    //if (cg.EmitPdbSequencePoints) cg.Builder.EmitOpCode(ILOpCode.Nop);

            //    // }
            //    cg.Builder.CloseLocalScope();
            //    // finally {
            //    cg.Builder.OpenLocalScope(ScopeType.Finally);

            //    // base.Finalize()
            //    thisPlace.EmitLoad(cg.Builder);
            //    cg.EmitCall(ILOpCode.Call, finalize.ExplicitOverride);
            //    //if (cg.EmitPdbSequencePoints) cg.Builder.EmitOpCode(ILOpCode.Nop);

            //    // }
            //    cg.Builder.CloseLocalScope();
            //    cg.Builder.CloseLocalScope();

            //    // .ret
            //    cg.EmitRet(DeclaringCompilation.GetSpecialType(SpecialType.System_Void));

            //}, null, diagnostics, false));

            //module.SynthesizedManager.AddMethod(this, finalize);
        }
示例#22
0
        void EmitPhpCallable(Emit.PEModuleBuilder module, DiagnosticBag diagnostics)
        {
            var iphpcallable = DeclaringCompilation.CoreTypes.IPhpCallable;

            var __invoke = TryGetMagicInvoke();

            if (__invoke == null ||
                IsAlreadyImplemented(__invoke) ||
                IsAlreadyImplemented(iphpcallable))
            {
                // already implemented in a base class
                return;
            }

            //
            // IPhpCallable.Invoke(Context <ctx>, PhpVaue[] arguments)
            //
            var invoke = new SynthesizedMethodSymbol(this, iphpcallable.FullName + ".Invoke", false, true, DeclaringCompilation.CoreTypes.PhpValue, isfinal: true)
            {
                ExplicitOverride = (MethodSymbol)iphpcallable.Symbol.GetMembers("Invoke").Single(),
                ForwardedCall    = __invoke,
            };

            invoke.SetParameters(
                new SpecialParameterSymbol(invoke, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0),
                new SynthesizedParameterSymbol(invoke, ArrayTypeSymbol.CreateSZArray(ContainingAssembly, DeclaringCompilation.CoreTypes.PhpValue.Symbol), 1, RefKind.None, name: "arguments", isParams: true));

            module.SetMethodBody(invoke, MethodGenerator.GenerateMethodBody(module, invoke, il =>
            {
                var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, new ParamPlace(invoke.Parameters[0]), new ArgPlace(this, 0))
                {
                    CallerType = this,
                };

                cg.EmitRet(cg.EmitForwardCall(__invoke, invoke, callvirt: true));
            }, null, diagnostics, false));

            module.SynthesizedManager.AddMethod(this, invoke);

            //
            // IPhpCallable.ToPhpValue()
            //
            var tophpvalue = new SynthesizedMethodSymbol(this, iphpcallable.FullName + ".ToPhpValue", false, true, DeclaringCompilation.CoreTypes.PhpValue, isfinal: true)
            {
                ExplicitOverride = (MethodSymbol)iphpcallable.Symbol.GetMembers("ToPhpValue").Single(),
            };

            //
            module.SetMethodBody(tophpvalue, MethodGenerator.GenerateMethodBody(module, tophpvalue, il =>
            {
                var thisPlace = new ArgPlace(this, 0);
                var ctxPlace  = new FieldPlace(thisPlace, this.ContextStore, module);
                var cg        = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace);

                // return PhpValue.FromClass(this)
                cg.EmitThis();
                cg.EmitRet(cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.FromClass_Object));
            }, null, diagnostics, false));

            module.SynthesizedManager.AddMethod(this, tophpvalue);
        }
        void EmitPhpCtors(ImmutableArray <MethodSymbol> instancectors, Emit.PEModuleBuilder module, DiagnosticBag diagnostics)
        {
            foreach (SynthesizedPhpCtorSymbol ctor in instancectors)
            {
                module.SetMethodBody(ctor, MethodGenerator.GenerateMethodBody(module, ctor, il =>
                {
                    if (ctor is SynthesizedParameterlessPhpCtorSymbol)
                    {
                        EmitParameterlessCtor(ctor, il, module, diagnostics);
                        return;
                    }

                    Debug.Assert(SpecialParameterSymbol.IsContextParameter(ctor.Parameters[0]));

                    var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, new ParamPlace(ctor.Parameters[0]), new ArgPlace(this, 0))
                    {
                        CallerType     = this,
                        ContainingFile = ContainingFile,
                    };

                    Debug.Assert(ctor.BaseCtor != null);

                    // base..ctor or this..ctor
                    cg.EmitPop(cg.EmitForwardCall(ctor.BaseCtor, ctor));

                    if (ctor.PhpConstructor == null)
                    {
                        // initialize <ctx> field, if field is declared within this type
                        var ctxField = this.ContextStore;
                        if (ctxField != null && object.ReferenceEquals((object)ctxField.ContainingType, this))
                        {
                            var ctxFieldPlace = new FieldPlace(cg.ThisPlaceOpt, ctxField, module);

                            // Debug.Assert(<ctx> != null)
                            cg.EmitDebugAssertNotNull(cg.ContextPlaceOpt, "Context cannot be null.");

                            // <this>.<ctx> = <ctx>
                            ctxFieldPlace.EmitStorePrepare(il);
                            cg.EmitLoadContext();
                            ctxFieldPlace.EmitStore(il);
                        }

                        // trait specific:
                        if (ctor is SynthesizedPhpTraitCtorSymbol tctor)
                        {
                            EmitTraitCtorInit(cg, tctor);
                        }

                        // trait instances:
                        foreach (var t in this.TraitUses)
                        {
                            EmitTraitInstanceInit(cg, ctor, t);
                        }

                        // initialize instance fields:
                        foreach (var f in this.GetMembers().OfType <IPhpPropertySymbol>().Where(f => f.FieldKind == PhpPropertyKind.InstanceField))
                        {
                            Debug.Assert(f.ContainingStaticsHolder == null);
                            f.EmitInit(cg);
                        }
                    }
                    else
                    {
                        Debug.Assert(ctor.BaseCtor.ContainingType == this);

                        // this.__construct
                        cg.EmitPop(cg.EmitForwardCall(ctor.PhpConstructor, ctor));
                    }

                    // ret
                    Debug.Assert(ctor.ReturnsVoid);
                    cg.EmitRet(ctor.ReturnType);
                }, null, diagnostics, false));
            }
        }
示例#24
0
 private int GetFieldPlaceCount(FieldPlace fp)
 {
     return(FieldPlaces.Where(fplace => fplace.FldName == fp.FldName).Count());
 }
示例#25
0
        /// <summary>
        /// Emit body of enumeration of app-wide global constants.
        /// </summary>
        internal void CreateEnumerateConstantsSymbol(DiagnosticBag diagnostic)
        {
            var method = this.ScriptType.EnumerateConstantsSymbol;
            var consts = this.Compilation.GlobalSemantics.GetExportedConstants();

            // void (Action<string, RuntimeMethodHandle> callback)
            var body = MethodGenerator.GenerateMethodBody(this, method,
                                                          (il) =>
            {
                var cg = new CodeGenerator(il, this, diagnostic, this.Compilation.Options.OptimizationLevel, false, this.ScriptType, null, null);

                // interface IConstantsComposition
                var constantscomposition = method.Parameters[0].Type;
                Debug.Assert(constantscomposition.Name == "IConstantsComposition");

                // Define(string, ...)
                var define_xxx = constantscomposition
                                 .GetMembers("Define")
                                 .OfType <MethodSymbol>()
                                 .Where(m => m.ParameterCount == 2)
                                 .ToArray();

                var define_string = define_xxx.Single(m => m.Parameters[1].Type.SpecialType == SpecialType.System_String);
                var define_long   = define_xxx.Single(m => m.Parameters[1].Type.SpecialType == SpecialType.System_Int64);
                var define_double = define_xxx.Single(m => m.Parameters[1].Type.SpecialType == SpecialType.System_Double);
                var define_func   = define_xxx.Single(m => m.Parameters[1].Type.Name == "Func");   // Func<PhpValue>
                var define_value  = define_xxx.Single(m => m.Parameters[1].Type == cg.CoreTypes.PhpValue);

                foreach (var c in consts.OfType <Symbol>())
                {
                    // composer.Define(c.Name, c.Value)
                    il.EmitLoadArgumentOpcode(0);

                    // string : name
                    il.EmitStringConstant(c.MetadataName);

                    if (c is FieldSymbol fld)
                    {
                        // PhpValue : value
                        TypeSymbol consttype;

                        var constvalue = fld.GetConstantValue(false);
                        if (constvalue != null)
                        {
                            consttype = cg.EmitLoadConstant(constvalue.Value, cg.CoreTypes.PhpValue);
                        }
                        else
                        {
                            consttype = new FieldPlace(null, fld, this).EmitLoad(il);
                        }

                        // Define(...)
                        if (consttype.SpecialType == SpecialType.System_Int32)
                        {
                            // i4 -> i8
                            il.EmitOpCode(ILOpCode.Conv_i8);
                            consttype = cg.CoreTypes.Long;
                        }

                        MethodSymbol define_method = null;

                        if (consttype.SpecialType == SpecialType.System_String)
                        {
                            define_method = define_string;
                        }
                        else if (consttype.SpecialType == SpecialType.System_Int64)
                        {
                            define_method = define_long;
                        }
                        else if (consttype.SpecialType == SpecialType.System_Double)
                        {
                            define_method = define_double;
                        }
                        else
                        {
                            cg.EmitConvertToPhpValue(consttype, 0);
                            define_method = define_value;
                        }

                        il.EmitCall(this, diagnostic, ILOpCode.Callvirt, define_method);
                    }
                    else if (c is PropertySymbol prop)
                    {
                        MethodSymbol getter_func;
                        // Func<PhpValue>
                        if (prop.Type == cg.CoreTypes.PhpValue)
                        {
                            getter_func = prop.GetMethod;
                        }
                        else
                        {
                            // static PhpValue get_XXX => get_prop();
                            getter_func = new SynthesizedMethodSymbol(ScriptType, "get_" + prop.Name, true, false, cg.CoreTypes.PhpValue, Accessibility.Internal);
                            SynthesizedManager.AddMethod(ScriptType, getter_func);
                            SetMethodBody(getter_func, MethodGenerator.GenerateMethodBody(this, getter_func, _il =>
                            {
                                var _cg = new CodeGenerator(_il, this, diagnostic, this.Compilation.Options.OptimizationLevel, false, ScriptType, null, null);

                                _cg.EmitRet(_cg.EmitConvertToPhpValue(_cg.EmitForwardCall(prop.GetMethod, getter_func, callvirt: false), 0));
                            }, null, diagnostic, false));
                        }

                        // new Func<PhpValue>(object @object = null, IntPtr method = getter_func)
                        cg.Builder.EmitNullConstant();     // null
                        cg.EmitOpCode(ILOpCode.Ldftn);     // method
                        cg.EmitSymbolToken(getter_func, null);
                        cg.EmitCall(ILOpCode.Newobj, Compilation.GetWellKnownType(WellKnownType.System_Func_T).Construct(cg.CoreTypes.PhpValue).InstanceConstructors[0]);

                        //
                        il.EmitCall(this, diagnostic, ILOpCode.Callvirt, define_func);
                    }
                    else
                    {
                        throw ExceptionUtilities.UnexpectedValue(c);
                    }
                }

                //
                il.EmitRet(true);
            },
                                                          null, diagnostic, false);

            SetMethodBody(method, body);
        }