示例#1
0
        /// <summary>
        /// Traces up the stack frame containing the method call that has caused an error.
        /// </summary>
        /// <returns>Found stack info.</returns>
        /// <remarks>
        /// Starts with a frame of a calling method and ends with the first frame belonging to user routine.
        /// If there was <see cref="ImplementsFunctionAttribute"/> found during the walk the last one's value
        /// is considered as the caller.
        /// If there was not such attribute found (error occured in an operator, directly in the code etc.)
        /// the last inspected method's debug info is returned.
        /// If the trace ends up with a function or method inside transient assembly an eval hierarchy is inspected
        /// and added to the resulting source position information.
        /// </remarks>
        internal static ErrorStackInfo TraceErrorFrame(ScriptContext /*!*/ context, bool lazy)
        {
            Debug.Assert(context != null);

            ErrorStackInfo result           = new ErrorStackInfo();
            int            cl_function_idx  = -1;
            string         cl_function_name = null;
            StackFrame     frame;
            int            eval_id = TransientAssembly.InvalidEvalId;

            // stack trace without debug info is constructed:
#if !SILVERLIGHT
            StackTrace trace = new StackTrace(1, false);

            // note: method stack frame contains a debug info about the call to the callee
            // hence if we find a method that reported the error we should look the next frame
            // to obtain a debug info

            int i = 0;
            for (; ;)
            {
                // gets frame:
                frame = trace.GetFrame(i++);

                // error has been thrown directly by Core without intermediary user code (all frames are invisible):
                if (frame == null)
                {
                    // cl_function_idx can be non-minus-one here because a callback can be called directly from Core
                    // (e.g. output buffer filter targeting class library function):
                    if (cl_function_idx != -1)
                    {
                        result.Caller        = cl_function_name;
                        result.LibraryCaller = true;
                    }

                    return(result);
                }

                MethodBase method = frame.GetMethod();
                if (lazy)
                {
                    if (method.Name == "Throw" && method.DeclaringType == typeof(PhpException))
                    {
                        lazy = false;
                    }
                    continue;
                }

                FrameKinds frame_kind = GetFrameKind(frame);

                if (frame_kind == FrameKinds.Visible || frame_kind == FrameKinds.Main)
                {
                    int eid = TransientModule.GetEvalId(context.ApplicationContext, method);

                    if (eval_id == TransientAssembly.InvalidEvalId)
                    {
                        eval_id = eid;
                    }

                    if (eid == TransientAssembly.InvalidEvalId)
                    {
                        break;
                    }
                }
                else if (frame_kind == FrameKinds.ClassLibraryFunction)
                {
                    cl_function_idx  = i;
                    cl_function_name = ImplementsFunctionAttribute.Reflect(method).Name;
                }
            }

            // skips i frames (the very first frame has been skipped in the previous
            // trace construction and we want to skip i-1 frames from that trace => i frames totally):
            frame = new StackFrame(1 + i - 1, true);

            // extracts a source info (file & position):
            if (eval_id != TransientAssembly.InvalidEvalId)
            {
                FillEvalStackInfo(context, eval_id, ref result, false);
            }
            else
            {
                result.Line   = frame.GetFileLineNumber();
                result.Column = frame.GetFileColumnNumber();
                result.File   = frame.GetFileName();
            }

            // determines a caller (either a library function or a user function/method):
            if (cl_function_idx >= 0)
            {
                result.Caller        = cl_function_name;
                result.LibraryCaller = true;
            }
            //else
            //{
            //  MethodBase method = frame.GetMethod();
            //  Type type = method.DeclaringType;

            //  // the caller has already been set by FillEvalStackInfo
            //  // if we are in eval and the function is Main helper of the script type:
            //  if (eval_id == TransientAssembly.InvalidEvalId)
            //  {
            //    result.LibraryCaller = false;

            //    if (type != null)
            //    {
            //      result.Caller = String.Concat(DTypeDesc.MakeFullName(type), "::", DRoutineDesc.MakeFullName(method));
            //    }
            //    else
            //    {
            //      result.Caller = DRoutineDesc.MakeFullName(method);
            //    }
            //  }
            //}
#endif

            // add missing info about file and line
            context.LastErrorLine = result.Line;
            context.LastErrorFile = result.File;

            //
            return(result);
        }
示例#2
0
        internal TransientModuleBuilder(int id, EvalKinds kind, TransientCompilationUnit /*!*/ compilationUnit,
                                        TransientAssemblyBuilder /*!*/ assemblyBuilder, TransientModule containingModule, string sourcePath)
            : base(id, kind, compilationUnit, assemblyBuilder.TransientAssembly, containingModule, sourcePath)
        {
            this.assemblyBuilder = assemblyBuilder;

            if (!compilationUnit.IsDynamic)
            {
                this.globalBuilder = assemblyBuilder.RealModuleBuilder.DefineType(MakeName("<Global>", true),
                                                                                  TypeAttributes.SpecialName | TypeAttributes.Class | TypeAttributes.Public);
            }
            else
            {
                this.globalBuilder = null;
            }
        }
示例#3
0
        /// <summary>
        /// Finds out a kind of a CLI frame from the PHP point of view.
        /// </summary>
        /// <param name="frame">The CLI frame.</param>
        /// <returns>The kind of the frame.</returns>
        private static FrameKinds GetFrameKind(StackFrame /*!*/ frame)
        {
            Debug.Assert(frame != null);

            MethodBase method_base = frame.GetMethod();

            // skip CLR ctors and generic methods (we don't emit any):
            if (method_base.IsConstructor || method_base.IsGenericMethod)
            {
                return(FrameKinds.Invisible);
            }

            // skip various stubs (special-name) except for Main helper:
            if (method_base.IsSpecialName)
            {
                // main helper in PHP module (script module):
                if (DRoutineDesc.GetSpecialName(method_base) == ScriptModule.MainHelperName &&
                    method_base.Module.Assembly.IsDefined(typeof(ScriptAssemblyAttribute), false))
                {
                    return(FrameKinds.Main);
                }

                return(FrameKinds.Invisible);
            }

            MethodInfo method = (MethodInfo)method_base;

            Type type = method.DeclaringType;

            if (type != null)
            {
                // methods //

                string ns = type.Namespace;

                if (ns != null)
                {
                    // skip Core and Extension Manger methods and Dynamic Wrapper Stubs:
                    if (ns.StartsWith(Namespaces.Core) || ns == Namespaces.ExtManager || ns == Namespaces.LibraryStubs)
                    {
                        return(FrameKinds.Invisible);
                    }

                    // skip Class Library methods including PHP functions and PHP methods (remembering the last function):
                    if (ns.StartsWith(Namespaces.Library))
                    {
                        // find out [ImplementsFunction] attributes assigned to the method:
                        if (method.IsDefined(Emit.Types.ImplementsFunctionAttribute, false))
                        {
                            return(FrameKinds.ClassLibraryFunction);
                        }
                        else
                        {
                            return(FrameKinds.Invisible);
                        }
                    }

                    return(FrameKinds.Visible);
                }
                else
                {
                    // skip export stubs (and other debugger hidden functions):
                    if (method.IsDefined(Emit.Types.DebuggerHiddenAttribute, false))
                    {
                        return(FrameKinds.Invisible);
                    }

                    return(FrameKinds.Visible);
                }
            }
            else
            {
                // global functions //

                // skip functions of ExtSupport (and other global non-PHP functions):
                if (method.Module.Assembly != DynamicCode.DynamicMethodType.Assembly &&
                    !method.Module.Assembly.IsDefined(typeof(DAssemblyAttribute), false))
                {
                    return(FrameKinds.Invisible);
                }

                // transient special names:
                if (TransientModule.IsSpecialName(method.Name))
                {
                    // main helper is visible as it contains user code:
                    if (DRoutineDesc.GetSpecialName(method) == ScriptModule.MainHelperName)
                    {
                        return(FrameKinds.Main);
                    }

                    return(FrameKinds.Invisible);
                }

                // skip export stubs (and other debugger hidden functions):
                if (method.IsDefined(Emit.Types.DebuggerHiddenAttribute, false))
                {
                    return(FrameKinds.Invisible);
                }

                //
                return(FrameKinds.Visible);
            }

            //// global functions (in extensions) are not included in the PHP stack trace:
            //if (type==null) return FrameKinds.Invisible;

            //string ns = type.Namespace;

            //// non-PHP user code:
            //if (ns == null)
            //  return FrameKinds.Visible;

            //// Core, System, and Extension Manger methods are skipped:
            //if (ns.StartsWith(Namespaces.Core) || ns.StartsWith(Namespaces.System) || ns == Namespaces.ExtManager)
            //  return FrameKinds.Invisible;

            //// skips library stubs:
            //if (ns == Namespaces.LibraryStubs)
            //  return FrameKinds.Invisible;

            //// methods in user namespace (either generated by Phalanger or written in other .NET language):
            //if (ns.StartsWith(Namespaces.User))
            //{
            //  // skips arg-less stubs (method is not a constructor => it has MethodInfo):
            //  if (PhpFunctionUtils.IsArglessStub((MethodInfo)method,null))
            //    return FrameKinds.Invisible;

            //  return FrameKinds.UserRoutine;
            //}

            //// skip Class Library methods including PHP functions and PHP methods (remembering the last function):
            //if (ns.StartsWith(Namespaces.Library))
            //{
            //  // find out [ImplementsFunction] attributes assigned to the method:
            //  if (method.IsDefined(Emit.Types.ImplementsFunctionAttribute,false))
            //    return FrameKinds.ClassLibraryFunction; else
            //    return FrameKinds.Invisible;
            //}

            //// non-PHP user code:
            //return FrameKinds.Visible;
        }
示例#4
0
        /// <summary>
        /// Implements PHP <c>eval</c> construct with given code prefix and suffix.
        /// A result of concatanation prefix + code + suffix is compiled.
        /// Prefix should contain no new line characters.
        /// </summary>
        internal static object EvalInternal(
            string prefix,
            string code,
            string suffix,
            EvalKinds kind,
            ScriptContext /*!*/ scriptContext,
            Dictionary <string, object> localVariables,
            DObject self,
            DTypeDesc referringType,
            SourceCodeDescriptor descriptor,
            bool entireFile,
            NamingContext namingContext)
        {
            Debug.Assert(prefix != null && suffix != null);

            // composes code to be compiled:
            code = String.Concat(prefix, code, suffix);

            TransientAssemblyBuilder assembly_builder = scriptContext.ApplicationContext.TransientAssemblyBuilder;

            // looks up the cache:
            TransientModule module = assembly_builder.TransientAssembly.GetModule(scriptContext, referringType, code, descriptor);

            if (module == null)
            {
                // double checked lock,
                // if module != null, it is definitely completed
                // since module is added into TransientAssembly at the end
                // of assembly_builder.Build
                lock (assembly_builder.TransientAssembly)
                {
                    // lookup again, since it could be added into TransientAssembly while lock
                    module = assembly_builder.TransientAssembly.GetModule(scriptContext, referringType, code, descriptor);

                    if (module == null)
                    {
                        if (kind == EvalKinds.SyntheticEval)
                        {
                            Debug.WriteLine("SYN EVAL", "Eval cache missed: '{0}'", code.Substring(0, Math.Max(code.IndexOf('{'), 0)).TrimEnd());
                        }
                        else
                        {
                            Debug.WriteLine("EVAL", "Eval cache missed: '{0}'({1},{2})", descriptor.ContainingSourcePath, descriptor.Line, descriptor.Column);
                        }

                        CompilerConfiguration config = new CompilerConfiguration(Configuration.Application);

                        CompilationContext context = new CompilationContext(scriptContext.ApplicationContext, null, config,
                                                                            new EvalErrorSink(-prefix.Length, config.Compiler.DisabledWarnings, config.Compiler.DisabledWarningNumbers),
                                                                            scriptContext.WorkingDirectory);

                        TransientCompilationUnit unit = assembly_builder.Build(code, descriptor, kind, context,
                                                                               scriptContext, referringType, namingContext, entireFile);

                        // compilation failed:
                        if (unit == null)
                        {
                            return(false);
                        }
                        module = unit.TransientModule;
                    }
                }
            }

            // activates unconditionally declared types, functions and constants:
            module.TransientCompilationUnit.Declare(scriptContext);

            return(module.Main(scriptContext, localVariables, self, referringType, true));
        }