private ConstantLookupResult TryLookupConstantNoLock(bool included, bool inherited, RubyGlobalScope autoloadScope, string/*!*/ name, out ConstantStorage value) { Context.RequiresClassHierarchyLock(); Debug.Assert(included || !inherited); value = default(ConstantStorage); while (true) { ConstantStorage result; RubyModule owner = included ? TryResolveConstantNoAutoloadCheck(inherited, name, out result) : (TryGetConstantNoAutoloadCheck(name, out result) ? this : null); if (owner == null) { return ConstantLookupResult.NotFound; } var autoloaded = result.Value as AutoloadedConstant; if (autoloaded == null) { value = result; return ConstantLookupResult.Found; } if (autoloadScope == null) { return ConstantLookupResult.FoundAutoload; } if (autoloadScope.Context != Context) { throw RubyExceptions.CreateTypeError(String.Format("Cannot autoload constants to a foreign runtime #{0}", autoloadScope.Context.RuntimeId)); } // autoloaded constants are removed before the associated file is loaded: object _; owner.TryRemoveConstantNoLock(name, out _); // load file and try lookup again (releases the class hierarchy lock when loading the file): if (!autoloaded.Load(autoloadScope)) { return ConstantLookupResult.NotFound; } } }
// thread-safe: // Returns null on success, the lexically inner-most module on failure. internal RubyModule TryResolveConstantNoLock(RubyGlobalScope autoloadScope, string/*!*/ name, out ConstantStorage result) { var context = RubyContext; context.RequiresClassHierarchyLock(); RubyScope scope = this; // lexical lookup first: RubyModule innerMostModule = null; do { RubyModule module = scope.Module; if (module != null) { if (module.TryGetConstant(context, autoloadScope, name, out result)) { return null; } // remember the module: if (innerMostModule == null) { innerMostModule = module; } } scope = scope.Parent; } while (scope != null); // check the inner most module and it's base classes/mixins: if (innerMostModule != null) { if (innerMostModule.TryResolveConstant(context, autoloadScope, name, out result)) { return null; } } else { innerMostModule = context.ObjectClass; } if (context.ObjectClass.TryResolveConstant(context, autoloadScope, name, out result)) { return null; } return innerMostModule; }
/// <summary> /// Get constant defined in this module or any of its ancestors. /// Autoloads if autoloadScope is not null. /// </summary> /// <remarks> /// Thread safe. /// </remarks> internal bool TryResolveConstant(RubyGlobalScope autoloadScope, string/*!*/ name, out ConstantStorage value) { using (Context.ClassHierarchyLocker()) { return TryResolveConstantNoLock(autoloadScope, name, out value); } }
/// <summary> /// Get constant defined in this module or any of its ancestors. /// </summary> internal bool TryResolveConstantNoLock(RubyGlobalScope autoloadScope, string/*!*/ name, out ConstantStorage value) { Context.RequiresClassHierarchyLock(); return TryLookupConstantNoLock(true, true, autoloadScope, name, out value) != ConstantLookupResult.NotFound; }
internal void SetConstantNoMutateNoLock(string/*!*/ name, object value) { Context.RequiresClassHierarchyLock(); InitializeConstantsNoLock(); _context.ConstantAccessVersion++; _constants[name] = new ConstantStorage(value); }
internal bool TryResolveConstant(RubyContext/*!*/ callerContext, RubyGlobalScope autoloadScope, string/*!*/ name, out ConstantStorage value) { return callerContext != Context ? TryResolveConstant(autoloadScope, name, out value) : TryResolveConstantNoLock(autoloadScope, name, out value); }
private void LoadNestedTypes() { Context.RequiresClassHierarchyLock(); Debug.Assert(_constants != null && _constants.Count == 0); // TODO: Inherited generic overloads. We need a custom TypeGroup to do it right - part of the type group might be removed // TODO: protected types var bindingFlags = BindingFlags.Public | BindingFlags.DeclaredOnly; if (Context.DomainManager.Configuration.PrivateBinding) { bindingFlags |= BindingFlags.NonPublic; } // if the constant is redefined/removed from the base class. This is similar to method overload inheritance. Type[] types = _typeTracker.Type.GetNestedTypes(bindingFlags); var trackers = new List<TypeTracker>(); var names = new List<string>(); foreach (var type in types) { TypeTracker tracker = (NestedTypeTracker)MemberTracker.FromMemberInfo(type); if (type.IsGenericType) { var name = ReflectionUtils.GetNormalizedTypeName(type); int index = names.IndexOf(name); if (index != -1) { trackers[index] = TypeGroup.UpdateTypeEntity(trackers[index], tracker); names[index] = name; } else { trackers.Add(tracker); names.Add(name); } } else { trackers.Add(tracker); names.Add(type.Name); } } for (int i = 0; i < trackers.Count; i++) { var tracker = trackers[i]; ConstantStorage storage; if (tracker is TypeGroup) { storage = new ConstantStorage(tracker, new WeakReference(tracker)); } else { var module = Context.GetModule(tracker.Type); storage = new ConstantStorage(module, module.WeakSelf); } _constants[names[i]] = storage; } }
// Returns the owner of the constant (this module) or null if the constant is not found. internal bool TryGetConstantNoAutoloadCheck(string/*!*/ name, out ConstantStorage storage) { Context.RequiresClassHierarchyLock(); InitializeConstantsNoLock(); if (_constants.TryGetValue(name, out storage)) { if (storage.IsRemoved) { storage = default(ConstantStorage); return false; } else { return true; } } if (_namespaceTracker != null) { object value; if (_namespaceTracker.TryGetValue(SymbolTable.StringToId(name), out value)) { storage = new ConstantStorage( _context.TrackerToModule(value)); return true; } } storage = default(ConstantStorage); return false; }
// Returns the owner of the constant or null if the constant is not found. private RubyModule TryResolveConstantNoAutoloadCheck(bool inherited, string/*!*/ name, out ConstantStorage value) { Context.RequiresClassHierarchyLock(); var storage = default(ConstantStorage); RubyModule owner = null; if (ForEachAncestor(inherited, (module) => (owner = module).TryGetConstantNoAutoloadCheck(name, out storage))) { value = storage; return owner; } else { value = storage; return null; } }
// thread-safe: // Returns null on success, the lexically inner-most module on failure. internal RubyModule TryResolveConstantNoLock(RubyGlobalScope autoloadScope, string /*!*/ name, out ConstantStorage result) { var context = RubyContext; context.RequiresClassHierarchyLock(); RubyScope scope = this; // lexical lookup first: RubyModule innerMostModule = null; do { RubyModule module = scope.Module; if (module != null) { if (module.TryGetConstant(context, autoloadScope, name, out result)) { return(null); } // remember the module: if (innerMostModule == null) { innerMostModule = module; } } scope = scope.Parent; } while (scope != null); // check the inner most module and it's base classes/mixins: if (innerMostModule != null) { if (innerMostModule.TryResolveConstant(context, autoloadScope, name, out result)) { return(null); } } else { innerMostModule = context.ObjectClass; } if (context.ObjectClass.TryResolveConstant(context, autoloadScope, name, out result)) { return(null); } return(innerMostModule); }
// Direct lookup into the constant table (if it exists). internal bool TryGetConstantNoAutoloadNoInit(string/*!*/ name, out ConstantStorage storage) { Context.RequiresClassHierarchyLock(); storage = default(ConstantStorage); return _constants != null && _constants.TryGetValue(name, out storage) && !storage.IsRemoved; }