Beispiel #1
0
        /// <summary>
        /// Emits load of cached <c>RoutineInfo</c> corresponding to this method.
        /// </summary>
        /// <returns>Type symbol of <c>RoutineInfo</c>.</returns>
        internal virtual TypeSymbol EmitLoadRoutineInfo(CodeGenerator cg)
        {
            var name = MetadataName;
            var type = this.ContainingType;

            name = (type != null ? type.GetFullName() : "?") + "." + name;

            // cache the instance of RoutineInfo
            var tmpfld = cg.Module.SynthesizedManager.GetOrCreateSynthesizedField(
                cg.Module.ScriptType,
                cg.CoreTypes.RoutineInfo,
                "<>" + name,
                Accessibility.Internal,
                isstatic: true,
                @readonly: false);

            // Template: (tmpfld ?? tmpfld = CreateUserRoutine)
            var tmpplace = new FieldPlace(null, tmpfld, cg.Module);

            tmpplace.EmitLoad(cg.Builder);
            cg.EmitNullCoalescing((cg_) =>
            {
                // TODO: Interlocked(ref fld, CreateRoutine, null)
                tmpplace.EmitStorePrepare(cg_.Builder);
                EmitCreateRoutine(cg_, this);

                cg_.Builder.EmitOpCode(ILOpCode.Dup);
                tmpplace.EmitStore(cg_.Builder);
            });

            //
            return(tmpfld.Type
                   .Expect(cg.CoreTypes.RoutineInfo));
        }
        void GenerateFieldAccessorProperty(Emit.PEModuleBuilder module, DiagnosticBag diagnostics, SourceFieldSymbol srcf, PropertySymbol paccessor)
        {
            //
            module.SynthesizedManager.AddProperty(this, paccessor);

            //
            var get_body = MethodGenerator.GenerateMethodBody(module, paccessor.GetMethod, (il) =>
            {
                // Template: return field;
                var place = new FieldPlace(new ArgPlace(this, 0), srcf.OverridenDefinition, module);
                place.EmitLoad(il);
                il.EmitRet(false);
            }, null, diagnostics, false);

            module.SetMethodBody(paccessor.GetMethod, get_body);
            module.SynthesizedManager.AddMethod(this, paccessor.GetMethod);

            //
            var set_body = MethodGenerator.GenerateMethodBody(module, paccessor.SetMethod, (il) =>
            {
                // Template: field = value;
                var place = new FieldPlace(new ArgPlace(this, 0), srcf.OverridenDefinition, module);
                place.EmitStorePrepare(il);
                new ArgPlace(this, 1).EmitLoad(il);
                place.EmitStore(il);
                il.EmitRet(true);
            }, null, diagnostics, false);

            module.SetMethodBody(paccessor.SetMethod, set_body);
            module.SynthesizedManager.AddMethod(this, paccessor.SetMethod);
        }
Beispiel #3
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();
                    }
                }
            }
        }
        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);
        }