GetTemporaryLocal() public method

Returns a LocalDefinition of a temporary local variable of a specified TypeSymbol.
If a LocalDefinition of the given TypeSymbol has already been declared and returned to the pool, this local is reused. Otherwise, a new local is declared. Use this method to obtain a short-lived temporary local. Return the local to the pool of locals available for reuse by calling ReturnTemporaryLocal.
public GetTemporaryLocal ( TypeSymbol type ) : Microsoft.CodeAnalysis.CodeGen.LocalDefinition
type TypeSymbol The requested of the local.
return Microsoft.CodeAnalysis.CodeGen.LocalDefinition
            /// <summary>
            /// Stores the value from top of the stack into this temporary local variable.
            /// </summary>
            public void EmitStore()
            {
                if (_loc != null)
                {
                    _cg.Builder.EmitLocalStore(_loc);
                }
                else
                {
                    Debug.Assert(_cg.TemporalLocalsPlace != null);
                    Debug.Assert(_tempName != null);

                    /*
                     * tmp = <STACK>
                     * <temporary>[name] = tmp;
                     */
                    var tmp = _cg.GetTemporaryLocal(Type, true);
                    _cg.Builder.EmitLocalStore(tmp);

                    _cg.TemporalLocalsPlace.EmitLoad(_cg.Builder);
                    _cg.EmitIntStringKey(_tempName);
                    _cg.Builder.EmitLocalLoad(tmp);
                    _cg.EmitConvert(Type, 0, _cg.CoreTypes.PhpValue);
                    _cg.EmitCall(System.Reflection.Metadata.ILOpCode.Callvirt, _cg.CoreMethods.PhpArray.SetItemValue_IntStringKey_PhpValue);
                }
            }
Esempio n. 2
0
                /// <summary>
                /// Emit runtime chain.
                /// </summary>
                /// <returns>Runtime chain value type pushed on top of the stack.</returns>
                public TypeSymbol EmitRuntimeChain(CodeGenerator cg)
                {
                    // create and initialize the chain struct
                    var chaintmp = cg.GetTemporaryLocal(this.Type, true);

                    cg.Builder.EmitLocalAddress(chaintmp);
                    cg.Builder.EmitOpCode(ILOpCode.Initobj);
                    cg.Builder.EmitSymbolToken(cg.Module, cg.Diagnostics, this.Type, null);

                    // fill in the fields
                    for (var element = this; element != null; element = element.Next)
                    {
                        Debug.Assert(element.Type.IsValueType);

                        if (element.Fields != null)
                        {
                            foreach (var pair in element.Fields)
                            {
                                // Template: ADDR chain.Next[.Next]
                                cg.Builder.EmitLocalAddress(chaintmp);
                                for (var x = this; x != element; x = x.Next)
                                {
                                    var nextfield = new FieldPlace_Raw((FieldSymbol)x.Type.GetMembers("Next").Single(), cg.Module);
                                    nextfield.EmitLoadAddress(cg.Builder);
                                }

                                // Template: .<Field> = <Value>
                                var valuefield = new FieldPlace_Raw((FieldSymbol)element.Type.GetMembers(pair.Key).Single(), cg.Module);
                                valuefield.EmitStorePrepare(cg.Builder);
                                if (pair.Value is BoundExpression valueexpr)
                                {
                                    cg.EmitConvert(valueexpr, valuefield.Type);
                                }
                                else if (pair.Value is BoundVariableName nameexpr)
                                {
                                    cg.EmitConvert(nameexpr.EmitVariableName(cg), 0, valuefield.Type);
                                }
                                else
                                {
                                    throw Peachpie.CodeAnalysis.Utilities.ExceptionUtilities.UnexpectedValue(pair.Value);
                                }
                                valuefield.EmitStore(cg.Builder);
                            }
                        }
                    }

                    //
                    cg.Builder.EmitLocalLoad(chaintmp);

                    //
                    return(this.Type);
                }
Esempio n. 3
0
        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;
        }
Esempio n. 4
0
        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;
        }
Esempio n. 5
0
        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);
            }
        }
Esempio n. 6
0
        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;
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        /// <summary>
        /// Emits the given conversion. 'from' and 'to' matches the classified conversion.
        /// </summary>
        public static void EmitConversion(this CodeGenerator cg, CommonConversion conversion, TypeSymbol from, TypeSymbol to, TypeSymbol op = null, bool @checked = false)
        {
            // {from}, {op} is loaded on stack

            //

            if (conversion.Exists == false)
            {
                throw cg.NotImplementedException($"Conversion from '{from}' to '{to}' ");
            }

            if (conversion.IsNullable)
            {
                if (from.IsNullableType(out var ttype))
                {
                    if (op != null)
                    {
                        // TODO
                        throw new ArgumentException(nameof(op));
                    }

                    var lbltrue = new NamedLabel("has value");
                    var lblend  = new NamedLabel("end");
                    var tmp     = cg.GetTemporaryLocal(from, true);
                    cg.Builder.EmitLocalStore(tmp);

                    // Template: tmp.HasValue ? convert(tmp.Value) : default
                    cg.Builder.EmitLocalAddress(tmp);
                    cg.EmitCall(ILOpCode.Call, cg.DeclaringCompilation.System_Nullable_T_HasValue(from));
                    cg.Builder.EmitBranch(ILOpCode.Brtrue, lbltrue);

                    // default:
                    cg.EmitLoadDefault(to);
                    cg.Builder.EmitBranch(ILOpCode.Br, lblend);
                    // cg.Builder.AdjustStack(-1); // ?

                    // lbltrue:
                    cg.Builder.MarkLabel(lbltrue);
                    // Template: convert( tmp.GetValueOrDefault() )
                    cg.Builder.EmitLocalAddress(tmp);
                    cg.EmitCall(ILOpCode.Call, cg.DeclaringCompilation.System_Nullable_T_GetValueOrDefault(from)).Expect(ttype);
                    EmitConversion(cg, conversion.WithIsNullable(false), ttype, to, op, @checked);

                    // lblend:
                    cg.Builder.MarkLabel(lblend);

                    return;
                }

                if (to.IsNullableType(out ttype)) // NOTE: not used yet
                {
                    // new Nullable<TType>( convert(from) )
                    EmitConversion(cg, conversion.WithIsNullable(false), from, ttype, op, @checked);
                    cg.EmitCall(ILOpCode.Newobj, ((NamedTypeSymbol)to).InstanceConstructors[0]); // new Nullable<T>( STACK )
                    return;
                }

                throw Roslyn.Utilities.ExceptionUtilities.Unreachable;
            }

            if (conversion.IsIdentity)
            {
                if (op != null)
                {
                    throw new ArgumentException(nameof(op));
                }

                if (to.SpecialType == SpecialType.System_Void)
                {
                    // POP
                    cg.EmitPop(from);
                }

                // nop
            }
            else if (conversion.IsNumeric)
            {
                if (op != null)
                {
                    throw new ArgumentException(nameof(op));
                }

                EmitNumericConversion(cg, from, to, @checked: @checked);
            }
            else if (conversion.IsReference)
            {
                if (op != null)
                {
                    throw new ArgumentException(nameof(op));
                }

                // TODO: ensure from/to is a valid reference type
                cg.EmitCastClass(to);
            }
            else if (conversion.IsUserDefined)
            {
                var method    = (MethodSymbol)conversion.MethodSymbol;
                var ps        = method.Parameters;
                int pconsumed = 0;

                if (method.HasThis)
                {
                    if (from.IsValueType)
                    {
                        if (op != null || from.IsVoid())
                        {
                            throw new ArgumentException(nameof(op));
                        }

                        cg.EmitStructAddr(from);
                    }
                }
                else
                {
                    if (ps[0].RefKind != RefKind.None)
                    {
                        throw new InvalidOperationException();
                    }
                    if (from != ps[0].Type)
                    {
                        if (op != null)
                        {
                            if (!ps[0].Type.IsAssignableFrom(from))
                            {
                                throw new ArgumentException(nameof(op));
                            }
                        }
                        else
                        {
                            EmitImplicitConversion(cg, from, ps[0].Type, @checked: @checked);
                        }
                    }
                    pconsumed++;
                }

                if (op != null)
                {
                    if (ps.Length > pconsumed)
                    {
                        EmitImplicitConversion(cg, op, ps[pconsumed].Type, @checked: @checked);
                    }
                    pconsumed++;
                }

                // Context ctx,
                if (ps.Length > pconsumed && SpecialParameterSymbol.IsContextParameter(ps[pconsumed]))
                {
                    cg.EmitLoadContext();
                    pconsumed++;
                }

                if (ps.Length != pconsumed)
                {
                    throw new InvalidOperationException();
                }

                EmitImplicitConversion(cg, cg.EmitCall(method.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call, method), to, @checked: true);
            }
            else
            {
                throw new NotImplementedException();
            }
        }
Esempio n. 9
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);
            }
        }
Esempio n. 10
0
        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);
        }
Esempio n. 11
0
        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();
        }
Esempio n. 12
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);
            }
        }
Esempio n. 13
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;
        }
Esempio n. 14
0
        /// <summary>
        /// Stores value from top of the evaluation stack to a temporary variable which will be returned from the exit block.
        /// </summary>
        internal void EmitTmpRet(CodeGenerator cg, Symbols.TypeSymbol stack)
        {
            // lazy initialize
            if (_retlbl == null)
            {
                _retlbl = new object();
            }

            if (_rettmp == null)
            {
                var rtype = cg.Routine.ReturnType;
                if (rtype.SpecialType != SpecialType.System_Void)
                {
                    _rettmp = cg.GetTemporaryLocal(rtype);
                }
            }

            // <rettmp> = <stack>;
            if (_rettmp != null)
            {
                cg.EmitConvert(stack, 0, (Symbols.TypeSymbol)_rettmp.Type);
                cg.Builder.EmitLocalStore(_rettmp);
                cg.Builder.EmitBranch(ILOpCode.Br, _retlbl);
            }
            else
            {
                cg.EmitPop(stack);
            }
        }
Esempio n. 15
0
            /// <summary>
            /// Loads temporary local variable as an argument to <paramref name="targetp"/>.
            /// </summary>
            /// <param name="cg"></param>
            /// <param name="targetp">Target parameter.</param>
            /// <param name="expr">Value to be passed as its argument.</param>
            /// <returns><see cref="WriteBackInfo"/> which has to be finalized with <see cref="WriteBackAndFree(CodeGenerator)"/> once the routine call ends.</returns>
            public static WriteBackInfo CreateAndLoad(CodeGenerator cg, ParameterSymbol targetp, BoundReferenceExpression expr)
            {
                var writeback =  new WriteBackInfo()
                {
                    TmpLocal = cg.GetTemporaryLocal(targetp.Type),
                    Target = expr,
                };

                //
                writeback.EmitLoadArgument(cg, targetp);

                //
                return writeback;
            }