/Languages/Ruby/Ruby/Runtime/RubyContext.cs
C# | 3085 lines | 2196 code | 574 blank | 315 comment | 400 complexity | 76f7b2770cb8793948b287af4862ca4f MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
Large files files are truncated, but you can click here to view the full file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
- #if FEATURE_CORE_DLR
- using MSA = System.Linq.Expressions;
- #else
- using MSA = Microsoft.Scripting.Ast;
- #endif
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Dynamic;
- using System.IO;
- using System.Reflection;
- using System.Runtime.CompilerServices;
- using System.Security;
- using System.Text;
- using System.Threading;
- using IronRuby.Builtins;
- using IronRuby.Compiler;
- using IronRuby.Compiler.Ast;
- using IronRuby.Compiler.Generation;
- using IronRuby.Hosting;
- using IronRuby.Runtime.Calls;
- using IronRuby.Runtime.Conversions;
- using Microsoft.Scripting;
- using Microsoft.Scripting.Actions;
- using Microsoft.Scripting.Runtime;
- using Microsoft.Scripting.Utils;
- using System.Collections.ObjectModel;
- using System.Globalization;
- namespace IronRuby.Runtime {
- [ReflectionCached]
- public sealed class RubyContext : LanguageContext {
- #region Constants
- internal static readonly Guid RubyLanguageGuid = new Guid("F03C4640-DABA-473f-96F1-391400714DAB");
- private static readonly Guid LanguageVendor_Microsoft = new Guid(-1723120188, -6423, 0x11d2, 0x90, 0x3f, 0, 0xc0, 0x4f, 0xa3, 2, 0xa1);
- private static int _RuntimeIdGenerator = 0;
- // MRI compliance:
- public string/*!*/ MriVersion {
- get { return "1.9.2"; }
- }
- public string/*!*/ StandardLibraryVersion {
- get { return "1.9.1"; }
- }
- public string/*!*/ MriReleaseDate {
- get { return "2010-08-18"; }
- }
- public int MriPatchLevel {
- get { return 0; }
- }
- public const string BinDirEnvironmentVariable = "IRONRUBY_11";
- // IronRuby:
- public const string IronRubyInformationalVersion = "1.1.3";
- #if !SILVERLIGHT
- public const string/*!*/ IronRubyVersionString = "1.1.3.0";
- public static readonly Version IronRubyVersion = new Version(1, 1, 3, 0);
- #else
- public const string/*!*/ IronRubyVersionString = "1.1.1302.0";
- public static readonly Version IronRubyVersion = new Version(1, 1, 1302, 0);
-
- #endif
- internal const string/*!*/ IronRubyDisplayName = "IronRuby";
- internal const string/*!*/ IronRubyNames = "IronRuby;Ruby;rb";
- internal const string/*!*/ IronRubyFileExtensions = ".rb";
- #endregion
- // TODO: remove
- internal static RubyContext _Default;
- private readonly int _runtimeId;
- private readonly RubyScope/*!*/ _emptyScope;
- private RubyOptions/*!*/ _options;
- private readonly TopNamespaceTracker _namespaces;
- private readonly Loader/*!*/ _loader;
- private readonly Scope/*!*/ _globalScope;
- private readonly RubyMetaBinderFactory/*!*/ _metaBinderFactory;
- private readonly RubyBinder _binder;
- private DynamicDelegateCreator _delegateCreator;
- private RubyService _rubyService;
- #region Global Variables (thread-safe access)
- /// <summary>
- /// $0
- /// </summary>
- public MutableString CommandLineProgramPath { get; set; }
- /// <summary>
- /// $? of type Process::Status
- /// </summary>
- [ThreadStatic]
- private static object _childProcessExitStatus;
- /// <summary>
- /// $/, $-O
- /// </summary>
- private MutableString _inputSeparator;
- /// <summary>
- /// $\
- /// </summary>
- private MutableString _outputSeparator;
- /// <summary>
- /// $;, $-F
- /// </summary>
- private object _stringSeparator;
- /// <summary>
- /// $,
- /// </summary>
- private MutableString _itemSeparator;
- private readonly Dictionary<string/*!*/, GlobalVariable>/*!*/ _globalVariables;
- public object/*!*/ GlobalVariablesLock { get { return _globalVariables; } }
- // not thread safe: use GlobalVariablesLock to synchronize access to the variables:
- public IEnumerable<KeyValuePair<string, GlobalVariable>>/*!*/ GlobalVariables {
- get { return _globalVariables; }
- }
-
- #endregion
- #region Random Number Generator
- private readonly object _randomNumberGeneratorLock = new object();
- private Random _randomNumberGenerator; // lazy
- private object _randomNumberGeneratorSeed = ScriptingRuntimeHelpers.Int32ToObject(0);
- public object RandomNumberGeneratorSeed {
- get { return _randomNumberGeneratorSeed; }
- }
- public void SeedRandomNumberGenerator(IntegerValue value) {
- lock (_randomNumberGeneratorLock) {
- _randomNumberGenerator = new Random(value.IsFixnum ? value.Fixnum : value.Bignum.GetHashCode());
- _randomNumberGeneratorSeed = value.ToObject();
- }
- }
- public Random/*!*/ RandomNumberGenerator {
- get {
- if (_randomNumberGenerator == null) {
- lock (_randomNumberGeneratorLock) {
- if (_randomNumberGenerator == null) {
- _randomNumberGenerator = new Random();
- }
- }
- }
- return _randomNumberGenerator;
- }
- }
- #endregion
- #region Threading
- // Thread#main
- private readonly Thread _mainThread;
- // Thread#critical=
- // We just need a bool. But we store the Thread object for easier debugging if there is a hang
- private Thread _criticalThread;
- private readonly object _criticalMonitor = new object();
- #endregion
- #region Tracing
- private readonly RubyInputProvider/*!*/ _inputProvider;
- private Proc _traceListener;
- [ThreadStatic]
- private bool _traceListenerSuspended;
-
- private readonly Stopwatch _upTime;
- // TODO: thread-safety
- internal Action<Expression, MSA.DynamicExpression> CallSiteCreated { get; set; }
- #endregion
- #region Look-aside tables
- /// <summary>
- /// Maps CLR types to Ruby classes/modules.
- /// Doesn't contain classes defined in Ruby.
- /// </summary>
- private readonly Dictionary<Type, RubyModule>/*!*/ _moduleCache;
- private object ModuleCacheLock { get { return _moduleCache; } }
- /// <summary>
- /// Maps CLR namespace trackers to Ruby modules.
- /// </summary>
- private readonly Dictionary<NamespaceTracker, RubyModule>/*!*/ _namespaceCache;
- private object NamespaceCacheLock { get { return _namespaceCache; } }
- // Maps objects to InstanceData. The keys store weak references to the objects.
- // Objects are compared by reference (identity).
- // An entry can be removed as soon as the key object becomes unreachable.
- private readonly WeakTable<object, RubyInstanceData>/*!*/ _referenceTypeInstanceData;
- private object/*!*/ ReferenceTypeInstanceDataLock { get { return _referenceTypeInstanceData; } }
- // Maps values to InstanceData. The keys store value representatives.
- // All objects that has the same value (value-equality) map to the same InstanceData.
- // Entries cannot be ever freed since anytime in future one may create a new object whose value has already been mapped to InstanceData.
- private readonly Dictionary<object, RubyInstanceData>/*!*/ _valueTypeInstanceData;
- private object/*!*/ ValueTypeInstanceDataLock { get { return _valueTypeInstanceData; } }
- // not thread-safe:
- private readonly RubyInstanceData/*!*/ _nilInstanceData = new RubyInstanceData(RubyUtils.NilObjectId);
- #endregion
- #region Class Hierarchy
- public IDisposable/*!*/ ClassHierarchyLocker() {
- return _classHierarchyLock.CreateLocker();
- }
- public IDisposable/*!*/ ClassHierarchyUnlocker() {
- return _classHierarchyLock.CreateUnlocker();
- }
- private readonly CheckedMonitor/*!*/ _classHierarchyLock = new CheckedMonitor();
- [Emitted]
- public int ConstantAccessVersion = 1;
- [Conditional("DEBUG")]
- internal void RequiresClassHierarchyLock() {
- Debug.Assert(_classHierarchyLock.IsLocked, "Code can only be executed while holding class hierarchy lock.");
- }
- // classes used by runtime (we need to update initialization generator if any of these are added):
- private RubyClass/*!*/ _basicObjectClass;
- private RubyModule/*!*/ _kernelModule;
- private RubyClass/*!*/ _objectClass;
- private RubyClass/*!*/ _classClass;
- private RubyClass/*!*/ _moduleClass;
- private RubyClass/*!*/ _nilClass;
- private RubyClass/*!*/ _trueClass;
- private RubyClass/*!*/ _falseClass;
- private RubyClass/*!*/ _exceptionClass;
- private RubyClass _standardErrorClass;
- private RubyClass _comObjectClass;
- private Action<RubyModule>/*!*/ _mainSingletonTrait;
- // internally set by Initializer:
- public RubyClass/*!*/ BasicObjectClass { get { return _basicObjectClass; } }
- public RubyModule/*!*/ KernelModule { get { return _kernelModule; } }
- public RubyClass/*!*/ ObjectClass { get { return _objectClass; } }
- public RubyClass/*!*/ ClassClass { get { return _classClass; } set { _classClass = value; } }
- public RubyClass/*!*/ ModuleClass { get { return _moduleClass; } set { _moduleClass = value; } }
- public RubyClass/*!*/ NilClass { get { return _nilClass; } set { _nilClass = value; } }
- public RubyClass/*!*/ TrueClass { get { return _trueClass; } set { _trueClass = value; } }
- public RubyClass/*!*/ FalseClass { get { return _falseClass; } set { _falseClass = value; } }
- public RubyClass ExceptionClass { get { return _exceptionClass; } set { _exceptionClass = value; } }
- public RubyClass StandardErrorClass { get { return _standardErrorClass; } set { _standardErrorClass = value; } }
-
- internal RubyClass ComObjectClass {
- get {
- #if !SILVERLIGHT // COM
- if (_comObjectClass == null) {
- GetOrCreateClass(TypeUtils.ComObjectType);
- }
- #endif
- return _comObjectClass;
- }
- }
- // Set of names that method_missing defined on any module was resolved for and that are cached. Lazy init.
- //
- // Note: We used to have this set per module but that doesn't work - see unit test MethodCallCaching_MethodMissing4.
- // Whenever a method is added to a class C we would need to traverse all its subclasses to see if any of them
- // has the added method in its MissingMethodsCachedInSites table.
- // TODO: Could we optimize this search? If so we could also free the per-module set if mm is removed.
- internal HashSet<string> MissingMethodsCachedInSites { get; set; }
- #endregion
- #region Properties
- public PlatformAdaptationLayer/*!*/ Platform {
- get { return DomainManager.Platform; }
- }
- public override LanguageOptions Options {
- get { return _options; }
- }
- public RubyOptions RubyOptions {
- get { return _options; }
- }
- internal RubyScope/*!*/ EmptyScope {
- get { return _emptyScope; }
- }
- public Thread MainThread {
- get { return _mainThread; }
- }
- public MutableString InputSeparator {
- get { return _inputSeparator; }
- set { _inputSeparator = value; }
- }
- public MutableString OutputSeparator {
- get { return _outputSeparator; }
- set { _outputSeparator = value; }
- }
- public object StringSeparator {
- get { return _stringSeparator; }
- set { _stringSeparator = value; }
- }
- public MutableString ItemSeparator {
- get { return _itemSeparator; }
- set { _itemSeparator = value; }
- }
- public object CriticalMonitor {
- get { return _criticalMonitor; }
- }
- public Thread CriticalThread {
- get { return _criticalThread; }
- set { _criticalThread = value; }
- }
- public Proc TraceListener {
- get { return _traceListener; }
- set { _traceListener = value; }
- }
- public RubyInputProvider/*!*/ InputProvider {
- get { return _inputProvider; }
- }
- public object ChildProcessExitStatus {
- get { return _childProcessExitStatus; }
- set { _childProcessExitStatus = value; }
- }
- public Scope/*!*/ TopGlobalScope {
- get { return _globalScope; }
- }
- internal RubyMetaBinderFactory/*!*/ MetaBinderFactory {
- get { return _metaBinderFactory; }
- }
- public Loader/*!*/ Loader {
- get { return _loader; }
- }
- public bool ShowCls {
- get { return false; }
- }
- public EqualityComparer/*!*/ EqualityComparer {
- get {
- if (_equalityComparer == null) {
- _equalityComparer = new EqualityComparer(this);
- }
- return _equalityComparer;
- }
- }
- private EqualityComparer _equalityComparer;
- public override Version LanguageVersion {
- get { return IronRubyVersion; }
- }
- public override Guid LanguageGuid {
- get { return RubyLanguageGuid; }
- }
- public override Guid VendorGuid {
- get { return LanguageVendor_Microsoft; }
- }
- public int RuntimeId {
- get { return _runtimeId; }
- }
- internal TopNamespaceTracker/*!*/ Namespaces {
- get { return _namespaces; }
- }
- public object Verbose { get; set; }
- private RubyEncoding/*!*/ _defaultExternalEncoding;
- public RubyEncoding/*!*/ DefaultExternalEncoding {
- get { return _defaultExternalEncoding; }
- set {
- ContractUtils.RequiresNotNull(value, "value");
- _defaultExternalEncoding = value;
- }
- }
- public RubyEncoding DefaultInternalEncoding { get; set; }
-
- #endregion
- #region Initialization
- public RubyContext(ScriptDomainManager/*!*/ manager, IDictionary<string, object> options)
- : base(manager) {
- ContractUtils.RequiresNotNull(manager, "manager");
- _options = new RubyOptions(options);
- _runtimeId = Interlocked.Increment(ref _RuntimeIdGenerator);
- _upTime = new Stopwatch();
- _upTime.Start();
-
- _binder = new RubyBinder(this);
- _symbols = new Dictionary<MutableString, RubySymbol>();
- _metaBinderFactory = new RubyMetaBinderFactory(this);
- _runtimeErrorSink = new RuntimeErrorSink(this);
- _equalityComparer = new EqualityComparer(this);
- _globalVariables = new Dictionary<string, GlobalVariable>();
- _moduleCache = new Dictionary<Type, RubyModule>();
- _namespaceCache = new Dictionary<NamespaceTracker, RubyModule>();
- _referenceTypeInstanceData = new WeakTable<object, RubyInstanceData>();
- _valueTypeInstanceData = new Dictionary<object, RubyInstanceData>();
- _inputProvider = new RubyInputProvider(this, _options.Arguments, _options.LocaleEncoding);
- _defaultExternalEncoding = _options.DefaultEncoding ?? _options.LocaleEncoding;
- _globalScope = DomainManager.Globals;
- _loader = new Loader(this);
- _emptyScope = new RubyTopLevelScope(this);
- _currentException = null;
- _currentSafeLevel = 0;
- _childProcessExitStatus = null;
- _inputSeparator = MutableString.CreateAscii("\n");
- _outputSeparator = null;
- _stringSeparator = null;
- _itemSeparator = null;
- _mainThread = Thread.CurrentThread;
-
- if (_options.MainFile != null) {
- CommandLineProgramPath = EncodePath(_options.MainFile);
- }
- if (_options.Verbosity <= 0) {
- Verbose = null;
- } else if (_options.Verbosity == 1) {
- Verbose = ScriptingRuntimeHelpers.False;
- } else {
- Verbose = ScriptingRuntimeHelpers.True;
- }
- _namespaces = new TopNamespaceTracker(manager);
- manager.AssemblyLoaded += new EventHandler<AssemblyLoadedEventArgs>((_, e) => AssemblyLoaded(e.Assembly));
- foreach (Assembly asm in manager.GetLoadedAssemblyList()) {
- AssemblyLoaded(asm);
- }
- // TODO:
- Interlocked.CompareExchange(ref _Default, this, null);
- _loader.LoadBuiltins();
- Debug.Assert(_exceptionClass != null && _standardErrorClass != null && _nilClass != null);
- Debug.Assert(_classClass != null && _moduleClass != null);
-
- // needs to run before globals and constants are initialized:
- InitializeFileDescriptors(DomainManager.SharedIO);
- InitializeGlobalConstants();
- InitializeGlobalVariables();
- }
- internal RubyBinder/*!*/ Binder {
- get { return _binder; }
- }
- /// <summary>
- /// Clears thread static variables.
- /// </summary>
- internal static void ClearThreadStatics() {
- _currentException = null;
- }
- private void InitializeGlobalVariables() {
- // special variables:
- Runtime.GlobalVariables.DefineVariablesNoLock(this);
- // TODO:
- // $-a
- // $F
- // $-i
- // $-l
- // $-p
- // $?
- // $0
- DefineGlobalVariableNoLock("PROGRAM_NAME", Runtime.GlobalVariables.CommandLineProgramPath);
- DefineGlobalVariableNoLock("stdin", Runtime.GlobalVariables.InputStream);
- DefineGlobalVariableNoLock("stdout", Runtime.GlobalVariables.OutputStream);
- DefineGlobalVariableNoLock("defout", Runtime.GlobalVariables.OutputStream);
- DefineGlobalVariableNoLock("stderr", Runtime.GlobalVariables.ErrorOutputStream);
- DefineGlobalVariableNoLock("LOADED_FEATURES", Runtime.GlobalVariables.LoadedFiles);
- DefineGlobalVariableNoLock("LOAD_PATH", Runtime.GlobalVariables.LoadPath);
- DefineGlobalVariableNoLock("-I", Runtime.GlobalVariables.LoadPath);
- DefineGlobalVariableNoLock("-O", Runtime.GlobalVariables.InputSeparator);
- DefineGlobalVariableNoLock("-F", Runtime.GlobalVariables.StringSeparator);
- DefineGlobalVariableNoLock("FILENAME", Runtime.GlobalVariables.InputFileName);
- GlobalVariableInfo debug = new GlobalVariableInfo(DomainManager.Configuration.DebugMode || RubyOptions.DebugVariable);
- DefineGlobalVariableNoLock("VERBOSE", Runtime.GlobalVariables.Verbose);
- DefineGlobalVariableNoLock("-v", Runtime.GlobalVariables.Verbose);
- DefineGlobalVariableNoLock("-w", Runtime.GlobalVariables.Verbose);
- DefineGlobalVariableNoLock("DEBUG", debug);
- DefineGlobalVariableNoLock("-d", debug);
- DefineGlobalVariableNoLock("KCODE", Runtime.GlobalVariables.KCode);
- DefineGlobalVariableNoLock("-K", Runtime.GlobalVariables.KCode);
- #if !SILVERLIGHT
- DefineGlobalVariableNoLock("SAFE", Runtime.GlobalVariables.SafeLevel);
- try {
- TrySetCurrentProcessVariables();
- } catch (SecurityException) {
- // nop
- }
- #endif
- }
- #if !SILVERLIGHT // process
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- private void TrySetCurrentProcessVariables() {
- Process process = Process.GetCurrentProcess();
- DefineGlobalVariableNoLock(Symbols.CurrentProcessId, new ReadOnlyGlobalVariableInfo(process.Id));
- }
- #endif
- private void InitializeGlobalConstants() {
- Debug.Assert(_objectClass != null);
- MutableString version = MutableString.CreateAscii(MriVersion);
- MutableString platform = MakePlatformString();
- MutableString releaseDate = MutableString.CreateAscii(MriReleaseDate);
- MutableString rubyEngine = MutableString.CreateAscii("ironruby");
- using (ClassHierarchyLocker()) {
- RubyClass obj = _objectClass;
- obj.SetConstantNoMutateNoLock("RUBY_ENGINE", rubyEngine);
- obj.SetConstantNoMutateNoLock("RUBY_VERSION", version);
- obj.SetConstantNoMutateNoLock("RUBY_PATCHLEVEL", MriPatchLevel);
- obj.SetConstantNoMutateNoLock("RUBY_PLATFORM", platform);
- obj.SetConstantNoMutateNoLock("RUBY_RELEASE_DATE", releaseDate);
- obj.SetConstantNoMutateNoLock("RUBY_DESCRIPTION", MutableString.CreateAscii(MakeDescriptionString()));
- obj.SetConstantNoMutateNoLock("VERSION", version);
- obj.SetConstantNoMutateNoLock("PLATFORM", platform);
- obj.SetConstantNoMutateNoLock("RELEASE_DATE", releaseDate);
- obj.SetConstantNoMutateNoLock("IRONRUBY_VERSION", MutableString.CreateAscii(RubyContext.IronRubyVersionString));
- obj.SetConstantNoMutateNoLock("STDIN", StandardInput);
- obj.SetConstantNoMutateNoLock("STDOUT", StandardOutput);
- obj.SetConstantNoMutateNoLock("STDERR", StandardErrorOutput);
- ConstantStorage argf;
- if (obj.TryGetConstantNoAutoloadCheck("ARGF", out argf)) {
- _inputProvider.Singleton = argf.Value;
- }
- obj.SetConstantNoMutateNoLock("ARGV", _inputProvider.CommandLineArguments);
- // Hash
- // SCRIPT_LINES__
- }
- }
- public static string/*!*/ MakeDescriptionString() {
- return String.Format(CultureInfo.InvariantCulture, "IronRuby {0} on {1}", IronRubyVersion, MakeRuntimeDesriptionString());
- }
- internal static string MakeRuntimeDesriptionString() {
- Type mono = typeof(object).Assembly.GetType("Mono.Runtime");
- return mono != null ?
- (string)mono.GetMethod("GetDisplayName", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, null)
- : String.Format(CultureInfo.InvariantCulture, ".NET {0}", Environment.Version);
- }
- private static MutableString/*!*/ MakePlatformString() {
- switch (Environment.OSVersion.Platform) {
- case PlatformID.MacOSX:
- return MutableString.CreateAscii("i386-darwin");
-
- case PlatformID.Unix:
- return MutableString.CreateAscii("i386-linux");
- case PlatformID.Win32NT:
- case PlatformID.Win32S:
- case PlatformID.Win32Windows:
- return MutableString.CreateAscii("i386-mswin32");
- default:
- return MutableString.CreateAscii("unknown");
- }
- }
- private void InitializeFileDescriptors(SharedIO/*!*/ io) {
- Debug.Assert(_fileDescriptors.Count == 0);
- Stream stream = new ConsoleStream(io, ConsoleStreamType.Input);
- StandardInput = new RubyIO(this, stream, AllocateFileDescriptor(stream), IOMode.ReadOnly);
- stream = new ConsoleStream(io, ConsoleStreamType.Output);
- StandardOutput = new RubyIO(this, stream, AllocateFileDescriptor(stream), IOMode.WriteOnly | IOMode.WriteAppends);
- stream = new ConsoleStream(io, ConsoleStreamType.ErrorOutput);
- StandardErrorOutput = new RubyIO(this, stream, AllocateFileDescriptor(stream), IOMode.WriteOnly | IOMode.WriteAppends);
- }
- // TODO: internal
- public void RegisterPrimitives(
- Action<RubyModule>/*!*/ mainSingletonTrait,
- Action<RubyModule>/*!*/ basicObjectInstanceTrait,
- Action<RubyModule>/*!*/ basicObjectClassTrait,
- Action<RubyModule> basicObjectConstantsInitializer,
- Action<RubyModule>/*!*/ kernelInstanceTrait,
- Action<RubyModule>/*!*/ kernelClassTrait,
- Action<RubyModule> kernelConstantsInitializer,
- Action<RubyModule>/*!*/ objectInstanceTrait,
- Action<RubyModule>/*!*/ objectClassTrait,
- Action<RubyModule> objectConstantsInitializer,
- Action<RubyModule>/*!*/ moduleInstanceTrait,
- Action<RubyModule>/*!*/ moduleClassTrait,
- Action<RubyModule> moduleConstantsInitializer,
- Action<RubyModule>/*!*/ classInstanceTrait,
- Action<RubyModule>/*!*/ classClassTrait,
- Action<RubyModule> classConstantsInitializer) {
- Assert.NotNull(mainSingletonTrait, basicObjectInstanceTrait, basicObjectClassTrait);
- Assert.NotNull(objectInstanceTrait, kernelInstanceTrait, moduleInstanceTrait, classInstanceTrait);
- Assert.NotNull(objectClassTrait, kernelClassTrait, moduleClassTrait, classClassTrait);
- _mainSingletonTrait = mainSingletonTrait;
- // inheritance hierarchy:
- //
- // Class
- // ^
- // BasicObject -> BasicObject'
- // ^ ^
- // Object -> Object'
- // ^ ^
- // Module -> Module'
- // ^ ^
- // Class -> Class'
- // ^
- // Object'
- //
- // only Object should expose CLR methods:
- TypeTracker objectTracker = ReflectionCache.GetTypeTracker(typeof(object));
- var moduleFactories = new Delegate[] {
- new Func<RubyScope, BlockParam, RubyClass, object>(RubyModule.CreateAnonymousModule),
- };
- var classFactories = new Delegate[] {
- new Func<RubyScope, BlockParam, RubyClass, RubyClass, object>(RubyClass.CreateAnonymousClass),
- };
- // locks to comply with lock requirements:
- using (ClassHierarchyLocker()) {
- _basicObjectClass = new RubyClass(this, Symbols.BasicObject, null, null, basicObjectInstanceTrait, basicObjectConstantsInitializer, null, null, null, null, null, false, false, ModuleRestrictions.Builtin & ~ModuleRestrictions.NoOverrides);
- _kernelModule = new RubyModule(this, Symbols.Kernel, kernelInstanceTrait, kernelConstantsInitializer, null, null, null, ModuleRestrictions.Builtin);
- _objectClass = new RubyClass(this, Symbols.Object, objectTracker.Type, null, objectInstanceTrait, objectConstantsInitializer, null, _basicObjectClass, new[] { _kernelModule }, objectTracker, null, false, false, ModuleRestrictions.Builtin & ~ModuleRestrictions.NoOverrides);
- _moduleClass = new RubyClass(this, Symbols.Module, typeof(RubyModule), null, moduleInstanceTrait, moduleConstantsInitializer, moduleFactories, _objectClass, null, null, null, false, false, ModuleRestrictions.Builtin);
- _classClass = new RubyClass(this, Symbols.Class, typeof(RubyClass), null, classInstanceTrait, classConstantsInitializer, classFactories, _moduleClass, null, null, null, false, false, ModuleRestrictions.Builtin);
- _basicObjectClass.InitializeImmediateClass(_basicObjectClass.CreateSingletonClass(_classClass, basicObjectClassTrait));
- _objectClass.InitializeImmediateClass(_objectClass.CreateSingletonClass(_basicObjectClass.ImmediateClass, objectClassTrait));
- _moduleClass.InitializeImmediateClass(_moduleClass.CreateSingletonClass(_objectClass.ImmediateClass, moduleClassTrait));
- _classClass.InitializeImmediateClass(_classClass.CreateSingletonClass(_moduleClass.ImmediateClass, classClassTrait));
- _moduleClass.InitializeDummySingleton();
- _classClass.InitializeDummySingleton();
- _basicObjectClass.ImmediateClass.InitializeImmediateClass(_classClass.GetDummySingletonClass());
- _objectClass.ImmediateClass.InitializeImmediateClass(_classClass.GetDummySingletonClass());
- _moduleClass.ImmediateClass.InitializeImmediateClass(_classClass.GetDummySingletonClass());
- _classClass.ImmediateClass.InitializeImmediateClass(_classClass.GetDummySingletonClass());
-
- _kernelModule.InitializeImmediateClass(_moduleClass, kernelClassTrait);
- _objectClass.SetConstantNoMutateNoLock(_basicObjectClass.Name, _basicObjectClass);
- _objectClass.SetConstantNoMutateNoLock(_moduleClass.Name, _moduleClass);
- _objectClass.SetConstantNoMutateNoLock(_classClass.Name, _classClass);
- _objectClass.SetConstantNoMutateNoLock(_objectClass.Name, _objectClass);
- _objectClass.SetConstantNoMutateNoLock(_kernelModule.Name, _kernelModule);
- }
- AddModuleToCacheNoLock(typeof(BasicObject), _basicObjectClass);
- AddModuleToCacheNoLock(typeof(Kernel), _kernelModule);
- AddModuleToCacheNoLock(objectTracker.Type, _objectClass);
- AddModuleToCacheNoLock(typeof(RubyObject), _objectClass);
- AddModuleToCacheNoLock(_moduleClass.GetUnderlyingSystemType(), _moduleClass);
- AddModuleToCacheNoLock(_classClass.GetUnderlyingSystemType(), _classClass);
- }
- #endregion
- #region CLR Types and Namespaces
- private void AssemblyLoaded(Assembly/*!*/ assembly) {
- _namespaces.LoadAssembly(assembly);
- AddExtensionAssembly(assembly);
- }
- internal void AddModuleToCacheNoLock(Type/*!*/ type, RubyModule/*!*/ module) {
- Assert.NotNull(type, module);
- _moduleCache.Add(type, module);
- }
- internal void AddNamespaceToCacheNoLock(NamespaceTracker/*!*/ namespaceTracker, RubyModule/*!*/ module) {
- Assert.NotNull(namespaceTracker, module);
- _namespaceCache.Add(namespaceTracker, module);
- }
- internal RubyModule/*!*/ GetOrCreateModule(NamespaceTracker/*!*/ tracker) {
- Assert.NotNull(tracker);
- lock (ModuleCacheLock) {
- return GetOrCreateModuleNoLock(tracker);
- }
- }
- internal bool TryGetModule(NamespaceTracker/*!*/ namespaceTracker, out RubyModule result) {
- lock (NamespaceCacheLock) {
- return _namespaceCache.TryGetValue(namespaceTracker, out result);
- }
- }
- internal RubyModule/*!*/ GetOrCreateModule(Type/*!*/ moduleType) {
- Debug.Assert(RubyModule.IsModuleType(moduleType));
- lock (ModuleCacheLock) {
- return GetOrCreateModuleNoLock(moduleType);
- }
- }
- public bool TryGetModule(Type/*!*/ type, out RubyModule result) {
- lock (ModuleCacheLock) {
- return _moduleCache.TryGetValue(type, out result);
- }
- }
- internal bool TryGetModuleNoLock(Type/*!*/ type, out RubyModule result) {
- return _moduleCache.TryGetValue(type, out result);
- }
- internal bool TryGetClassNoLock(Type/*!*/ type, out RubyClass result) {
- RubyModule module;
- if (_moduleCache.TryGetValue(type, out module)) {
- result = module as RubyClass;
- if (result == null) {
- throw new InvalidOperationException("Specified type doesn't represent a class");
- }
- return true;
- } else {
- result = null;
- return false;
- }
- }
- internal RubyClass/*!*/ GetOrCreateClass(Type/*!*/ type) {
- lock (ModuleCacheLock) {
- return GetOrCreateClassNoLock(type);
- }
- }
- private RubyModule/*!*/ GetOrCreateModuleNoLock(NamespaceTracker/*!*/ tracker) {
- Assert.NotNull(tracker);
- RubyModule result;
- if (_namespaceCache.TryGetValue(tracker, out result)) {
- return result;
- }
- result = CreateModule(GetQualifiedName(tracker), null, null, null, null, tracker, null, ModuleRestrictions.None);
- _namespaceCache[tracker] = result;
- return result;
- }
- private RubyModule/*!*/ GetOrCreateModuleNoLock(Type/*!*/ moduleType) {
- Debug.Assert(RubyModule.IsModuleType(moduleType));
- RubyModule result;
- if (_moduleCache.TryGetValue(moduleType, out result)) {
- return result;
- }
- TypeTracker tracker = (TypeTracker)TypeTracker.FromMemberInfo(moduleType);
- RubyModule[] mixins;
- if (moduleType.IsGenericType && !moduleType.IsGenericTypeDefinition) {
- // I<T0..Tn> mixes in its generic definition I<,..,>
- mixins = new[] { GetOrCreateModuleNoLock(moduleType.GetGenericTypeDefinition()) };
- } else {
- mixins = null;
- }
- result = CreateModule(GetQualifiedNameNoLock(moduleType), null, null, null, mixins, null, tracker, ModuleRestrictions.None);
- _moduleCache[moduleType] = result;
- return result;
- }
- private RubyClass/*!*/ GetOrCreateClassNoLock(Type/*!*/ type) {
- Debug.Assert(!RubyModule.IsModuleType(type));
- RubyClass result;
- if (TryGetClassNoLock(type, out result)) {
- return result;
- }
- RubyClass baseClass;
- if (type.IsByRef) {
- baseClass = _objectClass;
- } else {
- baseClass = GetOrCreateClassNoLock(type.BaseType);
- }
- TypeTracker tracker = (TypeTracker)TypeTracker.FromMemberInfo(type);
- RubyModule[] clrMixins = GetClrMixinsNoLock(type);
- RubyModule[] expandedMixins;
- if (clrMixins != null) {
- using (ClassHierarchyLocker()) {
- expandedMixins = RubyModule.ExpandMixinsNoLock(baseClass, clrMixins);
- }
- } else {
- expandedMixins = RubyModule.EmptyArray;
- }
- result = CreateClass(
- GetQualifiedNameNoLock(type), type, null, null, null, null, null,
- baseClass, expandedMixins, tracker, null, false, false, ModuleRestrictions.None
- );
- if (TypeUtils.IsComObjectType(type)) {
- _comObjectClass = result;
- }
- _moduleCache[type] = result;
- return result;
- }
- /// <summary>
- /// An interface is mixed into the type that implements it.
- /// A generic type definition is mixed into its instantiations.
- ///
- /// In both cases these modules don't themselves contribute any callable CLR methods
- /// yet they might contribute CLR extension methods and Ruby methods defined on them.
- /// </summary>
- private RubyModule[] GetClrMixinsNoLock(Type/*!*/ type) {
- List<RubyModule> modules = new List<RubyModule>();
- if (type.IsGenericType && !type.IsGenericTypeDefinition) {
- modules.Add(GetOrCreateModuleNoLock(type.GetGenericTypeDefinition()));
- }
-
- if (type.IsArray) {
- if (type.GetArrayRank() > 1) {
- RubyModule module;
- if (TryGetModuleNoLock(typeof(MultiDimensionalArray), out module)) {
- modules.Add(module);
- }
- }
- } else if (type.IsEnum) {
- if (type.IsDefined(typeof(FlagsAttribute), false)) {
- RubyModule module;
- if (TryGetModuleNoLock(typeof(FlagEnumeration), out module)) {
- modules.Add(module);
- }
- }
- }
- foreach (Type iface in ReflectionUtils.GetDeclaredInterfaces(type)) {
- modules.Add(GetOrCreateModuleNoLock(iface));
- }
- return modules.Count > 0 ? modules.ToArray() : null;
- }
- #endregion
- #region CLR Extension Methods
- private readonly object ExtensionsLock = new object();
-
- // List of assemblies that might include extension methods but whose processing was delayed until the first call of use_clr_extensions.
- // Null once use_clr_extensions has been called.
- private List<Assembly> _potentialExtensionAssemblies = new List<Assembly>();
- // A list of extension methods that are available for activation. Grouped by a declaring namespace.
- // Value is null if the namepsace has been activated.
- private Dictionary<string, List<IEnumerable<ExtensionMethodInfo>>> _availableExtensions;
- private void AddExtensionAssembly(Assembly/*!*/ assembly) {
- if (_potentialExtensionAssemblies != null) {
- lock (ExtensionsLock) {
- if (_potentialExtensionAssemblies != null) {
- _potentialExtensionAssemblies.Add(assembly);
- return;
- }
- }
- }
- LoadExtensions(ReflectionUtils.GetVisibleExtensionMethodGroups(assembly, true));
- }
- private void LoadExtensions(IEnumerable<KeyValuePair<string, IEnumerable<ExtensionMethodInfo>>>/*!*/ extensionMethodGroups) {
- List<IEnumerable<ExtensionMethodInfo>> immediatelyActivated = null;
- lock (ExtensionsLock) {
- foreach (var extensionMethodGroup in extensionMethodGroups) {
- if (_availableExtensions == null) {
- _availableExtensions = new Dictionary<string, List<IEnumerable<ExtensionMethodInfo>>>();
- }
- string ns = extensionMethodGroup.Key;
- List<IEnumerable<ExtensionMethodInfo>> extensions;
- if (_availableExtensions.TryGetValue(ns, out extensions)) {
- if (extensions == null) {
- if (immediatelyActivated == null) {
- immediatelyActivated = new List<IEnumerable<ExtensionMethodInfo>>();
- }
- extensions = immediatelyActivated;
- }
- } else {
- _availableExtensions.Add(ns, extensions = new List<IEnumerable<ExtensionMethodInfo>>());
- }
- extensions.Add(extensionMethodGroup.Value);
- }
- }
- if (immediatelyActivated != null) {
- ActivateExtensions(immediatelyActivated);
- }
- }
- public void ActivateExtensions(string/*!*/ @namespace) {
- ContractUtils.RequiresNotNull(@namespace, "namespace");
- Assembly[] assemblies = null;
- if (_potentialExtensionAssemblies != null) {
- lock (ExtensionsLock) {
- if (_potentialExtensionAssemblies != null) {
- assemblies = _potentialExtensionAssemblies.ToArray();
- _potentialExtensionAssemblies = null;
- }
- }
- }
- if (assemblies != null) {
- var extensionGroups = new List<KeyValuePair<string, IEnumerable<ExtensionMethodInfo>>>();
- foreach (var assembly in assemblies) {
- extensionGroups.AddRange(ReflectionUtils.GetVisibleExtensionMethodGroups(assembly, true));
- }
- LoadExtensions(extensionGroups);
- }
- List<IEnumerable<ExtensionMethodInfo>> extensions;
- lock (ExtensionsLock) {
- _availableExtensions.TryGetValue(@namespace, out extensions);
-
- // activate namespace:
- _availableExtensions[@namespace] = null;
- }
- if (extensions != null) {
- ActivateExtensions(extensions);
- }
- }
- private void ActivateExtensions(List<IEnumerable<ExtensionMethodInfo>>/*!*/ extensionLists) {
- var groupedByType = new Dictionary<Type, List<ExtensionMethodInfo>>();
- foreach (var extensionList in extensionLists) {
- foreach (var extension in extensionList) {
- Type extendedType = extension.ExtendedType;
- Debug.Assert(!extendedType.IsGenericTypeDefinition && !extendedType.IsPointer && !extendedType.IsByRef);
- Type target;
- if (extendedType.ContainsGenericParameters) {
- if (extendedType.IsGenericParameter) {
- // TODO: we can do better if there are constraints defined on the parameter
- target = typeof(object);
- } else {
- target = extendedType.IsArray ? typeof(Array) : extendedType.GetGenericTypeDefinition();
- }
- } else {
- target = extendedType;
- }
- List<ExtensionMethodInfo> list;
- if (!groupedByType.TryGetValue(target, out list)) {
- groupedByType.Add(target, list = new List<ExtensionMethodInfo>());
- }
- list.Add(extension);
- }
- }
- using (ClassHierarchyLocker()) {
- lock (ModuleCacheLock) {
- foreach (var entry in groupedByType) {
- Type target = entry.Key;
- var methods = entry.Value;
- RubyModule targetModule = (target.IsGenericTypeDefinition || target.IsInterface) ? GetOrCreateModuleNoLock(target) : GetOrCreateClassNoLock(target);
- targetModule.AddExtensionMethodsNoLock(methods);
- }
- }
- }
- }
- #endregion
- #region Class and Module Factories (thread-safe)
- /// <summary>
- /// Class factory. Do not use RubyClass constructor except for special cases (Object, Class, Module, singleton classes).
- /// </summary>
- internal RubyClass/*!*/ CreateClass(string name, Type type, object classSingletonOf,
- Action<RubyModule> instanceTrait, Action<RubyModule> classTrait, Action<RubyModule> constantsInitializer, Delegate/*!*/[] factories,
- RubyClass/*!*/ superClass, RubyModule/*!*/[] expandedMixins, TypeTracker tracker, RubyStruct.Info structInfo,
- bool isRubyClass, bool isSingletonClass, ModuleRestrictions restrictions) {
- Assert.NotNull(superClass);
- RubyClass result = new RubyClass(this, name, type, classSingletonOf,
- instanceTrait, constantsInitializer, factories, superClass, expandedMixins, tracker, structInfo,
- isRubyClass, isSingletonClass, restrictions
- );
- result.InitializeImmediateClass(superClass.ImmediateClass, classTrait);
- return result;
- }
- /// <summary>
- /// Module factory. Do not use RubyModule constructor except special cases (Kernel).
- /// </summary>
- internal RubyModule/*!*/ CreateModule(string name,
- Action<RubyModule> instanceTrait, Action<RubyModule> classTrait, Action<RubyModule> constantsInitializer,
- RubyModule/*!*/[] expandedMixins, NamespaceTracker namespaceTracker, TypeTracker typeTracker, ModuleRestrictions restrictions) {
- RubyModule result = new RubyModule(
- this, name, instanceTrait, constantsInitializer, expandedMixins, namespaceTracker, typeTracker, restrictions
- );
- result.InitializeImmediateClass(_moduleClass, classTrait);
- return result;
- }
- /// <summary>
- /// Creates a singleton class for specified object unless it already exists.
- /// </summary>
- public RubyClass/*!*/ GetOrCreateSingletonClass(object obj) {
- RubyModule module = obj as RubyModule;
- if (module != null) {
- return module.GetOrCreateSingletonClass();
- }
- return GetOrCreateInstanceSingleton(obj, null, null, null, null);
- }
- internal RubyClass/*!*/ GetOrCreateMainSingleton(object obj, RubyModule/*!*/[] expandedMixins) {
- return GetOrCreateInstanceSingleton(obj, _mainSingletonTrait, null, null, expandedMixins);
- }
- internal RubyClass/*!*/ GetOrCreateInstanceSingleton(object obj, Action<RubyModule> instanceTrait, Action<RubyModule> classTrait,
- Action<RubyModule> constantsInitializer, RubyModule/*!*/[] expandedMixins) {
- Debug.Assert(!(obj is RubyModule));
- Debug.Assert(RubyUtils.HasSingletonClass(obj));
- if (obj == null) {
- return _nilClass;
- }
- if (obj is bool) {
- return (bool)obj ? _trueClass : _falseClass;
- }
- RubyInstanceData data = null;
- RubyClass immediate = GetImmediateClassOf(obj, ref data);
- if (immediate.IsSingletonClass) {
- Debug.Assert(!immediate.IsDummySingletonClass);
- return immediate;
- }
- RubyClass result = CreateClass(
- null, null, obj, instanceTrait, classTrait, constantsInitializer, null,
- immediate, expandedMixins, null, null, true, true, ModuleRestrictions.None
- );
- using (ClassHierarchyLocker()) {
- // singleton might have been created by another thread:
- immediate = GetImmediateClassOf(obj, ref data);
- if (immediate.IsSingletonClass) {
- Debug.Assert(!immediate.IsDummySingletonClass);
- return immediate;
- }
- SetInstanceSingletonOfNoLock(obj, ref data, result);
- if (!(obj is IRubyObject)) {
- PerfTrack.NoteEvent(PerfTrack.Categories.Count, "Non-IRO singleton created " + immediate.NominalClass.Name);
- }
- }
- Debug.Assert(result.IsSingletonClass && !result.IsDummySingletonClass);
- return result;
- }
- /// <summary>
- /// Defines a new module nested in the given owner.
- /// The module is published into the global scope if the owner is Object.
- ///
- /// Thread safe.
- /// </summary>
- internal RubyModule/*!*/ DefineModule(RubyModule/*!*/ owner, string/*!*/ name) {
- RubyModule result = CreateModule(owner.MakeNestedModuleName(name), null, null, null, null, null, null, ModuleRestrictions.None);
- PublishModule(name, owner, result);
- return result;
- }
- /// <summary>
- /// Defines a new class nested in the given owner.
- /// The module is published into the global scope it if is not anonymous and the owner is Object.
- ///
- /// Thread safe.
- /// Triggers "inherited" event.
- /// </summary>
- internal RubyClass/*!*/ DefineClass(RubyModule/*!*/ owner, string name, RubyClass/*!*/ superClass, RubyStruct.Info structInfo) {
- Assert.NotNull(owner, superClass);
- if (superClass.TypeTracker != null && superClass.TypeTracker.Type.ContainsGenericParameters) {
- throw RubyExceptions.CreateTypeError(String.Format(
- "{0}: cannot inherit from open generic instantiation {1}. Only closed instantiations are supported.",
- name, superClass.Name
- ));
- }
- string qualifiedName = owner.MakeNestedModuleName(name);
- RubyClass result = CreateClass(
- qualifiedName, null, null, null, null, null, null, superClass, null, null, structInfo, true, false, ModuleRestrictions.None
- );
- PublishModule(name, owner, result);
- superClass.ClassInheritedEvent(result);
- return result;
- }
- private static void PublishModule(string name, RubyModule/*!*/ owner, RubyModule/*!*/ module) {
- if (name != null) {
- owner.SetConstant(name, module);
- if (owner.IsObjectClass) {
- module.Publish(name);
- }
- }
- }
- #endregion
- #region Libraries (thread-safe)
- //
- // Scenario…
Large files files are truncated, but you can click here to view the full file