Example #1
0
		/// <summary>
		/// Returns compiled module if exists.
		/// </summary>
		/// <param name="sourceFile">Source file.</param>
		/// <param name="ctx">A compilation context.</param>
		/// <returns>The <see cref="PhpModule"/> or a <B>null</B> reference.</returns>
		/// <remarks>
		/// Checks whether a module associated with a <paramref name="sourceFile"/> has already been compiled.
		/// If so returns the respective <see cref="PhpModule"/>. Otherwise a <B>null</B> reference is returned.
		/// Does no locking since application compiler is thread unsafe.
		/// </remarks>
		public PhpModule LockForCompiling(PhpSourceFile/*!*/ sourceFile, CompilationContext/*!*/ ctx)
		{
            // take a look into script library first
            if (applicationContext.ScriptLibraryDatabase.ContainsScript(sourceFile.FullPath))
            {
                return applicationContext.ScriptLibraryDatabase.GetScriptModule(sourceFile.FullPath);
            }

			return assemblyBuilder.Assembly.GetModule(sourceFile);
		}
Example #2
0
        /// <summary>
		/// Initializes a new instance of the <see cref="PHP.Core.CodeGenerator"/> class.
		/// </summary>
		public CodeGenerator(CompilationContext/*!*/ context)
		{
			ScriptContextPlace = new IndexedPlace(PlaceHolder.Argument, ScriptBuilder.ArgContext);
			TypeContextPlace = new IndexedPlace(PlaceHolder.Argument, ScriptBuilder.ArgIncluder);

			this.context = context;

			this.il = null;
			this.currentVariablesTable = null;
			this.currentLabels = null;
			this.locationStack = new CompilerLocationStack();
			this.branchingStack = new BranchingStack(this);
			this.chainBuilder = new ChainBuilder(this);
		}
		/// <summary>
		/// Called by compiler when information about compiling progress is available.
		/// </summary>
		/// <remarks>Ignored by this manager.</remarks>
		public void Info(PhpSourceFile/*!*/ sourceFile, CompilationContext ctx)
		{
			// nop //
		}
		/// <summary>
		/// Wakes up threads waiting for a script compilation finish.
		/// </summary>
		/// <param name="sourceFile">The compiled script's source file.</param>
		/// <param name="successful">Whether compilation has been successful.</param>
		/// <param name="ctx">A compilation context.</param>
		/// <remarks>Should be called after <see cref="Persist"/>.</remarks>
		public void UnlockForCompiling(PhpSourceFile/*!*/ sourceFile, bool successful, CompilationContext ctx)
		{
			Debug.Assert(sourceFile != null && ctx is WebCompilationContext);

			ManualResetEvent compilation_finished;

			lock (eventsMutex)
			{
				if (events.TryGetValue(sourceFile, out compilation_finished))
					events.Remove(sourceFile);
			}

			// any waiting thread can access the compiled assembly now:
			if (compilation_finished != null)
				compilation_finished.Set();
		}
Example #5
0
		public InclusionGraphBuilder(CompilationContext/*!*/ context)
		{
			this.context = context;
			Statistics.Inclusions.InitializeGraph();
		}
		public override bool Build(IEnumerable<PhpSourceFile>/*!!*/ sourceFiles, CompilationContext/*!*/ context)
		{
			return CompileScripts(sourceFiles, context);
		}
		public abstract bool Build(IEnumerable<PhpSourceFile>/*!!*/ sourceFiles, CompilationContext/*!*/ context);
Example #8
0
		/// <summary>
		/// Compiles a specified collection of scripts within the given compilation context.
		/// </summary>
		private static IEnumerable<PhpSourceFile>/*!*/ EnumerateScriptsInDirectory(IEnumerable<FullPath>/*!*/ sourcePaths,
            ICollection<string>/*!*/ fileExtensions, CompilationContext/*!*/ context)
		{
			Debug.Assert(sourcePaths != null && fileExtensions != null && context != null);

			FullPath source_root = context.Config.Compiler.SourceRoot;

			foreach (FullPath path in sourcePaths)
			{
				if (fileExtensions.Count != 0 && !path.HasAnyExtension(fileExtensions))
					continue;

                string pathString = path;
                bool skip = false;

                foreach (string skipPath in context.Config.Compiler.ForcedDynamicInclusionTranslatedFullPaths)
                    if (pathString.StartsWith(skipPath))
                    {
                        skip = true;
                        break;
                    }
                
                if (skip) continue;

				yield return new PhpSourceFile(source_root, path);
			}
		}
Example #9
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);
		}
Example #10
0
		/// <summary>
		/// Adds a new module to application's assembly.
		/// </summary>
		/// <param name="compiledUnit">Unit being compiled.</param>
		/// <param name="ctx">A compilation context.</param>
		/// <returns>The builder where compiler should emit the resulting code.</returns>
		public IPhpModuleBuilder/*!*/ DefineModuleBuilder(CompilationUnitBase/*!*/ compiledUnit, CompilationContext ctx)
		{
			return assemblyBuilder.DefineModule(compiledUnit);
		}
Example #11
0
		/// <summary>
		/// Triggered by the compiler on events such are start of compilation, end of compilation etc.
		/// </summary>
		/// <param name="sourceFile">A source path to a script being processed.</param>
		/// <param name="ctx">A compilation context.</param>
		public void Info(PhpSourceFile/*!*/ sourceFile, CompilationContext/*!*/ ctx)
		{
			Console.WriteLine(sourceFile.RelativePath);
		}
Example #12
0
		/// <summary>
		/// Remembers whether compilation has been successful.
		/// </summary>
		/// <param name="sourceFile">Source file.</param>
		/// <param name="successful">Whether compilation was successful.</param>
		/// <param name="ctx">A compilation context.</param>
		public void UnlockForCompiling(PhpSourceFile/*!*/ sourceFile, bool successful, CompilationContext/*!*/ ctx)
		{
			this.successful &= successful;
		}
Example #13
0
		/// <summary>
		/// Ignored. All modules are stored in a single assembly which is persisted in <see cref="Finish"/>.
		/// </summary>
		public void Persist(CompilationUnitBase/*!*/ compiledUnit, CompilationContext/*!*/ ctx)
		{
			// nop //
		}
Example #14
0
		public void CleanAllUnits(CompilationContext/*!*/ context, bool successful)
		{
			foreach (CompilationUnit unit in nodes.Values)
				unit.CleanUp(context, successful);
		}
Example #15
0
        /// <summary>
		/// Compiles an application.
		/// </summary>
		/// <param name="applicationContext">Application context.</param>
		/// <param name="config">Compiler configuration record.</param>
		/// <param name="errorSink">Error sink.</param>
		/// <param name="ps">Parameters.</param>
		/// <exception cref="InvalidSourceException">Cannot read a source file/directory. See the inner exception for details.</exception>
		public void Compile(
			ApplicationContext/*!*/ applicationContext,
			CompilerConfiguration/*!*/ config,
			ErrorSink/*!*/ errorSink,
			CompilationParameters/*!*/ ps)
		{
			if (applicationContext == null) throw new ArgumentNullException("applicationContext");
			if (config == null) throw new ArgumentNullException("config");
			if (errorSink == null) throw new ArgumentNullException("errorSink");
			ps.Validate();

			PhpSourceFile entry_point_file = (ps.StartupFile != null) ? new PhpSourceFile(config.Compiler.SourceRoot, ps.StartupFile) : null;
			List<ResourceFileReference> resource_files = ResourceFileReference.FromFiles(ps.Resources);

			// creates directory if not exists:
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(ps.OutPath));
			}
			catch (Exception ex)
			{
				errorSink.Add(FatalErrors.ErrorCreatingFile, null, ErrorPosition.Invalid, ps.OutPath, ex.Message);
			}	
				
			AssemblyKinds kind;

			switch (ps.Target)
			{
				case Targets.Dll:
					kind = AssemblyKinds.Library;
					entry_point_file = null;
					break;

				case Targets.Console:
					kind = AssemblyKinds.ConsoleApplication;
					break;

				case Targets.WinApp:
					kind = AssemblyKinds.WindowApplication;
					break;

				case Targets.Web:
					kind = AssemblyKinds.WebPage;
					entry_point_file = null;
					break;

				default:
                    throw new ArgumentException();
			}

			PhpAssemblyBuilder assembly_builder = PhpAssemblyBuilder.Create(applicationContext, kind, ps.Pure, ps.OutPath,
				ps.DocPath, entry_point_file, ps.Version, ps.Key, ps.Icon, resource_files, config.Compiler.Debug, ps.Force32Bit);

			assembly_builder.IsMTA = ps.IsMTA;
			
			Statistics.CompilationStarted();

			ICompilerManager manager = (!ps.Pure) ? new ApplicationCompilerManager(applicationContext, assembly_builder) : null;

            try
            {
                CompilationContext context = new CompilationContext(applicationContext, manager, config, errorSink, config.Compiler.SourceRoot);

                assembly_builder.Build(EnumerateScripts(ps.SourcePaths, ps.SourceDirs, ps.FileExtensions, context), context);

                if (!context.Errors.AnyError && (ps.Target == Targets.Console || ps.Target == Targets.WinApp))
                    CopyApplicationConfigFile(config.Compiler.SourceRoot, ps.OutPath);
            }
            catch (CompilerException e)
            {
                errorSink.Add(e.ErrorInfo, null, ErrorPosition.Invalid, e.ErrorParams);
            }
            catch (InvalidSourceException e)
            {
                e.Report(errorSink);
            }
            catch (Exception e)
            {
#if DEBUG
                //Console.WriteLine("Unexpected error: {0}", e.ToString());// removed, exception added into the error sink, so it's displayed in the VS Integration too
#endif
                errorSink.AddInternalError(e);  // compilation will fail, error will be displayed in Errors by VS Integration               
            }
			finally
			{
#if DEBUG
				Console.WriteLine();
				Console.WriteLine("Statistics:");
				Statistics.Dump(Console.Out, Path.GetDirectoryName(ps.OutPath));
				Console.WriteLine();
#endif
			}
        }
Example #16
0
		internal Analyzer(CompilationContext/*!*/ context)
		{
			this.context = context;

			condLevel = 0;
			loopNestingLevel = 0;
			state = States.Initial;
		}
Example #17
0
        private static IEnumerable<PhpSourceFile>/*!*/ EnumerateScripts(
			ICollection<FullPath>/*!*/ sourcePaths, ICollection<FullPath>/*!*/ sourceDirs,
			ICollection<string>/*!*/ fileExtensions, CompilationContext/*!*/ context)
		{
			Debug.Assert(sourcePaths != null && sourceDirs != null && fileExtensions != null && context != null);
			
			// enumerate listed source files:
            foreach (PhpSourceFile file in EnumerateScriptsInDirectory(sourcePaths, ArrayUtils.EmptyStrings, context))
				yield return file;

			// enumerate source files recursively located in specified directories:
			foreach (FullPath dir in sourceDirs)
			{
                foreach (PhpSourceFile file in EnumerateScriptsRecursive(dir, fileExtensions, context))
					yield return file;
			}
		}
		/// <summary>
		/// Checks whether a specified source file needs to be (re)compiled and if so locks 
		/// it so that any other compiler from the current app domain will wait until this compilation finishes.
		/// </summary>
		/// <param name="sourceFile">Source file.</param>
		/// <param name="ctx">Compilation context.</param>
		/// <returns>
		/// A compiled module associated with the <paramref name="sourceFile"/> or a <B>null</B> reference
		/// if a compilation of that file is needed.
		/// </returns>
		public PhpModule LockForCompiling(PhpSourceFile/*!*/ sourceFile, CompilationContext/*!*/ ctx)
		{
			Debug.Assert(ctx is WebCompilationContext);
			WebCompilationContext context = (WebCompilationContext)ctx;

            // take a look into script library first
            if (applicationContext.ScriptLibraryDatabase.ContainsScript(sourceFile.FullPath))
            {
                return applicationContext.ScriptLibraryDatabase.GetScriptModule(sourceFile.FullPath);
            }

			for (int i = 0; i < AttemptsToGetCompiledAssembly; i++)
			{
				string ns = ScriptModule.GetSubnamespace(sourceFile.RelativePath, false);

				CacheEntry cache_entry;

				// TODO: Single script assemblies can be loaded and reflected 
				//       but this still have to be done for MSAs
				if (TryLoadCachedEntry(ns, sourceFile, out cache_entry) && !cache_entry.ScriptAssembly.IsMultiScript)
					return cache_entry.ScriptAssembly.GetModule(sourceFile);

				// compilation is in progress or not started yet //
				ManualResetEvent compilation_finished;

				lock (eventsMutex)
				{
					// if compilation of the target file has not started yet:
					if (!events.TryGetValue(sourceFile, out compilation_finished))
					{
						// adds event which others wait on:
						events.Add(sourceFile, new ManualResetEvent(false));

						return null;
					}
				}

				// waits until compilation is finished and assembly has been persisted:
				compilation_finished.WaitOne(CompilationTimeout, false);
			}

			return null;
		}
Example #19
0
		/// <summary>
		/// Recursively searches a directory for all files matching the web script file pattern.
		/// </summary>
		/// <exception cref="InvalidSourceException">Error reading the directory.</exception>
		private static IEnumerable<PhpSourceFile>/*!*/ EnumerateScriptsRecursive(FullPath directory,
            ICollection<string>/*!*/ fileExtensions, CompilationContext/*!*/ context)
		{
			Debug.Assert(fileExtensions != null && context != null);
			Debug.Assert(!directory.IsEmpty);

            string pathString = directory;

            foreach (string skipPath in context.Config.Compiler.ForcedDynamicInclusionTranslatedFullPaths)
                if (pathString.StartsWith(skipPath))
                    yield break;
            
			FullPath[] files, directories;
			
			try
			{
				files = directory.GetFiles();
				directories = directory.GetDirectories();
			}
			catch (Exception e)
			{
				throw new InvalidSourceException(directory, e);
			}

			// compiles scripts in the current directory:
			foreach (PhpSourceFile file in EnumerateScriptsInDirectory(files, fileExtensions, context))
				yield return file;

			// processes subdirectories:
			foreach (FullPath dir in directories)
			{
                foreach (PhpSourceFile file in EnumerateScriptsRecursive(dir, fileExtensions, context))
					yield return file;
			}
        }
		/// <summary>
		/// Creates a new instance of <see cref="ScriptBuilder"/> to be used for compilation of the script's assembly.
		/// </summary>
		/// <param name="compiledUnit">Unit being compiled.</param>
		/// <param name="ctx">The current compilation context.</param>
		/// <returns>The script builder.</returns>
		public IPhpModuleBuilder DefineModuleBuilder(CompilationUnitBase/*!*/ compiledUnit, CompilationContext/*!*/ ctx)
		{
			Debug.Assert(compiledUnit is ScriptCompilationUnit && ctx is WebCompilationContext);
			WebCompilationContext context = (WebCompilationContext)ctx;
			ScriptCompilationUnit unit = (ScriptCompilationUnit)compiledUnit;

			// creates an assembly name:
			AssemblyName name = context.GetAssemblyFullName(unit.SourceUnit.SourceFile);

			// creates a script assembly builder:
			SingleScriptAssemblyBuilder builder = new SingleScriptAssemblyBuilder(applicationContext,
				name, outDir, name.Name + AssemblyExt, AssemblyKinds.WebPage, context.Config.Compiler.Debug, false, context.SaveOnlyAssembly, null);
            
			return builder.DefineScript(unit);
		}
		public override bool Build(IEnumerable<PhpSourceFile>/*!*/ sourceFiles, CompilationContext/*!*/ context)
		{
			PureCompilationUnit unit = new PureCompilationUnit(false, false);

			bool success = unit.Compile(sourceFiles, this, context, context.Config.Globalization.PageEncoding);

			if (success) Save();

			return success;
		}
		/// <summary>
		/// Persists a built script to a file.
		/// </summary>
		/// <param name="compilationUnit">The unit being compiled.</param>
		/// <param name="ctx">Compilation context.</param>
		public void Persist(CompilationUnitBase/*!*/ compilationUnit, CompilationContext/*!*/ ctx)
		{
			Debug.Assert(compilationUnit is ScriptCompilationUnit && ctx is WebCompilationContext);

			WebCompilationContext context = (WebCompilationContext)ctx;
			ScriptCompilationUnit unit = (ScriptCompilationUnit)compilationUnit;
			SingleScriptAssemblyBuilder assembly_builder = (SingleScriptAssemblyBuilder)unit.ModuleBuilder.AssemblyBuilder;

			assembly_builder.Save();

            string ns = ScriptModule.GetSubnamespace(unit.SourceUnit.SourceFile.RelativePath, false);

            if (SaveOnlyAssembly)
            {
                // assembly not loaded into memory yet (we need to load from fs to not break debugging)
                string file = assembly_builder.Assembly.Path;

                CacheEntry entry;
                LoadSSA(ns, file, out entry);
            }
            else
            {
                // We only add the assembly into the cache, if it was built and loaded into memory.
                // Otherwise the assembly has to be reloaded from the disk.
                // This is because of debugging, since we don't want to load dynamic assemblies into memory, which breaks debug symbols.

                // makes up a list of dependent assembly names:
                string[] includers = new string[unit.Includers.Count];
                int i = 0;
                foreach (StaticInclusion inclusion in unit.Includers)
                    includers[i++] = ScriptModule.GetSubnamespace(inclusion.Includer.SourceUnit.SourceFile.RelativePath, false);

                // what assemblies are included by this one?
                string[] inclusions = new string[unit.Inclusions.Count];
                int j = 0;
                foreach (StaticInclusion inclusion in unit.Inclusions)
                    inclusions[j++] = ScriptModule.GetSubnamespace(new RelativePath(0, inclusion.Includee.RelativeSourcePath), false);

                // adds dependencies on the source file and the included assemblies:
                SetCacheEntry(ns,
                    new CacheEntry(
                        assembly_builder.SingleScriptAssembly.GetScriptType(),
                        assembly_builder.SingleScriptAssembly, context.RequestTimestamp, includers, inclusions, true), true, true);
            }
		}
		public static bool CompileScripts(IEnumerable<PhpSourceFile>/*!!*/ sourceFiles, CompilationContext/*!*/ context)
		{
			bool success = true;
			InclusionGraphBuilder graph_builder = null;

			Debug.WriteLine("SAB", "CompileScripts()");

			try
			{
				graph_builder = new InclusionGraphBuilder(context);

				foreach (PhpSourceFile source_file in sourceFiles)
					success &= graph_builder.AnalyzeDfsTree(source_file);

				if (success)
					graph_builder.EmitAllUnits(new CodeGenerator(context));
			}
			catch (Exception)
			{
				success = false;
				throw;
			}
			finally
			{
				if (graph_builder != null)
				{
					graph_builder.CleanAllUnits(context, success);
					graph_builder.Dispose();
				}

				context.Manager.Finish(success);
			}

			return success;
		}
Example #24
0
		/// <summary>
		/// The argument <paramref name="completeSource" /> determines whether the source code
		/// is complete PHP script file, which is a case in dynamic include in Silverlight
		/// </summary>
		public TransientCompilationUnit Build(string/*!*/ sourceCode, SourceCodeDescriptor descriptor,
			EvalKinds kind, CompilationContext/*!*/ context, ScriptContext/*!*/ scriptContext,
			DTypeDesc referringType, NamingContext namingContext, bool completeSource)
		{
			PhpSourceFile source_file = new PhpSourceFile(context.Config.Compiler.SourceRoot,
				RelativePath.ParseCanonical(descriptor.ContainingSourcePath));

			Encoding encoding = context.Config.Globalization.PageEncoding;

			TransientCompilationUnit result = new TransientCompilationUnit
				(sourceCode, source_file, encoding, namingContext, descriptor.Line, descriptor.Column, completeSource);
			if (!result.PreCompile(context, scriptContext, descriptor, kind, referringType)) return null;

			DefineGlobalType(((TransientModuleBuilder)result.ModuleBuilder).AssemblyBuilder.RealModuleBuilder);
			if (!result.Compile(context, kind)) return null;

			BakeGlobals();
			result.PostCompile(descriptor);
			return result;
		}