public GetTemporaryLocal ( TypeSymbol type ) : Microsoft.CodeAnalysis.CodeGen.LocalDefinition | ||
type | TypeSymbol | The requested |
Résultat | Microsoft.CodeAnalysis.CodeGen.LocalDefinition |
/// <summary> /// Stores the value from top of the stack into this temporary local variable. /// </summary> public void EmitStore() { if (_loc != null) { _cg.Builder.EmitLocalStore(_loc); } else { Debug.Assert(_cg.TemporalLocalsPlace != null); Debug.Assert(_tempName != null); /* * tmp = <STACK> * <temporary>[name] = tmp; */ var tmp = _cg.GetTemporaryLocal(Type, true); _cg.Builder.EmitLocalStore(tmp); _cg.TemporalLocalsPlace.EmitLoad(_cg.Builder); _cg.EmitIntStringKey(_tempName); _cg.Builder.EmitLocalLoad(tmp); _cg.EmitConvert(Type, 0, _cg.CoreTypes.PhpValue); _cg.EmitCall(System.Reflection.Metadata.ILOpCode.Callvirt, _cg.CoreMethods.PhpArray.SetItemValue_IntStringKey_PhpValue); } }
/// <summary> /// Emit runtime chain. /// </summary> /// <returns>Runtime chain value type pushed on top of the stack.</returns> public TypeSymbol EmitRuntimeChain(CodeGenerator cg) { // create and initialize the chain struct var chaintmp = cg.GetTemporaryLocal(this.Type, true); cg.Builder.EmitLocalAddress(chaintmp); cg.Builder.EmitOpCode(ILOpCode.Initobj); cg.Builder.EmitSymbolToken(cg.Module, cg.Diagnostics, this.Type, null); // fill in the fields for (var element = this; element != null; element = element.Next) { Debug.Assert(element.Type.IsValueType); if (element.Fields != null) { foreach (var pair in element.Fields) { // Template: ADDR chain.Next[.Next] cg.Builder.EmitLocalAddress(chaintmp); for (var x = this; x != element; x = x.Next) { var nextfield = new FieldPlace_Raw((FieldSymbol)x.Type.GetMembers("Next").Single(), cg.Module); nextfield.EmitLoadAddress(cg.Builder); } // Template: .<Field> = <Value> var valuefield = new FieldPlace_Raw((FieldSymbol)element.Type.GetMembers(pair.Key).Single(), cg.Module); valuefield.EmitStorePrepare(cg.Builder); if (pair.Value is BoundExpression valueexpr) { cg.EmitConvert(valueexpr, valuefield.Type); } else if (pair.Value is BoundVariableName nameexpr) { cg.EmitConvert(nameexpr.EmitVariableName(cg), 0, valuefield.Type); } else { throw Peachpie.CodeAnalysis.Utilities.ExceptionUtilities.UnexpectedValue(pair.Value); } valuefield.EmitStore(cg.Builder); } } } // cg.Builder.EmitLocalLoad(chaintmp); // return(this.Type); }
internal override TypeSymbol Emit(CodeGenerator cg) { var result_type = cg.DeclaringCompilation.GetTypeFromTypeRef(cg.Routine, this.TypeRefMask); if (this.IfTrue != null) { object trueLbl = new object(); object endLbl = new object(); // Cond ? True : False cg.EmitConvert(this.Condition, cg.CoreTypes.Boolean); // i4 cg.Builder.EmitBranch(ILOpCode.Brtrue, trueLbl); // false: cg.EmitConvert(this.IfFalse, result_type); cg.Builder.EmitBranch(ILOpCode.Br, endLbl); cg.Builder.AdjustStack(-1); // workarounds assert in ILBuilder.MarkLabel, we're doing something wrong with ILBuilder // trueLbl: cg.Builder.MarkLabel(trueLbl); cg.EmitConvert(this.IfTrue, result_type); // endLbl: cg.Builder.MarkLabel(endLbl); } else { object trueLbl = new object(); object endLbl = new object(); // Cond ?: False // <stack> = <cond_var> = Cond var cond_type = cg.Emit(this.Condition); var cond_var = cg.GetTemporaryLocal(cond_type); cg.Builder.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitLocalStore(cond_var); cg.EmitConvertToBool(cond_type, this.Condition.TypeRefMask); cg.Builder.EmitBranch(ILOpCode.Brtrue, trueLbl); // false: cg.EmitConvert(this.IfFalse, result_type); cg.Builder.EmitBranch(ILOpCode.Br, endLbl); cg.Builder.AdjustStack(-1); // workarounds assert in ILBuilder.MarkLabel, we're doing something wrong with ILBuilder // trueLbl: cg.Builder.MarkLabel(trueLbl); cg.Builder.EmitLocalLoad(cond_var); cg.EmitConvert(cond_type, this.Condition.TypeRefMask, result_type); // endLbl: cg.Builder.MarkLabel(endLbl); // cg.ReturnTemporaryLocal(cond_var); } // if (Access.IsNone) { cg.EmitPop(result_type); result_type = cg.CoreTypes.Void; } // return result_type; }
internal override TypeSymbol Emit(CodeGenerator cg) { Debug.Assert(this.Access.IsNone || Access.IsRead); Debug.Assert(!this.Access.IsReadRef); Debug.Assert(!this.Access.IsWrite); Debug.Assert(this.Target.Access.IsRead && this.Target.Access.IsWrite); Debug.Assert(this.Value.Access.IsRead); Debug.Assert(this.Value is BoundLiteral); if (this.UsesOperatorMethod) { throw new NotImplementedException(); } TypeSymbol result_type = cg.CoreTypes.Void; LocalDefinition postfix_temp = null; var read = this.Access.IsRead; var target_place = this.Target.BindPlace(cg); Debug.Assert(target_place != null); using (var instance_holder = new InstanceCacheHolder()) { // prepare target for store operation target_place.EmitStorePrepare(cg, instance_holder); // load target value target_place.EmitLoadPrepare(cg, instance_holder); } var target_load_type = target_place.EmitLoad(cg); TypeSymbol op_type; if (read && IsPostfix) { // store original value of target // <temp> = TARGET postfix_temp = cg.GetTemporaryLocal(target_load_type); cg.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitLocalStore(postfix_temp); } if (IsIncrement) { op_type = BoundBinaryEx.EmitAdd(cg, target_load_type, this.Value, target_place.TypeOpt); } else { Debug.Assert(IsDecrement); op_type = BoundBinaryEx.EmitSub(cg, target_load_type, this.Value, target_place.TypeOpt); } if (read) { if (IsPostfix) { // READ <temp> cg.Builder.EmitLocalLoad(postfix_temp); result_type = target_load_type; // cg.ReturnTemporaryLocal(postfix_temp); postfix_temp = null; } else { // dup resulting value // READ (++TARGET OR --TARGET) cg.Builder.EmitOpCode(ILOpCode.Dup); result_type = op_type; } } // target_place.EmitStore(cg, op_type); Debug.Assert(postfix_temp == null); Debug.Assert(!read || result_type.SpecialType != SpecialType.System_Void); // return result_type; }
internal override TypeSymbol Emit(CodeGenerator cg) { Debug.Assert(Access.IsRead || Access.IsNone); // target X= value; var target_place = this.Target.BindPlace(cg); Debug.Assert(target_place != null); Debug.Assert(target_place.TypeOpt == null || target_place.TypeOpt.SpecialType != SpecialType.System_Void); // helper class maintaining reference to already evaluated instance of the eventual chain using (var instance_holder = new InstanceCacheHolder()) { // <target> = <target> X <value> target_place.EmitStorePrepare(cg, instance_holder); // target_place.EmitLoadPrepare(cg, instance_holder); } var xtype = target_place.EmitLoad(cg); // type of left value operand TypeSymbol result_type; switch (this.Operation) { case Operations.AssignAdd: result_type = BoundBinaryEx.EmitAdd(cg, xtype, Value, target_place.TypeOpt); break; //case Operations.AssignAnd: // binaryop = Operations.And; // break; case Operations.AssignAppend: result_type = EmitAppend(cg, xtype, Value); break; ////case Operations.AssignPrepend: //// break; case Operations.AssignDiv: result_type = BoundBinaryEx.EmitDiv(cg, xtype, Value, target_place.TypeOpt); break; //case Operations.AssignMod: // binaryop = Operations.Mod; // break; case Operations.AssignMul: result_type = BoundBinaryEx.EmitMul(cg, xtype, Value, target_place.TypeOpt); break; //case Operations.AssignOr: // binaryop = Operations.Or; // break; case Operations.AssignPow: result_type = BoundBinaryEx.EmitPow(cg, xtype, /*this.Target.TypeRefMask*/0, Value); break; //case Operations.AssignShiftLeft: // binaryop = Operations.ShiftLeft; // break; //case Operations.AssignShiftRight: // binaryop = Operations.ShiftRight; // break; case Operations.AssignSub: result_type = BoundBinaryEx.EmitSub(cg, xtype, Value, target_place.TypeOpt); break; //case Operations.AssignXor: // binaryop = Operations.Xor; // break; default: throw ExceptionUtilities.UnexpectedValue(this.Operation); } LocalDefinition tmp = null; switch (this.Access.Flags) { case AccessMask.Read: tmp = cg.GetTemporaryLocal(result_type, false); cg.Builder.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitLocalStore(tmp); break; case AccessMask.None: break; default: throw ExceptionUtilities.UnexpectedValue(this.Access); } target_place.EmitStore(cg, result_type); // switch (this.Access.Flags) { case AccessMask.None: return cg.CoreTypes.Void; case AccessMask.Read: Debug.Assert(tmp != null); cg.Builder.EmitLoad(tmp); cg.ReturnTemporaryLocal(tmp); return result_type; default: throw ExceptionUtilities.UnexpectedValue(this.Access); } }
internal override TypeSymbol Emit(CodeGenerator cg) { var target_place = this.Target.BindPlace(cg); Debug.Assert(target_place != null); Debug.Assert(target_place.TypeOpt == null || target_place.TypeOpt.SpecialType != SpecialType.System_Void); // T tmp; // in case access is Read var t_value = target_place.TypeOpt; if (t_value == cg.CoreTypes.PhpAlias || t_value == cg.CoreTypes.PhpValue) t_value = null; // no inplace conversion LocalDefinition tmp = null; // <target> = <value> target_place.EmitStorePrepare(cg); // TODO: load value & dereference eventually if (t_value != null) cg.EmitConvert(this.Value, t_value); // TODO: do not convert here yet else t_value = cg.Emit(this.Value); switch (this.Access.Flags) { case AccessMask.Read: tmp = cg.GetTemporaryLocal(t_value, false); cg.Builder.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitLocalStore(tmp); break; case AccessMask.None: break; default: throw ExceptionUtilities.UnexpectedValue(this.Access); } target_place.EmitStore(cg, t_value); // switch (this.Access.Flags) { case AccessMask.None: t_value = cg.CoreTypes.Void; break; case AccessMask.Read: cg.Builder.EmitLocalLoad(tmp); break; default: throw ExceptionUtilities.UnexpectedValue(this.Access); } if (tmp != null) { cg.ReturnTemporaryLocal(tmp); } // return t_value; }
void IBoundReference.EmitStore(CodeGenerator cg, TypeSymbol valueType) { var rtype = cg.CoreTypes.IPhpArray; cg.EmitConvert(valueType, 0, rtype); var tmp = cg.GetTemporaryLocal(rtype); cg.Builder.EmitLocalStore(tmp); // NOTE: since PHP7, variables are assigned from left to right var vars = this.Variables; for (int i = 0; i < vars.Length; i++) { var target = vars[i]; if (target == null) continue; var boundtarget = target.BindPlace(cg); boundtarget.EmitStorePrepare(cg); // LOAD IPhpArray.GetItemValue(IntStringKey{i}) cg.Builder.EmitLocalLoad(tmp); cg.EmitIntStringKey(i); var itemtype = cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.IPhpArray.GetItemValue_IntStringKey); // STORE vars[i] boundtarget.EmitStore(cg, itemtype); } // cg.ReturnTemporaryLocal(tmp); }
/// <summary> /// Emits the given conversion. 'from' and 'to' matches the classified conversion. /// </summary> public static void EmitConversion(this CodeGenerator cg, CommonConversion conversion, TypeSymbol from, TypeSymbol to, TypeSymbol op = null, bool @checked = false) { // {from}, {op} is loaded on stack // if (conversion.Exists == false) { throw cg.NotImplementedException($"Conversion from '{from}' to '{to}' "); } if (conversion.IsNullable) { if (from.IsNullableType(out var ttype)) { if (op != null) { // TODO throw new ArgumentException(nameof(op)); } var lbltrue = new NamedLabel("has value"); var lblend = new NamedLabel("end"); var tmp = cg.GetTemporaryLocal(from, true); cg.Builder.EmitLocalStore(tmp); // Template: tmp.HasValue ? convert(tmp.Value) : default cg.Builder.EmitLocalAddress(tmp); cg.EmitCall(ILOpCode.Call, cg.DeclaringCompilation.System_Nullable_T_HasValue(from)); cg.Builder.EmitBranch(ILOpCode.Brtrue, lbltrue); // default: cg.EmitLoadDefault(to); cg.Builder.EmitBranch(ILOpCode.Br, lblend); // cg.Builder.AdjustStack(-1); // ? // lbltrue: cg.Builder.MarkLabel(lbltrue); // Template: convert( tmp.GetValueOrDefault() ) cg.Builder.EmitLocalAddress(tmp); cg.EmitCall(ILOpCode.Call, cg.DeclaringCompilation.System_Nullable_T_GetValueOrDefault(from)).Expect(ttype); EmitConversion(cg, conversion.WithIsNullable(false), ttype, to, op, @checked); // lblend: cg.Builder.MarkLabel(lblend); return; } if (to.IsNullableType(out ttype)) // NOTE: not used yet { // new Nullable<TType>( convert(from) ) EmitConversion(cg, conversion.WithIsNullable(false), from, ttype, op, @checked); cg.EmitCall(ILOpCode.Newobj, ((NamedTypeSymbol)to).InstanceConstructors[0]); // new Nullable<T>( STACK ) return; } throw Roslyn.Utilities.ExceptionUtilities.Unreachable; } if (conversion.IsIdentity) { if (op != null) { throw new ArgumentException(nameof(op)); } if (to.SpecialType == SpecialType.System_Void) { // POP cg.EmitPop(from); } // nop } else if (conversion.IsNumeric) { if (op != null) { throw new ArgumentException(nameof(op)); } EmitNumericConversion(cg, from, to, @checked: @checked); } else if (conversion.IsReference) { if (op != null) { throw new ArgumentException(nameof(op)); } // TODO: ensure from/to is a valid reference type cg.EmitCastClass(to); } else if (conversion.IsUserDefined) { var method = (MethodSymbol)conversion.MethodSymbol; var ps = method.Parameters; int pconsumed = 0; if (method.HasThis) { if (from.IsValueType) { if (op != null || from.IsVoid()) { throw new ArgumentException(nameof(op)); } cg.EmitStructAddr(from); } } else { if (ps[0].RefKind != RefKind.None) { throw new InvalidOperationException(); } if (from != ps[0].Type) { if (op != null) { if (!ps[0].Type.IsAssignableFrom(from)) { throw new ArgumentException(nameof(op)); } } else { EmitImplicitConversion(cg, from, ps[0].Type, @checked: @checked); } } pconsumed++; } if (op != null) { if (ps.Length > pconsumed) { EmitImplicitConversion(cg, op, ps[pconsumed].Type, @checked: @checked); } pconsumed++; } // Context ctx, if (ps.Length > pconsumed && SpecialParameterSymbol.IsContextParameter(ps[pconsumed])) { cg.EmitLoadContext(); pconsumed++; } if (ps.Length != pconsumed) { throw new InvalidOperationException(); } EmitImplicitConversion(cg, cg.EmitCall(method.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call, method), to, @checked: true); } else { throw new NotImplementedException(); } }
internal override void Generate(CodeGenerator cg) { Debug.Assert(this.Enumeree != null); // get the enumerator, // bind actual MoveNext() and CurrentValue and CurrentKey // Template: using( // a) enumerator = enumeree.GetEnumerator() // b) enumerator = Operators.GetEnumerator(enumeree) // ) ... cg.EmitSequencePoint(this.Enumeree.PhpSyntax); var enumereeType = cg.Emit(this.Enumeree); Debug.Assert(enumereeType.SpecialType != SpecialType.System_Void); var getEnumeratorMethod = enumereeType.LookupMember<MethodSymbol>(WellKnownMemberNames.GetEnumeratorMethodName); TypeSymbol enumeratorType; if (enumereeType.IsOfType(cg.CoreTypes.PhpArray)) { cg.Builder.EmitBoolConstant(_aliasedValues); // PhpArray.GetForeachtEnumerator(bool) enumeratorType = cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpArray.GetForeachEnumerator_Boolean); // TODO: IPhpArray } // TODO: IPhpEnumerable // TODO: IPhpArray // TODO: Iterator else if (getEnumeratorMethod != null && getEnumeratorMethod.ParameterCount == 0 && enumereeType.IsReferenceType) { // enumeree.GetEnumerator() enumeratorType = cg.EmitCall(getEnumeratorMethod.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call, getEnumeratorMethod); } else { cg.EmitConvertToPhpValue(enumereeType, 0); cg.Builder.EmitBoolConstant(_aliasedValues); cg.EmitCallerRuntimeTypeHandle(); // Operators.GetForeachEnumerator(PhpValue, bool, RuntimeTypeHandle) enumeratorType = cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.GetForeachEnumerator_PhpValue_Bool_RuntimeTypeHandle); } // _current = enumeratorType.LookupMember<PropertySymbol>(WellKnownMemberNames.CurrentPropertyName); // TODO: Err if no Current _currentValue = enumeratorType.LookupMember<PropertySymbol>(_aliasedValues ? "CurrentValueAliased" : "CurrentValue"); _currentKey = enumeratorType.LookupMember<PropertySymbol>("CurrentKey"); _disposeMethod = enumeratorType.LookupMember<MethodSymbol>("Dispose", m => m.ParameterCount == 0 && !m.IsStatic); // _enumeratorLoc = cg.GetTemporaryLocal(enumeratorType); cg.Builder.EmitLocalStore(_enumeratorLoc); // bind methods _moveNextMethod = enumeratorType.LookupMember<MethodSymbol>(WellKnownMemberNames.MoveNextMethodName); // TODO: Err if there is no MoveNext() Debug.Assert(_moveNextMethod.ReturnType.SpecialType == SpecialType.System_Boolean); Debug.Assert(_moveNextMethod.IsStatic == false); if (_disposeMethod != null) { /* Template: try { body } finally { enumerator.Dispose } */ // try { cg.Builder.AssertStackEmpty(); cg.Builder.OpenLocalScope(ScopeType.TryCatchFinally); cg.Builder.OpenLocalScope(ScopeType.Try); // EmitBody(cg); // } cg.Builder.CloseLocalScope(); // /Try // finally { cg.Builder.OpenLocalScope(ScopeType.Finally); // enumerator.Dispose() & cleanup EmitDisposeAndClean(cg); // } cg.Builder.CloseLocalScope(); // /Finally cg.Builder.CloseLocalScope(); // /TryCatchFinally } else { EmitBody(cg); EmitDisposeAndClean(cg); } }
internal override void Generate(CodeGenerator cg) { // four cases: // 1. just single or none case label that can be replaced with single IF // 2. switch over integers, using native CIL switch // 3. switch over strings, using C# static Dictionary and CIL switch // 4. PHP style switch which is just a bunch of IFs if (this.CaseBlocks.Length == 0 || this.CaseBlocks[0].IsDefault) { Debug.Assert(this.CaseBlocks.Length <= 1); // no SWITCH or IF needed cg.EmitPop(this.SwitchValue.WithAccess(BoundAccess.None).Emit(cg)); // None Access, also using BoundExpression.Emit directly to avoid CodeGenerator type specialization which is not needed if (this.CaseBlocks.Length == 1) { cg.GenerateScope(this.CaseBlocks[0], NextBlock.Ordinal); } } else { // CIL Switch: bool allconsts = this.CaseBlocks.All(c => c.IsDefault || c.CaseValue.ConstantValue.HasValue); bool allconstints = allconsts && this.CaseBlocks.All(c => c.IsDefault || IsInt32(c.CaseValue.ConstantValue.Value)); //bool allconststrings = allconsts && this.CaseBlocks.All(c => c.IsDefault || IsString(c.CaseValue.ConstantValue.Value)); var default_block = this.DefaultBlock; // <switch_loc> = <SwitchValue>; TypeSymbol switch_type; LocalDefinition switch_loc; // Switch Header if (allconstints) { switch_type = cg.CoreTypes.Int32; cg.EmitSequencePoint(this.SwitchValue.PhpSyntax); cg.EmitConvert(this.SwitchValue, switch_type); switch_loc = cg.GetTemporaryLocal(switch_type); cg.Builder.EmitLocalStore(switch_loc); // switch (labels) cg.Builder.EmitIntegerSwitchJumpTable(GetSwitchCaseLabels(CaseBlocks), default_block ?? NextBlock, switch_loc, switch_type.PrimitiveTypeCode); } //else if (allconststrings) //{ //} else { // legacy jump table // IF (case_i) GOTO label_i; cg.EmitSequencePoint(this.SwitchValue.PhpSyntax); switch_type = cg.Emit(this.SwitchValue); switch_loc = cg.GetTemporaryLocal(switch_type); cg.Builder.EmitLocalStore(switch_loc); // for (int i = 0; i < this.CaseBlocks.Length; i++) { var this_block = this.CaseBlocks[i]; if (this_block.CaseValue != null) { // <CaseValue>: cg.EmitSequencePoint(this_block.CaseValue.PhpSyntax); // if (<switch_loc> == c.CaseValue) goto this_block; cg.Builder.EmitLocalLoad(switch_loc); BoundBinaryEx.EmitEquality(cg, switch_type, this_block.CaseValue); cg.Builder.EmitBranch(ILOpCode.Brtrue, this_block); } } // default: cg.Builder.EmitBranch(ILOpCode.Br, default_block ?? NextBlock); } // FREE <switch_loc> cg.ReturnTemporaryLocal(switch_loc); // Switch Body this.CaseBlocks.ForEach((i, this_block) => { var next_case = (i + 1 < this.CaseBlocks.Length) ? this.CaseBlocks[i + 1] : null; // { cg.GenerateScope(this_block, (next_case ?? NextBlock).Ordinal); // } }); } // cg.Scope.ContinueWith(NextBlock); }
void EmitCatchBlock(CodeGenerator cg, CatchBlock catchBlock) { Debug.Assert(catchBlock.Variable.Variable != null); if (catchBlock.TypeRef.ResolvedType == null) { throw new NotImplementedException("handle exception type dynamically"); // TODO: if (ex is ctx.ResolveType(ExceptionTypeName)) { ... } } var extype = catchBlock.TypeRef.ResolvedType; cg.Builder.AdjustStack(1); // Account for exception on the stack. cg.Builder.OpenLocalScope(ScopeType.Catch, (Microsoft.Cci.ITypeReference)extype); // <tmp> = <ex> var tmploc = cg.GetTemporaryLocal(extype); cg.Builder.EmitLocalStore(tmploc); var varplace = catchBlock.Variable.BindPlace(cg); Debug.Assert(varplace != null); // $x = <tmp> varplace.EmitStorePrepare(cg); cg.Builder.EmitLocalLoad(tmploc); varplace.EmitStore(cg, (TypeSymbol)tmploc.Type); // cg.ReturnTemporaryLocal(tmploc); tmploc = null; // cg.GenerateScope(catchBlock, NextBlock.Ordinal); // cg.Builder.CloseLocalScope(); }
/// <summary> /// Emits name as string, uses cached variable. /// </summary> void EmitName(CodeGenerator cg, BoundExpression name) { Contract.ThrowIfNull(cg); Contract.ThrowIfNull(name); if (_name_loc != null) { cg.Builder.EmitLocalLoad(_name_loc); } else { _cg = cg; // return (<loc> = <name>) _name_loc = cg.GetTemporaryLocal(cg.CoreTypes.String); cg.EmitConvert(name, cg.CoreTypes.String); cg.Builder.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitLocalStore(_name_loc); } }
/// <summary> /// Emits <see name="_instance"/>, uses cached value if initialized already. /// </summary> TypeSymbol EmitInstance(CodeGenerator cg, Func<TypeSymbol> emitter) { Debug.Assert(cg != null); if (_instance_loc != null) { cg.Builder.EmitLocalLoad(_instance_loc); } else { _cg = cg; // return (<loc> = <instance>); _instance_loc = cg.GetTemporaryLocal(emitter()); cg.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitLocalStore(_instance_loc); } return (TypeSymbol)_instance_loc.Type; }
/// <summary> /// Stores value from top of the evaluation stack to a temporary variable which will be returned from the exit block. /// </summary> internal void EmitTmpRet(CodeGenerator cg, Symbols.TypeSymbol stack) { // lazy initialize if (_retlbl == null) { _retlbl = new object(); } if (_rettmp == null) { var rtype = cg.Routine.ReturnType; if (rtype.SpecialType != SpecialType.System_Void) { _rettmp = cg.GetTemporaryLocal(rtype); } } // <rettmp> = <stack>; if (_rettmp != null) { cg.EmitConvert(stack, 0, (Symbols.TypeSymbol)_rettmp.Type); cg.Builder.EmitLocalStore(_rettmp); cg.Builder.EmitBranch(ILOpCode.Br, _retlbl); } else { cg.EmitPop(stack); } }
/// <summary> /// Loads temporary local variable as an argument to <paramref name="targetp"/>. /// </summary> /// <param name="cg"></param> /// <param name="targetp">Target parameter.</param> /// <param name="expr">Value to be passed as its argument.</param> /// <returns><see cref="WriteBackInfo"/> which has to be finalized with <see cref="WriteBackAndFree(CodeGenerator)"/> once the routine call ends.</returns> public static WriteBackInfo CreateAndLoad(CodeGenerator cg, ParameterSymbol targetp, BoundReferenceExpression expr) { var writeback = new WriteBackInfo() { TmpLocal = cg.GetTemporaryLocal(targetp.Type), Target = expr, }; // writeback.EmitLoadArgument(cg, targetp); // return writeback; }