public ReturnTemporaryLocal ( Microsoft.CodeAnalysis.CodeGen.LocalDefinition definition ) : void | ||
definition | Microsoft.CodeAnalysis.CodeGen.LocalDefinition | The |
return | void |
public void Dispose() { if (_loc != null) { _cg.ReturnTemporaryLocal(_loc); _loc = null; } else if (_tempName != null) { // <temporary>.RemoveKey(name) Debug.Assert(_cg.TemporalLocalsPlace != null); _cg.TemporalLocalsPlace.EmitLoad(_cg.Builder); _cg.EmitIntStringKey(_tempName); _cg.EmitPop(_cg.EmitCall(System.Reflection.Metadata.ILOpCode.Callvirt, _cg.CoreMethods.PhpArray.RemoveKey_IntStringKey)); _tempName = null; } }
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); }
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 EmitDisposeAndClean(CodeGenerator cg) { // enumerator.Dispose() if (_disposeMethod != null) { // TODO: if (enumerator != null) if (_enumeratorLoc.Type.IsValueType) cg.Builder.EmitLocalAddress(_enumeratorLoc); else cg.Builder.EmitLocalLoad(_enumeratorLoc); cg.EmitCall(_disposeMethod.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call, _disposeMethod) .Expect(SpecialType.System_Void); } //// enumerator = null; //if (!_enumeratorLoc.Type.IsValueType) //{ // cg.Builder.EmitNullConstant(); // cg.Builder.EmitLocalStore(_enumeratorLoc); //} // cg.ReturnTemporaryLocal(_enumeratorLoc); _enumeratorLoc = null; // unbind _moveNextMethod = null; _disposeMethod = null; _currentValue = null; _currentKey = null; _current = null; }
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> /// Writes the value back to <see cref="Target"/> and free resources. /// </summary> public void WriteBackAndFree(CodeGenerator cg) { // Template: <Target> = <TmpLocal>; var place = Target.BindPlace(cg); place.EmitStorePrepare(cg, null); cg.Builder.EmitLocalLoad(TmpLocal); place.EmitStore(cg, (TypeSymbol)TmpLocal.Type); // free <TmpLocal> cg.ReturnTemporaryLocal(TmpLocal); TmpLocal = null; }