PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/Microsoft.Scripting/Hosting/ScriptRuntime.cs

https://bitbucket.org/stefanrusek/xronos
C# | 384 lines | 249 code | 63 blank | 72 comment | 20 complexity | 35dc04a7ce7298f689d92a503701a11a MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if CODEPLEX_40
  16. using System;
  17. #else
  18. using System; using Microsoft;
  19. #endif
  20. using System.Collections.Generic;
  21. using System.Diagnostics;
  22. using System.IO;
  23. using System.Reflection;
  24. using System.Security.Permissions;
  25. using System.Text;
  26. using System.Threading;
  27. using Microsoft.Scripting.Runtime;
  28. using Microsoft.Scripting.Utils;
  29. namespace Microsoft.Scripting.Hosting {
  30. /// <summary>
  31. /// Represents a Dynamic Language Runtime in Hosting API.
  32. /// Hosting API counterpart for <see cref="ScriptDomainManager"/>.
  33. /// </summary>
  34. public sealed class ScriptRuntime
  35. #if !SILVERLIGHT
  36. : MarshalByRefObject
  37. #endif
  38. {
  39. private readonly Dictionary<LanguageContext, ScriptEngine> _engines;
  40. private readonly ScriptDomainManager _manager;
  41. private readonly InvariantContext _invariantContext;
  42. private readonly ScriptIO _io;
  43. private readonly ScriptHost _host;
  44. private readonly ScriptRuntimeSetup _setup;
  45. private ScriptScope _globals;
  46. private ScriptEngine _invariantEngine;
  47. /// <summary>
  48. /// Creates ScriptRuntime in the current app-domain and initialized according to the the specified settings.
  49. /// Creates an instance of host class specified in the setup and associates it with the created runtime.
  50. /// Both Runtime and ScriptHost are collocated in the current app-domain.
  51. /// </summary>
  52. public ScriptRuntime(ScriptRuntimeSetup setup) {
  53. ContractUtils.RequiresNotNull(setup, "setup");
  54. // Do this first, so we detect configuration errors immediately
  55. DlrConfiguration config = setup.ToConfiguration();
  56. _setup = setup;
  57. _host = ReflectionUtils.CreateInstance<ScriptHost>(setup.HostType, setup.HostArguments.ToArray<object>());
  58. ScriptHostProxy hostProxy = new ScriptHostProxy(_host);
  59. _manager = new ScriptDomainManager(hostProxy, config);
  60. _invariantContext = new InvariantContext(_manager);
  61. _io = new ScriptIO(_manager.SharedIO);
  62. _engines = new Dictionary<LanguageContext, ScriptEngine>();
  63. bool freshEngineCreated;
  64. _globals = new ScriptScope(GetEngineNoLockNoNotification(_invariantContext, out freshEngineCreated), _manager.Globals);
  65. // runtime needs to be all set at this point, host code is called
  66. _host.SetRuntime(this);
  67. object noDefaultRefs;
  68. if (!setup.Options.TryGetValue("NoDefaultReferences", out noDefaultRefs) || Convert.ToBoolean(noDefaultRefs) == false) {
  69. LoadAssembly(typeof(string).Assembly);
  70. LoadAssembly(typeof(System.Diagnostics.Debug).Assembly);
  71. }
  72. }
  73. internal ScriptDomainManager Manager {
  74. get { return _manager; }
  75. }
  76. public ScriptHost Host {
  77. get { return _host; }
  78. }
  79. public ScriptIO IO {
  80. get { return _io; }
  81. }
  82. /// <summary>
  83. /// Creates a new runtime with languages set up according to the current application configuration
  84. /// (using System.Configuration).
  85. /// </summary>
  86. public static ScriptRuntime CreateFromConfiguration() {
  87. return new ScriptRuntime(ScriptRuntimeSetup.ReadConfiguration());
  88. }
  89. #region Remoting
  90. #if !SILVERLIGHT
  91. /// <summary>
  92. /// Creates ScriptRuntime in the current app-domain and initialized according to the the specified settings.
  93. /// Creates an instance of host class specified in the setup and associates it with the created runtime.
  94. /// Both Runtime and ScriptHost are collocated in the specified app-domain.
  95. /// </summary>
  96. public static ScriptRuntime CreateRemote(AppDomain domain, ScriptRuntimeSetup setup) {
  97. ContractUtils.RequiresNotNull(domain, "domain");
  98. #if SYSTEM_CORE
  99. return (ScriptRuntime)domain.CreateInstanceAndUnwrap(
  100. typeof(ScriptRuntime).Assembly.FullName,
  101. typeof(ScriptRuntime).FullName,
  102. false,
  103. BindingFlags.Default,
  104. null,
  105. new object[] { setup },
  106. null,
  107. null
  108. );
  109. #else
  110. //The API CreateInstanceAndUnwrap is obsolete in Dev10.
  111. return (ScriptRuntime)domain.CreateInstanceAndUnwrap(
  112. typeof(ScriptRuntime).Assembly.FullName,
  113. typeof(ScriptRuntime).FullName,
  114. false,
  115. BindingFlags.Default,
  116. null,
  117. new object[] { setup },
  118. null,
  119. null,
  120. null
  121. );
  122. #endif
  123. }
  124. // TODO: Figure out what is the right lifetime
  125. [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  126. public override object InitializeLifetimeService() {
  127. return null;
  128. }
  129. #endif
  130. #endregion
  131. public ScriptRuntimeSetup Setup {
  132. get {
  133. return _setup;
  134. }
  135. }
  136. #region Engines
  137. public ScriptEngine GetEngine(string languageName) {
  138. ContractUtils.RequiresNotNull(languageName, "languageName");
  139. ScriptEngine engine;
  140. if (!TryGetEngine(languageName, out engine)) {
  141. throw new ArgumentException(String.Format("Unknown language name: '{0}'", languageName));
  142. }
  143. return engine;
  144. }
  145. public ScriptEngine GetEngineByTypeName(string assemblyQualifiedTypeName) {
  146. ContractUtils.RequiresNotNull(assemblyQualifiedTypeName, "assemblyQualifiedTypeName");
  147. return GetEngine(_manager.GetLanguageByTypeName(assemblyQualifiedTypeName));
  148. }
  149. /// <exception cref="ArgumentException"></exception>
  150. /// <exception cref="ArgumentNullException"></exception>
  151. public ScriptEngine GetEngineByFileExtension(string fileExtension) {
  152. ContractUtils.RequiresNotNull(fileExtension, "fileExtension");
  153. ScriptEngine engine;
  154. if (!TryGetEngineByFileExtension(fileExtension, out engine)) {
  155. throw new ArgumentException(String.Format("Unknown file extension: '{0}'", fileExtension));
  156. }
  157. return engine;
  158. }
  159. public bool TryGetEngine(string languageName, out ScriptEngine engine) {
  160. LanguageContext language;
  161. if (!_manager.TryGetLanguage(languageName, out language)) {
  162. engine = null;
  163. return false;
  164. }
  165. engine = GetEngine(language);
  166. return true;
  167. }
  168. public bool TryGetEngineByFileExtension(string fileExtension, out ScriptEngine engine) {
  169. LanguageContext language;
  170. if (!_manager.TryGetLanguageByFileExtension(fileExtension, out language)) {
  171. engine = null;
  172. return false;
  173. }
  174. engine = GetEngine(language);
  175. return true;
  176. }
  177. /// <summary>
  178. /// Gets engine for the specified language.
  179. /// </summary>
  180. internal ScriptEngine GetEngine(LanguageContext language) {
  181. Assert.NotNull(language);
  182. ScriptEngine engine;
  183. bool freshEngineCreated;
  184. lock (_engines) {
  185. engine = GetEngineNoLockNoNotification(language, out freshEngineCreated);
  186. }
  187. if (freshEngineCreated && !ReferenceEquals(language, _invariantContext)) {
  188. _host.EngineCreated(engine);
  189. }
  190. return engine;
  191. }
  192. /// <summary>
  193. /// Looks up the engine for the specified language. It the engine hasn't been created in this Runtime, it is instantiated here.
  194. /// The method doesn't lock nor send notifications to the host.
  195. /// </summary>
  196. private ScriptEngine GetEngineNoLockNoNotification(LanguageContext language, out bool freshEngineCreated) {
  197. Debug.Assert(_engines != null, "Invalid ScriptRuntime initialiation order");
  198. ScriptEngine engine;
  199. if (freshEngineCreated = !_engines.TryGetValue(language, out engine)) {
  200. engine = new ScriptEngine(this, language);
  201. Thread.MemoryBarrier();
  202. _engines.Add(language, engine);
  203. }
  204. return engine;
  205. }
  206. #endregion
  207. #region Compilation, Module Creation
  208. public ScriptScope CreateScope() {
  209. return InvariantEngine.CreateScope();
  210. }
  211. public ScriptScope CreateScope(string languageId) {
  212. return GetEngine(languageId).CreateScope();
  213. }
  214. public ScriptScope CreateScope(IAttributesCollection dictionary) {
  215. return InvariantEngine.CreateScope(dictionary);
  216. }
  217. public ScriptScope CreateScope(string languageId, IAttributesCollection dictionary) {
  218. return GetEngine(languageId).CreateScope(dictionary);
  219. }
  220. #endregion
  221. // TODO: file IO exceptions, parse exceptions, execution exceptions, etc.
  222. /// <exception cref="ArgumentException">
  223. /// path is empty, contains one or more of the invalid characters defined in GetInvalidPathChars or doesn't have an extension.
  224. /// </exception>
  225. public ScriptScope ExecuteFile(string path) {
  226. ContractUtils.RequiresNotEmpty(path, "path");
  227. string extension = Path.GetExtension(path);
  228. ScriptEngine engine;
  229. if (!TryGetEngineByFileExtension(extension, out engine)) {
  230. throw new ArgumentException(String.Format("File extension '{0}' is not associated with any language.", extension));
  231. }
  232. return engine.ExecuteFile(path);
  233. }
  234. /// <exception cref="ArgumentNullException">path is null</exception>
  235. /// <exception cref="ArgumentException">file extension does not map to language engine</exception>
  236. /// <exception cref="InvalidOperationException">language does not have any search paths</exception>
  237. /// <exception cref="FileNotFoundException">file does exist in language's search path</exception>
  238. public ScriptScope UseFile(string path) {
  239. ContractUtils.RequiresNotEmpty(path, "path");
  240. string extension = Path.GetExtension(path);
  241. ScriptEngine engine;
  242. if (!TryGetEngineByFileExtension(extension, out engine)) {
  243. throw new ArgumentException(string.Format("File extension '{0}' is not associated with any language.", extension));
  244. }
  245. var searchPaths = engine.GetSearchPaths();
  246. if (searchPaths.Count == 0) {
  247. throw new InvalidOperationException(string.Format("No search paths defined for language '{0}'", engine.Setup.DisplayName));
  248. }
  249. // See if the file is already loaded, if so return the scope
  250. foreach (string searchPath in searchPaths) {
  251. string filePath = Path.Combine(searchPath, path);
  252. ScriptScope scope = engine.GetScope(filePath);
  253. if (scope != null) {
  254. return scope;
  255. }
  256. }
  257. // Find the file on disk, then load it
  258. foreach (string searchPath in searchPaths) {
  259. string filePath = Path.Combine(searchPath, path);
  260. if (_manager.Platform.FileExists(filePath)) {
  261. return ExecuteFile(filePath);
  262. }
  263. }
  264. // Didn't find the file, throw
  265. string allPaths = searchPaths.Aggregate((x, y) => x + ", " + y);
  266. throw new FileNotFoundException(string.Format("File '{0}' not found in language's search path: {1}", path, allPaths));
  267. }
  268. /// <summary>
  269. /// This property returns the "global object" or name bindings of the ScriptRuntime as a ScriptScope.
  270. ///
  271. /// You can set the globals scope, which you might do if you created a ScriptScope with an
  272. /// IAttributesCollection so that your host could late bind names.
  273. /// </summary>
  274. public ScriptScope Globals {
  275. get { return _globals; }
  276. set {
  277. ContractUtils.RequiresNotNull(value, "value");
  278. // TODO: this is wrong, we ignore other parts of the scope here
  279. _globals = value;
  280. _manager.SetGlobalsDictionary(_globals.Scope.Dict);
  281. }
  282. }
  283. /// <summary>
  284. /// This method walks the assembly's namespaces and name bindings to ScriptRuntime.Globals
  285. /// to represent the types available in the assembly. Each top-level namespace name gets
  286. /// bound in Globals to a dynamic object representing the namespace. Within each top-level
  287. /// namespace object, nested namespace names are bound to dynamic objects representing each
  288. /// tier of nested namespaces. When this method encounters the same namespace-qualified name,
  289. /// it merges names together objects representing the namespaces.
  290. /// </summary>
  291. /// <param name="assembly"></param>
  292. public void LoadAssembly(Assembly assembly) {
  293. _manager.LoadAssembly(assembly);
  294. }
  295. public ObjectOperations Operations {
  296. get {
  297. return InvariantEngine.Operations;
  298. }
  299. }
  300. public ObjectOperations CreateOperations() {
  301. return InvariantEngine.CreateOperations();
  302. }
  303. public void Shutdown() {
  304. List<LanguageContext> lcs;
  305. lock (_engines) {
  306. lcs = new List<LanguageContext>(_engines.Keys);
  307. }
  308. foreach (var language in lcs) {
  309. language.Shutdown();
  310. }
  311. }
  312. internal ScriptEngine InvariantEngine {
  313. get {
  314. if (_invariantEngine == null) {
  315. _invariantEngine = GetEngine(_invariantContext);
  316. }
  317. return _invariantEngine;
  318. }
  319. }
  320. }
  321. }