internal void EmitLoad(LocalOrParameter localOrParameter) { if (localOrParameter.Local != null) { EmitLocalLoad(localOrParameter.Local); } else { EmitLoadArgumentOpcode(localOrParameter.ParameterIndex); } }
internal SwitchIntegralJumpTableEmitter( ILBuilder builder, KeyValuePair <ConstantValue, object>[] caseLabels, object fallThroughLabel, Cci.PrimitiveTypeCode keyTypeCode, LocalOrParameter key) { _builder = builder; _key = key; _keyTypeCode = keyTypeCode; _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(caseLabels); }
internal void EmitIntegerSwitchJumpTable( KeyValuePair <ConstantValue, object>[] caseLabels, object fallThroughLabel, LocalOrParameter key, Cci.PrimitiveTypeCode keyTypeCode) { Debug.Assert(caseLabels.Length > 0); Debug.Assert(keyTypeCode != 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, key); emitter.EmitJumpTable(); }
internal SwitchIntegralJumpTableEmitter( ILBuilder builder, KeyValuePair<ConstantValue, object>[] caseLabels, object fallThroughLabel, Cci.PrimitiveTypeCode keyTypeCode, LocalOrParameter key) { this.builder = builder; this.key = key; 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(caseLabels); }
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; }
internal SwitchStringJumpTableEmitter( ILBuilder builder, LocalOrParameter key, KeyValuePair <ConstantValue, object>[] caseLabels, object fallThroughLabel, LocalDefinition?keyHash, EmitStringCompareAndBranch emitStringCondBranchDelegate, GetStringHashCode computeStringHashcodeDelegate) { Debug.Assert(caseLabels.Length > 0); RoslynDebug.Assert(emitStringCondBranchDelegate != null); _builder = builder; _key = key; _caseLabels = caseLabels; _fallThroughLabel = fallThroughLabel; _keyHash = keyHash; _emitStringCondBranchDelegate = emitStringCondBranchDelegate; _computeStringHashcodeDelegate = computeStringHashcodeDelegate; }
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(); }
/// <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(LocalOrParameter 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.EmitLoad(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); }
private void EmitStringSwitchJumpTable( BoundSwitchStatement switchStatement, KeyValuePair<ConstantValue, object>[] switchCaseLabels, LabelSymbol fallThroughLabel, LocalOrParameter key, SyntaxNode syntaxNode) { LocalDefinition keyHash = null; // Condition is necessary, but not sufficient (e.g. might be missing a special or well-known member). if (SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch(_module, switchCaseLabels.Length)) { Debug.Assert(_module.SupportsPrivateImplClass); var privateImplClass = _module.GetPrivateImplClass(syntaxNode, _diagnostics); 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.EmitLoad(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); } } Cci.IReference stringEqualityMethodRef = _module.Translate(switchStatement.StringEquality, syntaxNode, _diagnostics); 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.EmitLoad(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.EmitLoad(keyArg); _builder.EmitBranch(ILOpCode.Brfalse, skipToNext, ILOpCode.Brtrue); _builder.EmitLoad(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); } }
/// <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="key">Local or parameter 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, LocalOrParameter key, Cci.PrimitiveTypeCode keyTypeCode) { Debug.Assert(caseLabels.Length > 0); Debug.Assert(keyTypeCode != 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, key); emitter.EmitJumpTable(); }
/// <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(); }