/CoolEngine/IronPython/Src/Microsoft.Scripting.Core/Runtime/ScriptCode.cs
# · C# · 258 lines · 155 code · 51 blank · 52 comment · 23 complexity · 4e9bb534f01d5a86b091c81079cfe2c2 MD5 · raw file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Reflection;
- using System.Reflection.Emit;
-
- using Microsoft.Contracts;
- using Microsoft.Scripting.Ast;
- using Microsoft.Scripting.Generation;
- using Microsoft.Scripting.Runtime;
- using Microsoft.Scripting.Utils;
-
- namespace Microsoft.Scripting {
- /// <summary>
- /// ScriptCode is an instance of compiled code that is bound to a specific LanguageContext
- /// but not a specific ScriptScope. The code can be re-executed multiple times in different
- /// contexts. Hosting API counterpart for this class is <c>CompiledCode</c>.
- /// </summary>
- public sealed partial class ScriptCode {
- private readonly LambdaExpression/*!*/ _code;
- private readonly LanguageContext/*!*/ _languageContext;
- private readonly CompilerContext/*!*/ _compilerContext;
-
- private DlrMainCallTarget _simpleTarget;
-
- private DlrMainCallTarget _optimizedTarget;
- private Scope _optimizedScope;
-
- private ScriptCode(DlrMainCallTarget callTarget, LanguageContext context, Scope optimizedScope, CompilerContext compilerContext) {
- if (optimizedScope != null) {
- _optimizedTarget = callTarget;
- } else {
- _simpleTarget = callTarget;
- }
-
- _optimizedScope = optimizedScope;
- _languageContext = context;
- _compilerContext = compilerContext;
- }
-
- internal ScriptCode(LambdaExpression/*!*/ code, LanguageContext/*!*/ languageContext, CompilerContext/*!*/ compilerContext) {
- Assert.NotNull(code, languageContext, compilerContext);
-
- _code = code;
- _languageContext = languageContext;
- _compilerContext = compilerContext;
- }
-
- public LanguageContext/*!*/ LanguageContext {
- get { return _languageContext; }
- }
-
- public CompilerContext/*!*/ CompilerContext {
- get { return _compilerContext; }
- }
-
- public SourceUnit/*!*/ SourceUnit {
- get { return _compilerContext.SourceUnit; }
- }
-
- public LambdaExpression/*!*/ Lambda {
- get {
- return _code;
- }
- }
-
- private bool EmitDebugSymbols {
- get {
- return SourceUnit.HasPath && _languageContext.DomainManager.GlobalOptions.DebugMode;
- }
- }
-
- public void EnsureCompiled() {
- if (_simpleTarget != null) {
- return;
- }
-
- lock (this) { // TODO: mutex object
- if (_simpleTarget == null) {
- // Rewrite globals to runtime lookups on the Scope
- LambdaExpression lambda = new GlobalLookupRewriter().RewriteLambda(_code, "Initialize");
-
- _simpleTarget = LambdaCompiler.CompileLambda<DlrMainCallTarget>(lambda, EmitDebugSymbols);
- }
- }
- }
-
- public object Run() {
- return Run(MakeOptimizedScope());
- }
-
- public object Run(Scope/*!*/ scope) {
- ContractUtils.RequiresNotNull(scope, "scope");
-
- return Run(GetContextForScope(scope));
- }
-
- public object Run(CodeContext/*!*/ context) {
- ContractUtils.RequiresNotNull(context, "context");
-
- if (context.GlobalScope == _optimizedScope) {
- return _optimizedTarget(context);
- }
-
- EnsureCompiled();
- return _simpleTarget(context);
- }
-
- [Confined]
- public override string/*!*/ ToString() {
- return string.Format("ScriptCode '{0}' from {1}", SourceUnit, _languageContext.DisplayName);
- }
-
- public Scope/*!*/ MakeOptimizedScope() {
- if (_optimizedScope != null) {
- return _optimizedScope;
- }
-
- return CompileOptimizedScope();
- }
-
- private CodeContext GetContextForScope(Scope scope) {
- ScopeExtension scopeExtension = _languageContext.EnsureScopeExtension(scope.ModuleScope);
-
- return new CodeContext(scope, _languageContext);
- }
-
-
- /// <summary>
- /// This takes an assembly name including extension and saves the provided ScriptCode objects into the assembly.
- ///
- /// The provided script codes can constitute code from multiple languages. The assemblyName can be either a fully qualified
- /// or a relative path. The DLR will simply save the assembly to the desired location. The assembly is created by the DLR and
- /// if a file already exists than an exception is raised.
- ///
- /// The DLR determines the internal format of the ScriptCode and the DLR can feel free to rev this as appropriate.
- /// </summary>
- public static void SaveToDisk(string/*!*/ assemblyName, params ScriptCode/*!*/[]/*!*/ codes) {
- ContractUtils.RequiresNotNull(assemblyName, "assemblyName");
- ContractUtils.RequiresNotNullItems(codes, "codes");
-
- // break the assemblyName into it's dir/name/extension
- string dir = Path.GetDirectoryName(assemblyName);
- if (String.IsNullOrEmpty(dir)) {
- dir = Environment.CurrentDirectory;
- }
-
- string name = Path.GetFileNameWithoutExtension(assemblyName);
- string ext = Path.GetExtension(assemblyName);
-
- // build the assembly & type gen that all the script codes will live in...
- AssemblyGen ag = new AssemblyGen(new AssemblyName(name), dir, ext, /*emitSymbols*/false);
- TypeBuilder tb = ag.DefinePublicType("DLRCachedCode", typeof(object), true);
- TypeGen tg = new TypeGen(ag, tb);
-
- // then compile all of the code
- foreach (ScriptCode sc in codes) {
- sc.CompileToDisk(tg);
- }
-
- tg.FinishType();
-
- ag.Dump();
- }
-
-
- /// <summary>
- /// This will take an assembly object which the user has loaded and return a new set of ScriptCodes which have
- /// been loaded into the provided ScriptDomainManager.
- ///
- /// If the language associated with the ScriptCodes has not already been loaded the DLR will load the
- /// LanguageContext into the ScriptDomainManager based upon the saved LanguageContext type.
- ///
- /// If the LanguageContext or the version of the DLR the language was compiled against is unavailable a
- /// TypeLoadException will be raised unless policy has been applied by the administrator to redirect bindings.
- /// </summary>
- public static ScriptCode[] LoadFromAssembly(ScriptDomainManager/*!*/ runtime, Assembly/*!*/ assembly) {
- ContractUtils.RequiresNotNull(runtime, "runtime");
- ContractUtils.RequiresNotNull(assembly, "assembly");
-
- // get the type which has our cached code...
- Type t = assembly.GetType("DLRCachedCode");
- if (t == null) {
- return new ScriptCode[0];
- }
-
- List<ScriptCode> codes = new List<ScriptCode>();
-
- // look for methods which are associated with a saved ScriptCode...
- foreach (MethodInfo mi in t.GetMethods()) {
- // we mark the methods as special name when we generate them because the
- // method name implies the filename.
- if (!mi.IsSpecialName) {
- continue;
- }
-
- // we also put an attribute which contains additional information
- DlrCachedCodeAttribute[] code = (DlrCachedCodeAttribute[])mi.GetCustomAttributes(typeof(DlrCachedCodeAttribute), false);
- if (code.Length == 0) {
- continue;
- }
-
- LanguageContext lc = runtime.GetLanguageContext(code[0].LanguageContextType);
- Scope scope;
-
- if (code[0].Names != null) {
-
- // create the storage for the global scope
- GlobalsDictionary dict = new GlobalsDictionary(SymbolTable.StringsToIds(code[0].Names));
-
- // create the CodeContext for the code from the storage
- scope = new Scope(dict);
- CodeContext context = new CodeContext(scope, lc);
-
- // initialize the tuple
- IModuleDictionaryInitialization ici = dict as IModuleDictionaryInitialization;
- if (ici != null) {
- ici.InitializeModuleDictionary(context);
- }
- } else {
- scope = null;
- }
-
- // create the CompilerContext for the ScriptCode
- SourceUnit su = new SourceUnit(lc, NullTextContentProvider.Null, mi.Name, SourceCodeKind.File);
- CompilerContext ctx = new CompilerContext(su, lc.GetCompilerOptions(), ErrorSink.Null);
-
- // finally generate the ScriptCode
- ScriptCode sc = new ScriptCode(
- (DlrMainCallTarget)Delegate.CreateDelegate(typeof(DlrMainCallTarget), mi),
- lc,
- scope,
- ctx
- );
-
- codes.Add(sc);
- }
-
- return codes.ToArray();
- }
- }
- }