PageRenderTime 82ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/CoolEngine/IronPython/Src/Microsoft.Scripting.Core/Runtime/ScriptCode.cs

#
C# | 258 lines | 155 code | 51 blank | 52 comment | 23 complexity | 4e9bb534f01d5a86b091c81079cfe2c2 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. using System;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.IO;
  19. using System.Reflection;
  20. using System.Reflection.Emit;
  21. using Microsoft.Contracts;
  22. using Microsoft.Scripting.Ast;
  23. using Microsoft.Scripting.Generation;
  24. using Microsoft.Scripting.Runtime;
  25. using Microsoft.Scripting.Utils;
  26. namespace Microsoft.Scripting {
  27. /// <summary>
  28. /// ScriptCode is an instance of compiled code that is bound to a specific LanguageContext
  29. /// but not a specific ScriptScope. The code can be re-executed multiple times in different
  30. /// contexts. Hosting API counterpart for this class is <c>CompiledCode</c>.
  31. /// </summary>
  32. public sealed partial class ScriptCode {
  33. private readonly LambdaExpression/*!*/ _code;
  34. private readonly LanguageContext/*!*/ _languageContext;
  35. private readonly CompilerContext/*!*/ _compilerContext;
  36. private DlrMainCallTarget _simpleTarget;
  37. private DlrMainCallTarget _optimizedTarget;
  38. private Scope _optimizedScope;
  39. private ScriptCode(DlrMainCallTarget callTarget, LanguageContext context, Scope optimizedScope, CompilerContext compilerContext) {
  40. if (optimizedScope != null) {
  41. _optimizedTarget = callTarget;
  42. } else {
  43. _simpleTarget = callTarget;
  44. }
  45. _optimizedScope = optimizedScope;
  46. _languageContext = context;
  47. _compilerContext = compilerContext;
  48. }
  49. internal ScriptCode(LambdaExpression/*!*/ code, LanguageContext/*!*/ languageContext, CompilerContext/*!*/ compilerContext) {
  50. Assert.NotNull(code, languageContext, compilerContext);
  51. _code = code;
  52. _languageContext = languageContext;
  53. _compilerContext = compilerContext;
  54. }
  55. public LanguageContext/*!*/ LanguageContext {
  56. get { return _languageContext; }
  57. }
  58. public CompilerContext/*!*/ CompilerContext {
  59. get { return _compilerContext; }
  60. }
  61. public SourceUnit/*!*/ SourceUnit {
  62. get { return _compilerContext.SourceUnit; }
  63. }
  64. public LambdaExpression/*!*/ Lambda {
  65. get {
  66. return _code;
  67. }
  68. }
  69. private bool EmitDebugSymbols {
  70. get {
  71. return SourceUnit.HasPath && _languageContext.DomainManager.GlobalOptions.DebugMode;
  72. }
  73. }
  74. public void EnsureCompiled() {
  75. if (_simpleTarget != null) {
  76. return;
  77. }
  78. lock (this) { // TODO: mutex object
  79. if (_simpleTarget == null) {
  80. // Rewrite globals to runtime lookups on the Scope
  81. LambdaExpression lambda = new GlobalLookupRewriter().RewriteLambda(_code, "Initialize");
  82. _simpleTarget = LambdaCompiler.CompileLambda<DlrMainCallTarget>(lambda, EmitDebugSymbols);
  83. }
  84. }
  85. }
  86. public object Run() {
  87. return Run(MakeOptimizedScope());
  88. }
  89. public object Run(Scope/*!*/ scope) {
  90. ContractUtils.RequiresNotNull(scope, "scope");
  91. return Run(GetContextForScope(scope));
  92. }
  93. public object Run(CodeContext/*!*/ context) {
  94. ContractUtils.RequiresNotNull(context, "context");
  95. if (context.GlobalScope == _optimizedScope) {
  96. return _optimizedTarget(context);
  97. }
  98. EnsureCompiled();
  99. return _simpleTarget(context);
  100. }
  101. [Confined]
  102. public override string/*!*/ ToString() {
  103. return string.Format("ScriptCode '{0}' from {1}", SourceUnit, _languageContext.DisplayName);
  104. }
  105. public Scope/*!*/ MakeOptimizedScope() {
  106. if (_optimizedScope != null) {
  107. return _optimizedScope;
  108. }
  109. return CompileOptimizedScope();
  110. }
  111. private CodeContext GetContextForScope(Scope scope) {
  112. ScopeExtension scopeExtension = _languageContext.EnsureScopeExtension(scope.ModuleScope);
  113. return new CodeContext(scope, _languageContext);
  114. }
  115. /// <summary>
  116. /// This takes an assembly name including extension and saves the provided ScriptCode objects into the assembly.
  117. ///
  118. /// The provided script codes can constitute code from multiple languages. The assemblyName can be either a fully qualified
  119. /// or a relative path. The DLR will simply save the assembly to the desired location. The assembly is created by the DLR and
  120. /// if a file already exists than an exception is raised.
  121. ///
  122. /// The DLR determines the internal format of the ScriptCode and the DLR can feel free to rev this as appropriate.
  123. /// </summary>
  124. public static void SaveToDisk(string/*!*/ assemblyName, params ScriptCode/*!*/[]/*!*/ codes) {
  125. ContractUtils.RequiresNotNull(assemblyName, "assemblyName");
  126. ContractUtils.RequiresNotNullItems(codes, "codes");
  127. // break the assemblyName into it's dir/name/extension
  128. string dir = Path.GetDirectoryName(assemblyName);
  129. if (String.IsNullOrEmpty(dir)) {
  130. dir = Environment.CurrentDirectory;
  131. }
  132. string name = Path.GetFileNameWithoutExtension(assemblyName);
  133. string ext = Path.GetExtension(assemblyName);
  134. // build the assembly & type gen that all the script codes will live in...
  135. AssemblyGen ag = new AssemblyGen(new AssemblyName(name), dir, ext, /*emitSymbols*/false);
  136. TypeBuilder tb = ag.DefinePublicType("DLRCachedCode", typeof(object), true);
  137. TypeGen tg = new TypeGen(ag, tb);
  138. // then compile all of the code
  139. foreach (ScriptCode sc in codes) {
  140. sc.CompileToDisk(tg);
  141. }
  142. tg.FinishType();
  143. ag.Dump();
  144. }
  145. /// <summary>
  146. /// This will take an assembly object which the user has loaded and return a new set of ScriptCode’s which have
  147. /// been loaded into the provided ScriptDomainManager.
  148. ///
  149. /// If the language associated with the ScriptCode’s has not already been loaded the DLR will load the
  150. /// LanguageContext into the ScriptDomainManager based upon the saved LanguageContext type.
  151. ///
  152. /// If the LanguageContext or the version of the DLR the language was compiled against is unavailable a
  153. /// TypeLoadException will be raised unless policy has been applied by the administrator to redirect bindings.
  154. /// </summary>
  155. public static ScriptCode[] LoadFromAssembly(ScriptDomainManager/*!*/ runtime, Assembly/*!*/ assembly) {
  156. ContractUtils.RequiresNotNull(runtime, "runtime");
  157. ContractUtils.RequiresNotNull(assembly, "assembly");
  158. // get the type which has our cached code...
  159. Type t = assembly.GetType("DLRCachedCode");
  160. if (t == null) {
  161. return new ScriptCode[0];
  162. }
  163. List<ScriptCode> codes = new List<ScriptCode>();
  164. // look for methods which are associated with a saved ScriptCode...
  165. foreach (MethodInfo mi in t.GetMethods()) {
  166. // we mark the methods as special name when we generate them because the
  167. // method name implies the filename.
  168. if (!mi.IsSpecialName) {
  169. continue;
  170. }
  171. // we also put an attribute which contains additional information
  172. DlrCachedCodeAttribute[] code = (DlrCachedCodeAttribute[])mi.GetCustomAttributes(typeof(DlrCachedCodeAttribute), false);
  173. if (code.Length == 0) {
  174. continue;
  175. }
  176. LanguageContext lc = runtime.GetLanguageContext(code[0].LanguageContextType);
  177. Scope scope;
  178. if (code[0].Names != null) {
  179. // create the storage for the global scope
  180. GlobalsDictionary dict = new GlobalsDictionary(SymbolTable.StringsToIds(code[0].Names));
  181. // create the CodeContext for the code from the storage
  182. scope = new Scope(dict);
  183. CodeContext context = new CodeContext(scope, lc);
  184. // initialize the tuple
  185. IModuleDictionaryInitialization ici = dict as IModuleDictionaryInitialization;
  186. if (ici != null) {
  187. ici.InitializeModuleDictionary(context);
  188. }
  189. } else {
  190. scope = null;
  191. }
  192. // create the CompilerContext for the ScriptCode
  193. SourceUnit su = new SourceUnit(lc, NullTextContentProvider.Null, mi.Name, SourceCodeKind.File);
  194. CompilerContext ctx = new CompilerContext(su, lc.GetCompilerOptions(), ErrorSink.Null);
  195. // finally generate the ScriptCode
  196. ScriptCode sc = new ScriptCode(
  197. (DlrMainCallTarget)Delegate.CreateDelegate(typeof(DlrMainCallTarget), mi),
  198. lc,
  199. scope,
  200. ctx
  201. );
  202. codes.Add(sc);
  203. }
  204. return codes.ToArray();
  205. }
  206. }
  207. }