/// <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); }
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); }