/// <summary> /// Initializes a new instance. /// </summary> /// <param name="counterExampleMetadata">The state vector layout expected by the counter example.</param> /// <param name="modelMetadata">The state vector layout expected by the model.</param> internal StateVectorMismatchException(StateVectorLayout counterExampleMetadata, StateVectorLayout modelMetadata) : base("Mismatch detected between the layout of the state vector as expected by the counter example and the " + "actual layout of the state vector used by the instantiated model.") { CounterExampleMetadata = counterExampleMetadata; ModelMetadata = modelMetadata; }
/// <summary> /// Initializes a new instance. /// </summary> /// <param name="serializedData">The serialized data describing the model.</param> /// <param name="stateHeaderBytes"> /// The number of bytes that should be reserved at the beginning of each state vector for the model checker tool. /// </param> internal RuntimeModel(SerializedRuntimeModel serializedData, int stateHeaderBytes = 0) { Requires.That(serializedData.Model != null, "Expected a valid model instance."); var buffer = serializedData.Buffer; var rootComponents = serializedData.Model.Roots; var objectTable = serializedData.ObjectTable; var formulas = serializedData.Formulas; Requires.NotNull(buffer, nameof(buffer)); Requires.NotNull(rootComponents, nameof(rootComponents)); Requires.NotNull(objectTable, nameof(objectTable)); Requires.NotNull(formulas, nameof(formulas)); Requires.That(stateHeaderBytes % 4 == 0, nameof(stateHeaderBytes), "Expected a multiple of 4."); Model = serializedData.Model; SerializedModel = buffer; RootComponents = rootComponents.Cast <Component>().ToArray(); Faults = objectTable.OfType <Fault>().Where(fault => fault.Activation == Activation.Nondeterministic && fault.IsUsed).ToArray(); ActivationSensitiveFaults = Faults.Where(fault => fault.RequiresActivationNotification).ToArray(); StateFormulas = objectTable.OfType <StateFormula>().ToArray(); Formulas = formulas; // Create a local object table just for the objects referenced by the model; only these objects // have to be serialized and deserialized. The local object table does not contain, for instance, // the closure types of the state formulas var objects = Model.ReferencedObjects; var deterministicFaults = objectTable.OfType <Fault>().Where(fault => fault.Activation != Activation.Nondeterministic); _serializedObjects = new ObjectTable(objects.Except(deterministicFaults, ReferenceEqualityComparer <object> .Default)); Objects = objectTable; StateVectorLayout = SerializationRegistry.Default.GetStateVectorLayout(Model, _serializedObjects, SerializationMode.Optimized); _deserialize = StateVectorLayout.CreateDeserializer(_serializedObjects); _serialize = StateVectorLayout.CreateSerializer(_serializedObjects); _restrictRanges = StateVectorLayout.CreateRangeRestrictor(_serializedObjects); _stateHeaderBytes = stateHeaderBytes; PortBinding.BindAll(objectTable); _choiceResolver = new ChoiceResolver(objectTable); ConstructionState = new byte[StateVectorSize]; fixed(byte *state = ConstructionState) { Serialize(state); _restrictRanges(); } FaultSet.CheckFaultCount(Faults.Length); StateFormulaSet.CheckFormulaCount(StateFormulas.Length); }
protected void GenerateCode(SerializationMode mode, params object[] objects) { objects = SerializationRegistry.Default.GetReferencedObjects(objects, mode).ToArray(); var model = TestModel.InitializeModel(new DummyComponent(objects)); _objectTable = new ObjectTable(objects); StateVectorLayout = SerializationRegistry.Default.GetStateVectorLayout(model, _objectTable, mode); _serializer = StateVectorLayout.CreateSerializer(_objectTable); _deserializer = StateVectorLayout.CreateDeserializer(_objectTable); _rangeRestrictor = StateVectorLayout.CreateRangeRestrictor(_objectTable); StateSlotCount = StateVectorLayout.SizeInBytes / 4; StateVectorSize = StateVectorLayout.SizeInBytes; _buffer = new MemoryBuffer(); _buffer.Resize(StateVectorSize, zeroMemory: true); SerializedState = _buffer.Pointer; Output.Log("{0}", StateVectorLayout); }
protected void GenerateCode(SerializationMode mode, params object[] objects) { objects = SerializationRegistry.Default.GetReferencedObjects(objects, mode).ToArray(); var model = TestModel.InitializeModel(new DummyComponent(objects)); _objectTable = new ObjectTable(objects); StateVectorLayout = SerializationRegistry.Default.GetStateVectorLayout(model, _objectTable, mode); _serializer = StateVectorLayout.CreateSerializer(_objectTable); _deserializer = StateVectorLayout.CreateDeserializer(_objectTable); _rangeRestrictor = StateVectorLayout.CreateRangeRestrictor(_objectTable); StateSlotCount = StateVectorLayout.SizeInBytes / 4; StateVectorSize = StateVectorLayout.SizeInBytes; _buffer = new MemoryBuffer(); _buffer.Resize(StateVectorSize, zeroMemory: true); SerializedState = _buffer.Pointer; Output.Log("{0}", StateVectorLayout); }
/// <summary> /// Initializes a new instance. /// </summary> /// <param name="serializedData">The serialized data describing the model.</param> /// <param name="stateHeaderBytes"> /// The number of bytes that should be reserved at the beginning of each state vector for the model checker tool. /// </param> internal SafetySharpRuntimeModel(SerializedRuntimeModel serializedData, int stateHeaderBytes = 0) : base(stateHeaderBytes) { Requires.That(serializedData.Model != null, "Expected a valid model instance."); var buffer = serializedData.Buffer; var rootComponents = serializedData.Model.Roots; var objectTable = serializedData.ObjectTable; var formulas = serializedData.Formulas; Requires.NotNull(buffer, nameof(buffer)); Requires.NotNull(rootComponents, nameof(rootComponents)); Requires.NotNull(objectTable, nameof(objectTable)); Requires.NotNull(formulas, nameof(formulas)); Requires.That(stateHeaderBytes % 4 == 0, nameof(stateHeaderBytes), "Expected a multiple of 4."); Model = serializedData.Model; SerializedModel = buffer; RootComponents = rootComponents.Cast <Component>().ToArray(); ExecutableStateFormulas = objectTable.OfType <ExecutableStateFormula>().ToArray(); Formulas = formulas; StateConstraints = Model.Components.Cast <Component>().SelectMany(component => component.StateConstraints).ToArray(); // Create a local object table just for the objects referenced by the model; only these objects // have to be serialized and deserialized. The local object table does not contain, for instance, // the closure types of the state formulas. Faults = objectTable.OfType <Fault>().Where(fault => fault.IsUsed).ToArray(); _serializedObjects = new ObjectTable(Model.ReferencedObjects); Objects = objectTable; StateVectorLayout = SerializationRegistry.Default.GetStateVectorLayout(Model, _serializedObjects, SerializationMode.Optimized); UpdateFaultSets(); _deserialize = StateVectorLayout.CreateDeserializer(_serializedObjects); _serialize = StateVectorLayout.CreateSerializer(_serializedObjects); _restrictRanges = StateVectorLayout.CreateRangeRestrictor(_serializedObjects); PortBinding.BindAll(objectTable); InitializeConstructionState(); CheckConsistencyAfterInitialization(); }
/// <summary> /// Initializes a new instance. /// </summary> /// <param name="layout">The layout of the state vector..</param> /// <param name="capacity">The capacity of the cache, i.e., the number of states that can be stored in the cache.</param> public StateStorage(StateVectorLayout layout, int capacity) { Requires.NotNull(layout, nameof(layout)); Requires.InRange(capacity, nameof(capacity), 1024, Int32.MaxValue); _stateVectorSize = layout.SizeInBytes; _capacity = capacity; _stateBuffer.Resize((long)_capacity * _stateVectorSize, zeroMemory: false); _stateMemory = _stateBuffer.Pointer; // We allocate enough space so that we can align the returned pointer such that index 0 is the start of a cache line _hashBuffer.Resize((long)_capacity * sizeof(int) + CacheLineSize, zeroMemory: true); _hashMemory = (int *)_hashBuffer.Pointer; if ((ulong)_hashMemory % CacheLineSize != 0) { _hashMemory = (int *)(_hashBuffer.Pointer + (CacheLineSize - (ulong)_hashBuffer.Pointer % CacheLineSize)); } Assert.InRange((ulong)_hashMemory - (ulong)_hashBuffer.Pointer, 0ul, (ulong)CacheLineSize); Assert.That((ulong)_hashMemory % CacheLineSize == 0, "Invalid buffer alignment."); }
/// <summary> /// Loads a counter example from the <paramref name="file" />. /// </summary> /// <param name="file">The path to the file the counter example should be loaded from.</param> public static CounterExample Load(string file) { Requires.NotNullOrWhitespace(file, nameof(file)); using (var reader = new BinaryReader(File.OpenRead(file), Encoding.UTF8)) { if (reader.ReadInt32() != FileHeader) throw new InvalidOperationException("The file does not contain a counter example that is compatible with this version of S#."); var endsWithException = reader.ReadBoolean(); var serializedRuntimeModel = reader.ReadBytes(reader.ReadInt32()); var modelData = RuntimeModelSerializer.LoadSerializedData(serializedRuntimeModel); foreach (var fault in modelData.ObjectTable.OfType<Fault>()) fault.Activation = (Activation)reader.ReadInt32(); var runtimeModel = new RuntimeModel(modelData); runtimeModel.UpdateFaultSets(); var metadataStream = new MemoryStream(reader.ReadBytes(reader.ReadInt32())); var formatter = new BinaryFormatter(); var slotMetadata = new StateVectorLayout((StateSlotMetadata[])formatter.Deserialize(metadataStream)); var modelMetadata = runtimeModel.StateVectorLayout; var counterExample = new byte[reader.ReadInt32()][]; var slotCount = reader.ReadInt32(); if (slotCount != runtimeModel.StateVectorSize) { throw new InvalidOperationException( $"State slot count mismatch; the instantiated model requires {runtimeModel.StateVectorSize} state slots, " + $"whereas the counter example uses {slotCount} state slots."); } if (slotMetadata.SlotCount != modelMetadata.SlotCount) { throw new InvalidOperationException( $"State slot metadata count mismatch; the instantiated model has {modelMetadata.SlotCount} state slot metadata entries, " + $"whereas the counter example has {slotMetadata.SlotCount} state slot entries."); } for (var i = 0; i < slotMetadata.SlotCount; ++i) { if (modelMetadata[i] != slotMetadata[i]) throw new StateVectorMismatchException(slotMetadata, modelMetadata); } for (var i = 0; i < counterExample.Length; ++i) { counterExample[i] = new byte[runtimeModel.StateVectorSize]; for (var j = 0; j < runtimeModel.StateVectorSize; ++j) counterExample[i][j] = reader.ReadByte(); } var replayInfo = new int[reader.ReadInt32()][]; for (var i = 0; i < replayInfo.Length; ++i) { replayInfo[i] = new int[reader.ReadInt32()]; for (var j = 0; j < replayInfo[i].Length; ++j) replayInfo[i][j] = reader.ReadInt32(); } return new CounterExample(runtimeModel, counterExample, replayInfo, endsWithException); } }
/// <summary> /// Generates the <see cref="StateVectorLayout" /> for the <paramref name="objects" />. /// </summary> /// <param name="model">The model the state vector should be layouted for.</param> /// <param name="objects">The objects consisting of state values the state vector layout should be generated for.</param> /// <param name="mode">The serialization mode that should be used to generate the state vector layout.</param> internal StateVectorLayout GetStateVectorLayout(ModelBase model, ObjectTable objects, SerializationMode mode) { Requires.NotNull(model, nameof(model)); Requires.NotNull(objects, nameof(objects)); Requires.InRange(mode, nameof(mode)); var layout = new StateVectorLayout(); foreach (var slot in objects.SelectMany(obj => GetSerializer(obj).GetStateSlotMetadata(obj, objects.GetObjectIdentifier(obj), mode))) layout.Add(slot); layout.Compact(model, mode); return layout; }
/// <summary> /// Serializes the <paramref name="model" />. /// </summary> private unsafe void SerializeModel(BinaryWriter writer, ModelBase model, Formula[] formulas) { // Collect all objects contained in the model var objectTable = CreateObjectTable(model, formulas); // Prepare the serialization of the model's initial state lock (_syncObject) { _stateVector = SerializationRegistry.Default.GetStateVectorLayout(model, objectTable, SerializationMode.Full); _deserializer = null; } var stateVectorSize = _stateVector.SizeInBytes; var serializer = _stateVector.CreateSerializer(objectTable); // Serialize the object table SerializeObjectTable(objectTable, writer); // Serialize the object identifier of the model itself and the formulas writer.Write(objectTable.GetObjectIdentifier(model)); writer.Write(formulas.Length); foreach (var formula in formulas) writer.Write(objectTable.GetObjectIdentifier(formula)); // Serialize the initial state var serializedState = stackalloc byte[stateVectorSize]; serializer(serializedState); // Copy the serialized state to the stream writer.Write(stateVectorSize); for (var i = 0; i < stateVectorSize; ++i) writer.Write(serializedState[i]); }
/// <summary> /// Deserializes a <see cref="RuntimeModel" /> from the <paramref name="reader" />. /// </summary> private unsafe SerializedRuntimeModel DeserializeModel(byte[] buffer, BinaryReader reader) { // Deserialize the object table var objectTable = DeserializeObjectTable(reader); // Deserialize the object identifiers of the model itself and the root formulas var model = (ModelBase)objectTable.GetObject(reader.ReadUInt16()); var formulas = new Formula[reader.ReadInt32()]; for (var i = 0; i < formulas.Length; ++i) formulas[i] = (Formula)objectTable.GetObject(reader.ReadUInt16()); // Copy the serialized initial state from the stream var stateVectorSize = reader.ReadInt32(); var serializedState = stackalloc byte[stateVectorSize]; for (var i = 0; i < stateVectorSize; ++i) serializedState[i] = reader.ReadByte(); // Deserialize the model's initial state OpenSerializationDelegate deserializer; lock (_syncObject) { if (_stateVector == null) _stateVector = SerializationRegistry.Default.GetStateVectorLayout(model, objectTable, SerializationMode.Full); if (_deserializer == null) _deserializer = _stateVector.CreateDeserializer(); deserializer = _deserializer; } deserializer(objectTable, serializedState); // We instantiate the runtime type for each component and replace the original component // instance with the new runtime instance; we also replace all of the component's fault effects // with that instance and deserialize the initial state again. Afterwards, we have completely // replaced the original instance with its runtime instance, taking over all serialized data objectTable.SubstituteRuntimeInstances(); deserializer(objectTable, serializedState); // We substitute the dummy delegate objects with the actual instances obtained from the DelegateMetadata instances objectTable.SubstituteDelegates(); deserializer(objectTable, serializedState); // Return the serialized model data return new SerializedRuntimeModel(model, buffer, objectTable, formulas); }
/// <summary> /// Loads a counter example from the <paramref name="file" />. /// </summary> /// <param name="file">The path to the file the counter example should be loaded from.</param> public static CounterExample Load(string file) { Requires.NotNullOrWhitespace(file, nameof(file)); using (var reader = new BinaryReader(File.OpenRead(file), Encoding.UTF8)) { if (reader.ReadInt32() != FileHeader) { throw new InvalidOperationException("The file does not contain a counter example that is compatible with this version of S#."); } var endsWithException = reader.ReadBoolean(); var serializedRuntimeModel = reader.ReadBytes(reader.ReadInt32()); var modelData = RuntimeModelSerializer.LoadSerializedData(serializedRuntimeModel); foreach (var fault in modelData.ObjectTable.OfType <Fault>()) { fault.Activation = (Activation)reader.ReadInt32(); } var runtimeModel = new RuntimeModel(modelData); var metadataStream = new MemoryStream(reader.ReadBytes(reader.ReadInt32())); var formatter = new BinaryFormatter(); var slotMetadata = new StateVectorLayout((StateSlotMetadata[])formatter.Deserialize(metadataStream)); var modelMetadata = runtimeModel.StateVectorLayout; var counterExample = new byte[reader.ReadInt32()][]; var slotCount = reader.ReadInt32(); if (slotCount != runtimeModel.StateVectorSize) { throw new InvalidOperationException( $"State slot count mismatch; the instantiated model requires {runtimeModel.StateVectorSize} state slots, " + $"whereas the counter example uses {slotCount} state slots."); } if (slotMetadata.SlotCount != modelMetadata.SlotCount) { throw new InvalidOperationException( $"State slot metadata count mismatch; the instantiated model has {modelMetadata.SlotCount} state slot metadata entries, " + $"whereas the counter example has {slotMetadata.SlotCount} state slot entries."); } for (var i = 0; i < slotMetadata.SlotCount; ++i) { if (modelMetadata[i] != slotMetadata[i]) { throw new StateVectorMismatchException(slotMetadata, modelMetadata); } } for (var i = 0; i < counterExample.Length; ++i) { counterExample[i] = new byte[runtimeModel.StateVectorSize]; for (var j = 0; j < runtimeModel.StateVectorSize; ++j) { counterExample[i][j] = reader.ReadByte(); } } var replayInfo = new int[reader.ReadInt32()][]; for (var i = 0; i < replayInfo.Length; ++i) { replayInfo[i] = new int[reader.ReadInt32()]; for (var j = 0; j < replayInfo[i].Length; ++j) { replayInfo[i][j] = reader.ReadInt32(); } } return(new CounterExample(runtimeModel, counterExample, replayInfo, endsWithException)); } }