/// <summary> /// Recompiles the class which involves recalculating caches state. /// </summary> /// <remarks> /// This flushes internal caches for the class and any affected /// classes (subclasses or possible superclasses). /// /// The process includes: /// - Resetting cached subclasses collection. /// - Remapping instance-names to indexes. /// - Remapping class-instance-names to indexes. /// - Register the class for mapping between native .Net types and Smalltalk classes. /// - Write-protects dictionaries of imported pools, variables and methods (etc.) /// </remarks> public void Recompile() { SmalltalkClass superclass = this.Superclass; if (superclass != null) { lock (superclass) superclass._subclasses = null; } this.RecompileIndexedVariables(); this.RegisterNativeTypeMapping(); lock (this) this._subclasses = null; foreach (SmalltalkClass cls in this.Subclasses) { cls.Recompile(); } this.ClassInstanceVariableBindings.WriteProtect(); this.ClassVariableBindings.WriteProtect(); this.ImportedPoolBindings.WriteProtect(); this.InstanceBehavior.WriteProtect(); this.InstanceVariableBindings.WriteProtect(); }
/// <summary> /// Create a new SmalltalkObject for a given SmalltalkClass. /// </summary> /// <param name="cls">The SmalltalkClass that this object will be instance of.</param> public SmalltalkObject(SmalltalkClass cls) { if (cls == null) { throw new ArgumentNullException(); } this.Class = cls; this.InstanceVariables = new object[cls.InstanceSize]; }
/// <summary> /// Create a new ByteIndexable SmalltalkObject for a given SmalltalkClass. /// </summary> /// <param name="cls">The SmalltalkClass that this object will be instance of.</param> /// <param name="objectSize">Number of unnamed instance variables.</param> public ByteIndexableSmalltalkObject(SmalltalkClass cls, int objectSize) : base(cls) { if (cls.InstanceState != SmalltalkClass.InstanceStateEnum.ByteIndexable) { throw new ArgumentOutOfRangeException("cls", cls.InstanceState, "Expected a ByteIndexable class"); } if (objectSize < 0) { throw new ArgumentOutOfRangeException("objectSize"); } this.Contents = new byte[objectSize]; }
/// <summary> /// Internal! This is used by the Installer to create new classes. /// </summary> /// <param name="runtime">Smalltalk runtime this class is part of.</param> /// <param name="name">Name of the class.</param> /// <param name="superclass">Optional binding to the class' superclass.</param> /// <param name="instanceState">State of the class' instances (named, object-indexable, byte-indexable).</param> /// <param name="instanceVariables">Instance variables bindings. Those are initially not initialized.</param> /// <param name="classVariables">Class variable binding.</param> /// <param name="classInstanceVariables">Class-instance variables bindings. Those are initially not initialized.</param> /// <param name="importedPools">Collection of pools that are imported by the class.</param> /// <param name="instanceMethods">Collection with the methods defining the instance behaviors.</param> /// <param name="classMethods">Collection with the methods defining the class behaviors.</param> public SmalltalkClass(SmalltalkRuntime runtime, Symbol name, ClassBinding superclass, InstanceStateEnum instanceState, BindingDictionary <InstanceVariableBinding> instanceVariables, DiscreteBindingDictionary <ClassVariableBinding> classVariables, BindingDictionary <ClassInstanceVariableBinding> classInstanceVariables, DiscreteBindingDictionary <PoolBinding> importedPools, InstanceMethodDictionary instanceMethods, ClassMethodDictionary classMethods) { if (runtime == null) { throw new ArgumentNullException("runtime"); } if ((name == null) || (name.Value.Length == 0)) { throw new ArgumentNullException("name"); } if (!SmalltalkClass.ValidateIdentifiers <InstanceVariableBinding>(instanceVariables)) { throw new ArgumentException("Invalid or duplicate instance variable name found", "instanceVariables"); } if (!SmalltalkClass.ValidateIdentifiers <ClassVariableBinding>(classVariables)) { throw new ArgumentException("Invalid or duplicate class variable name found", "classVariables"); } if (!SmalltalkClass.ValidateIdentifiers <ClassInstanceVariableBinding>(classInstanceVariables)) { throw new ArgumentException("Invalid or duplicate class instance variable name found", "classInstanceVariables"); } if (!SmalltalkClass.ValidateIdentifiers <PoolBinding>(importedPools)) { throw new ArgumentException("Invalid or duplicate imported pool name found", "importedPools"); } if (!SmalltalkClass.CheckDuplicates <InstanceVariableBinding, ClassVariableBinding>(instanceVariables, classVariables)) { throw new ArgumentException("Duplicate instance or class variable name. Instance and class variable names must be unique."); } if (!SmalltalkClass.CheckDuplicates <ClassInstanceVariableBinding, ClassVariableBinding>(classInstanceVariables, classVariables)) { throw new ArgumentException("Duplicate class-instance or class variable name. Class-instance and class variable names must be unique."); } this.Runtime = runtime; this.ClassInstanceVariableBindings = classInstanceVariables ?? new BindingDictionary <ClassInstanceVariableBinding>(this.Runtime, 1); this.ClassBehavior = classMethods ?? new ClassMethodDictionary(this.Runtime); this.ClassVariableBindings = classVariables ?? new DiscreteBindingDictionary <ClassVariableBinding>(this.Runtime, 1); this.ImportedPoolBindings = importedPools ?? new DiscreteBindingDictionary <PoolBinding>(this.Runtime, 1); this.InstanceBehavior = instanceMethods ?? new InstanceMethodDictionary(this.Runtime); this.InstanceState = instanceState; this.InstanceVariableBindings = instanceVariables ?? new BindingDictionary <InstanceVariableBinding>(this.Runtime, 1); this.Name = name; this.SuperclassBinding = superclass; // Null is OK .... Object has null this.InstanceSize = 0; this.ClassInstanceSize = 0; this.ClassInstanceVariables = new object[0]; }
private void RecompileIndexedVariables() { lock (this) this._subclasses = null; #if DEBUG { // Validate that we don't have some bug or inconsistency in the calculation. SmalltalkClass scls = this.Superclass; int lastVar = Int32.MaxValue; while (scls != null) { if (scls.InstanceSize > lastVar) { throw new InvalidOperationException("Broken instance variable binding. Bad implementation."); } IEnumerable <InstanceVariableBinding> vars = scls.InstanceVariableBindings; if (vars.Any()) { int min = vars.Min(binding => binding.Value); int max = vars.Max(binding => binding.Value); if (max >= lastVar) { throw new InvalidOperationException("Broken instance variable binding. Bad implementation."); } lastVar = min; } else { lastVar = scls.InstanceSize; } scls = scls.Superclass; } // ... and the class-instance variables ... scls = this.Superclass; lastVar = Int32.MaxValue; while (scls != null) { if (scls.ClassInstanceSize > lastVar) { throw new InvalidOperationException("Broken class-instance variable binding. Bad implementation."); } IEnumerable <ClassInstanceVariableBinding> vars = scls.ClassInstanceVariableBindings; if (vars.Any()) { int min = vars.Min(binding => binding.Value); int max = vars.Max(binding => binding.Value); if (max >= lastVar) { throw new InvalidOperationException("Broken class-instance variable binding. Bad implementation."); } lastVar = min; } else { lastVar = scls.ClassInstanceSize; } scls = scls.Superclass; } } #endif SmalltalkClass cls = this.Superclass; int idx = (cls == null) ? 0 : cls.InstanceSize; foreach (InstanceVariableBinding binding in this.InstanceVariableBindings) { binding.SetValue(idx); idx++; } this.InstanceSize = idx; idx = (cls == null) ? 0 : cls.ClassInstanceSize; foreach (ClassInstanceVariableBinding binding in this.ClassInstanceVariableBindings) { binding.SetValue(idx); idx++; } this.ClassInstanceSize = idx; object[] clsInstVars = new object[idx]; Array.Copy(this.ClassInstanceVariables, 0, clsInstVars, 0, Math.Min(this.ClassInstanceVariables.Length, clsInstVars.Length)); this.ClassInstanceVariables = clsInstVars; }