Manages context of local variables, their merged type and return value type.
Beispiel #1
0
        /// <summary>
        /// Creates new type context, flow context and flow state for the routine.
        /// </summary>
        public static FlowState CreateInitialState(SourceRoutineSymbol /*!*/ routine)
        {
            Contract.ThrowIfNull(routine);

            // create typeCtx
            var typeCtx = routine.TypeRefContext;

            // create FlowContext
            var flowCtx = new FlowContext(typeCtx, routine);

            // create FlowState
            var state = new FlowState(flowCtx);

            // handle input parameters type
            var parameters = routine.Parameters.OfType <SourceParameterSymbol>().ToImmutableArray();

            foreach (var p in parameters)
            {
                state.SetVar(p.Name, p.GetResultType(typeCtx));

                if (p.Syntax.PassedByRef)
                {
                    state.SetVarRef(p.Name);
                }
            }

            // $this
            if (routine.HasThis)
            {
                InitThisVar(flowCtx, state);
            }

            //
            return(state);
        }
Beispiel #2
0
        /// <summary>
        /// Creates new type context, flow context and flow state for the routine.
        /// </summary>
        public static FlowState CreateInitialState(SourceRoutineSymbol /*!*/ routine, FlowContext flowCtx = null)
        {
            Contract.ThrowIfNull(routine);

            // get or create typeCtx
            var typeCtx = routine.TypeRefContext;

            if (flowCtx == null)
            {
                // create FlowContext
                flowCtx = new FlowContext(typeCtx, routine);
            }

            // create FlowState
            var state = new FlowState(flowCtx);

            // handle input parameters type
            foreach (var p in routine.SourceParameters)
            {
                var local = state.GetLocalHandle(new VariableName(p.Name));
                var ptype = p.GetResultType(typeCtx);
                state.SetLocalType(local, ptype);
            }

            // $this
            if (routine.GetPhpThisVariablePlace() != null)
            {
                InitThisVar(flowCtx, state);
            }

            //
            return(state);
        }
Beispiel #3
0
        /// <summary>
        /// Merge constructor.
        /// </summary>
        public FlowState(FlowState state1, FlowState state2)
        {
            Debug.Assert(state1 != null);
            Debug.Assert(state2 != null);
            Debug.Assert(state1.FlowContext == state2.FlowContext);

            //
            _varsType        = EnumeratorExtension.MixArrays(state1._varsType, state2._varsType, TypeRefMask.Or);
            _flowCtx         = state1._flowCtx;
            _initializedMask = state1._initializedMask & state2._initializedMask;

            // intersection of other variable flags
            if (state1._lessThanLongMax != null && state2._lessThanLongMax != null)
            {
                _lessThanLongMax = new HashSet <VariableHandle>(state1._lessThanLongMax);
                _lessThanLongMax.Intersect(state2._lessThanLongMax);
            }

            //// merge variables kind,
            //// conflicting kinds are not allowed currently!
            //if (state1._varKindMap != null || state1._varKindMap != null)
            //{
            //    _varKindMap = new Dictionary<VariableName, VariableKind>();
            //    if (state1._varKindMap != null) state1._varKindMap.Foreach(k => SetVarKind(k.Key, k.Value));
            //    if (state2._varKindMap != null) state2._varKindMap.Foreach(k => SetVarKind(k.Key, k.Value));
            //}
        }
Beispiel #4
0
        /// <summary>
        /// Merge constructor.
        /// </summary>
        public FlowState(FlowState state1, FlowState state2)
        {
            Debug.Assert(state1 != null);
            Debug.Assert(state2 != null);
            Debug.Assert(state1.FlowContext == state2.FlowContext);
            Debug.Assert(state1.Version == state2.Version);

            //
            _flowCtx         = state1._flowCtx;
            _varsType        = EnumeratorExtension.MergeArrays(state1._varsType, state2._varsType, MergeType);
            _initializedMask = state1._initializedMask | state2._initializedMask;

            // intersection of other variable flags
            if (state1._notes != null && state2._notes != null)
            {
                _notes = new HashSet <NoteData>(state1._notes);
                _notes.Intersect(state2._notes);
            }

            _version = state1.Version;

            //// merge variables kind,
            //// conflicting kinds are not allowed currently!
            //if (state1._varKindMap != null || state1._varKindMap != null)
            //{
            //    _varKindMap = new Dictionary<VariableName, VariableKind>();
            //    if (state1._varKindMap != null) state1._varKindMap.Foreach(k => SetVarKind(k.Key, k.Value));
            //    if (state2._varKindMap != null) state2._varKindMap.Foreach(k => SetVarKind(k.Key, k.Value));
            //}
        }
Beispiel #5
0
        /// <summary>
        /// Creates new type context, flow context and flow state for the routine.
        /// </summary>
        public static FlowState CreateInitialState(SourceRoutineSymbol/*!*/routine)
        {
            Contract.ThrowIfNull(routine);

            // create typeCtx
            var typeCtx = routine.TypeRefContext;

            // create FlowContext 
            var flowCtx = new FlowContext(typeCtx, routine);

            // create FlowState
            var state = new FlowState(flowCtx);

            // handle input parameters type
            var parameters = routine.Parameters.OfType<SourceParameterSymbol>().ToImmutableArray();
            foreach (var p in parameters)
            {
                state.SetVar(p.Name, p.GetResultType(typeCtx));

                if (p.Syntax.PassedByRef)
                {
                    state.SetVarRef(p.Name);
                }
            }

            // $this
            if (routine.HasThis)
            {
                InitThisVar(flowCtx, state);
            }

            //
            return state;
        }
Beispiel #6
0
        /// <summary>
        /// Copy constructor.
        /// </summary>
        private FlowState(FlowContext /*!*/ flowCtx, TypeRefMask[] /*!*/ varsType)
        {
            Contract.ThrowIfNull(flowCtx);
            Contract.ThrowIfNull(varsType);

            _flowCtx  = flowCtx;
            _varsType = (TypeRefMask[])varsType.Clone();
        }
Beispiel #7
0
        /// <summary>
        /// Initial locals state for the Start block.
        /// </summary>
        internal FlowState(FlowContext /*!*/ flowcontext, CommonState /*!*/ common)
        {
            Contract.ThrowIfNull(flowcontext);

            _common          = common;
            _initializedMask = (ulong)0;

            var count = flowcontext.Locals.Length;

            _varsType = new TypeRefMask[count];
        }
Beispiel #8
0
 /// <summary>
 /// Sets the initial routine return type.
 /// </summary>
 /// <param name="ctx"></param>
 /// <param name="initialState"></param>
 /// <param name="phpdoc"></param>
 static void InitReturn(FlowContext /*!*/ ctx, FlowState /*!*/ initialState, PHPDocBlock phpdoc)
 {
     Debug.Assert(ctx.ReturnVarIndex >= 0);
     if (phpdoc != null)
     {
         var returnTag = phpdoc.Returns;
         if (returnTag != null && returnTag.TypeNamesArray.Length != 0)
         {
             initialState.SetVar(ctx.ReturnVarIndex, PHPDoc.GetTypeMask(ctx.TypeRefContext, returnTag.TypeNamesArray));
         }
     }
 }
Beispiel #9
0
        /// <summary>
        /// Initializes <c>$this</c> variable, its type and initialized state.
        /// </summary>
        private static void InitThisVar(FlowContext /*!*/ ctx, FlowState /*!*/ initialState, int varIndex)
        {
            var thisVarType = ctx.TypeRefContext.GetThisTypeMask();

            if (thisVarType.IsUninitialized)
            {
                thisVarType = TypeRefMask.AnyType;
            }

            //
            initialState.SetVarUsed(varIndex);
            initialState.SetVar(varIndex, thisVarType);
        }
Beispiel #10
0
        /// <summary>
        /// Initializes <c>$this</c> variable, its type and initialized state.
        /// </summary>
        private static void InitThisVar(FlowContext/*!*/ctx, FlowState/*!*/initialState)
        {
            var thisVarType = ctx.TypeRefContext.GetThisTypeMask();
            if (thisVarType.IsUninitialized)
            {
                thisVarType = TypeRefMask.AnyType;
            }

            //
            var thisIdx = ctx.GetVarIndex(VariableName.ThisVariableName);
            initialState.SetVarUsed(thisIdx);
            initialState.SetVar(thisIdx, thisVarType);
        }
Beispiel #11
0
        /// <summary>
        /// Initial locals state for the Start block.
        /// </summary>
        internal FlowState(FlowContext /*!*/ flowCtx)
        {
            Contract.ThrowIfNull(flowCtx);

            _flowCtx         = flowCtx;
            _initializedMask = (ulong)0;

            // initial size of the array
            var countHint = (flowCtx.Routine != null)
                ? flowCtx.Routine.LocalsTable.Count
                : 0;

            _varsType = new TypeRefMask[countHint];
        }
Beispiel #12
0
        /// <summary>
        /// Sets all variables as initialized at this state and with a <c>mixed</c> type.
        /// </summary>
        public void SetAllUnknown(bool maybeRef)
        {
            var tmask = maybeRef
                ? TypeRefMask.AnyType.WithRefFlag
                : TypeRefMask.AnyType;

            foreach (var v in FlowContext.EnumerateVariables())
            {
                SetLocalType(v, tmask);
            }

            // all initialized
            _initializedMask = ~0u;
        }
Beispiel #13
0
        /// <summary>
        /// Creates new type context, flow context and flow state for the routine.
        /// </summary>
        public static FlowState CreateInitialState(SourceRoutineSymbol /*!*/ routine, FlowContext flowCtx = null)
        {
            Contract.ThrowIfNull(routine);

            // get or create typeCtx
            var typeCtx = routine.TypeRefContext;

            if (flowCtx == null)
            {
                // create FlowContext
                flowCtx = new FlowContext(typeCtx, routine);
            }

            // create FlowState
            var state = new FlowState(flowCtx);

            // handle input parameters type
            foreach (var p in routine.SourceParameters)
            {
                var local = state.GetLocalHandle(new VariableName(p.Name));
                var ptype = p.GetResultType(typeCtx);
                if (p.IsNotNull)
                {
                    // remove 'null' type from the mask,
                    // it cannot be null
                    ptype = typeCtx.WithoutNull(ptype);
                }
                else if (p.Type.IsReferenceType)    // a reference type that can be null
                {
                    ptype |= typeCtx.GetNullTypeMask();
                }

                state.SetLocalType(local, ptype);

                if (p.Syntax.PassedByRef && !p.Syntax.IsVariadic)
                {
                    state.MarkLocalByRef(local);
                }
            }

            // $this
            if (routine.GetPhpThisVariablePlace() != null)
            {
                InitThisVar(flowCtx, state);
            }

            //
            return(state);
        }
Beispiel #14
0
        /// <summary>
        /// Initializes <c>$this</c> variable, its type and initialized state.
        /// </summary>
        private static void InitThisVar(FlowContext /*!*/ ctx, FlowState /*!*/ initialState)
        {
            var thisVarType = ctx.TypeRefContext.GetThisTypeMask();

            if (thisVarType.IsUninitialized)
            {
                thisVarType = TypeRefMask.AnyType;
            }

            //
            var thisIdx = ctx.GetVarIndex(VariableName.ThisVariableName);

            initialState.SetVarUsed(thisIdx);
            initialState.SetVar(thisIdx, thisVarType);
        }
Beispiel #15
0
        /// <summary>
        /// Initializes <c>$this</c> variable, its type and initialized state.
        /// </summary>
        private static void InitThisVar(FlowContext /*!*/ ctx, FlowState /*!*/ initialState)
        {
            var thisVarType = ctx.TypeRefContext.GetThisTypeMask();

            if (thisVarType.IsUninitialized)
            {
                thisVarType = TypeRefMask.AnyType;
            }

            //
            var thisHandle = ctx.GetVarIndex(VariableName.ThisVariableName);

            initialState.SetLocalType(thisHandle, thisVarType); // set $this type
            initialState.VisitLocal(thisHandle);                // mark as visited (used) to not report as unused
        }
Beispiel #16
0
        /// <summary>
        /// Initial locals state for the Start block.
        /// </summary>
        internal FlowState(FlowContext /*!*/ flowCtx)
        {
            Contract.ThrowIfNull(flowCtx);

            FlowContext      = flowCtx;
            _initializedMask = 0ul;

            // initial size of the array
            var countHint = (flowCtx.Routine != null)
                ? flowCtx.VarsType.Length
                : 0;

            _varsType = countHint != 0 ? new TypeRefMask[countHint] : Array.Empty <TypeRefMask>();

            Version = flowCtx.Version;
        }
Beispiel #17
0
        /// <summary>
        /// Initial locals state for the Start block.
        /// </summary>
        internal FlowState(FlowContext /*!*/ flowCtx)
        {
            Contract.ThrowIfNull(flowCtx);

            FlowContext      = flowCtx;
            _initializedMask = (ulong)0;

            // initial size of the array
            var countHint = (flowCtx.Routine != null)
                ? flowCtx.VarsType.Length
                : 0;

            _varsType = new TypeRefMask[countHint];

            Version = flowCtx.Version;
        }
Beispiel #18
0
            public CommonState(FlowContext /*!*/ flowcontext, Symbols.SourceRoutineSymbol /*!*/ routine)
            {
                Debug.Assert(flowcontext != null);
                Debug.Assert(routine != null);

                _flowcontext = flowcontext;
                _routine     = routine;

                var locals = flowcontext.Locals;
                var dict   = new Dictionary <string, int>(locals.Length, StringComparer.OrdinalIgnoreCase);

                for (int i = 0; i < locals.Length; i++)
                {
                    dict[locals[i].Name] = i;
                }

                _varsIndex = dict;
            }
Beispiel #19
0
        /// <summary>
        /// Creates new type context, flow context and flow state for the routine.
        /// </summary>
        public static FlowState CreateInitialState(SourceRoutineSymbol /*!*/ routine)
        {
            Contract.ThrowIfNull(routine);

            // create typeCtx
            var typeCtx = routine.TypeRefContext;

            // create FlowContext
            var flowCtx = new FlowContext(typeCtx, routine);

            // create FlowState
            var state = new FlowState(flowCtx);

            // handle input parameters type
            var parameters = routine.SourceParameters;

            foreach (var p in parameters)
            {
                var local = state.GetLocalHandle(new VariableName(p.Name));
                state.SetLocalType(local, p.GetResultType(typeCtx));

                if (p.Syntax.PassedByRef && !p.Syntax.IsVariadic)
                {
                    state.MarkLocalByRef(local);
                }
            }

            // $this
            if (routine.GetPhpThisVariablePlace() != null)
            {
                InitThisVar(flowCtx, state);
            }

            //
            return(state);
        }
Beispiel #20
0
        /// <summary>
        /// Creates new type context, flow context and flow state for the routine.
        /// </summary>
        public static FlowState CreateInitialState(SourceRoutineSymbol routine)
        {
            Contract.ThrowIfNull(routine);

            var containingType = routine.ContainingType as SourceNamedTypeSymbol;

            // collect locals
            var locals    = LocalsBinder.BindLocals(routine);
            var returnIdx = locals.IndexOf(x => x.VariableKind == VariableKind.ReturnVariable);

            // create typeCtx
            var typeCtx = routine.TypeRefContext;

            // create FlowContext
            var flowCtx = new FlowContext(typeCtx, locals, returnIdx);

            // create FlowState
            var state = new FlowState(flowCtx, routine);

            // handle parameters passed by reference
            var parameters = routine.Parameters.OfType <SourceParameterSymbol>().ToImmutableArray();

            foreach (var p in parameters)
            {
                if (p.Syntax.PassedByRef)
                {
                    state.SetVarRef(p.Name);
                }
            }

            // mark $this as initialized
            // mark global variables as ByRef, used
            // mark function parameters as used, initialized, typed
            // construct initial state for variables

            int paramIdx = 0;

            for (int i = 0; i < locals.Length; i++)
            {
                switch (locals[i].VariableKind)
                {
                case VariableKind.GlobalVariable:
                    state.SetVarRef(i);     // => used, byref, initialized
                    break;

                case VariableKind.Parameter:
                    //state.SetVarUsed(i);
                    var paramtag = PHPDoc.GetParamTag(routine.PHPDocBlock, paramIdx, locals[i].Name);
                    state.SetVar(i, GetParamType(typeCtx, paramtag, parameters[paramIdx].Syntax, default(CallInfo), paramIdx));
                    paramIdx++;
                    break;

                //case VariableKind.UseParameter:
                //    state.SetVar(i, TypeRefMask.AnyType);
                //    break;
                case VariableKind.ThisParameter:
                    InitThisVar(flowCtx, state, i);
                    break;

                case VariableKind.StaticVariable:
                    state.SetVarInitialized(i);
                    break;

                case VariableKind.ReturnVariable:
                    InitReturn(flowCtx, state, routine.PHPDocBlock);
                    break;
                }
            }
            //
            return(state);
        }
Beispiel #21
0
 /// <summary>
 /// Initial locals state for the Start block.
 /// </summary>
 public FlowState(FlowContext /*!*/ context, Symbols.SourceRoutineSymbol /*!*/ routine)
     : this(context, new CommonState(context, routine))
 {
 }
Beispiel #22
0
        /// <summary>
        /// Creates new type context, flow context and flow state for the routine.
        /// </summary>
        public static FlowState CreateInitialState(SourceRoutineSymbol /*!*/ routine, FlowContext flowCtx = null)
        {
            Contract.ThrowIfNull(routine);

            // get or create typeCtx
            var typeCtx = routine.TypeRefContext;

            // create or reuse FlowContext
            flowCtx ??= new FlowContext(typeCtx, routine);

            // pre-allocate locals map // https://github.com/peachpiecompiler/peachpie/issues/1002
            foreach (var variable in routine.LocalsTable.Variables)
            {
                if (variable is Semantics.LocalVariableReference local && local.VariableKind == VariableKind.LocalVariable)
                {
                    flowCtx.GetVarIndex(variable.BoundName.NameValue);
                }
            }

            // create FlowState
            var state = new FlowState(flowCtx);

            // populate input parameters type
            foreach (var p in routine.SourceParameters)
            {
                var local = state.GetLocalHandle(new VariableName(p.Name));
                var ptype = p.GetResultType(typeCtx);
                state.SetLocalType(local, ptype);
            }

            // $this
            if (routine.GetPhpThisVariablePlace() != null)
            {
                InitThisVar(flowCtx, state);
            }

            //
            return(state);
        }
Beispiel #23
0
 /// <summary>
 /// Gets variable handle use for other variable operations.
 /// </summary>
 public VariableHandle /*!*/ GetLocalHandle(VariableName varname)
 {
     return(FlowContext.GetVarIndex(varname));
 }
Beispiel #24
0
 /// <summary>
 /// Handles use of a local variable.
 /// </summary>
 public void VisitLocal(VariableHandle handle)
 {
     handle.ThrowIfInvalid();
     FlowContext.SetUsed(handle);
 }