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); }
//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); }
/// <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); }
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)); } }
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); }
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); } }
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); }
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)); }
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; }
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); } } }
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; }
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; } }
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); }); }
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); }
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)); } }
private int GetFieldPlaceCount(FieldPlace fp) { return(FieldPlaces.Where(fplace => fplace.FldName == fp.FldName).Count()); }
/// <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); }