From cd988456fb3d102da84056e8e150d5376284cc8e Mon Sep 17 00:00:00 2001 From: Jim Deville Date: Thu, 19 Mar 2009 15:34:24 -0700 Subject: [PATCH 1/2] syncing to head of tfs. Changes IronRuby to version 0.3 --- .../rubyspec/core/file/expand_path_spec.rb | 2 +- Merlin/Main/Config/Signed/App.config | 2 +- Merlin/Main/Config/Unsigned/App.config | 2 +- .../PythonGlobalVariableExpression.cs | 2 +- .../IronPython/Runtime/Operations/ScopeOps.cs | 11 +- .../Runtime/Operations/StringOps.cs | 22 +- .../Languages/Ruby/IronRuby.Tests/Driver.cs | 34 +- .../Languages/Ruby/IronRuby.Tests/Helpers.cs | 2 +- .../Ruby/IronRuby.Tests/Parser/ParserTests.cs | 4 +- .../IronRuby.Tests/Runtime/BacktraceTests.cs | 7 +- .../IronRuby.Tests/Runtime/LoaderTests.cs | 8 +- .../Builtins/ModuleOps.cs | 2 +- .../Libraries.LCA_RESTRICTED/Protocols.cs | 6 +- .../Languages/Ruby/Ruby/Builtins/RubyClass.cs | 2 +- .../Ruby/Ruby/Builtins/RubyModule.cs | 8 + .../Ruby/Ruby/Compiler/Ast/BlockDefinition.cs | 7 +- .../Ast/Declarations/MethodDeclaration.cs | 3 +- .../Languages/Ruby/Ruby/Ruby.Build.csproj | Bin 41396 -> 41626 bytes Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj | 4 + .../Ruby/Runtime/Calls/BlockDispatcher.cs | 18 +- .../Languages/Ruby/Ruby/Runtime/Loader.cs | 8 - .../Ruby/Ruby/Runtime/RubyContext.cs | 20 +- .../Ruby/Ruby/Runtime/RubyExceptionData.cs | 16 +- .../Ruby/Ruby/Runtime/RubyMethodDebugInfo.cs | 65 ++++ .../Ruby/Ruby/Runtime/RubyScriptCode.cs | 94 +++++ .../Languages/Ruby/Ruby/Runtime/RubyUtils.cs | 2 +- .../IronRuby.Libraries.Scanner/Program.cs | 4 +- .../Generation/CompilerHelpers.cs | 26 +- .../Runtime/LanguageContext.cs | 2 +- .../Scripting/Ast/LambdaExpression.cs | 50 ++- .../Scripting/Compiler/AnalyzedTree.cs | 12 +- .../Compiler/CompilerScope.Storage.cs | 8 +- .../Scripting/Compiler/DebugInfoGenerator.cs | 56 +++ .../Microsoft/Scripting/Compiler/ILGen.cs | 2 + .../Microsoft/Scripting/Compiler/LabelInfo.cs | 2 + .../Compiler/LambdaCompiler.Expressions.cs | 20 +- .../Compiler/LambdaCompiler.Lambda.cs | 2 +- .../Compiler/LambdaCompiler.Statements.cs | 2 +- .../Scripting/Compiler/LambdaCompiler.cs | 34 +- .../Compiler/OffsetTrackingILGenerator.cs | 357 ++++++++++++++++++ .../Compiler/SymbolDocumentGenerator.cs | 61 +++ .../Scripting/Microsoft.Scripting.Core.csproj | 3 + .../Utils/ExceptionFactory.Generated.cs | 9 - 43 files changed, 859 insertions(+), 142 deletions(-) create mode 100644 Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyMethodDebugInfo.cs create mode 100644 Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyScriptCode.cs create mode 100644 ndp/fx/src/Core/Microsoft/Scripting/Compiler/DebugInfoGenerator.cs create mode 100644 ndp/fx/src/Core/Microsoft/Scripting/Compiler/OffsetTrackingILGenerator.cs create mode 100644 ndp/fx/src/Core/Microsoft/Scripting/Compiler/SymbolDocumentGenerator.cs diff --git a/Merlin/External/Languages/IronRuby/mspec/rubyspec/core/file/expand_path_spec.rb b/Merlin/External/Languages/IronRuby/mspec/rubyspec/core/file/expand_path_spec.rb index caf886da5d..380636700a 100644 --- a/Merlin/External/Languages/IronRuby/mspec/rubyspec/core/file/expand_path_spec.rb +++ b/Merlin/External/Languages/IronRuby/mspec/rubyspec/core/file/expand_path_spec.rb @@ -40,7 +40,7 @@ end # FIXME: do not use conditionals like this around #it blocks - unless not home = ENV['HOME'] + unless not home = ENV['HOME'].tr('\\', '/') it "converts a pathname to an absolute pathname, using ~ (home) as base" do File.expand_path('~').should == home File.expand_path('~', '/tmp/gumby/ddd').should == home diff --git a/Merlin/Main/Config/Signed/App.config b/Merlin/Main/Config/Signed/App.config index ebbe48d466..b9efbbdd31 100644 --- a/Merlin/Main/Config/Signed/App.config +++ b/Merlin/Main/Config/Signed/App.config @@ -7,7 +7,7 @@ - + diff --git a/Merlin/Main/Config/Unsigned/App.config b/Merlin/Main/Config/Unsigned/App.config index 665b4f86de..3752261eeb 100644 --- a/Merlin/Main/Config/Unsigned/App.config +++ b/Merlin/Main/Config/Unsigned/App.config @@ -7,7 +7,7 @@ - + diff --git a/Merlin/Main/Languages/IronPython/IronPython/Compiler/PythonGlobalVariableExpression.cs b/Merlin/Main/Languages/IronPython/IronPython/Compiler/PythonGlobalVariableExpression.cs index d1e7cd06ce..b766a5cc33 100644 --- a/Merlin/Main/Languages/IronPython/IronPython/Compiler/PythonGlobalVariableExpression.cs +++ b/Merlin/Main/Languages/IronPython/IronPython/Compiler/PythonGlobalVariableExpression.cs @@ -267,7 +267,7 @@ class LookupGlobalInstruction : Instruction { _name = SymbolTable.StringToId(name); _isLocal = isLocal; } - + public override int ConsumedStack { get { return 1; } } public override int ProducedStack { get { return 1; } } public override int Run(StackFrame frame) { if (_isLocal) { diff --git a/Merlin/Main/Languages/IronPython/IronPython/Runtime/Operations/ScopeOps.cs b/Merlin/Main/Languages/IronPython/IronPython/Runtime/Operations/ScopeOps.cs index 6e930f8ea1..72e32cd6f0 100644 --- a/Merlin/Main/Languages/IronPython/IronPython/Runtime/Operations/ScopeOps.cs +++ b/Merlin/Main/Languages/IronPython/IronPython/Runtime/Operations/ScopeOps.cs @@ -59,14 +59,21 @@ public static class ScopeOps { } } - public static object __getattribute__(Scope/*!*/ self, string name) { + public static object __getattribute__(CodeContext/*!*/ context, Scope/*!*/ self, string name) { + switch (name) { + // never look in the dict for these... + case "__dict__": return Get__dict__(self); + case "__class__": return DynamicHelpers.GetPythonType(self); + } + SymbolId si = SymbolTable.StringToId(name); object res; if (self.TryGetName(si, out res)) { return res; } - throw PythonOps.AttributeErrorForMissingAttribute("module", si); + // fall back to object to provide all of our other attributes (e.g. __setattr__, etc...) + return ObjectOps.__getattribute__(context, self, name); } public static void __setattr__(Scope/*!*/ self, string name, object value) { diff --git a/Merlin/Main/Languages/IronPython/IronPython/Runtime/Operations/StringOps.cs b/Merlin/Main/Languages/IronPython/IronPython/Runtime/Operations/StringOps.cs index d630ba1261..d416748906 100644 --- a/Merlin/Main/Languages/IronPython/IronPython/Runtime/Operations/StringOps.cs +++ b/Merlin/Main/Languages/IronPython/IronPython/Runtime/Operations/StringOps.cs @@ -179,7 +179,7 @@ public static class StringOps { if (cls == TypeCache.String) { return FastNew(context, @object); } else { - return cls.CreateInstance(context, @object); + return cls.CreateInstance(context, __new__(context, TypeCache.String, @object)); } } @@ -197,7 +197,7 @@ public static class StringOps { if (cls == TypeCache.String) { return FastNew(context, @object); } else { - return cls.CreateInstance(context, @object); + return cls.CreateInstance(context, __new__(context, TypeCache.String, @object)); } } @@ -206,7 +206,7 @@ public static class StringOps { if (cls == TypeCache.String) { return CheckAsciiString(context, ScriptingRuntimeHelpers.CharToString(@object)); } else { - return cls.CreateInstance(context, @object); + return cls.CreateInstance(context, __new__(context, TypeCache.String, @object)); } } @@ -215,7 +215,7 @@ public static class StringOps { if (cls == TypeCache.String) { return @object.ToString(); } else { - return cls.CreateInstance(context, @object); + return cls.CreateInstance(context, __new__(context, TypeCache.String, @object)); } } @@ -224,7 +224,7 @@ public static class StringOps { if (cls == TypeCache.String) { return FastNew(context, @object); } else { - return cls.CreateInstance(context, @object); + return cls.CreateInstance(context, __new__(context, TypeCache.String, @object)); } } @@ -233,7 +233,7 @@ public static class StringOps { if (cls == TypeCache.String) { return @object.ToString(); } else { - return cls.CreateInstance(context, @object); + return cls.CreateInstance(context, __new__(context, TypeCache.String, @object)); } } @@ -242,7 +242,7 @@ public static class StringOps { if (cls == TypeCache.String) { return @object.ToString(); } else { - return cls.CreateInstance(context, @object); + return cls.CreateInstance(context, __new__(context, TypeCache.String, @object)); } } @@ -251,7 +251,7 @@ public static class StringOps { if (cls == TypeCache.String) { return DoubleOps.__str__(context, @object); } else { - return cls.CreateInstance(context, @object); + return cls.CreateInstance(context, __new__(context, TypeCache.String, @object)); } } @@ -260,7 +260,7 @@ public static class StringOps { if (cls == TypeCache.String) { return FastNew(context, @object); } else { - return cls.CreateInstance(context, @object); + return cls.CreateInstance(context, __new__(context, TypeCache.String, @object)); } } @@ -269,7 +269,7 @@ public static class StringOps { if (cls == TypeCache.String) { return SingleOps.__str__(context, @object); } else { - return cls.CreateInstance(context, @object); + return cls.CreateInstance(context, __new__(context, TypeCache.String, @object)); } } @@ -285,7 +285,7 @@ public static class StringOps { if (cls == TypeCache.String) { return decode(context, str, encoding ?? PythonContext.GetContext(context).GetDefaultEncodingName(), errors); } else { - return cls.CreateInstance(context, str, encoding, errors); + return cls.CreateInstance(context, __new__(context, TypeCache.String, str, encoding, errors)); } } diff --git a/Merlin/Main/Languages/Ruby/IronRuby.Tests/Driver.cs b/Merlin/Main/Languages/Ruby/IronRuby.Tests/Driver.cs index 294cfe6a60..da7a59186d 100644 --- a/Merlin/Main/Languages/Ruby/IronRuby.Tests/Driver.cs +++ b/Merlin/Main/Languages/Ruby/IronRuby.Tests/Driver.cs @@ -59,7 +59,7 @@ public class TestRuntime { _driver = driver; _testName = testCase.Name; - if (_driver.IsDebug) { + if (_driver.SaveToAssemblies) { Environment.SetEnvironmentVariable("DLR_AssembliesFileName", _testName); } @@ -72,8 +72,7 @@ public class TestRuntime { } } - // TODO: dynamic modules with symbols are not available in partial trust - runtimeSetup.DebugMode = !driver.PartialTrust; + runtimeSetup.DebugMode = _driver.IsDebug; languageSetup.Options["InterpretedMode"] = _driver.Interpret; languageSetup.Options["Verbosity"] = 2; languageSetup.Options["Compatibility"] = testCase.Compatibility; @@ -94,6 +93,7 @@ public class Driver { private TestRuntime _testRuntime; private static bool _excludeSelectedCases; private static bool _isDebug; + private static bool _saveToAssemblies; private static bool _runTokenizerDriver; private static bool _displayList; private static bool _partialTrust; @@ -116,6 +116,10 @@ public class Driver { get { return _isDebug; } } + public bool SaveToAssemblies { + get { return _saveToAssemblies; } + } + public bool PartialTrust { get { return _partialTrust; } } @@ -132,8 +136,10 @@ public class Driver { if (args.Contains("/help") || args.Contains("-?") || args.Contains("/?") || args.Contains("-help")) { Console.WriteLine("Partial trust : /partial"); Console.WriteLine("Interpret : /interpret"); + Console.WriteLine("Save to assemblies : /save"); + Console.WriteLine("Debug Mode : /debug"); Console.WriteLine("Disable Python interop tests : /py-"); - Console.WriteLine("Run Specific Tests : [/debug] [/exclude] [test_to_run ...]"); + Console.WriteLine("Run Specific Tests : [/exclude] [test_to_run ...]"); Console.WriteLine("List Tests : /list"); Console.WriteLine("Tokenizer baseline : /tokenizer "); Console.WriteLine("Productions dump : /tokenizer /prod "); @@ -150,6 +156,11 @@ public class Driver { _isDebug = true; } + if (args.Contains("/save")) { + args.Remove("/save"); + _saveToAssemblies = true; + } + if (args.Contains("/partial")) { args.Remove("/partial"); _partialTrust = true; @@ -278,7 +289,7 @@ public sealed class Loader : MarshalByRefObject { } private static void InitializeDomain() { - if (_isDebug) { + if (_saveToAssemblies) { string _dumpDir = Path.Combine(Path.GetTempPath(), "RubyTests"); if (Directory.Exists(_dumpDir)) { @@ -374,7 +385,11 @@ public sealed class Loader : MarshalByRefObject { failedCases.Add(test); Console.Error.WriteLine(); - WriteError("{0}) {1} {2} : {3}", failedCases.Count, test, frame.GetFileName(), frame.GetFileLineNumber()); + if (_partialTrust) { + WriteError("{0}) {1}", failedCases.Count, test); + } else { + WriteError("{0}) {1} {2} : {3}", failedCases.Count, test, frame.GetFileName(), frame.GetFileLineNumber()); + } Console.Error.WriteLine(message); } } @@ -397,7 +412,12 @@ public sealed class Loader : MarshalByRefObject { Console.ForegroundColor = ConsoleColor.Gray; } else { Console.WriteLine(); - Console.Write("Repro: {0}", Environment.CommandLine); + // TODO: + if (!_partialTrust) { + Console.Write("Repro: {0}", Environment.CommandLine); + } else { + Console.Write("Repro: IronRuby.Tests.exe /partial"); + } if (largs.Count == 0) { Console.Write(" {0}", String.Join(" ", failedCases.ToArray())); } diff --git a/Merlin/Main/Languages/Ruby/IronRuby.Tests/Helpers.cs b/Merlin/Main/Languages/Ruby/IronRuby.Tests/Helpers.cs index 21d386c9d7..2708ad91a6 100644 --- a/Merlin/Main/Languages/Ruby/IronRuby.Tests/Helpers.cs +++ b/Merlin/Main/Languages/Ruby/IronRuby.Tests/Helpers.cs @@ -113,7 +113,7 @@ public partial class Tests { string name = _driver.TestRuntime.TestName; - if (_driver.IsDebug) { + if (_driver.SaveToAssemblies) { string path = Path.Combine(Snippets.Shared.SnippetsDirectory, name + ".rb"); Directory.CreateDirectory(Snippets.Shared.SnippetsDirectory); File.WriteAllText(path, code); diff --git a/Merlin/Main/Languages/Ruby/IronRuby.Tests/Parser/ParserTests.cs b/Merlin/Main/Languages/Ruby/IronRuby.Tests/Parser/ParserTests.cs index 8b07291e31..2fae29bea4 100644 --- a/Merlin/Main/Languages/Ruby/IronRuby.Tests/Parser/ParserTests.cs +++ b/Merlin/Main/Languages/Ruby/IronRuby.Tests/Parser/ParserTests.cs @@ -890,8 +890,8 @@ p __ENCODING__ const int Id = 0x12345678; - var lambda = CallSiteTracer.Transform(ast, sourceUnit, options, Id); - var code = new LegacyScriptCode(lambda, sourceUnit); + var lambda = CallSiteTracer.Transform>(ast, sourceUnit, options, Id); + var code = new RubyScriptCode(lambda, sourceUnit); var locations = new List(); CallSiteTracer.Register((context, args, result, id, location) => { diff --git a/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/BacktraceTests.cs b/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/BacktraceTests.cs index b6601d683b..b853b58283 100644 --- a/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/BacktraceTests.cs +++ b/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/BacktraceTests.cs @@ -15,10 +15,11 @@ using Microsoft.Scripting; using System; + namespace IronRuby.Tests { public partial class Tests { private bool PreciseTraces { - get { return !_driver.PartialTrust || _driver.Interpret; } + get { return Runtime.Setup.DebugMode || _driver.Interpret; } } public void Backtrace1() { @@ -171,13 +172,13 @@ def foo }, PreciseTraces ? @" Backtrace4.rb:7:in `baz' Backtrace4.rb:11:in `foo' -*.cs:*:in `Bar' +*:*:in `Bar' Backtrace4.rb:11:in `foo' Backtrace4.rb:14 " : @" Backtrace4.rb:6:in `baz' Backtrace4.rb:11:in `foo' -:0:in `Bar' +*:*:in `Bar' Backtrace4.rb:10:in `foo' Backtrace4.rb:0 ", OutputFlags.Match); diff --git a/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/LoaderTests.cs b/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/LoaderTests.cs index d6f469eb1b..1f85d5fe36 100644 --- a/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/LoaderTests.cs +++ b/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/LoaderTests.cs @@ -41,14 +41,14 @@ public partial class Tests { b = Loader.TryParseAssemblyName(str, out type, out assembly); Assert(b == false); - str = "IronRuby.Runtime.RubyContext, IronRuby, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; + str = "IronRuby.Runtime.RubyContext, IronRuby, Version=0.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; b = Loader.TryParseAssemblyName(str, out type, out assembly); Assert(b == true && - assembly == "IronRuby, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" && + assembly == "IronRuby, Version=0.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" && type == "IronRuby.Runtime.RubyContext" ); - str = "IronRuby, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; + str = "IronRuby, Version=0.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; b = Loader.TryParseAssemblyName(str, out type, out assembly); Assert(b == true && assembly == str && type == null); @@ -56,7 +56,7 @@ public partial class Tests { b = Loader.TryParseAssemblyName(str, out type, out assembly); Assert(b == true && assembly == str && type == null); - str = "IronRuby, Version=1.0.0.0"; + str = "IronRuby, Version=0.3.0.0"; b = Loader.TryParseAssemblyName(str, out type, out assembly); Assert(b == true && assembly == str && type == null); } diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs index 37863b0e1a..b34e9afca3 100644 --- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs +++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs @@ -324,7 +324,7 @@ public static class ModuleOps { ); } - self.SetDefinedMethodNoEventNoLock(self.Context, methodName, info, attributesScope.Visibility); + self.SetDefinedMethodNoEventNoLock(self.Context, methodName, info, visibility); } self.Context.MethodAdded(self, methodName); diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Protocols.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Protocols.cs index 4b5ec1150c..15a2016da5 100644 --- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Protocols.cs +++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Protocols.cs @@ -395,9 +395,9 @@ public static class Protocols { return tt.Type; } - RubyClass rc = value as RubyClass; - if (rc != null) { - return rc.GetUnderlyingSystemType(); + RubyModule module = value as RubyModule; + if (module != null) { + return module.GetUnderlyingSystemType(); } throw RubyExceptions.InvalidValueForType(context, value, "Class"); diff --git a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyClass.cs b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyClass.cs index f5bf53c429..ca5adfc2c4 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyClass.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyClass.cs @@ -166,7 +166,7 @@ public sealed partial class RubyClass : RubyModule, IDuplicable { } #endif - public Type/*!*/ GetUnderlyingSystemType() { + public override Type/*!*/ GetUnderlyingSystemType() { if (_isSingletonClass) { throw new InvalidOperationException("Singleton class doesn't have underlying system type."); } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.cs b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.cs index 6f03fad58d..b3badb9c18 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.cs @@ -108,6 +108,14 @@ private enum MemberTableState { get { return _tracker != null && _tracker.Type.IsInterface; } } + public virtual Type/*!*/ GetUnderlyingSystemType() { + if (IsInterface) { + return _tracker.Type; + } else { + throw new InvalidOperationException(); + } + } + public RubyClass/*!*/ SingletonClass { get { Debug.Assert(_singletonClass != null); diff --git a/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/BlockDefinition.cs b/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/BlockDefinition.cs index 65633ba847..aae55e67e7 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/BlockDefinition.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/BlockDefinition.cs @@ -173,11 +173,12 @@ public BlockDefinition(LexicalScope definedScope, CompoundLeftValue/*!*/ paramet gen.CurrentScopeVariable, gen.CurrentRfcVariable, gen.CurrentSelfVariable, - Ast.Lambda( - BlockDispatcher.GetDelegateType(parameterCount, attributes), + BlockDispatcher.CreateLambda( body, RubyExceptionData.EncodeMethodName(gen.SourceUnit, gen.CurrentMethod.MethodName, Location), - new ReadOnlyCollection(parameters) + new ReadOnlyCollection(parameters), + parameterCount, + attributes ), AstUtils.Constant(parameterCount), AstUtils.Constant(attributes) diff --git a/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Declarations/MethodDeclaration.cs b/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Declarations/MethodDeclaration.cs index 3d5f696bbd..4aca020cf5 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Declarations/MethodDeclaration.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Declarations/MethodDeclaration.cs @@ -156,8 +156,7 @@ public partial class MethodDeclaration : DeclarationExpression { } bodyWithParamInit[parameters.Length] = body; - return Ast.Lambda( - RubyMethodInfo.ParamsArrayDelegateType, + return Ast.Lambda>( Ast.Block( new ReadOnlyCollection(parameters), new ReadOnlyCollection(bodyWithParamInit) diff --git a/Merlin/Main/Languages/Ruby/Ruby/Ruby.Build.csproj b/Merlin/Main/Languages/Ruby/Ruby/Ruby.Build.csproj index 3478c5c26ffdd852aa42382138c3cfcacad2bac1..a0479cbe375f916412a483ded9f596ab0dc96606 100644 GIT binary patch delta 63 zcmV-F0KosW!vdPc0fQUE2tX diff --git a/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj b/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj index 2598517518..ebb68a1602 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj +++ b/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj @@ -61,6 +61,7 @@ true true ..\..\..\Utilities\Silverlight\x86ret\ + 414,219 ..\..\..\Bin\Silverlight Release\ @@ -71,6 +72,7 @@ prompt true ..\..\..\Utilities\Silverlight\x86ret\ + 414,219 @@ -309,11 +311,13 @@ + + diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcher.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcher.cs index 439ff00887..a09f62001f 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcher.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcher.cs @@ -22,6 +22,7 @@ using System.Linq.Expressions; using System.Reflection; using IronRuby.Builtins; +using System.Collections.ObjectModel; namespace IronRuby.Runtime.Calls { using Ast = System.Linq.Expressions.Expression; @@ -108,18 +109,19 @@ public abstract class BlockDispatcher { return new BlockDispatcherUnsplatN((BlockCallTargetUnsplatN)method, parameterCount, attributes); } - internal static Type/*!*/ GetDelegateType(int parameterCount, BlockSignatureAttributes attributes) { + internal static LambdaExpression/*!*/ CreateLambda(Expression body, string name, ReadOnlyCollection parameters, + int parameterCount, BlockSignatureAttributes attributes) { if ((attributes & BlockSignatureAttributes.HasUnsplatParameter) == 0) { switch (parameterCount) { - case 0: return typeof(BlockCallTarget0); - case 1: return typeof(BlockCallTarget1); - case 2: return typeof(BlockCallTarget2); - case 3: return typeof(BlockCallTarget3); - case 4: return typeof(BlockCallTarget4); - default: return typeof(BlockCallTargetN); + case 0: return Ast.Lambda(body, name, parameters); + case 1: return Ast.Lambda(body, name, parameters); + case 2: return Ast.Lambda(body, name, parameters); + case 3: return Ast.Lambda(body, name, parameters); + case 4: return Ast.Lambda(body, name, parameters); + default: return Ast.Lambda(body, name, parameters); } } - return typeof(BlockCallTargetUnsplatN); + return Ast.Lambda(body, name, parameters); } private static void CopyArgumentsFromSplattee(object[]/*!*/ args, int initializedArgCount, int parameterCount, diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Loader.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Loader.cs index c62852e58a..982391868c 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Loader.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Loader.cs @@ -81,7 +81,6 @@ private struct CompiledFile { [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] private int _compiledFileCount; - internal static long _ILGenerationTimeTicks; internal static long _ScriptCodeGenerationTimeTicks; /// @@ -477,13 +476,6 @@ private class ResolvedFile { } internal object CompileAndRun(Scope globalScope, ScriptCode/*!*/ code, bool tryEvaluate) { - long ts1 = Stopwatch.GetTimestamp(); - if (code is LegacyScriptCode) { - ((LegacyScriptCode)code).EnsureCompiled(); - } - long ts2 = Stopwatch.GetTimestamp(); - Interlocked.Add(ref _ILGenerationTimeTicks, ts2 - ts1); - return globalScope != null ? code.Run(globalScope) : code.Run(); } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyContext.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyContext.cs index 5cde67e228..bdd9c6fd17 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyContext.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyContext.cs @@ -48,9 +48,9 @@ public sealed class RubyContext : LanguageContext { public static readonly string/*!*/ MriReleaseDate = "2008-05-28"; // IronRuby: - public const string/*!*/ IronRubyVersionString = "1.0.0.0"; - public static readonly Version IronRubyVersion = new Version(1, 0, 0, 0); - internal const string/*!*/ IronRubyDisplayName = "IronRuby 1.0 Alpha"; + public const string/*!*/ IronRubyVersionString = "0.3.0.0"; + public static readonly Version IronRubyVersion = new Version(0, 3, 0, 0); + internal const string/*!*/ IronRubyDisplayName = "IronRuby 0.3"; internal const string/*!*/ IronRubyNames = "IronRuby;Ruby;rb"; internal const string/*!*/ IronRubyFileExtensions = ".rb"; @@ -1568,7 +1568,7 @@ public RubyContext(ScriptDomainManager/*!*/ manager, IDictionary } #endif - Expression lambda = ParseSourceCode(sourceUnit, (RubyCompilerOptions)options, errorSink); + var lambda = ParseSourceCode>(sourceUnit, (RubyCompilerOptions)options, errorSink); if (lambda == null) { return null; } @@ -1576,7 +1576,7 @@ public RubyContext(ScriptDomainManager/*!*/ manager, IDictionary if (Options.InterpretedMode) { return new InterpretedScriptCode(lambda, sourceUnit); } else { - return new LegacyScriptCode(lambda, sourceUnit); + return new RubyScriptCode(lambda, sourceUnit); } } @@ -1662,6 +1662,12 @@ public RubyContext(ScriptDomainManager/*!*/ manager, IDictionary return _runtimeErrorSink; } + protected override ScriptCode/*!*/ LoadCompiledCode(Delegate/*!*/ method, string path) { + // TODO: + SourceUnit su = new SourceUnit(this, NullTextContentProvider.Null, path, SourceCodeKind.File); + return new RubyScriptCode((Func)method, su); + } + public void CheckConstantName(string name) { if (!Tokenizer.IsConstantName(name, _options.Compatibility >= RubyCompatibility.Ruby19 || KCode != null)) { throw RubyExceptions.CreateNameError(String.Format("`{0}' is not allowed as a constant name", name)); @@ -1818,14 +1824,14 @@ public RubyContext(ScriptDomainManager/*!*/ manager, IDictionary parse: {1} ast transform: {2} script code: {3} - il: {4} + il: {4} (TODO) binding: {5} ({6} calls) ", _upTime.Elapsed, new TimeSpan(_ParseTimeTicks), new TimeSpan(_AstGenerationTimeTicks), new TimeSpan(Loader._ScriptCodeGenerationTimeTicks), - new TimeSpan(Loader._ILGenerationTimeTicks), + new TimeSpan(), // TODO: new TimeSpan(Loader._ILGenerationTimeTicks), #if MEASURE new TimeSpan(MetaAction.BindingTimeTicks), MetaAction.BindCallCount diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyExceptionData.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyExceptionData.cs index 045da682c8..65f63d0ade 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyExceptionData.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyExceptionData.cs @@ -227,13 +227,27 @@ public class RubyExceptionData { methodName = method.Name; fileName = (hasFileAccessPermission) ? frame.GetFileName() : null; - line = frame.GetFileLineNumber(); + var sourceLine = line = frame.GetFileLineNumber(); if (TryParseRubyMethodName(ref methodName, ref fileName, ref line)) { // Ruby method: if (methodName == TopLevelMethodName) { methodName = null; } + + if (sourceLine == 0) { + RubyMethodDebugInfo debugInfo; + if (RubyMethodDebugInfo.TryGet(method, out debugInfo)) { + var ilOffset = frame.GetILOffset(); + if (ilOffset >= 0) { + var mappedLine = debugInfo.Map(ilOffset); + if (mappedLine != 0) { + line = mappedLine; + } + } + } + } + return true; } else if (method.IsDefined(typeof(RubyStackTraceHiddenAttribute), false)) { return false; diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyMethodDebugInfo.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyMethodDebugInfo.cs new file mode 100644 index 0000000000..5f517f0a87 --- /dev/null +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyMethodDebugInfo.cs @@ -0,0 +1,65 @@ +/* **************************************************************************** + * + * 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 + * ironruby@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.Text; +using System.Reflection; + +namespace IronRuby.Runtime { + internal sealed class RubyMethodDebugInfo { + private static readonly Dictionary _Infos = new Dictionary(); + + private readonly List/*!*/ _offsets = new List(); + private readonly List/*!*/ _lines = new List(); + + public static bool TryGet(MethodBase/*!*/ method, out RubyMethodDebugInfo info) { + lock (_Infos) { + return _Infos.TryGetValue(method.Name, out info); + } + } + + public static RubyMethodDebugInfo GetOrCreate(string/*!*/ methodName) { + lock (_Infos) { + RubyMethodDebugInfo info; + if (!_Infos.TryGetValue(methodName, out info)) { + info = new RubyMethodDebugInfo(); + _Infos.Add(methodName, info); + } + return info; + } + } + + public void AddMapping(int ilOffset, int line) { + _offsets.Add(ilOffset); + _lines.Add(line); + } + + public int Map(int ilOffset) { + int index =_offsets.BinarySearch(ilOffset); + if (index >= 0) { + return _lines[index]; + } + index = ~index; + if (index > 0) { + return _lines[index - 1]; + } + if (_lines.Count > 0) { + return _lines[0]; + } + return 0; + } + } +} diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyScriptCode.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyScriptCode.cs new file mode 100644 index 0000000000..244d023283 --- /dev/null +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyScriptCode.cs @@ -0,0 +1,94 @@ +/* **************************************************************************** + * + * 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 + * ironruby@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 ScriptCodeFunc = System.Func; + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Scripting; +using System.Linq.Expressions; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Generation; +using System.Threading; +using System.Linq.Expressions.Compiler; +using System.Reflection; +using Microsoft.Scripting.Utils; +using System.Runtime.CompilerServices; +using System.Security; + +namespace IronRuby.Runtime { + internal sealed class RubyScriptCode : ScriptCode { + private sealed class CustomGenerator : DebugInfoGenerator { + public override void MarkSequencePoint(LambdaExpression method, int ilOffset, DebugInfoExpression node) { + RubyMethodDebugInfo.GetOrCreate(method.Name).AddMapping(ilOffset, node.StartLine); + } + } + + private readonly Expression _code; + private ScriptCodeFunc _target; + + public RubyScriptCode(Expression/*!*/ code, SourceUnit/*!*/ sourceUnit) + : base(sourceUnit) { + Assert.NotNull(code); + _code = code; + } + + internal RubyScriptCode(ScriptCodeFunc/*!*/ target, SourceUnit/*!*/ sourceUnit) + : base(sourceUnit) { + Assert.NotNull(target); + _target = target; + } + + private ScriptCodeFunc/*!*/ Target { + get { + if (_target == null) { + var compiledMethod = CompileLambda(_code, SourceUnit.LanguageContext.DomainManager.Configuration.DebugMode); + Interlocked.CompareExchange(ref _target, compiledMethod, null); + } + return _target; + } + } + + public override object Run() { + return Target(CreateScope(), SourceUnit.LanguageContext); + } + + public override object Run(Scope/*!*/ scope) { + return Target(scope, SourceUnit.LanguageContext); + } + + private static bool _HasPdbPermissions = true; + + internal static T/*!*/ CompileLambda(Expression/*!*/ lambda, bool debugMode) { + if (debugMode) { +#if !SILVERLIGHT + // try to use PDBs and fallback to CustomGenerator if not allowed to: + if (_HasPdbPermissions) { + try { + return CompilerHelpers.CompileToMethod(lambda, DebugInfoGenerator.CreatePdbGenerator(), true); + } catch (SecurityException) { + // do not attempt next time in this app-domain: + _HasPdbPermissions = false; + } + } +#endif + return CompilerHelpers.CompileToMethod(lambda, new CustomGenerator(), false); + } else { + return lambda.Compile(); + } + } + } +} diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyUtils.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyUtils.cs index c0f7185c3e..0b6134e5d8 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyUtils.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyUtils.cs @@ -710,7 +710,7 @@ private class RecursionHandle : IDisposable { targetScope.RuntimeFlowControl ); } else { - return lambda.Compile(source.EmitDebugSymbols)( + return RubyScriptCode.CompileLambda(lambda, context.DomainManager.Configuration.DebugMode)( targetScope, self, module, diff --git a/Merlin/Main/Languages/Ruby/Utils/IronRuby.Libraries.Scanner/Program.cs b/Merlin/Main/Languages/Ruby/Utils/IronRuby.Libraries.Scanner/Program.cs index 0089629ff1..7a56c61145 100644 --- a/Merlin/Main/Languages/Ruby/Utils/IronRuby.Libraries.Scanner/Program.cs +++ b/Merlin/Main/Languages/Ruby/Utils/IronRuby.Libraries.Scanner/Program.cs @@ -167,9 +167,9 @@ where t.IsDefined(typeof(RubyModuleAttribute), false) } #if SIGNED - const string RubyAssembly = @"IronRuby.Libraries, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; + const string RubyAssembly = @"IronRuby.Libraries, Version=0.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; #else - const string RubyAssembly = @"IronRuby.Libraries, Version=1.0.0.0, Culture=neutral"; + const string RubyAssembly = @"IronRuby.Libraries, Version=0.3.0.0, Culture=neutral"; #endif internal static Dictionary ExtensionModules; diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Generation/CompilerHelpers.cs b/Merlin/Main/Runtime/Microsoft.Scripting/Generation/CompilerHelpers.cs index 8661baeab7..0d73bb9134 100644 --- a/Merlin/Main/Runtime/Microsoft.Scripting/Generation/CompilerHelpers.cs +++ b/Merlin/Main/Runtime/Microsoft.Scripting/Generation/CompilerHelpers.cs @@ -25,6 +25,7 @@ using Microsoft.Scripting.Runtime; using Microsoft.Scripting.Utils; using Microsoft.Scripting.Interpreter; +using System.Linq.Expressions.Compiler; using AstUtils = Microsoft.Scripting.Ast.Utils; namespace Microsoft.Scripting.Generation { @@ -692,6 +693,22 @@ public static class CompilerHelpers { return (T)(object)LightCompile((LambdaExpression)lambda); } + /// + /// Compiles the lambda into a method definition. + /// + /// the lambda to compile + /// A which will be used to hold the lambda's IL. + /// A parameter that indicates if debugging information should be emitted to a PDB symbol store. + public static void CompileToMethod(this LambdaExpression lambda, MethodBuilder method, bool emitDebugSymbols) { + if (emitDebugSymbols) { + var module = method.Module as ModuleBuilder; + ContractUtils.Requires(module != null, "method", "MethodBuilder does not have a valid ModuleBuilder"); + lambda.CompileToMethod(method, DebugInfoGenerator.CreatePdbGenerator()); + } else { + lambda.CompileToMethod(method); + } + } + /// /// Compiles the LambdaExpression. /// @@ -706,7 +723,7 @@ public static class CompilerHelpers { /// true to generate a debuggable method, false otherwise /// the compiled delegate public static T Compile(this Expression lambda, bool emitDebugSymbols) { - return emitDebugSymbols ? CompileToMethod(lambda, true) : lambda.Compile(); + return emitDebugSymbols ? CompileToMethod(lambda, DebugInfoGenerator.CreatePdbGenerator(), true) : lambda.Compile(); } /// @@ -717,10 +734,11 @@ public static class CompilerHelpers { /// have debugging information. /// /// the lambda to compile - /// true to generate a debuggable method, false otherwise + /// Debugging information generator used by the compiler to mark sequence points and annotate local variables. + /// True if debug symbols (PDBs) are emitted by the . /// the compiled delegate [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] - public static T CompileToMethod(Expression lambda, bool emitDebugSymbols) { + public static T CompileToMethod(Expression lambda, DebugInfoGenerator debugInfoGenerator, bool emitDebugSymbols) { var type = Snippets.Shared.DefineType(lambda.Name, typeof(object), false, emitDebugSymbols).TypeBuilder; var rewriter = new BoundConstantsRewriter(type); lambda = (Expression)rewriter.Visit(lambda); @@ -728,7 +746,7 @@ public static class CompilerHelpers { //Create a unique method name when the lambda doesn't have a name or the name is empty. string methodName = String.IsNullOrEmpty(lambda.Name) ? GetUniqueMethodName() : lambda.Name; var method = type.DefineMethod(methodName, CompilerHelpers.PublicStatic); - lambda.CompileToMethod(method, emitDebugSymbols); + lambda.CompileToMethod(method, debugInfoGenerator); var finished = type.CreateType(); diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Runtime/LanguageContext.cs b/Merlin/Main/Runtime/Microsoft.Scripting/Runtime/LanguageContext.cs index 3ce2e3cbc1..c0f092c067 100644 --- a/Merlin/Main/Runtime/Microsoft.Scripting/Runtime/LanguageContext.cs +++ b/Merlin/Main/Runtime/Microsoft.Scripting/Runtime/LanguageContext.cs @@ -147,7 +147,7 @@ public abstract class LanguageContext { internal protected abstract ScriptCode CompileSourceCode(SourceUnit sourceUnit, CompilerOptions options, ErrorSink errorSink); internal protected virtual ScriptCode LoadCompiledCode(Delegate method, string path) { - return LegacyScriptCode.Load((DlrMainCallTarget)method, this, path); + throw new NotSupportedException(); } #endregion diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Ast/LambdaExpression.cs b/ndp/fx/src/Core/Microsoft/Scripting/Ast/LambdaExpression.cs index 1b669dd162..5dd9ba6096 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Ast/LambdaExpression.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Ast/LambdaExpression.cs @@ -21,6 +21,7 @@ using System.Reflection; using System.Reflection.Emit; using System.Threading; +using System.Runtime.CompilerServices; namespace System.Linq.Expressions { /// @@ -115,27 +116,44 @@ ReadOnlyCollection parameters /// /// A delegate containing the compiled version of the lambda. public Delegate Compile() { - return LambdaCompiler.Compile(this); + return LambdaCompiler.Compile(this, null); + } + + /// + /// Produces a delegate that represents the lambda expression. + /// + /// Debugging information generator used by the compiler to mark sequence points and annotate local variables. + /// A delegate containing the compiled version of the lambda. + public Delegate Compile(DebugInfoGenerator debugInfoGenerator) { + ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator"); + return LambdaCompiler.Compile(this, debugInfoGenerator); } /// /// Compiles the lambda into a method definition. /// /// A which will be used to hold the lambda's IL. - /// A parameter that indicates if debugging information should be emitted. - public void CompileToMethod(MethodBuilder method, bool emitDebugSymbols) { + public void CompileToMethod(MethodBuilder method) { + CompileToMethodInternal(method, null); + } + + /// + /// Compiles the lambda into a method definition and custom debug information. + /// + /// A which will be used to hold the lambda's IL. + /// Debugging information generator used by the compiler to mark sequence points and annotate local variables. + public void CompileToMethod(MethodBuilder method, DebugInfoGenerator debugInfoGenerator) { + ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator"); + CompileToMethodInternal(method, debugInfoGenerator); + } + + private void CompileToMethodInternal(MethodBuilder method, DebugInfoGenerator debugInfoGenerator) { ContractUtils.RequiresNotNull(method, "method"); ContractUtils.Requires(method.IsStatic, "method"); - var type = method.DeclaringType as TypeBuilder; ContractUtils.Requires(type != null, "method", Strings.MethodBuilderDoesNotHaveTypeBuilder); - - if (emitDebugSymbols) { - var module = method.Module as ModuleBuilder; - ContractUtils.Requires(module != null, "method", Strings.MethodBuilderDoesNotHaveModuleBuilder); - } - LambdaCompiler.Compile(this, method, emitDebugSymbols); + LambdaCompiler.Compile(this, method, debugInfoGenerator); } internal abstract LambdaExpression Accept(StackSpiller spiller); @@ -159,7 +177,17 @@ internal Expression(Expression body, string name, bool tailCall, ReadOnlyCollect /// /// A delegate containing the compiled version of the lambda. public new TDelegate Compile() { - return (TDelegate)(object)LambdaCompiler.Compile(this); + return (TDelegate)(object)LambdaCompiler.Compile(this, null); + } + + /// + /// Produces a delegate that represents the lambda expression. + /// + /// Debugging information generator used by the compiler to mark sequence points and annotate local variables. + /// A delegate containing the compiled version of the lambda. + public new TDelegate Compile(DebugInfoGenerator debugInfoGenerator) { + ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator"); + return (TDelegate)(object)LambdaCompiler.Compile(this, debugInfoGenerator); } internal override Expression Accept(ExpressionVisitor visitor) { diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/AnalyzedTree.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/AnalyzedTree.cs index e95b1749e5..5d6dc8031d 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/AnalyzedTree.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/AnalyzedTree.cs @@ -17,22 +17,14 @@ using System.Collections.Generic; using System.Diagnostics.SymbolStore; using System.Dynamic.Utils; +using System.Runtime.CompilerServices; namespace System.Linq.Expressions.Compiler { internal sealed class AnalyzedTree { internal readonly Dictionary Scopes = new Dictionary(); internal readonly Dictionary Constants = new Dictionary(); - // Lazy initialized because many trees will not need it - private Dictionary _symbolWriters; - internal Dictionary SymbolWriters { - get { - if (_symbolWriters == null) { - _symbolWriters = new Dictionary(); - } - return _symbolWriters; - } - } + internal DebugInfoGenerator DebugInfoGenerator { get; set; } // Created by VariableBinder internal AnalyzedTree() { diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/CompilerScope.Storage.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/CompilerScope.Storage.cs index 7b2b18c3c5..8d67bfc75d 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/CompilerScope.Storage.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/CompilerScope.Storage.cs @@ -46,13 +46,13 @@ private abstract class Storage { private sealed class LocalStorage : Storage { private readonly LocalBuilder _local; - internal LocalStorage(LambdaCompiler compiler, ParameterExpression v) - : base(compiler, v) { + internal LocalStorage(LambdaCompiler compiler, ParameterExpression variable) + : base(compiler, variable) { // ByRef variables are supported. This is used internally by // the compiler when emitting an inlined lambda invoke, to // handle ByRef parameters. BlockExpression prevents this // from being exposed to user created trees. - _local = compiler.GetNamedLocal(v.IsByRef ? v.Type.MakeByRefType() : v.Type, v.Name); + _local = compiler.GetNamedLocal(variable.IsByRef ? variable.Type.MakeByRefType() : variable.Type, variable); } internal override void EmitLoad() { @@ -145,7 +145,7 @@ internal LocalBoxStorage(LambdaCompiler compiler, ParameterExpression variable) : base(compiler, variable) { _boxType = typeof(StrongBox<>).MakeGenericType(variable.Type); _boxValueField = _boxType.GetField("Value"); - _boxLocal = compiler.GetNamedLocal(_boxType, variable.Name); + _boxLocal = compiler.GetNamedLocal(_boxType, variable); } internal override void EmitLoad() { diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/DebugInfoGenerator.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/DebugInfoGenerator.cs new file mode 100644 index 0000000000..96b3df8f05 --- /dev/null +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/DebugInfoGenerator.cs @@ -0,0 +1,56 @@ +/* **************************************************************************** + * + * 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 ILGenerator = System.Linq.Expressions.Compiler.OffsetTrackingILGenerator; + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection.Emit; +using System.Diagnostics; +using System.Diagnostics.SymbolStore; +using System.Reflection; +using System.Linq.Expressions; + +namespace System.Runtime.CompilerServices { + /// + /// Generates debug information for lambdas in an expression tree. + /// + public abstract class DebugInfoGenerator { + /// + /// Creates PDB symbol generator. + /// + /// PDB symbol generator. + public static DebugInfoGenerator CreatePdbGenerator() { + return new SymbolDocumentGenerator(); + } + + /// + /// Marks a sequence point. + /// + /// The lambda being generated. + /// IL offset where to mark the sequence point. + /// Debug informaton corresponding to the sequence point. + public abstract void MarkSequencePoint(LambdaExpression method, int ilOffset, DebugInfoExpression sequencePoint); + + internal virtual void MarkSequencePoint(LambdaExpression method, MethodBase methodBase, ILGenerator ilg, DebugInfoExpression sequencePoint) { + MarkSequencePoint(method, ilg.CurrentOffset, sequencePoint); + } + + internal virtual void SetLocalName(LocalBuilder localBuilder, string name) { + // nop + } + } +} diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/ILGen.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/ILGen.cs index aff1eccbdb..c726c477b7 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/ILGen.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/ILGen.cs @@ -13,6 +13,8 @@ * * ***************************************************************************/ +using ILGenerator = System.Linq.Expressions.Compiler.OffsetTrackingILGenerator; + using System.Collections.Generic; using System.Diagnostics; using System.Dynamic.Utils; diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LabelInfo.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LabelInfo.cs index 5e545637ec..6b5889df1d 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LabelInfo.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LabelInfo.cs @@ -13,6 +13,8 @@ * * ***************************************************************************/ +using ILGenerator = System.Linq.Expressions.Compiler.OffsetTrackingILGenerator; + using System.Collections.Generic; using System.Diagnostics; using System.Dynamic.Utils; diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Expressions.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Expressions.cs index 5c4bb8a7d6..2dc394cf3f 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Expressions.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Expressions.cs @@ -724,36 +724,22 @@ internal enum CompilationFlags { } private void EmitDebugInfoExpression(Expression expr) { - if (!_emitDebugSymbols) { + if (!EmitDebugSymbols) { return; } var node = (DebugInfoExpression)expr; - var symbolWriter = GetSymbolWriter(node.Document); - if (node.IsClear && _sequencePointCleared) { // Emitting another clearance after one clearance does not // have any effect, so we can save it. return; } - _ilg.MarkSequencePoint(symbolWriter, node.StartLine, node.StartColumn, node.EndLine, node.EndColumn); + + _tree.DebugInfoGenerator.MarkSequencePoint(_lambda, _method, _ilg, node); _ilg.Emit(OpCodes.Nop); _sequencePointCleared = node.IsClear; } - private ISymbolDocumentWriter GetSymbolWriter(SymbolDocumentInfo document) { - Debug.Assert(_emitDebugSymbols); - - ISymbolDocumentWriter result; - if (!_tree.SymbolWriters.TryGetValue(document, out result)) { - var module = (ModuleBuilder)_typeBuilder.Module; - result = module.DefineDocument(document.FileName, document.Language, document.LanguageVendor, SymbolGuids.DocumentType_Text); - _tree.SymbolWriters.Add(document, result); - } - - return result; - } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "expr")] private static void EmitExtensionExpression(Expression expr) { throw Error.ExtensionNotReduced(); diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Lambda.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Lambda.cs index 0da02ed007..26de64a7f7 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Lambda.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Lambda.cs @@ -113,7 +113,7 @@ partial class LambdaCompiler { // When the lambda does not have a name or the name is empty, generate a unique name for it. string name = String.IsNullOrEmpty(lambda.Name) ? GetUniqueMethodName() : lambda.Name; MethodBuilder mb = _typeBuilder.DefineMethod(name, MethodAttributes.Private | MethodAttributes.Static); - impl = new LambdaCompiler(_tree, lambda, mb, _emitDebugSymbols); + impl = new LambdaCompiler(_tree, lambda, mb); } // 2. emit the lambda diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Statements.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Statements.cs index 88537df04d..0a3ea63652 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Statements.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Statements.cs @@ -40,7 +40,7 @@ partial class LambdaCompiler { var e = node.GetExpression(index); var next = node.GetExpression(index + 1); - if (_emitDebugSymbols) { + if (EmitDebugSymbols) { // No need to emit a clearance if the next expression in the block is also a // DebugInfoExprssion. var debugInfo = e as DebugInfoExpression; diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.cs index 82724b99f0..693937dcc3 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.cs @@ -13,6 +13,8 @@ * * ***************************************************************************/ +using ILGenerator = System.Linq.Expressions.Compiler.OffsetTrackingILGenerator; + using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -59,7 +61,7 @@ internal sealed partial class LambdaCompiler { private readonly bool _hasClosureArgument; // True if we want to emitting debug symbols - private readonly bool _emitDebugSymbols; + private bool EmitDebugSymbols { get { return _tree.DebugInfoGenerator != null; } } // Runtime constants bound to the delegate private readonly BoundConstants _boundConstants; @@ -88,7 +90,9 @@ internal sealed partial class LambdaCompiler { _tree = tree; _lambda = lambda; _method = method; - _ilg = method.GetILGenerator(); + + _ilg = new OffsetTrackingILGenerator(method.GetILGenerator()); + _hasClosureArgument = true; // These are populated by AnalyzeTree/VariableBinder @@ -101,7 +105,7 @@ internal sealed partial class LambdaCompiler { /// /// Creates a lambda compiler that will compile into the provided Methodbuilder /// - private LambdaCompiler(AnalyzedTree tree, LambdaExpression lambda, MethodBuilder method, bool emitDebugSymbols) { + private LambdaCompiler(AnalyzedTree tree, LambdaExpression lambda, MethodBuilder method) { _hasClosureArgument = tree.Scopes[lambda].NeedsClosure; Type[] paramTypes = GetParameterTypes(lambda); if (_hasClosureArgument) { @@ -121,8 +125,8 @@ internal sealed partial class LambdaCompiler { _lambda = lambda; _typeBuilder = (TypeBuilder)method.DeclaringType; _method = method; - _ilg = method.GetILGenerator(); - _emitDebugSymbols = emitDebugSymbols; + + _ilg = new OffsetTrackingILGenerator(method.GetILGenerator()); // These are populated by AnalyzeTree/VariableBinder _scope = tree.Scopes[lambda]; @@ -141,7 +145,6 @@ internal sealed partial class LambdaCompiler { _ilg = parent._ilg; _hasClosureArgument = parent._hasClosureArgument; _typeBuilder = parent._typeBuilder; - _emitDebugSymbols = parent._emitDebugSymbols; _scope = _tree.Scopes[lambda]; _boundConstants = parent._boundConstants; } @@ -170,11 +173,14 @@ internal sealed partial class LambdaCompiler { /// Compiler entry point /// /// LambdaExpression to compile. + /// Debug info generator. /// The compiled delegate. - internal static Delegate Compile(LambdaExpression lambda) { + internal static Delegate Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator) { // 1. Bind lambda AnalyzedTree tree = AnalyzeLambda(ref lambda); + tree.DebugInfoGenerator = debugInfoGenerator; + // 2. Create lambda compiler LambdaCompiler c = new LambdaCompiler(tree, lambda); @@ -191,12 +197,14 @@ internal sealed partial class LambdaCompiler { /// /// (probably shouldn't be modifying parameters/return type...) /// - internal static void Compile(LambdaExpression lambda, MethodBuilder method, bool emitDebugSymbols) { + internal static void Compile(LambdaExpression lambda, MethodBuilder method, DebugInfoGenerator debugInfoGenerator) { // 1. Bind lambda AnalyzedTree tree = AnalyzeLambda(ref lambda); + tree.DebugInfoGenerator = debugInfoGenerator; + // 2. Create lambda compiler - LambdaCompiler c = new LambdaCompiler(tree, lambda, method, emitDebugSymbols); + LambdaCompiler c = new LambdaCompiler(tree, lambda, method); // 3. Emit c.EmitLambdaBody(); @@ -231,12 +239,12 @@ internal sealed partial class LambdaCompiler { } } - internal LocalBuilder GetNamedLocal(Type type, string name) { - Debug.Assert(type != null); + internal LocalBuilder GetNamedLocal(Type type, ParameterExpression variable) { + Debug.Assert(type != null && variable != null); LocalBuilder lb = _ilg.DeclareLocal(type); - if (_emitDebugSymbols && name != null) { - lb.SetLocalSymInfo(name); + if (EmitDebugSymbols && variable.Name != null) { + _tree.DebugInfoGenerator.SetLocalName(lb, variable.Name); } return lb; } diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/OffsetTrackingILGenerator.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/OffsetTrackingILGenerator.cs new file mode 100644 index 0000000000..fe47564ccc --- /dev/null +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/OffsetTrackingILGenerator.cs @@ -0,0 +1,357 @@ +/* **************************************************************************** + * + * 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.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Reflection.Emit; +using System.Diagnostics.SymbolStore; + +namespace System.Linq.Expressions.Compiler { + /// + /// Wraps ILGenerator with code that tracks the current IL offset as instructions are emitted into the IL stream. + /// We can conditionally compile this for non-Dev10 release only (using #ifdef MICROSOFT_SCRIPTING) + /// as soon as Dev10 feature request (http://vstfdevdiv:8080/WorkItemTracking/WorkItem.aspx?artifactMoniker=599427) gets implemented. + /// + internal sealed class OffsetTrackingILGenerator { + private readonly ILGenerator _ilg; + internal int _offset; + + internal int CurrentOffset { get { return _offset; } } + + internal OffsetTrackingILGenerator(ILGenerator ilg) { + Debug.Assert(ilg != null); + _ilg = ilg; + } + + private void AdvanceOffset(OpCode opcode) { + _offset += opcode.Size; + } + + private void AdvanceOffsetWithLabel(OpCode opcode) { + AdvanceOffset(opcode); + if (OpCodes.TakesSingleByteArgument(opcode)) { + _offset++; + } else { + _offset += 4; + } + } + + #region Simple Instructions + + internal void Emit(OpCode opcode) { + _ilg.Emit(opcode); + AdvanceOffset(opcode); + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, byte arg) { + _ilg.Emit(opcode, arg); + AdvanceOffset(opcode); + _offset++; + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, sbyte arg) { + _ilg.Emit(opcode, arg); + AdvanceOffset(opcode); + _offset++; + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, int arg) { + _ilg.Emit(opcode, arg); + AdvanceOffset(opcode); + _offset += 4; + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, MethodInfo meth) { + _ilg.Emit(opcode, meth); + AdvanceOffset(opcode); + _offset += 4; + AssertOffsetMatches(); + } + + internal void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes) { + _ilg.EmitCall(opcode, methodInfo, optionalParameterTypes); + AdvanceOffset(opcode); + _offset += 4; + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, ConstructorInfo con) { + _ilg.Emit(opcode, con); + AdvanceOffset(opcode); + _offset += 4; + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, Type cls) { + _ilg.Emit(opcode, cls); + AdvanceOffset(opcode); + _offset += 4; + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, long arg) { + _ilg.Emit(opcode, arg); + AdvanceOffset(opcode); + _offset += 8; + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, float arg) { + _ilg.Emit(opcode, arg); + AdvanceOffset(opcode); + _offset += 4; + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, double arg) { + _ilg.Emit(opcode, arg); + AdvanceOffset(opcode); + _offset += 8; + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, Label label) { + _ilg.Emit(opcode, label); + AdvanceOffsetWithLabel(opcode); + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, Label[] labels) { + _ilg.Emit(opcode, labels); + AdvanceOffset(opcode); + _offset += 4; + for (int remaining = labels.Length * 4, i = 0; remaining > 0; remaining -= 4, i++) { + _offset += 4; + } + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, FieldInfo field) { + _ilg.Emit(opcode, field); + AdvanceOffset(opcode); + _offset += 4; + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, String str) { + _ilg.Emit(opcode, str); + AdvanceOffset(opcode); + _offset += 4; + AssertOffsetMatches(); + } + + internal void Emit(OpCode opcode, LocalBuilder local) { + _ilg.Emit(opcode, local); + int tempVal = local.LocalIndex; + if (opcode.Equals(OpCodes.Ldloc)) { + switch (tempVal) { + case 0: + opcode = OpCodes.Ldloc_0; + break; + case 1: + opcode = OpCodes.Ldloc_1; + break; + case 2: + opcode = OpCodes.Ldloc_2; + break; + case 3: + opcode = OpCodes.Ldloc_3; + break; + default: + if (tempVal <= 255) + opcode = OpCodes.Ldloc_S; + break; + } + } else if (opcode.Equals(OpCodes.Stloc)) { + switch (tempVal) { + case 0: + opcode = OpCodes.Stloc_0; + break; + case 1: + opcode = OpCodes.Stloc_1; + break; + case 2: + opcode = OpCodes.Stloc_2; + break; + case 3: + opcode = OpCodes.Stloc_3; + break; + default: + if (tempVal <= 255) + opcode = OpCodes.Stloc_S; + break; + } + } else if (opcode.Equals(OpCodes.Ldloca)) { + if (tempVal <= 255) + opcode = OpCodes.Ldloca_S; + } + + AdvanceOffset(opcode); + + if (opcode.OperandType == OperandType.InlineNone) + return; + else if (!OpCodes.TakesSingleByteArgument(opcode)) { + _offset += 2; + } else { + _offset++; + } + AssertOffsetMatches(); + } + + #endregion + + #region Exception Handling + + private enum ExceptionState { + Try = 0, + Filter = 1, + Catch = 2, + Finally = 3, + Fault = 4, + } + + private Stack _exceptionState = new Stack(); + + internal void BeginExceptionBlock() { + _ilg.BeginExceptionBlock(); + _exceptionState.Push(ExceptionState.Try); + AssertOffsetMatches(); + } + + internal void EndExceptionBlock() { + _ilg.EndExceptionBlock(); + + ExceptionState state = _exceptionState.Pop(); + if (state == ExceptionState.Catch) { + AdvanceOffsetWithLabel(OpCodes.Leave); + } else if (state == ExceptionState.Finally || state == ExceptionState.Fault) { + AdvanceOffset(OpCodes.Endfinally); + } + + AssertOffsetMatches(); + } + + internal void BeginExceptFilterBlock() { + _ilg.BeginExceptFilterBlock(); + + _exceptionState.Pop(); + _exceptionState.Push(ExceptionState.Filter); + + AssertOffsetMatches(); + } + + internal void BeginCatchBlock(Type exceptionType) { + _ilg.BeginCatchBlock(exceptionType); + + ExceptionState state = _exceptionState.Pop(); + if (state == ExceptionState.Filter) { + AdvanceOffset(OpCodes.Endfilter); + } else { + AdvanceOffsetWithLabel(OpCodes.Leave); + } + + _exceptionState.Push(ExceptionState.Catch); + + AssertOffsetMatches(); + } + + internal void BeginFaultBlock() { + _ilg.BeginFaultBlock(); + + AdvanceOffsetWithLabel(OpCodes.Leave); + _exceptionState.Pop(); + _exceptionState.Push(ExceptionState.Fault); + + AssertOffsetMatches(); + } + + internal void BeginFinallyBlock() { + _ilg.BeginFinallyBlock(); + + ExceptionState state = _exceptionState.Pop(); + if (state != ExceptionState.Try) { + // leave for any preceeding catch clause + AdvanceOffsetWithLabel(OpCodes.Leave); + } + + // leave for try clause + AdvanceOffsetWithLabel(OpCodes.Leave); + _exceptionState.Push(ExceptionState.Finally); + + AssertOffsetMatches(); + } + + #endregion + + #region Labels and Locals + + internal Label DefineLabel() { + return _ilg.DefineLabel(); + } + + internal void MarkLabel(Label loc) { + _ilg.MarkLabel(loc); + } + + internal LocalBuilder DeclareLocal(Type localType) { + return _ilg.DeclareLocal(localType); + } + + internal void MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn) { + _ilg.MarkSequencePoint(document, startLine, startColumn, endLine, endColumn); + } + + #endregion + + #region Assertions + +#if STRESS_DEBUG + private FieldInfo _ilgOffsetField; + private bool _checkOffset = true; +#endif + + [Conditional("STRESS_DEBUG")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] + private void AssertOffsetMatches() { +#if STRESS_DEBUG + if (!_checkOffset) { + return; + } + + int m_length = -1; + try { + if (_ilgOffsetField == null) { + _ilgOffsetField = typeof(ILGenerator).GetField("m_length", BindingFlags.NonPublic | BindingFlags.Instance); + } + m_length = (int)_ilgOffsetField.GetValue(_ilg); + } catch (Exception) { + _checkOffset = false; + } + + if (_checkOffset) { + Debug.Assert(m_length == _offset); + } +#endif + } + + #endregion + } + +} diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/SymbolDocumentGenerator.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/SymbolDocumentGenerator.cs new file mode 100644 index 0000000000..004f2ced0b --- /dev/null +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/SymbolDocumentGenerator.cs @@ -0,0 +1,61 @@ +/* **************************************************************************** + * + * 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.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.SymbolStore; +using System.Linq.Expressions; +using System.Linq.Expressions.Compiler; +using System.Reflection; +using System.Reflection.Emit; +using ILGenerator = System.Linq.Expressions.Compiler.OffsetTrackingILGenerator; + +namespace System.Runtime.CompilerServices { + /// + /// Generator of PDB debugging information for expression trees. + /// + internal sealed class SymbolDocumentGenerator : DebugInfoGenerator { + private Dictionary _symbolWriters; + + private ISymbolDocumentWriter GetSymbolWriter(MethodBuilder method, SymbolDocumentInfo document) { + ISymbolDocumentWriter result; + if (_symbolWriters == null) { + _symbolWriters = new Dictionary(); + } + + if (!_symbolWriters.TryGetValue(document, out result)) { + result = ((ModuleBuilder)method.Module).DefineDocument(document.FileName, document.Language, document.LanguageVendor, SymbolGuids.DocumentType_Text); + _symbolWriters.Add(document, result); + } + + return result; + } + + internal override void MarkSequencePoint(LambdaExpression method, MethodBase methodBase, ILGenerator ilg, DebugInfoExpression sequencePoint) { + MethodBuilder builder = methodBase as MethodBuilder; + if (builder != null) { + ilg.MarkSequencePoint(GetSymbolWriter(builder, sequencePoint.Document), sequencePoint.StartLine, sequencePoint.StartColumn, sequencePoint.EndLine, sequencePoint.EndColumn); + } + } + + public override void MarkSequencePoint(LambdaExpression method, int ilOffset, DebugInfoExpression sequencePoint) { + Debug.Assert(false); + } + + internal override void SetLocalName(LocalBuilder localBuilder, string name) { + localBuilder.SetLocalSymInfo(name); + } + } +} diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Microsoft.Scripting.Core.csproj b/ndp/fx/src/Core/Microsoft/Scripting/Microsoft.Scripting.Core.csproj index e6dfe9ec81..cd2b37cd4e 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Microsoft.Scripting.Core.csproj +++ b/ndp/fx/src/Core/Microsoft/Scripting/Microsoft.Scripting.Core.csproj @@ -149,6 +149,7 @@ + @@ -206,11 +207,13 @@ + + diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Utils/ExceptionFactory.Generated.cs b/ndp/fx/src/Core/Microsoft/Scripting/Utils/ExceptionFactory.Generated.cs index 5e3e0b15e7..8e137f05c9 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Utils/ExceptionFactory.Generated.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Utils/ExceptionFactory.Generated.cs @@ -319,15 +319,6 @@ internal static partial class Strings { } } - /// - /// A string like "MethodBuilder does not have a valid ModuleBuilder" - /// - internal static string MethodBuilderDoesNotHaveModuleBuilder { - get { - return "MethodBuilder does not have a valid ModuleBuilder"; - } - } - /// /// A string like "MethodBuilder does not have a valid TypeBuilder" /// From 41219b1128f61bd146b28dd80b9088732b867596 Mon Sep 17 00:00:00 2001 From: Jim Deville Date: Sat, 21 Mar 2009 22:57:33 -0700 Subject: [PATCH 2/2] syncing to head of tfs --- .../IronPython/IronPython/Runtime/List.cs | 4 +- .../Runtime/Operations/ComplexOps.cs | 7 +- .../IronPython/Runtime/Types/NewTypeMaker.cs | 131 +++++++++++++----- .../IronPython/IronPythonTest/InheritTest.cs | 32 +++++ .../Languages/Ruby/Ruby/Runtime/RubyScope.cs | 13 +- .../Ast/VariableDictionaryExpression.cs | 2 +- .../Generation/CompilerHelpers.cs | 37 +++++ .../Interpretation/InterpreterVariables.cs | 94 +------------ .../Interpreter/Instruction.cs | 5 +- .../Interpreter/LightCompiler.cs | 2 +- .../Interpreter/LightLambdaClosureVisitor.cs | 90 +++--------- .../Interpreter/RuntimeVariables.cs | 46 ++++++ .../Microsoft.Scripting.Build.csproj | Bin 55944 -> 56066 bytes .../Microsoft.Scripting.csproj | 3 +- .../Runtime/LocalsDictionary.cs | 24 ++-- .../Scripting/Actions/DynamicMetaObject.cs | 10 +- .../Ast/RuntimeVariablesExpression.cs | 2 +- .../Scripting/Ast/SymbolDocumentInfo.cs | 2 + .../Scripting/Compiler/ExpressionQuoter.cs | 100 +++++-------- .../Compiler/LambdaCompiler.Address.cs | 2 - .../Scripting/Compiler/RuntimeVariableList.cs | 108 +++++---------- .../Scripting/Microsoft.Scripting.Core.csproj | 1 + .../Utils/ExceptionFactory.Generated.cs | 14 ++ .../Scripting/Utils/IRuntimeVariables.cs | 33 +++++ 24 files changed, 387 insertions(+), 375 deletions(-) create mode 100644 Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/RuntimeVariables.cs create mode 100644 ndp/fx/src/Core/Microsoft/Scripting/Utils/IRuntimeVariables.cs diff --git a/Merlin/Main/Languages/IronPython/IronPython/Runtime/List.cs b/Merlin/Main/Languages/IronPython/IronPython/Runtime/List.cs index c419be27bb..f22a9a1faa 100644 --- a/Merlin/Main/Languages/IronPython/IronPython/Runtime/List.cs +++ b/Merlin/Main/Languages/IronPython/IronPython/Runtime/List.cs @@ -264,7 +264,7 @@ internal List(ICollection items) n = self._size; //??? is this useful optimization //???if (n == 1) return new List(Array.ArrayList.Repeat(this[0], count)); - newCount = n * count; + newCount = checked(n * count); ret = ArrayOps.CopyArray(self._data, newCount); } @@ -344,7 +344,7 @@ internal List(ICollection items) public List InPlaceMultiply(int count) { lock (this) { int n = this._size; - int newCount = n * count; + int newCount = checked(n * count); EnsureSize(newCount); int block = n; diff --git a/Merlin/Main/Languages/IronPython/IronPython/Runtime/Operations/ComplexOps.cs b/Merlin/Main/Languages/IronPython/IronPython/Runtime/Operations/ComplexOps.cs index ae2fefbd91..334c8d8a54 100644 --- a/Merlin/Main/Languages/IronPython/IronPython/Runtime/Operations/ComplexOps.cs +++ b/Merlin/Main/Languages/IronPython/IronPython/Runtime/Operations/ComplexOps.cs @@ -166,11 +166,8 @@ public static partial class ComplexOps { public static object __getnewargs__(CodeContext context, Complex64 self) { if (!Object.ReferenceEquals(self, null)) { return PythonTuple.MakeTuple( - ComplexOps.__new__(context, - TypeCache.Complex64, - PythonOps.GetBoundAttr(context, self, Symbols.RealPart), - PythonOps.GetBoundAttr(context, self, Symbols.ImaginaryPart) - ) + PythonOps.GetBoundAttr(context, self, Symbols.RealPart), + PythonOps.GetBoundAttr(context, self, Symbols.ImaginaryPart) ); } throw PythonOps.TypeErrorForBadInstance("__getnewargs__ requires a 'complex' object but received a '{0}'", self); diff --git a/Merlin/Main/Languages/IronPython/IronPython/Runtime/Types/NewTypeMaker.cs b/Merlin/Main/Languages/IronPython/IronPython/Runtime/Types/NewTypeMaker.cs index 76aaf64a72..9b2b399c30 100644 --- a/Merlin/Main/Languages/IronPython/IronPython/Runtime/Types/NewTypeMaker.cs +++ b/Merlin/Main/Languages/IronPython/IronPython/Runtime/Types/NewTypeMaker.cs @@ -884,6 +884,9 @@ sealed class NewTypeMaker { private void OverrideSpecialName(MethodInfo mi, Dictionary specialNames, Dictionary overridden) { if (!mi.IsVirtual || mi.IsFinal) { + // TODO: A better check here would be mi.IsFamily && mi.IsSpecialName. But we need to also check + // the other property method (getter if we're a setter, setter if we're a getter) because if one is protected + // and the other isn't we need to still override both (so our newslot property is also both a getter and a setter). if ((mi.IsFamily || mi.IsSpecialName) && (mi.Name.StartsWith("get_") || mi.Name.StartsWith("set_"))) { // need to be able to call into protected getter/setter methods from derived types, // even if these methods aren't virtual and we are in partial trust. @@ -891,7 +894,8 @@ sealed class NewTypeMaker { MethodBuilder mb = CreateSuperCallHelper(mi); foreach (PropertyInfo pi in mi.DeclaringType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { - if (pi.GetGetMethod(true) == mi || pi.GetSetMethod(true) == mi) { + + if (pi.GetGetMethod(true).MemberEquals(mi) || pi.GetSetMethod(true).MemberEquals(mi)) { AddPublicProperty(mi, overridden, mb, pi); break; } @@ -901,11 +905,11 @@ sealed class NewTypeMaker { string name; EventInfo[] eis = mi.DeclaringType.GetEvents(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (EventInfo ei in eis) { - if (ei.GetAddMethod() == mi) { + if (ei.GetAddMethod().MemberEquals(mi)) { if (NameConverter.TryGetName(DynamicHelpers.GetPythonTypeFromType(mi.DeclaringType), ei, mi, out name) == NameType.None) return; CreateVTableEventOverride(mi, mi.Name); return; - } else if (ei.GetRemoveMethod() == mi) { + } else if (ei.GetRemoveMethod().MemberEquals(mi)) { if (NameConverter.TryGetName(DynamicHelpers.GetPythonTypeFromType(mi.DeclaringType), ei, mi, out name) == NameType.None) return; CreateVTableEventOverride(mi, mi.Name); return; @@ -925,14 +929,14 @@ sealed class NewTypeMaker { PropertyInfo foundProperty = null; foreach (PropertyInfo pi in pis) { if (pi.GetIndexParameters().Length > 0) { - if (mi == pi.GetGetMethod(true)) { + if (mi.MemberEquals(pi.GetGetMethod(true))) { mb = CreateVTableMethodOverride(mi, "__getitem__"); if (!mi.IsAbstract) { CreateSuperCallHelper(mi); } foundProperty = pi; break; - } else if (mi == pi.GetSetMethod(true)) { + } else if (mi.MemberEquals(pi.GetSetMethod(true))) { mb = CreateVTableMethodOverride(mi, "__setitem__"); if (!mi.IsAbstract) { CreateSuperCallHelper(mi); @@ -940,9 +944,9 @@ sealed class NewTypeMaker { foundProperty = pi; break; } - } else if (mi == pi.GetGetMethod(true)) { + } else if (mi.MemberEquals(pi.GetGetMethod(true))) { if (mi.Name != "get_PythonType") { - if (NameConverter.TryGetName(DynamicHelpers.GetPythonTypeFromType(mi.DeclaringType), pi, mi, out name) == NameType.None) { + if (NameConverter.TryGetName(GetBaseTypeForMethod(mi), pi, mi, out name) == NameType.None) { return true; } mb = CreateVTableGetterOverride(mi, name); @@ -952,8 +956,8 @@ sealed class NewTypeMaker { } foundProperty = pi; break; - } else if (mi == pi.GetSetMethod(true)) { - if (NameConverter.TryGetName(DynamicHelpers.GetPythonTypeFromType(mi.DeclaringType), pi, mi, out name) == NameType.None) { + } else if (mi.MemberEquals(pi.GetSetMethod(true))) { + if (NameConverter.TryGetName(GetBaseTypeForMethod(mi), pi, mi, out name) == NameType.None) { return true; } mb = CreateVTableSetterOverride(mi, name); @@ -987,9 +991,9 @@ sealed class NewTypeMaker { overridden[foundProperty] = builder = _tg.DefineProperty(foundProperty.Name, foundProperty.Attributes, foundProperty.PropertyType, paramTypes); } - if (foundProperty.GetGetMethod(true) == mi) { + if (foundProperty.GetGetMethod(true).MemberEquals(mi)) { builder.SetGetMethod(mb); - } else if (foundProperty.GetSetMethod(true) == mi) { + } else if (foundProperty.GetSetMethod(true).MemberEquals(mi)) { builder.SetSetMethod(mb); } } @@ -1032,14 +1036,7 @@ sealed class NewTypeMaker { return; } - PythonType basePythonType; - if (_baseType == mi.DeclaringType || _baseType.IsSubclassOf(mi.DeclaringType)) { - basePythonType = DynamicHelpers.GetPythonTypeFromType(_baseType); - } else { - // We must be inherting from an interface - Debug.Assert(mi.DeclaringType.IsInterface); - basePythonType = DynamicHelpers.GetPythonTypeFromType(mi.DeclaringType); - } + PythonType basePythonType = GetBaseTypeForMethod(mi); string name = null; if (NameConverter.TryGetName(basePythonType, mi, out name) == NameType.None) @@ -1057,6 +1054,18 @@ sealed class NewTypeMaker { } } + private PythonType GetBaseTypeForMethod(MethodInfo mi) { + PythonType basePythonType; + if (_baseType == mi.DeclaringType || _baseType.IsSubclassOf(mi.DeclaringType)) { + basePythonType = DynamicHelpers.GetPythonTypeFromType(_baseType); + } else { + // We must be inherting from an interface + Debug.Assert(mi.DeclaringType.IsInterface); + basePythonType = DynamicHelpers.GetPythonTypeFromType(mi.DeclaringType); + } + return basePythonType; + } + /// /// Emits code to check if the class has overridden this specific /// function. For example: @@ -1072,23 +1081,36 @@ sealed class NewTypeMaker { Label instanceCall = il.DefineLabel(); LocalBuilder callTarget = il.DeclareLocal(typeof(object)); + // first lookup under the property name il.EmitLoadArg(0); EmitSymbolId(il, name); il.Emit(OpCodes.Ldloca, callTarget); il.EmitCall(typeof(UserTypeOps), "TryGetNonInheritedValueHelper"); - il.Emit(OpCodes.Brtrue, instanceCall); + // then look up under the method name (get_Foo/set_Foo) + LocalBuilder methodTarget = EmitNonInheritedMethodLookup(baseMethod.Name, il); + Label instanceCallMethod = il.DefineLabel(); + il.Emit(OpCodes.Brtrue, instanceCallMethod); + + // method isn't overridden using either form EmitBaseMethodDispatch(baseMethod, il); + // we're calling the get_/set_ method + il.MarkLabel(instanceCallMethod); + EmitClrCallStub(il, baseMethod, methodTarget); + il.Emit(OpCodes.Ret); + il.MarkLabel(instanceCall); + // we're accessing a property return callTarget; } - + private MethodBuilder CreateVTableGetterOverride(MethodInfo mi, string name) { MethodBuilder impl; - ILGen il = DefineMethodOverride(MethodAttributes.Public, mi, out impl); + ILGen il; + DefineVTableMethodOverride(mi, out impl, out il); LocalBuilder callTarget = EmitBaseClassCallCheckForProperties(il, mi, name); il.Emit(OpCodes.Ldloc, callTarget); @@ -1141,7 +1163,8 @@ sealed class NewTypeMaker { private MethodBuilder CreateVTableSetterOverride(MethodInfo mi, string name) { MethodBuilder impl; - ILGen il = DefineMethodOverride(MethodAttributes.Public, mi, out impl); + ILGen il; + DefineVTableMethodOverride(mi, out impl, out il); LocalBuilder callTarget = EmitBaseClassCallCheckForProperties(il, mi, name); il.Emit(OpCodes.Ldloc, callTarget); // property @@ -1160,7 +1183,7 @@ sealed class NewTypeMaker { MethodBuilder impl; ILGen il = DefineMethodOverride(mi, out impl); - LocalBuilder callTarget = EmitBaseClassCallCheckForProperties(il, mi, name); + LocalBuilder callTarget = EmitBaseClassCallCheckForEvents(il, mi, name); il.Emit(OpCodes.Ldloc, callTarget); il.EmitLoadArg(0); @@ -1172,23 +1195,39 @@ sealed class NewTypeMaker { _tg.DefineMethodOverride(impl, mi); } + /// + /// Emits code to check if the class has overridden this specific + /// function. For example: + /// + /// MyDerivedType.SomeVirtualFunction = ... + /// or + /// + /// class MyDerivedType(MyBaseType): + /// def SomeVirtualFunction(self, ...): + /// + /// + private LocalBuilder EmitBaseClassCallCheckForEvents(ILGen il, MethodInfo baseMethod, string name) { + Label instanceCall = il.DefineLabel(); + LocalBuilder callTarget = il.DeclareLocal(typeof(object)); + + il.EmitLoadArg(0); + EmitSymbolId(il, name); + il.Emit(OpCodes.Ldloca, callTarget); + il.EmitCall(typeof(UserTypeOps), "TryGetNonInheritedValueHelper"); + + il.Emit(OpCodes.Brtrue, instanceCall); + + EmitBaseMethodDispatch(baseMethod, il); + + il.MarkLabel(instanceCall); + + return callTarget; + } + private MethodBuilder CreateVTableMethodOverride(MethodInfo mi, string name) { - ParameterInfo[] parameters = mi.GetParameters(); MethodBuilder impl; ILGen il; - if (mi.IsVirtual && !mi.IsFinal) { - il = DefineMethodOverride(MethodAttributes.Public, mi, out impl); - } else { - impl = _tg.DefineMethod( - mi.Name, - mi.IsVirtual ? - (mi.Attributes | MethodAttributes.NewSlot) : - ((mi.Attributes & ~MethodAttributes.MemberAccessMask) | MethodAttributes.Public), - mi.ReturnType, - ReflectionUtils.GetParameterTypes(parameters)); - CopyGenericMethodAttributes(mi, impl); - il = new ILGen(impl.GetILGenerator()); - } + DefineVTableMethodOverride(mi, out impl, out il); //CompilerHelpers.GetArgumentNames(parameters)); TODO: Set names LocalBuilder callTarget = EmitNonInheritedMethodLookup(name, il); @@ -1209,6 +1248,22 @@ sealed class NewTypeMaker { return impl; } + private void DefineVTableMethodOverride(MethodInfo mi, out MethodBuilder impl, out ILGen il) { + if (mi.IsVirtual && !mi.IsFinal) { + il = DefineMethodOverride(MethodAttributes.Public, mi, out impl); + } else { + impl = _tg.DefineMethod( + mi.Name, + mi.IsVirtual ? + (mi.Attributes | MethodAttributes.NewSlot) : + ((mi.Attributes & ~MethodAttributes.MemberAccessMask) | MethodAttributes.Public), + mi.ReturnType, + ReflectionUtils.GetParameterTypes(mi.GetParameters())); + CopyGenericMethodAttributes(mi, impl); + il = new ILGen(impl.GetILGenerator()); + } + } + /// /// Emits the call to lookup a member defined in the user's type. Returns /// the local which stores the resulting value and leaves a value on the diff --git a/Merlin/Main/Languages/IronPython/IronPythonTest/InheritTest.cs b/Merlin/Main/Languages/IronPython/IronPythonTest/InheritTest.cs index 2545830de7..c470c57d85 100644 --- a/Merlin/Main/Languages/IronPython/IronPythonTest/InheritTest.cs +++ b/Merlin/Main/Languages/IronPython/IronPythonTest/InheritTest.cs @@ -1044,6 +1044,38 @@ public interface IGenericMethods { } + public class MixedProperties { + private object _foo, _bar; + public object Foo { + get { + return _foo; + } + protected set { + _foo = value; + } + } + + public object Bar { + protected get { + return _bar; + } + set { + _bar = value; + } + } + + public object GetFoo() { + return _foo; + } + + public object GetBar() { + return _bar; + } + } + + public class MixedPropertiesInherited : MixedProperties { + } + public static class GenericMethodTester { public static int TestIntFactory0(IGenericMethods i) { return i.Factory0(); } public static string TestStringFactory0(IGenericMethods i) { return i.Factory0(); } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyScope.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyScope.cs index 79753ad440..56d5cb93ec 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyScope.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyScope.cs @@ -41,7 +41,18 @@ public enum ScopeKind { [DebuggerTypeProxy(typeof(RubyScope.DebugView))] #endif public abstract class RubyScope { - internal static readonly LocalsDictionary _EmptyLocals = new LocalsDictionary(new IStrongBox[0], new SymbolId[0]); + private sealed class EmptyRuntimeVariables : IRuntimeVariables { + int IRuntimeVariables.Count { + get { return 0; } + } + + object IRuntimeVariables.this[int index] { + get { throw new IndexOutOfRangeException(); } + set { throw new IndexOutOfRangeException(); } + } + } + + internal static readonly LocalsDictionary _EmptyLocals = new LocalsDictionary(new EmptyRuntimeVariables(), new SymbolId[0]); private readonly IAttributesCollection/*!*/ _frame; private readonly RubyTopLevelScope/*!*/ _top; diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Ast/VariableDictionaryExpression.cs b/Merlin/Main/Runtime/Microsoft.Scripting/Ast/VariableDictionaryExpression.cs index b5f3bb6796..6cc04bac17 100644 --- a/Merlin/Main/Runtime/Microsoft.Scripting/Ast/VariableDictionaryExpression.cs +++ b/Merlin/Main/Runtime/Microsoft.Scripting/Ast/VariableDictionaryExpression.cs @@ -29,7 +29,7 @@ public partial class Utils { public static Expression VariableDictionary(IEnumerable variables) { var vars = variables.ToReadOnly(); return Expression.New( - typeof(LocalsDictionary).GetConstructor(new[] { typeof(IList), typeof(SymbolId[]) }), + typeof(LocalsDictionary).GetConstructor(new[] { typeof(IRuntimeVariables), typeof(SymbolId[]) }), Expression.RuntimeVariables(vars), AstUtils.Constant(vars.Map(v => SymbolTable.StringToIdOrEmpty(v.Name))) ); diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Generation/CompilerHelpers.cs b/Merlin/Main/Runtime/Microsoft.Scripting/Generation/CompilerHelpers.cs index 0d73bb9134..0d6b40d65b 100644 --- a/Merlin/Main/Runtime/Microsoft.Scripting/Generation/CompilerHelpers.cs +++ b/Merlin/Main/Runtime/Microsoft.Scripting/Generation/CompilerHelpers.cs @@ -413,6 +413,43 @@ public static class CompilerHelpers { return visible; } + /// + /// Sees if two MemberInfos point to the same underlying construct in IL. This + /// ignores the ReflectedType property which exists on MemberInfos which + /// causes direct comparisons to be false even if they are the same member. + /// + public static bool MemberEquals(this MemberInfo self, MemberInfo other) { + if ((self == null) != (other == null)) { + // one null, the other isn't. + return false; + } else if (self == null) { + // both null + return true; + } + + if (self.MemberType != other.MemberType) { + return false; + } + + switch (self.MemberType) { + case MemberTypes.Field: + return ((FieldInfo)self).FieldHandle.Equals(((FieldInfo)other).FieldHandle); + case MemberTypes.Method: + return ((MethodInfo)self).MethodHandle.Equals(((MethodInfo)other).MethodHandle); + case MemberTypes.Constructor: + return ((ConstructorInfo)self).MethodHandle.Equals(((ConstructorInfo)other).MethodHandle); + case MemberTypes.NestedType: + case MemberTypes.TypeInfo: + return ((Type)self).TypeHandle.Equals(((Type)other).TypeHandle); + case MemberTypes.Event: + case MemberTypes.Property: + default: + return + ((MemberInfo)self).Module == ((MemberInfo)other).Module && + ((MemberInfo)self).MetadataToken == ((MemberInfo)other).MetadataToken; + } + } + /// /// Given a MethodInfo which may be declared on a non-public type this attempts to /// return a MethodInfo which will dispatch to the original MethodInfo but is declared diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Interpretation/InterpreterVariables.cs b/Merlin/Main/Runtime/Microsoft.Scripting/Interpretation/InterpreterVariables.cs index ddff999b40..3312abe848 100644 --- a/Merlin/Main/Runtime/Microsoft.Scripting/Interpretation/InterpreterVariables.cs +++ b/Merlin/Main/Runtime/Microsoft.Scripting/Interpretation/InterpreterVariables.cs @@ -13,12 +13,9 @@ * * ***************************************************************************/ -using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq.Expressions; using System.Runtime.CompilerServices; -using System; -using Microsoft.Scripting.Utils; namespace Microsoft.Scripting.Interpretation { @@ -31,26 +28,7 @@ namespace Microsoft.Scripting.Interpretation { /// full variable binding pass, something the interpreter doesn't need /// today. The only thing that this breaks is Python's func_closure /// - internal sealed class InterpreterVariables : IList { - - // TODO: InterpreterState should store values in strongly typed - // StrongBox, which gives us the correct cast error if the wrong - // type is set at runtime. - private sealed class InterpreterBox : IStrongBox { - private readonly InterpreterState _state; - private readonly Expression _variable; - - internal InterpreterBox(InterpreterState state, Expression variable) { - _state = state; - _variable = variable; - } - - public object Value { - get { return _state.GetValue(_variable); } - set { _state.SetValue(_variable, value); } - } - } - + internal sealed class InterpreterVariables : IRuntimeVariables { private readonly InterpreterState _state; private readonly ReadOnlyCollection _vars; @@ -59,79 +37,17 @@ private sealed class InterpreterBox : IStrongBox { _vars = node.Variables; } - public int Count { + int IRuntimeVariables.Count { get { return _vars.Count; } } - public IStrongBox this[int index] { + object IRuntimeVariables.this[int index] { get { - return new InterpreterBox(_state, _vars[index]); + return _state.GetValue(_vars[index]); } set { - throw CollectionReadOnly(); - } - } - - public int IndexOf(IStrongBox item) { - for (int i = 0, n = _vars.Count; i < n; i++) { - if (this[i] == item) { - return i; - } + _state.SetValue(_vars[index], value); } - return -1; - } - - public bool Contains(IStrongBox item) { - return IndexOf(item) >= 0; - } - - public void CopyTo(IStrongBox[] array, int arrayIndex) { - ContractUtils.RequiresNotNull(array, "array"); - int count = _vars.Count; - if (arrayIndex < 0 || arrayIndex + count > array.Length) { - throw new ArgumentOutOfRangeException("arrayIndex"); - } - for (int i = 0; i < count; i++) { - array[arrayIndex++] = this[i]; - } - } - - bool ICollection.IsReadOnly { - get { return true; } - } - - public IEnumerator GetEnumerator() { - for (int i = 0, n = _vars.Count; i < n; i++) { - yield return this[i]; - } - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return GetEnumerator(); - } - - void IList.Insert(int index, IStrongBox item) { - throw CollectionReadOnly(); - } - - void IList.RemoveAt(int index) { - throw CollectionReadOnly(); - } - - void ICollection.Add(IStrongBox item) { - throw CollectionReadOnly(); - } - - void ICollection.Clear() { - throw CollectionReadOnly(); - } - - bool ICollection.Remove(IStrongBox item) { - throw CollectionReadOnly(); - } - - private static Exception CollectionReadOnly() { - throw new NotSupportedException("Collection is read-only."); } } } diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/Instruction.cs b/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/Instruction.cs index a50d38f0ef..39a76c3564 100644 --- a/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/Instruction.cs +++ b/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/Instruction.cs @@ -509,6 +509,7 @@ public class CallInstruction : Instruction { object ret = _target.Invoke(args); if (!_isVoid) frame.Push(ret); + return +1; } @@ -529,7 +530,7 @@ public class CreateDelegateInstruction : Instruction { public override int ProducedStack { get { return 1; } } public override int Run(StackFrame frame) { StrongBox[] closure = new StrongBox[ConsumedStack]; - for (int i = closure.Length - 1; i >= 0; i-- ) { + for (int i = closure.Length - 1; i >= 0; i--) { closure[i] = (StrongBox)frame.Pop(); } @@ -740,7 +741,7 @@ public class RuntimeVariablesInstruction : Instruction { for (int i = ret.Length - 1; i >= 0; i--) { ret[i] = (IStrongBox)frame.Pop(); } - frame.Push(ret); + frame.Push(RuntimeVariables.Create(ret)); return +1; } } diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/LightCompiler.cs b/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/LightCompiler.cs index a237cdc93d..421c969a24 100644 --- a/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/LightCompiler.cs +++ b/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/LightCompiler.cs @@ -1121,7 +1121,7 @@ class ParameterVisitor : ExpressionVisitor { } private void CompileRuntimeVariablesExpression(Expression expr) { - //Generates an IList for all requested variables + // Generates IRuntimeVariables for all requested variables var node = (RuntimeVariablesExpression)expr; foreach (var variable in node.Variables) { this.EnsureAvailableForClosure(variable); diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/LightLambdaClosureVisitor.cs b/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/LightLambdaClosureVisitor.cs index 1f5ae0ae4c..cc293ae21a 100644 --- a/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/LightLambdaClosureVisitor.cs +++ b/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/LightLambdaClosureVisitor.cs @@ -15,12 +15,9 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq.Expressions; -using System.Reflection; using System.Runtime.CompilerServices; using Microsoft.Scripting.Generation; -using Microsoft.Scripting.Runtime; using Microsoft.Scripting.Utils; using AstUtils = Microsoft.Scripting.Ast.Utils; @@ -171,14 +168,14 @@ internal sealed class LightLambdaClosureVisitor : ExpressionVisitor { // All of them were rewritten. Just return the array, wrapped in a // read-only collection. if (vars.Count == 0) { - return Expression.New( - typeof(ReadOnlyCollection).GetConstructor(new[] { typeof(IList) }), + return Expression.Invoke( + Expression.Constant((Func)RuntimeVariables.Create), boxesArray ); } // Otherwise, we need to return an object that merges them - Func, IList, int[], IList> helper = MergedRuntimeVariables.Create; + Func helper = MergedRuntimeVariables.Create; return Expression.Invoke(AstUtils.Constant(helper), Expression.RuntimeVariables(vars), boxesArray, AstUtils.Constant(indexes)); } @@ -201,7 +198,7 @@ internal sealed class LightLambdaClosureVisitor : ExpressionVisitor { // We need to convert to object to store the value in the box. return Expression.Block( new[] { variable }, - Expression.Assign(variable, Visit(node.Right)), + Expression.Assign(variable, Visit(node.Right)), Expression.Assign(Expression.Field(box, "Value"), Ast.Utils.Convert(variable, typeof(object))), variable ); @@ -231,104 +228,51 @@ internal sealed class LightLambdaClosureVisitor : ExpressionVisitor { return Visit(node.ReduceExtensions()); } + #region MergedRuntimeVariables /// /// Provides a list of variables, supporing read/write of the values /// - private sealed class MergedRuntimeVariables : IList { - private readonly IList _first; - private readonly IList _second; + private sealed class MergedRuntimeVariables : IRuntimeVariables { + private readonly IRuntimeVariables _first; + private readonly IRuntimeVariables _second; // For reach item, the index into the first or second list // Positive values mean the first array, negative means the second private readonly int[] _indexes; - private MergedRuntimeVariables(IList first, IList second, int[] indexes) { + private MergedRuntimeVariables(IRuntimeVariables first, IRuntimeVariables second, int[] indexes) { _first = first; _second = second; _indexes = indexes; } - internal static IList Create(IList first, IList second, int[] indexes) { + internal static IRuntimeVariables Create(IRuntimeVariables first, IRuntimeVariables second, int[] indexes) { return new MergedRuntimeVariables(first, second, indexes); } - public int Count { + int IRuntimeVariables.Count { get { return _indexes.Length; } } - public IStrongBox this[int index] { + object IRuntimeVariables.this[int index] { get { index = _indexes[index]; return (index >= 0) ? _first[index] : _second[-1 - index]; } set { - throw new NotSupportedException("Collection is read-only."); - } - } - - public int IndexOf(IStrongBox item) { - for (int i = 0, n = _indexes.Length; i < n; i++) { - if (this[i] == item) { - return i; + index = _indexes[index]; + if (index >= 0) { + _first[index] = value; + } else { + _second[-1 - index] = value; } } - return -1; - } - - public bool Contains(IStrongBox item) { - return IndexOf(item) >= 0; - } - - public void CopyTo(IStrongBox[] array, int arrayIndex) { - ContractUtils.RequiresNotNull(array, "array"); - int count = _indexes.Length; - if (arrayIndex < 0 || arrayIndex + count > array.Length) { - throw new ArgumentOutOfRangeException("arrayIndex"); - } - for (int i = 0; i < count; i++) { - array[arrayIndex++] = this[i]; - } - } - - bool ICollection.IsReadOnly { - get { return true; } - } - - public IEnumerator GetEnumerator() { - for (int i = 0, n = _indexes.Length; i < n; i++) { - yield return this[i]; - } - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return GetEnumerator(); - } - - void IList.Insert(int index, IStrongBox item) { - throw new NotSupportedException("Collection is read-only."); - } - - void IList.RemoveAt(int index) { - throw new NotSupportedException("Collection is read-only."); - } - - void ICollection.Add(IStrongBox item) { - throw new NotSupportedException("Collection is read-only."); - } - - void ICollection.Clear() { - throw new NotSupportedException("Collection is read-only."); - } - - bool ICollection.Remove(IStrongBox item) { - throw new NotSupportedException("Collection is read-only."); } } #endregion #endregion - } } diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/RuntimeVariables.cs b/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/RuntimeVariables.cs new file mode 100644 index 0000000000..46e4df8fcf --- /dev/null +++ b/Merlin/Main/Runtime/Microsoft.Scripting/Interpreter/RuntimeVariables.cs @@ -0,0 +1,46 @@ +/* **************************************************************************** + * + * 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.Runtime.CompilerServices; + +namespace Microsoft.Scripting.Interpreter { + internal sealed class RuntimeVariables : IRuntimeVariables { + private readonly IStrongBox[] _boxes; + + private RuntimeVariables(IStrongBox[] boxes) { + _boxes = boxes; + } + + int IRuntimeVariables.Count { + get { + return _boxes.Length; + } + } + + object IRuntimeVariables.this[int index] { + get { + return _boxes[index].Value; + } + set { + _boxes[index].Value = value; + } + } + + internal static IRuntimeVariables Create(IStrongBox[] boxes) { + return new RuntimeVariables(boxes); + } + } +} diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Microsoft.Scripting.Build.csproj b/Merlin/Main/Runtime/Microsoft.Scripting/Microsoft.Scripting.Build.csproj index 584a77de9f783cc5c3d69df86239b722c469c318..6a0a67875437ed0541cb5823572fad446f8595b1 100644 GIT binary patch delta 36 scmeC!%G|V#dBeY%yg>}540#MC44DkM45^c^PD-EbFo9+BpP4-l00QI=kN^Mx delta 14 WcmZqL#@w-$dBeY%n=58@IRF4Q8V6DU diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Microsoft.Scripting.csproj b/Merlin/Main/Runtime/Microsoft.Scripting/Microsoft.Scripting.csproj index 1c8a26f47c..1197735e0d 100644 --- a/Merlin/Main/Runtime/Microsoft.Scripting/Microsoft.Scripting.csproj +++ b/Merlin/Main/Runtime/Microsoft.Scripting/Microsoft.Scripting.csproj @@ -2,7 +2,7 @@ Debug AnyCPU - 9.0.30729 + 9.0.21022 2.0 {EB66B766-6354-4208-A3D4-AACBDCB5C3B3} Library @@ -182,6 +182,7 @@ + diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Runtime/LocalsDictionary.cs b/Merlin/Main/Runtime/Microsoft.Scripting/Runtime/LocalsDictionary.cs index 4cce36a1bb..78eec4e936 100644 --- a/Merlin/Main/Runtime/Microsoft.Scripting/Runtime/LocalsDictionary.cs +++ b/Merlin/Main/Runtime/Microsoft.Scripting/Runtime/LocalsDictionary.cs @@ -24,22 +24,22 @@ namespace Microsoft.Scripting.Runtime { /// Creates a dictionary of locals in this scope /// public sealed class LocalsDictionary : CustomSymbolDictionary { - private readonly IList _locals; + private readonly IRuntimeVariables _locals; private readonly SymbolId[] _symbols; - private Dictionary _boxes; + private Dictionary _boxes; - public LocalsDictionary(IList locals, SymbolId[] symbols) { + public LocalsDictionary(IRuntimeVariables locals, SymbolId[] symbols) { Assert.NotNull(locals, symbols); _locals = locals; _symbols = symbols; } - + private void EnsureBoxes() { if (_boxes == null) { int count = _symbols.Length; - Dictionary boxes = new Dictionary(count); + Dictionary boxes = new Dictionary(count); for (int i = 0; i < count; i++) { - boxes[_symbols[i]] = _locals[i]; + boxes[_symbols[i]] = i; } _boxes = boxes; } @@ -52,9 +52,9 @@ public sealed class LocalsDictionary : CustomSymbolDictionary { protected internal override bool TrySetExtraValue(SymbolId key, object value) { EnsureBoxes(); - IStrongBox box; - if (_boxes.TryGetValue(key, out box)) { - box.Value = value; + int index; + if (_boxes.TryGetValue(key, out index)) { + _locals[index] = value; return true; } @@ -64,9 +64,9 @@ public sealed class LocalsDictionary : CustomSymbolDictionary { protected internal override bool TryGetExtraValue(SymbolId key, out object value) { EnsureBoxes(); - IStrongBox box; - if (_boxes.TryGetValue(key, out box)) { - value = box.Value; + int index; + if (_boxes.TryGetValue(key, out index)) { + value = _locals[index]; return true; } value = null; diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Actions/DynamicMetaObject.cs b/ndp/fx/src/Core/Microsoft/Scripting/Actions/DynamicMetaObject.cs index 4635b42534..9d77af98a7 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Actions/DynamicMetaObject.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Actions/DynamicMetaObject.cs @@ -307,12 +307,12 @@ public DynamicMetaObject(Expression expression, BindingRestrictions restrictions if (ido != null) { #endif var idoMetaObject = ido.GetMetaObject(expression); - if (idoMetaObject.Value != ido) { - throw new InvalidOperationException(); - } - if (idoMetaObject.Expression != expression) { - throw new InvalidOperationException(); + if (idoMetaObject == null || + !idoMetaObject.HasValue || + idoMetaObject.Value == null || + (object)idoMetaObject.Expression != (object)expression) { + throw Error.InvalidMetaObjectCreated(ido.GetType()); } return idoMetaObject; diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Ast/RuntimeVariablesExpression.cs b/ndp/fx/src/Core/Microsoft/Scripting/Ast/RuntimeVariablesExpression.cs index e05ba50819..e8b2b88755 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Ast/RuntimeVariablesExpression.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Ast/RuntimeVariablesExpression.cs @@ -40,7 +40,7 @@ public sealed class RuntimeVariablesExpression : Expression { /// /// The that represents the static type of the expression. protected override Type TypeImpl() { - return typeof(IList); + return typeof(IRuntimeVariables); } /// diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Ast/SymbolDocumentInfo.cs b/ndp/fx/src/Core/Microsoft/Scripting/Ast/SymbolDocumentInfo.cs index 33ad148632..ff39ae4860 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Ast/SymbolDocumentInfo.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Ast/SymbolDocumentInfo.cs @@ -66,12 +66,14 @@ internal sealed class SymbolDocumentWithGuids : SymbolDocumentInfo { internal SymbolDocumentWithGuids(string fileName, ref Guid language) : base(fileName) { _language = language; + _documentType = Compiler.SymbolGuids.DocumentType_Text; } internal SymbolDocumentWithGuids(string fileName, ref Guid language, ref Guid vendor) : base(fileName) { _language = language; _vendor = vendor; + _documentType = Compiler.SymbolGuids.DocumentType_Text; } internal SymbolDocumentWithGuids(string fileName, ref Guid language, ref Guid vendor, ref Guid documentType) diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/ExpressionQuoter.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/ExpressionQuoter.cs index 17e12960fc..6550dbab2b 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/ExpressionQuoter.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/ExpressionQuoter.cs @@ -14,12 +14,11 @@ * ***************************************************************************/ using System.Collections.Generic; -using System.Collections.ObjectModel; +using System.ComponentModel; using System.Diagnostics; using System.Dynamic.Utils; using System.Linq.Expressions; using System.Linq.Expressions.Compiler; -using System.ComponentModel; namespace System.Runtime.CompilerServices { public partial class RuntimeOps { @@ -45,7 +44,7 @@ public partial class RuntimeOps { /// The index array indicating which list to get variables from. /// The merged runtime variables. [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)] - public static IList MergeRuntimeVariables(IList first, IList second, int[] indexes) { + public static IRuntimeVariables MergeRuntimeVariables(IRuntimeVariables first, IRuntimeVariables second, int[] indexes) { return new MergedRuntimeVariables(first, second, indexes); } @@ -129,7 +128,7 @@ private sealed class ExpressionQuoter : ExpressionVisitor { return node; } - var boxesConst = Expression.Constant(new ReadOnlyCollection(boxes.ToArray())); + var boxesConst = Expression.Constant(new RuntimeVariables(boxes.ToArray()), typeof(IRuntimeVariables)); // All of them were rewritten. Just return the array as a constant if (vars.Count == 0) { return boxesConst; @@ -180,20 +179,40 @@ private sealed class ExpressionQuoter : ExpressionVisitor { } } + private sealed class RuntimeVariables : IRuntimeVariables { + private readonly IStrongBox[] _boxes; + + internal RuntimeVariables(IStrongBox[] boxes) { + _boxes = boxes; + } + + int IRuntimeVariables.Count { + get { return _boxes.Length; } + } + + object IRuntimeVariables.this[int index] { + get { + return _boxes[index].Value; + } + set { + _boxes[index].Value = value; + } + } + } /// /// Provides a list of variables, supporing read/write of the values /// Exposed via RuntimeVariablesExpression /// - private sealed class MergedRuntimeVariables : IList { - private readonly IList _first; - private readonly IList _second; + private sealed class MergedRuntimeVariables : IRuntimeVariables { + private readonly IRuntimeVariables _first; + private readonly IRuntimeVariables _second; // For reach item, the index into the first or second list // Positive values mean the first array, negative means the second private readonly int[] _indexes; - internal MergedRuntimeVariables(IList first, IList second, int[] indexes) { + internal MergedRuntimeVariables(IRuntimeVariables first, IRuntimeVariables second, int[] indexes) { _first = first; _second = second; _indexes = indexes; @@ -203,72 +222,19 @@ private sealed class MergedRuntimeVariables : IList { get { return _indexes.Length; } } - public IStrongBox this[int index] { + public object this[int index] { get { index = _indexes[index]; return (index >= 0) ? _first[index] : _second[-1 - index]; } set { - throw Error.CollectionReadOnly(); - } - } - - public int IndexOf(IStrongBox item) { - for (int i = 0, n = _indexes.Length; i < n; i++) { - if (this[i] == item) { - return i; + index = _indexes[index]; + if (index >= 0) { + _first[index] = value; + } else { + _second[-1 - index] = value; } } - return -1; - } - - public bool Contains(IStrongBox item) { - return IndexOf(item) >= 0; - } - - public void CopyTo(IStrongBox[] array, int arrayIndex) { - ContractUtils.RequiresNotNull(array, "array"); - int count = _indexes.Length; - if (arrayIndex < 0 || arrayIndex + count > array.Length) { - throw new ArgumentOutOfRangeException("arrayIndex"); - } - for (int i = 0; i < count; i++) { - array[arrayIndex++] = this[i]; - } - } - - bool ICollection.IsReadOnly { - get { return true; } - } - - public IEnumerator GetEnumerator() { - for (int i = 0, n = _indexes.Length; i < n; i++) { - yield return this[i]; - } - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return GetEnumerator(); - } - - void IList.Insert(int index, IStrongBox item) { - throw Error.CollectionReadOnly(); - } - - void IList.RemoveAt(int index) { - throw Error.CollectionReadOnly(); - } - - void ICollection.Add(IStrongBox item) { - throw Error.CollectionReadOnly(); - } - - void ICollection.Clear() { - throw Error.CollectionReadOnly(); - } - - bool ICollection.Remove(IStrongBox item) { - throw Error.CollectionReadOnly(); } } } diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Address.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Address.cs index 52deb141f9..8c23d9bd08 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Address.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/LambdaCompiler.Address.cs @@ -152,7 +152,6 @@ partial class LambdaCompiler { LocalBuilder temp = GetLocal(GetMemberType(member)); _ilg.Emit(OpCodes.Stloc, temp); _ilg.Emit(OpCodes.Ldloca, temp); - FreeLocal(temp); } @@ -206,7 +205,6 @@ partial class LambdaCompiler { LocalBuilder tmp = GetLocal(type); _ilg.Emit(OpCodes.Stloc, tmp); _ilg.Emit(OpCodes.Ldloca, tmp); - FreeLocal(tmp); } diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/RuntimeVariableList.cs b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/RuntimeVariableList.cs index 84a32d69f3..85e7d3981c 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Compiler/RuntimeVariableList.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Compiler/RuntimeVariableList.cs @@ -13,11 +13,8 @@ * * ***************************************************************************/ -using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; -using System.Dynamic.Utils; -using System.Linq.Expressions; using System.Linq.Expressions.Compiler; namespace System.Runtime.CompilerServices { @@ -35,7 +32,7 @@ public static partial class RuntimeOps { /// An array of indicies into the closure array where variables are found. /// An interface to access variables. [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)] - public static IList CreateRuntimeVariables(object[] data, long[] indexes) { + public static IRuntimeVariables CreateRuntimeVariables(object[] data, long[] indexes) { return new RuntimeVariableList(data, indexes); } @@ -44,15 +41,30 @@ public static partial class RuntimeOps { /// /// An interface to access variables. [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)] - public static IList CreateRuntimeVariables() { - return EmptyReadOnlyCollection.Instance; + public static IRuntimeVariables CreateRuntimeVariables() { + return new EmptyRuntimeVariables(); + } + + private sealed class EmptyRuntimeVariables : IRuntimeVariables { + int IRuntimeVariables.Count { + get { return 0; } + } + + object IRuntimeVariables.this[int index] { + get { + throw new ArgumentOutOfRangeException("index"); + } + set { + throw new ArgumentOutOfRangeException("index"); + } + } } /// /// Provides a list of variables, supporing read/write of the values /// Exposed via RuntimeVariablesExpression /// - private sealed class RuntimeVariableList : IList { + private sealed class RuntimeVariableList : IRuntimeVariables { // The top level environment. It contains pointers to parent // environments, which are always in the first element private readonly object[] _data; @@ -77,83 +89,29 @@ private sealed class RuntimeVariableList : IList { get { return _indexes.Length; } } - public IStrongBox this[int index] { + public object this[int index] { get { - // We lookup the closure using two ints: - // 1. The high dword is the number of parents to go up - // 2. The low dword is the index into that array - long closureKey = _indexes[index]; - - // walk up the parent chain to find the real environment - object[] result = _data; - for (int parents = (int)(closureKey >> 32); parents > 0; parents--) { - result = HoistedLocals.GetParent(result); - } - - // Return the variable storage - return (IStrongBox)result[(int)closureKey]; + return GetStrongBox(index).Value; } set { - throw Error.CollectionReadOnly(); - } - } - - public int IndexOf(IStrongBox item) { - for (int i = 0, n = _indexes.Length; i < n; i++) { - if (this[i] == item) { - return i; - } - } - return -1; - } - - public bool Contains(IStrongBox item) { - return IndexOf(item) >= 0; - } - - public void CopyTo(IStrongBox[] array, int arrayIndex) { - ContractUtils.RequiresNotNull(array, "array"); - int count = _indexes.Length; - if (arrayIndex < 0 || arrayIndex + count > array.Length) { - throw new ArgumentOutOfRangeException("arrayIndex"); - } - for (int i = 0; i < count; i++) { - array[arrayIndex++] = this[i]; + GetStrongBox(index).Value = value; } } - bool ICollection.IsReadOnly { - get { return true; } - } + private IStrongBox GetStrongBox(int index) { + // We lookup the closure using two ints: + // 1. The high dword is the number of parents to go up + // 2. The low dword is the index into that array + long closureKey = _indexes[index]; - public IEnumerator GetEnumerator() { - for (int i = 0, n = _indexes.Length; i < n; i++) { - yield return this[i]; + // walk up the parent chain to find the real environment + object[] result = _data; + for (int parents = (int)(closureKey >> 32); parents > 0; parents--) { + result = HoistedLocals.GetParent(result); } - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return GetEnumerator(); - } - - void IList.Insert(int index, IStrongBox item) { - throw Error.CollectionReadOnly(); - } - - void IList.RemoveAt(int index) { - throw Error.CollectionReadOnly(); - } - - void ICollection.Add(IStrongBox item) { - throw Error.CollectionReadOnly(); - } - - void ICollection.Clear() { - throw Error.CollectionReadOnly(); - } - bool ICollection.Remove(IStrongBox item) { - throw Error.CollectionReadOnly(); + // Return the variable storage + return (IStrongBox)result[(int)closureKey]; } } } diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Microsoft.Scripting.Core.csproj b/ndp/fx/src/Core/Microsoft/Scripting/Microsoft.Scripting.Core.csproj index cd2b37cd4e..306f77a922 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Microsoft.Scripting.Core.csproj +++ b/ndp/fx/src/Core/Microsoft/Scripting/Microsoft.Scripting.Core.csproj @@ -226,6 +226,7 @@ + diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Utils/ExceptionFactory.Generated.cs b/ndp/fx/src/Core/Microsoft/Scripting/Utils/ExceptionFactory.Generated.cs index 8e137f05c9..65e68ca11b 100644 --- a/ndp/fx/src/Core/Microsoft/Scripting/Utils/ExceptionFactory.Generated.cs +++ b/ndp/fx/src/Core/Microsoft/Scripting/Utils/ExceptionFactory.Generated.cs @@ -1462,6 +1462,13 @@ internal static partial class Strings { return FormatString("Switch value of type '{0}' cannot be used for the comparison method parameter of type '{1}'", p0, p1); } + /// + /// A string like "An IDynamicMetaObjectProvider {0} created an invalid DynamicMetaObject instance." + /// + internal static string InvalidMetaObjectCreated(object p0) { + return FormatString("An IDynamicMetaObjectProvider {0} created an invalid DynamicMetaObject instance.", p0); + } + } /// /// Strongly-typed and parameterized exception factory. @@ -2455,6 +2462,13 @@ internal static partial class Error { return new ArgumentException(Strings.SwitchValueTypeDoesNotMatchComparisonMethodParameter(p0, p1)); } + /// + /// InvalidOperationException with message like "An IDynamicMetaObjectProvider {0} created an invalid DynamicMetaObject instance." + /// + internal static Exception InvalidMetaObjectCreated(object p0) { + return new InvalidOperationException(Strings.InvalidMetaObjectCreated(p0)); + } + } // *** END GENERATED CODE *** diff --git a/ndp/fx/src/Core/Microsoft/Scripting/Utils/IRuntimeVariables.cs b/ndp/fx/src/Core/Microsoft/Scripting/Utils/IRuntimeVariables.cs new file mode 100644 index 0000000000..cf77b0934a --- /dev/null +++ b/ndp/fx/src/Core/Microsoft/Scripting/Utils/IRuntimeVariables.cs @@ -0,0 +1,33 @@ +/* **************************************************************************** + * + * 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. + * + * + * ***************************************************************************/ + +namespace System.Runtime.CompilerServices { + /// + /// An interface to represent values of runtime variables. + /// + public interface IRuntimeVariables { + /// + /// Count of the variables. + /// + int Count { get; } + + /// + /// An indexer to get/set the values of the runtime variables. + /// + /// An index of the runtime variable. + /// The value of the runtime variable. + object this[int index] { get; set; } + } +}