Пример #1
0
        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);
            }
        }
Пример #2
0
        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;
        }
Пример #3
0
        /// <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();
        }
Пример #4
0
        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;
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
            }
Пример #8
0
        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);
        }
Пример #9
0
        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;
        }
Пример #11
0
        /// <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);
        }
Пример #13
0
        // 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);
            }
        }
Пример #14
0
        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);
                }
            }
        }
Пример #15
0
        // 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);
            }
        }
Пример #16
0
        // 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;
            }
        }
Пример #17
0
 public LocalPlace(LocalDefinition def)
 {
     Contract.ThrowIfNull(def);
     _def = def;
 }
Пример #18
0
 /// <summary>
 /// Frees an optional temp.
 /// </summary>
 private void FreeOptTemp(LocalDefinition temp)
 {
     if (temp != null)
     {
         FreeTemp(temp);
     }
 }
Пример #19
0
        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;
        }
Пример #20
0
        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);
            }
        }
Пример #21
0
 internal bool PossiblyDefinedOutsideOfTry(LocalDefinition local)
     => _scopeManager.PossiblyDefinedOutsideOfTry(local);
Пример #22
0
 internal bool PossiblyDefinedOutsideOfTry(LocalDefinition local)
 => _scopeManager.PossiblyDefinedOutsideOfTry(local);
Пример #23
0
        // 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);
            }
        }
Пример #24
0
 /// <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);
 }
Пример #25
0
 internal bool PossiblyDefinedOutsideOfTry(LocalDefinition local)
 {
     return(scopeManager.PossiblyDefinedOutsideOfTry(local));
 }
Пример #26
0
 /// <summary>
 /// Puts local variable into current scope.
 /// </summary>
 internal void AddLocalToScope(LocalDefinition local)
 {
     HasDynamicLocal |= !local.DynamicTransformFlags.IsEmpty;
     _scopeManager.AddLocal(local);
 }
Пример #27
0
        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);
            }
        }
Пример #28
0
 /// <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);
 }
Пример #29
0
        /// <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();
        }
Пример #30
0
        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;
        }
Пример #31
0
        /// <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();
        }
Пример #32
0
        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);
        }
Пример #33
0
        // 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);
            }
        }
Пример #34
0
 /// <summary>
 /// Puts local variable into current scope.
 /// </summary>
 internal void AddLocalToScope(LocalDefinition local)
 {
     HasDynamicLocal |= local.IsDynamic;
     _scopeManager.AddLocal(local);
 }
Пример #35
0
            /// <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;
            }
Пример #36
0
 /// <summary>
 /// Puts local variable into current scope.
 /// </summary>
 internal void AddLocalToScope(LocalDefinition local)
 {
     HasDynamicLocal |= local.IsDynamic;
     _scopeManager.AddLocal(local);
 }
Пример #37
0
        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);
                }
            }
        }
Пример #38
0
 /// <summary>
 /// Puts local variable into current scope.
 /// </summary>
 internal void AddLocalToScope(LocalDefinition local)
 {
     HasDynamicLocal |= !local.DynamicTransformFlags.IsEmpty;
     _scopeManager.AddLocal(local);
 }
Пример #39
0
        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);
            }
        }
Пример #40
0
 private LocalOrParameter(LocalDefinition local, int parameterIndex)
 {
     this.Local          = local;
     this.ParameterIndex = parameterIndex;
 }
Пример #41
0
 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);
 }
Пример #42
0
        /// <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));
 }
Пример #44
0
 /// <summary>
 /// Frees a temp.
 /// </summary>
 private void FreeTemp(LocalDefinition temp)
 {
     _builder.LocalSlotManager.FreeSlot(temp);
 }
Пример #45
0
        /// <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);
            }
        }
Пример #46
0
 internal virtual bool ContainsLocal(LocalDefinition local)
 {
     return(false);
 }
Пример #47
0
 private LocalOrParameter(LocalDefinition local, int parameterIndex)
 {
     this.Local = local;
     this.ParameterIndex = parameterIndex;
 }
            internal void AddLocal(LocalDefinition variable)
            {
                LocalScopeInfo scope = (LocalScopeInfo)CurrentScope;

                scope.AddLocal(variable);
            }
Пример #49
0
            internal override bool ContainsLocal(LocalDefinition local)
            {
                var locals = _localVariables;

                return(locals != null && locals.Contains(local));
            }
 internal virtual bool ContainsLocal(LocalDefinition local) => false;
Пример #51
0
 private void EmitAssignmentPostfix(LocalDefinition temp)
 {
     if (temp != null)
     {
         _builder.EmitLocalLoad(temp);
         FreeTemp(temp);
     }
 }
Пример #52
0
 // 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;
     }
 }
Пример #53
0
        /// <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;
        }