public EncLocalSlotManager(ImmutableArray<EncLocalInfo> previousLocals, GetPreviousLocalSlot getPreviousLocalSlot) { this.allLocals = new List<LocalDefinition>(); this.getPreviousLocalSlot = getPreviousLocalSlot; // Add placeholders for previous locals. The actual // identities are populated if/when the locals are reused. for (int i = 0; i < previousLocals.Length; i++) { var localInfo = previousLocals[i]; Debug.Assert(localInfo.Type != null); var local = new LocalDefinition( identity: null, name: null, type: localInfo.Type, slot: i, isCompilerGenerated: true, // The placeholder local is marked as compiler-generated // so it will be excluded from the PDB and debugger if not // replaced by a valid local in DeclareLocalInternal. constraints: localInfo.Constraints, isDynamic: false, dynamicTransformFlags: default(ImmutableArray<TypedConstant>)); this.allLocals.Add(local); } }
protected override LocalDefinition DeclareLocalInternal( Microsoft.Cci.ITypeReference type, object identity, string name, bool isCompilerGenerated, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray<TypedConstant> dynamicTransformFlags) { if (allLocals == null) { allLocals = ImmutableArray.CreateBuilder<LocalDefinition>(1); } var local = new LocalDefinition( identity: identity, name: name, type: type, slot: this.allLocals.Count, isCompilerGenerated: isCompilerGenerated, constraints: constraints, isDynamic: isDynamic, dynamicTransformFlags: dynamicTransformFlags); this.allLocals.Add(local); return local; }
/// <summary> /// Primary method for emitting integer switch jump table /// </summary> /// <param name="caseLabels">switch case labels</param> /// <param name="fallThroughLabel">fall through label for the jump table</param> /// <param name="keyLocal">Local holding the value to switch on. /// This value has already been loaded onto the execution stack. /// </param> /// <param name="keyTypeCode">Primitive type code of switch key</param> internal void EmitIntegerSwitchJumpTable( KeyValuePair <ConstantValue, object>[] caseLabels, object fallThroughLabel, LocalDefinition keyLocal, Microsoft.Cci.PrimitiveTypeCode keyTypeCode) { Debug.Assert(caseLabels.Length > 0); Debug.Assert(keyTypeCode != Microsoft.Cci.PrimitiveTypeCode.String); // CONSIDER: SwitchIntegralJumpTableEmitter will modify the caseLabels array by sorting it. // CONSIDER: Currently, only purpose of creating this caseLabels array is for Emitting the jump table. // CONSIDER: If this requirement changes, we may want to pass in ArrayBuilder<KeyValuePair<ConstantValue, object>> instead. var emitter = new SwitchIntegralJumpTableEmitter(this, caseLabels, fallThroughLabel, keyTypeCode, keyLocal, -1); emitter.EmitJumpTable(); }
protected override LocalDefinition DeclareLocalInternal( Microsoft.Cci.ITypeReference type, object identity, string name, bool isCompilerGenerated, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray<TypedConstant> dynamicTransformFlags) { LocalDefinition local; if (identity != null) { int slot = this.getPreviousLocalSlot(identity, type, constraints); if (slot >= 0) { Debug.Assert(this.allLocals[slot].Identity == null); local = new LocalDefinition( identity: identity, name: name, type: type, slot: slot, isCompilerGenerated: isCompilerGenerated, constraints: constraints, isDynamic: isDynamic, dynamicTransformFlags: dynamicTransformFlags); this.allLocals[slot] = local; return local; } } local = new LocalDefinition( identity: identity, name: name, type: type, slot: this.allLocals.Count, isCompilerGenerated: isCompilerGenerated, constraints: constraints, isDynamic: isDynamic, dynamicTransformFlags: dynamicTransformFlags); this.allLocals.Add(local); return local; }
private LocalDefinition DeclareLocalImpl( Cci.ITypeReference type, ILocalSymbolInternal symbolOpt, string nameOpt, SynthesizedLocalKind kind, LocalDebugId id, LocalVariableAttributes pdbAttributes, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray <TypedConstant> dynamicTransformFlags) { if (_lazyAllLocals == null) { _lazyAllLocals = new ArrayBuilder <Cci.ILocalDefinition>(1); } LocalDefinition local; if (symbolOpt != null && _slotAllocatorOpt != null) { local = _slotAllocatorOpt.GetPreviousLocal(type, symbolOpt, nameOpt, kind, id, pdbAttributes, constraints, isDynamic, dynamicTransformFlags); if (local != null) { int slot = local.SlotIndex; _lazyAllLocals[slot] = local; return(local); } } local = new LocalDefinition( symbolOpt: symbolOpt, nameOpt: nameOpt, type: type, slot: _lazyAllLocals.Count, synthesizedKind: kind, id: id, pdbAttributes: pdbAttributes, constraints: constraints, isDynamic: isDynamic, dynamicTransformFlags: dynamicTransformFlags); _lazyAllLocals.Add(local); return(local); }
protected override LocalDefinition DeclareLocalInternal( Microsoft.Cci.ITypeReference type, object identity, string name, bool isCompilerGenerated, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray <TypedConstant> dynamicTransformFlags) { LocalDefinition local; if (identity != null) { int slot = this.getPreviousLocalSlot(identity, type, constraints); if (slot >= 0) { Debug.Assert(this.allLocals[slot].Identity == null); local = new LocalDefinition( identity: identity, name: name, type: type, slot: slot, isCompilerGenerated: isCompilerGenerated, constraints: constraints, isDynamic: isDynamic, dynamicTransformFlags: dynamicTransformFlags); this.allLocals[slot] = local; return(local); } } local = new LocalDefinition( identity: identity, name: name, type: type, slot: this.allLocals.Count, isCompilerGenerated: isCompilerGenerated, constraints: constraints, isDynamic: isDynamic, dynamicTransformFlags: dynamicTransformFlags); this.allLocals.Add(local); return(local); }
internal bool PossiblyDefinedOutsideOfTry(LocalDefinition local) { foreach (ScopeInfo s in _scopes) { if (s.ContainsLocal(local)) { return(false); } if (s.Type == ScopeType.Try) { return(true); } } // not recorded in scopes, could be a temp // we cannot tell anything. return(true); }
private LocalDefinition DeclareLocalImpl( Cci.ITypeReference type, ILocalSymbol symbolOpt, string nameOpt, CommonSynthesizedLocalKind synthesizedKind, uint pdbAttributes, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray <TypedConstant> dynamicTransformFlags) { if (this.lazyAllLocals == null) { this.lazyAllLocals = new ArrayBuilder <Cci.ILocalDefinition>(1); } LocalDefinition local; if (symbolOpt != null && slotAllocatorOpt != null) { local = this.slotAllocatorOpt.GetPreviousLocal(type, symbolOpt, nameOpt, synthesizedKind, pdbAttributes, constraints, isDynamic, dynamicTransformFlags); if (local != null) { int slot = local.SlotIndex; this.lazyAllLocals[slot] = local; return(local); } } local = new LocalDefinition( symbolOpt: symbolOpt, nameOpt: nameOpt, type: type, slot: this.lazyAllLocals.Count, synthesizedKind: synthesizedKind, pdbAttributes: pdbAttributes, constraints: constraints, isDynamic: isDynamic, dynamicTransformFlags: dynamicTransformFlags); this.lazyAllLocals.Add(local); return(local); }
internal SwitchStringJumpTableEmitter( ILBuilder builder, LocalDefinition key, KeyValuePair <ConstantValue, object>[] caseLabels, object fallThroughLabel, LocalDefinition keyHash, EmitStringCompareAndBranch emitStringCondBranchDelegate, GetStringHashCode computeStringHashcodeDelegate) { Debug.Assert(caseLabels.Length > 0); Debug.Assert(emitStringCondBranchDelegate != null); this.builder = builder; this.key = key; this.caseLabels = caseLabels; this.fallThroughLabel = fallThroughLabel; this.keyHash = keyHash; this.emitStringCondBranchDelegate = emitStringCondBranchDelegate; this.computeStringHashcodeDelegate = computeStringHashcodeDelegate; }
internal SwitchStringJumpTableEmitter( ILBuilder builder, LocalOrParameter key, KeyValuePair<ConstantValue, object>[] caseLabels, object fallThroughLabel, LocalDefinition keyHash, EmitStringCompareAndBranch emitStringCondBranchDelegate, GetStringHashCode computeStringHashcodeDelegate) { Debug.Assert(caseLabels.Length > 0); Debug.Assert(emitStringCondBranchDelegate != null); _builder = builder; _key = key; _caseLabels = caseLabels; _fallThroughLabel = fallThroughLabel; _keyHash = keyHash; _emitStringCondBranchDelegate = emitStringCondBranchDelegate; _computeStringHashcodeDelegate = computeStringHashcodeDelegate; }
/// <summary> /// Primary method for emitting string switch jump table /// </summary> /// <param name="caseLabels">switch case labels</param> /// <param name="fallThroughLabel">fall through label for the jump table</param> /// <param name="key">Local holding the value to switch on. /// This value has already been loaded onto the execution stack. /// </param> /// <param name="keyHash">Local holding the hash value of the key for emitting /// hash table switch. Hash value has already been computed and loaded into keyHash. /// This parameter is null if emitting non hash table switch. /// </param> /// <param name="emitStringCondBranchDelegate"> /// Delegate to emit string compare call and conditional branch based on the compare result. /// </param> /// <param name="computeStringHashcodeDelegate"> /// Delegate to compute string hash consistent with value of keyHash. /// </param> internal void EmitStringSwitchJumpTable( KeyValuePair <ConstantValue, object>[] caseLabels, object fallThroughLabel, LocalOrParameter key, LocalDefinition keyHash, SwitchStringJumpTableEmitter.EmitStringCompareAndBranch emitStringCondBranchDelegate, SwitchStringJumpTableEmitter.GetStringHashCode computeStringHashcodeDelegate) { Debug.Assert(caseLabels.Length > 0); var emitter = new SwitchStringJumpTableEmitter( this, key, caseLabels, fallThroughLabel, keyHash, emitStringCondBranchDelegate, computeStringHashcodeDelegate); emitter.EmitJumpTable(); }
internal SwitchIntegralJumpTableEmitter( ILBuilder builder, KeyValuePair <ConstantValue, object>[] caseLabels, object fallThroughLabel, Microsoft.Cci.PrimitiveTypeCode keyTypeCode, LocalDefinition keyLocal = null, int keyArgument = -1) { Debug.Assert(keyArgument == -1 ^ keyLocal == null, "cannot have both valid key argument and valid key local"); this.builder = builder; this.keyLocal = keyLocal; this.keyArgument = keyArgument; this.keyTypeCode = keyTypeCode; this.fallThroughLabel = fallThroughLabel; // Sort the switch case labels, see comments below for more details. Debug.Assert(caseLabels.Length > 0); Array.Sort(caseLabels, CompareIntegralSwitchLabels); sortedCaseLabels = ImmutableArray.Create <KeyValuePair <ConstantValue, object> >(caseLabels); }
// Generate a "load local" opcode with the given slot number. internal void EmitLocalLoad(LocalDefinition local) { var slot = local.SlotIndex; switch (slot) { case 0: EmitOpCode(ILOpCode.Ldloc_0); break; case 1: EmitOpCode(ILOpCode.Ldloc_1); break; case 2: EmitOpCode(ILOpCode.Ldloc_2); break; case 3: EmitOpCode(ILOpCode.Ldloc_3); break; default: if (slot < 0xFF) { EmitOpCode(ILOpCode.Ldloc_s); EmitInt8(unchecked ((sbyte)slot)); } else { EmitOpCode(ILOpCode.Ldloc); EmitInt32(slot); } break; } // As in ILGENREC::dumpLocal // CONSIDER: this is somewhat C# specific - it might be better to incorporate this // into the bound tree as a conversion to int. // VSADOV: pinned locals are used in C# to represent pointers in "fixed" statements. // in the user's code they are used as pointers (*), however in their implementation // they hold pinned references (O or &) to the fixed data so they need to be converted // them to unmanaged pointer type when loaded. if (local.IsPinned) { EmitOpCode(ILOpCode.Conv_i); } }
internal void EmitLocalAddress(LocalDefinition local) { if (local.IsReference) { EmitLocalLoad(local); } else { int slot = local.SlotIndex; if (slot < 0xFF) { EmitOpCode(ILOpCode.Ldloca_s); EmitInt8(unchecked ((sbyte)slot)); } else { EmitOpCode(ILOpCode.Ldloca); EmitInt32(slot); } } }
// Generate a "load local" opcode with the given slot number. internal void EmitLocalLoad(LocalDefinition local) { var slot = local.SlotIndex; switch (slot) { case 0: EmitOpCode(ILOpCode.Ldloc_0); break; case 1: EmitOpCode(ILOpCode.Ldloc_1); break; case 2: EmitOpCode(ILOpCode.Ldloc_2); break; case 3: EmitOpCode(ILOpCode.Ldloc_3); break; default: if (slot < 0xFF) { EmitOpCode(ILOpCode.Ldloc_s); EmitInt8(unchecked ((sbyte)slot)); } else { EmitOpCode(ILOpCode.Ldloc); EmitInt32(slot); } break; } // As in ILGENREC::dumpLocal // CONSIDER: this is somewhat C# specific - it might be better to incorporate this // into the bound tree as a conversion to int. // VSADOV: we do not expect fixed locals to be used for anything other than unmanaged // interop workaround so we will always convert them into native ints as soon as they are loaded. if (local.IsPinned) { EmitOpCode(ILOpCode.Conv_i); } }
// Generate a "store local" opcode with the given slot number. internal void EmitLocalStore(LocalDefinition local) { var slot = local.SlotIndex; switch (slot) { case 0: EmitOpCode(ILOpCode.Stloc_0); break; case 1: EmitOpCode(ILOpCode.Stloc_1); break; case 2: EmitOpCode(ILOpCode.Stloc_2); break; case 3: EmitOpCode(ILOpCode.Stloc_3); break; default: if (slot < 0xFF) { EmitOpCode(ILOpCode.Stloc_s); EmitInt8(unchecked ((sbyte)slot)); } else { EmitOpCode(ILOpCode.Stloc); EmitInt32(slot); } break; } }
public LocalPlace(LocalDefinition def) { Contract.ThrowIfNull(def); _def = def; }
/// <summary> /// Frees an optional temp. /// </summary> private void FreeOptTemp(LocalDefinition temp) { if (temp != null) { FreeTemp(temp); } }
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; }
private void EmitStringSwitchJumpTable( BoundSwitchStatement switchStatement, KeyValuePair<ConstantValue, object>[] switchCaseLabels, LabelSymbol fallThroughLabel, LocalDefinition key, CSharpSyntaxNode syntaxNode) { LocalDefinition keyHash = null; // Condition is necessary, but not sufficient (e.g. might be missing a special or well-known member). if (SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch(this.module, switchCaseLabels.Length)) { Debug.Assert(this.module.SupportsPrivateImplClass); var privateImplClass = this.module.GetPrivateImplClass(syntaxNode, diagnostics); Microsoft.Cci.IReference stringHashMethodRef = privateImplClass.GetMethod(PrivateImplementationDetails.SynthesizedStringHashFunctionName); // Heuristics and well-known member availability determine the existence // of this helper. Rather than reproduce that (language-specific) logic here, // we simply check for the information we really want - whether the helper is // available. if (stringHashMethodRef != null) { // static uint ComputeStringHash(string s) // pop 1 (s) // push 1 (uint return value) // stackAdjustment = (pushCount - popCount) = 0 builder.EmitLocalLoad(key); builder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0); builder.EmitToken(stringHashMethodRef, syntaxNode, diagnostics); var UInt32Type = module.Compilation.GetSpecialType(SpecialType.System_UInt32); keyHash = AllocateTemp(UInt32Type, syntaxNode); builder.EmitLocalStore(keyHash); } } Microsoft.Cci.IReference stringEqualityMethodRef = module.Translate(switchStatement.StringEquality, syntaxNode, diagnostics); Microsoft.Cci.IMethodReference stringLengthRef = null; var stringLengthMethod = module.Compilation.GetSpecialTypeMember(SpecialMember.System_String__Length) as MethodSymbol; if (stringLengthMethod != null && !stringLengthMethod.HasUseSiteError) { stringLengthRef = module.Translate(stringLengthMethod, syntaxNode, diagnostics); } SwitchStringJumpTableEmitter.EmitStringCompareAndBranch emitStringCondBranchDelegate = (keyArg, stringConstant, targetLabel) => { if (stringConstant == ConstantValue.Null) { // if (key == null) // goto targetLabel builder.EmitLocalLoad(keyArg); builder.EmitBranch(ILOpCode.Brfalse, targetLabel, ILOpCode.Brtrue); } else if (stringConstant.StringValue.Length == 0 && stringLengthRef != null) { // if (key != null && key.Length == 0) // goto targetLabel object skipToNext = new object(); builder.EmitLocalLoad(keyArg); builder.EmitBranch(ILOpCode.Brfalse, skipToNext, ILOpCode.Brtrue); builder.EmitLocalLoad(keyArg); // Stack: key --> length builder.EmitOpCode(ILOpCode.Call, 0); var diag = DiagnosticBag.GetInstance(); builder.EmitToken(stringLengthRef, null, diag); Debug.Assert(diag.IsEmptyWithoutResolution); diag.Free(); builder.EmitBranch(ILOpCode.Brfalse, targetLabel, ILOpCode.Brtrue); builder.MarkLabel(skipToNext); } else { this.EmitStringCompareAndBranch(key, syntaxNode, stringConstant, targetLabel, stringEqualityMethodRef); } }; builder.EmitStringSwitchJumpTable( caseLabels: switchCaseLabels, fallThroughLabel: fallThroughLabel, key: key, keyHash: keyHash, emitStringCondBranchDelegate: emitStringCondBranchDelegate, computeStringHashcodeDelegate: SynthesizedStringSwitchHashMethod.ComputeStringHash); if (keyHash != null) { FreeTemp(keyHash); } }
internal bool PossiblyDefinedOutsideOfTry(LocalDefinition local) => _scopeManager.PossiblyDefinedOutsideOfTry(local);
// Generate a "load local" opcode with the given slot number. internal void EmitLocalLoad(LocalDefinition local) { var slot = local.SlotIndex; switch (slot) { case 0: EmitOpCode(ILOpCode.Ldloc_0); break; case 1: EmitOpCode(ILOpCode.Ldloc_1); break; case 2: EmitOpCode(ILOpCode.Ldloc_2); break; case 3: EmitOpCode(ILOpCode.Ldloc_3); break; default: if (slot < 0xFF) { EmitOpCode(ILOpCode.Ldloc_s); EmitInt8(unchecked((sbyte)slot)); } else { EmitOpCode(ILOpCode.Ldloc); EmitInt32(slot); } break; } // As in ILGENREC::dumpLocal // CONSIDER: this is somewhat C# specific - it might be better to incorporate this // into the bound tree as a conversion to int. // VSADOV: we do not expect fixed locals to be used for anything other than unmanaged // interop workaround so we will always convert them into native ints as soon as they are loaded. if (local.IsPinned) { EmitOpCode(ILOpCode.Conv_i); } }
/// <summary> /// Frees a local slot. /// </summary> internal void FreeSlot(LocalDefinition slot) { Debug.Assert(slot.Name == null); FreeSlots.Push(new LocalSignature(slot.Type, slot.Constraints), slot); }
internal bool PossiblyDefinedOutsideOfTry(LocalDefinition local) { return(scopeManager.PossiblyDefinedOutsideOfTry(local)); }
/// <summary> /// Puts local variable into current scope. /// </summary> internal void AddLocalToScope(LocalDefinition local) { HasDynamicLocal |= !local.DynamicTransformFlags.IsEmpty; _scopeManager.AddLocal(local); }
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); } }
/// <summary> /// Returns a <see cref="LocalDefinition"/> previously obtained from <see cref="GetTemporaryLocal(TypeSymbol,bool)"/> to the /// pool of locals available for reuse. /// </summary> /// <param name="definition">The <see cref="LocalDefinition"/> to return to the pool.</param> public void ReturnTemporaryLocal(LocalDefinition/*!*/ definition) { _il.LocalSlotManager.FreeSlot(definition); }
/// <summary> /// Primary method for emitting integer switch jump table /// </summary> /// <param name="caseLabels">switch case labels</param> /// <param name="fallThroughLabel">fall through label for the jump table</param> /// <param name="keyLocal">Local holding the value to switch on. /// This value has already been loaded onto the execution stack. /// </param> /// <param name="keyTypeCode">Primitive type code of switch key</param> internal void EmitIntegerSwitchJumpTable( KeyValuePair<ConstantValue, object>[] caseLabels, object fallThroughLabel, LocalDefinition keyLocal, Microsoft.Cci.PrimitiveTypeCode keyTypeCode) { Debug.Assert(caseLabels.Length > 0); Debug.Assert(keyTypeCode != Microsoft.Cci.PrimitiveTypeCode.String); // CONSIDER: SwitchIntegralJumpTableEmitter will modify the caseLabels array by sorting it. // CONSIDER: Currently, only purpose of creating this caseLabels array is for Emitting the jump table. // CONSIDER: If this requirement changes, we may want to pass in ArrayBuilder<KeyValuePair<ConstantValue, object>> instead. var emitter = new SwitchIntegralJumpTableEmitter(this, caseLabels, fallThroughLabel, keyTypeCode, keyLocal, -1); emitter.EmitJumpTable(); }
public void Dispose() { if (_instance_loc != null) { _cg.ReturnTemporaryLocal(_instance_loc); _instance_loc = null; } if (_name_loc != null) { _cg.ReturnTemporaryLocal(_name_loc); _name_loc = null; } _cg = null; }
/// <summary> /// Primary method for emitting string switch jump table /// </summary> /// <param name="caseLabels">switch case labels</param> /// <param name="fallThroughLabel">fall through label for the jump table</param> /// <param name="key">Local holding the value to switch on. /// This value has already been loaded onto the execution stack. /// </param> /// <param name="keyHash">Local holding the hash value of the key for emitting /// hash table switch. Hash value has already been computed and loaded into keyHash. /// This parameter is null if emitting non hash table switch. /// </param> /// <param name="emitStringCondBranchDelegate"> /// Delegate to emit string compare call and conditional branch based on the compare result. /// </param> /// <param name="computeStringHashcodeDelegate"> /// Delegate to compute string hash consistent with value of keyHash. /// </param> internal void EmitStringSwitchJumpTable( KeyValuePair<ConstantValue, object>[] caseLabels, object fallThroughLabel, LocalOrParameter key, LocalDefinition keyHash, SwitchStringJumpTableEmitter.EmitStringCompareAndBranch emitStringCondBranchDelegate, SwitchStringJumpTableEmitter.GetStringHashCode computeStringHashcodeDelegate) { Debug.Assert(caseLabels.Length > 0); var emitter = new SwitchStringJumpTableEmitter( this, key, caseLabels, fallThroughLabel, keyHash, emitStringCondBranchDelegate, computeStringHashcodeDelegate); emitter.EmitJumpTable(); }
private static EncLocalInfo GetLocalInfo( IReadOnlyDictionary<SyntaxNode, int> declaratorToIndex, LocalDefinition localDef) { // Local symbol will be null for short-lived temporaries. var local = (LocalSymbol)localDef.Identity; if ((object)local != null) { var syntaxRefs = local.DeclaringSyntaxReferences; Debug.Assert(!syntaxRefs.IsDefault); if (!syntaxRefs.IsDefaultOrEmpty) { var syntax = syntaxRefs[0].GetSyntax(); var offset = declaratorToIndex[syntax]; return new EncLocalInfo(offset, localDef.Type, localDef.Constraints, (int)local.TempKind); } } return new EncLocalInfo(localDef.Type, localDef.Constraints); }
// Generate a "load local" opcode with the given slot number. internal void EmitLocalLoad(LocalDefinition local) { var slot = local.SlotIndex; switch (slot) { case 0: EmitOpCode(ILOpCode.Ldloc_0); break; case 1: EmitOpCode(ILOpCode.Ldloc_1); break; case 2: EmitOpCode(ILOpCode.Ldloc_2); break; case 3: EmitOpCode(ILOpCode.Ldloc_3); break; default: if (slot < 0xFF) { EmitOpCode(ILOpCode.Ldloc_s); EmitInt8(unchecked((sbyte)slot)); } else { EmitOpCode(ILOpCode.Ldloc); EmitInt32(slot); } break; } // As in ILGENREC::dumpLocal // CONSIDER: this is somewhat C# specific - it might be better to incorporate this // into the bound tree as a conversion to int. // VSADOV: pinned locals are used in C# to represent pointers in "fixed" statements. // in the user's code they are used as pointers (*), however in their implementation // they hold pinned references (O or &) to the fixed data so they need to be converted // them to unmanaged pointer type when loaded. if (local.IsPinned) { EmitOpCode(ILOpCode.Conv_i); } }
/// <summary> /// Puts local variable into current scope. /// </summary> internal void AddLocalToScope(LocalDefinition local) { HasDynamicLocal |= local.IsDynamic; _scopeManager.AddLocal(local); }
/// <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; }
internal void EmitLocalAddress(LocalDefinition local) { if (local.IsReference) { EmitLocalLoad(local); } else { int slot = local.SlotIndex; if (slot < 0xFF) { EmitOpCode(ILOpCode.Ldloca_s); EmitInt8(unchecked((sbyte)slot)); } else { EmitOpCode(ILOpCode.Ldloca); EmitInt32(slot); } } }
private void EmitAssignmentPostfix(BoundAssignmentOperator assignment, LocalDefinition temp, UseKind useKind) { if (temp != null) { _builder.EmitLocalLoad(temp); FreeTemp(temp); } if (useKind == UseKind.UsedAsValue && assignment.RefKind != RefKind.None) { EmitLoadIndirect(assignment.Type, assignment.Syntax); } }
private LocalOrParameter(LocalDefinition local, int parameterIndex) { this.Local = local; this.ParameterIndex = parameterIndex; }
public static LocalInfo ToLocalInfo(LocalDefinition local) { // May be null for deleted locals in edit and continue. if (local == null) { return default(LocalInfo); } return new LocalInfo(local.Name, local.Type, local.IsPinned, local.IsReference); }
/// <summary> /// Delegate to emit string compare call and conditional branch based on the compare result. /// </summary> /// <param name="key">Key to compare</param> /// <param name="syntaxNode">Node for diagnostics.</param> /// <param name="stringConstant">Case constant to compare the key against</param> /// <param name="targetLabel">Target label to branch to if key = stringConstant</param> /// <param name="stringEqualityMethodRef">String equality method</param> private void EmitStringCompareAndBranch(LocalDefinition key, SyntaxNode syntaxNode, ConstantValue stringConstant, object targetLabel, Microsoft.Cci.IReference stringEqualityMethodRef) { // Emit compare and branch: // if (key == stringConstant) // goto targetLabel; Debug.Assert(stringEqualityMethodRef != null); #if DEBUG var assertDiagnostics = DiagnosticBag.GetInstance(); Debug.Assert(stringEqualityMethodRef == module.Translate((MethodSymbol)module.Compilation.GetSpecialTypeMember(SpecialMember.System_String__op_Equality), (CSharpSyntaxNode)syntaxNode, assertDiagnostics)); assertDiagnostics.Free(); #endif // static bool String.Equals(string a, string b) // pop 2 (a, b) // push 1 (bool return value) // stackAdjustment = (pushCount - popCount) = -1 builder.EmitLocalLoad(key); builder.EmitConstantValue(stringConstant); builder.EmitOpCode(ILOpCode.Call, stackAdjustment: -1); builder.EmitToken(stringEqualityMethodRef, syntaxNode, diagnostics); // Branch to targetLabel if String.Equals returned true. builder.EmitBranch(ILOpCode.Brtrue, targetLabel, ILOpCode.Brfalse); }
internal override bool ContainsLocal(LocalDefinition local) { ImmutableArray <LocalDefinition> .Builder locals = _localVariables; return(locals != null && locals.Contains(local)); }
/// <summary> /// Frees a temp. /// </summary> private void FreeTemp(LocalDefinition temp) { _builder.LocalSlotManager.FreeSlot(temp); }
/// <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); } }
internal virtual bool ContainsLocal(LocalDefinition local) { return(false); }
internal void AddLocal(LocalDefinition variable) { LocalScopeInfo scope = (LocalScopeInfo)CurrentScope; scope.AddLocal(variable); }
internal override bool ContainsLocal(LocalDefinition local) { var locals = _localVariables; return(locals != null && locals.Contains(local)); }
internal virtual bool ContainsLocal(LocalDefinition local) => false;
private void EmitAssignmentPostfix(LocalDefinition temp) { if (temp != null) { _builder.EmitLocalLoad(temp); FreeTemp(temp); } }
// Generate a "store local" opcode with the given slot number. internal void EmitLocalStore(LocalDefinition local) { var slot = local.SlotIndex; switch (slot) { case 0: EmitOpCode(ILOpCode.Stloc_0); break; case 1: EmitOpCode(ILOpCode.Stloc_1); break; case 2: EmitOpCode(ILOpCode.Stloc_2); break; case 3: EmitOpCode(ILOpCode.Stloc_3); break; default: if (slot < 0xFF) { EmitOpCode(ILOpCode.Stloc_s); EmitInt8(unchecked((sbyte)slot)); } else { EmitOpCode(ILOpCode.Stloc); EmitInt32(slot); } break; } }
/// <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; }