void ActivityInstanceMap.IActivityReferenceWithEnvironment.UpdateEnvironment(EnvironmentUpdateMap map, Activity activity) { Fx.Assert(this.SubState != Substate.ResolvingVariables, "We must have already performed the same validations in advance."); Fx.Assert(this.SubState != Substate.ResolvingArguments, "We must have already performed the same validations in advance."); if (this.SerializedNoSymbols) { // create a new LocationReference and this ActivityInstance becomes the owner of the // created environment. var oldParentEnvironment = this.environment; Fx.Assert(oldParentEnvironment != null, "environment must never be null."); this.environment = new LocationEnvironment(oldParentEnvironment, map.NewArgumentCount + map.NewVariableCount + map.NewPrivateVariableCount + map.RuntimeDelegateArgumentCount); this.SerializedNoSymbols = false; // traverse the activity instance chain. Update all its non-environment-owning // decedent instances to point to the newly created enviroment, and, update all its // environment-owning decendent instances to have their environment's parent to // point to the newly created environment. UpdateLocationEnvironmentHierarchy(oldParentEnvironment, this.environment, this); } this.Environment.Update(map, activity); }
void CopyRuntimeDelegateArguments(EnvironmentUpdateMap map, Location[] newLocations) { for (int i = 1; i <= map.RuntimeDelegateArgumentCount; i++) { newLocations[newLocations.Length - i] = this.locations[this.locations.Length - i]; } }
private static bool IsInvalidEnvironmentUpdate(InstanceList instanceList, DynamicUpdateMap.UpdatedActivity updatedActivity, ref Collection <ActivityBlockingUpdate> updateErrors) { if (updatedActivity.MapEntry == null || !updatedActivity.MapEntry.HasEnvironmentUpdates) { return(false); } for (int j = 0; j < instanceList.Count; j++) { ActivityInstance activityInstance = instanceList[j] as ActivityInstance; if (activityInstance != null) { string error = null; if (activityInstance.SubState == ActivityInstance.Substate.ResolvingVariables) { // if the entry has Environment update to do when the instance is in the // middle of resolving variable, it is an error. error = SR.CannotUpdateEnvironmentInTheMiddleOfResolvingVariables; } else if (activityInstance.SubState == ActivityInstance.Substate.ResolvingArguments) { // if the entry has Environment update to do when the instance is in the // middle of resolving arguments, it is an error. error = SR.CannotUpdateEnvironmentInTheMiddleOfResolvingArguments; } if (error != null) { AddBlockingActivity(ref updateErrors, updatedActivity, new QualifiedId(instanceList.ActivityId), error, activityInstance.Id); return(true); } } else { LocationEnvironment environment = instanceList[j] as LocationEnvironment; if (environment != null) { // environment that is referenced by a secondary root Adding a variable or // argument that requires expression scheduling to this instanceless // environment is not allowed. List <int> dummyIndexes; EnvironmentUpdateMap envMap = updatedActivity.MapEntry.EnvironmentUpdateMap; if ((envMap.HasVariableEntries && TryGatherSchedulableExpressions(envMap.VariableEntries, out dummyIndexes)) || (envMap.HasPrivateVariableEntries && TryGatherSchedulableExpressions(envMap.PrivateVariableEntries, out dummyIndexes)) || (envMap.HasArgumentEntries && TryGatherSchedulableExpressions(envMap.ArgumentEntries, out dummyIndexes))) { AddBlockingActivity(ref updateErrors, updatedActivity, new QualifiedId(instanceList.ActivityId), SR.VariableOrArgumentAdditionToReferencedEnvironmentNoDUSupported, null); return(true); } } } } return(false); }
void UpdatePrivateVariables(EnvironmentUpdateMap map, Location[] newLocations, Activity activity) { UpdateVariables( map.NewArgumentCount + map.NewVariableCount, map.OldArgumentCount + map.OldVariableCount, map.NewPrivateVariableCount, map.OldPrivateVariableCount, map.PrivateVariableEntries, activity.ImplementationVariables, newLocations); }
void UpdatePublicVariables(EnvironmentUpdateMap map, Location[] newLocations, Activity activity) { UpdateVariables( map.NewArgumentCount, map.OldArgumentCount, map.NewVariableCount, map.OldVariableCount, map.VariableEntries, activity.RuntimeVariables, newLocations); }
void UnregisterRemovedVariables(EnvironmentUpdateMap map) { bool hasMappableLocationsRemaining = false; int offset = map.OldArgumentCount; FindVariablesToUnregister(false, map, map.OldVariableCount, offset, ref hasMappableLocationsRemaining); offset = map.OldArgumentCount + map.OldVariableCount; FindVariablesToUnregister(true, map, map.OldPrivateVariableCount, offset, ref hasMappableLocationsRemaining); this.hasMappableLocations = hasMappableLocationsRemaining; }
private void FindVariablesToUnregister(bool forImplementation, EnvironmentUpdateMap map, int oldVariableCount, int offset, ref bool hasMappableLocationsRemaining) { for (int i = 0; i < oldVariableCount; i++) { Location location = this.locations[i + offset]; if (location.CanBeMapped) { if ((forImplementation && map.GetNewPrivateVariableIndex(i).HasValue) || (!forImplementation && map.GetNewVariableIndex(i).HasValue)) { hasMappableLocationsRemaining = true; } else { ActivityUtilities.Add(ref this.locationsToUnregister, location); } } } }
void UpdateArguments(EnvironmentUpdateMap map, Location[] newLocations) { if (map.HasArgumentEntries) { for (int i = 0; i < map.ArgumentEntries.Count; i++) { EnvironmentUpdateMapEntry entry = map.ArgumentEntries[i]; Fx.Assert(entry.NewOffset >= 0 && entry.NewOffset < map.NewArgumentCount, "Argument offset is out of range"); if (entry.IsAddition) { // Location allocation will be performed later during ResolveDynamicallyAddedArguments(). // for now, simply assign a dummy location so we know not to copy over the old value. newLocations[entry.NewOffset] = dummyLocation; } else { Fx.Assert(this.locations != null && this.singleLocation == null, "Caller should have copied singleLocation into locations array"); // rearrangement of existing arguments // this entry here doesn't describe argument removal newLocations[entry.NewOffset] = this.locations[entry.OldOffset]; } } } // copy over unchanged Locations, and null out DummyLocations for (int i = 0; i < map.NewArgumentCount; i++) { if (newLocations[i] == null) { Fx.Assert(this.locations != null && this.locations.Length > i, "locations must be non-null and index i must be within the range of locations."); newLocations[i] = this.locations[i]; } else if (newLocations[i] == dummyLocation) { newLocations[i] = null; } } }
public void UpdateEnvironments(EnvironmentUpdateMap map, Activity activity) { if (base.SingleItem != null) { IActivityReferenceWithEnvironment reference = base.SingleItem as IActivityReferenceWithEnvironment; if (reference != null) { reference.UpdateEnvironment(map, activity); } } else { for (int i = 0; i < base.MultipleItems.Count; i++) { IActivityReferenceWithEnvironment reference = base.MultipleItems[i] as IActivityReferenceWithEnvironment; if (reference != null) { reference.UpdateEnvironment(map, activity); } } } }
// this is called after all instances have been loaded and fixedup public void UpdateInstanceByActivityParticipation(ActivityExecutor activityExecutor, DynamicUpdateMap rootMap, ref Collection <ActivityBlockingUpdate> updateErrors) { foreach (InstanceListNeedingUpdate participant in this.updateList) { if (participant.NothingChanged || participant.ParentIdShiftOnly) { Fx.Assert(participant.UpdateMap == null && participant.MapEntry == null, "UpdateMap and MapEntry must be null if we are here."); // create a temporary NoChanges UpdateMap as well as a temporary no change MapEntry // so that we can create a NativeActivityUpdateContext object in order to invoke UpdateInstance() on an activity which // doesn't have a corresponding map and an map entry. // The scenario enabled here is scheduling a newly added reference branch to a Parallel inside an activity's implementation. participant.UpdateMap = DynamicUpdateMap.DummyMap; participant.MapEntry = DynamicUpdateMapEntry.DummyMapEntry; } // now let activities participate in update for (int i = 0; i < participant.InstanceList.Count; i++) { ActivityInstance instance = participant.InstanceList[i] as ActivityInstance; if (instance == null) { continue; } IInstanceUpdatable activity = instance.Activity as IInstanceUpdatable; if (activity != null && instance.SubState == ActivityInstance.Substate.Executing) { NativeActivityUpdateContext updateContext = new NativeActivityUpdateContext(this, activityExecutor, instance, participant.UpdateMap, participant.MapEntry, rootMap); try { activity.InternalUpdateInstance(updateContext); if (updateContext.IsUpdateDisallowed) { ActivityBlockingUpdate.AddBlockingActivity(ref updateErrors, instance.Activity, new QualifiedId(participant.OriginalId).ToString(), updateContext.DisallowedReason, instance.Id); continue; } } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } throw FxTrace.Exception.AsError(new InstanceUpdateException(SR.NativeActivityUpdateInstanceThrewException(e.Message), e)); } finally { updateContext.Dispose(); } } } } // Schedule evaluation of newly added arguments and newly added variables. // This needs to happen after all the invokations of UpdateInstance above, so that newly // added arguments and newly added variables get evaluated before any newly added activities get executed. // We iterate the list in reverse so that parents are always scheduled after (and thus // execute before) their children, which may depend on the parents. for (int i = this.updateList.Count - 1; i >= 0; i--) { InstanceListNeedingUpdate participant = this.updateList[i]; if (!participant.MapEntryExists) { // if the given InstanceList has no map entry, // then there is no new LocationReferences to resolve. continue; } Fx.Assert(participant.MapEntry != null, "MapEntry must be non-null here."); if (!participant.MapEntry.HasEnvironmentUpdates) { // if there is no environment updates for this MapEntry, // then there is no new LocationReferences to resolve. continue; } for (int j = 0; j < participant.InstanceList.Count; j++) { ActivityInstance instance = participant.InstanceList[j] as ActivityInstance; if (instance == null || instance.SubState != ActivityInstance.Substate.Executing) { // if the given ActivityInstance is not in Substate.Executing, // then, do not try to resolve new LocationReferences continue; } List <int> addedArgumentIndexes; List <int> addedVariableIndexes; List <int> addedPrivateVariableIndexes; EnvironmentUpdateMap envMap = participant.MapEntry.EnvironmentUpdateMap; if (envMap.HasVariableEntries && TryGatherSchedulableExpressions(envMap.VariableEntries, out addedVariableIndexes)) { // schedule added variable default expressions instance.ResolveNewVariableDefaultsDuringDynamicUpdate(activityExecutor, addedVariableIndexes, false); } if (envMap.HasPrivateVariableEntries && TryGatherSchedulableExpressions(envMap.PrivateVariableEntries, out addedPrivateVariableIndexes)) { // schedule added private variable default expressions // HasPrivateMemberChanged() check disallows addition of private variable default that offsets the private IdSpace, // However, the added private variable default expression can be an imported activity, which has no affect on the private IdSpace. // For such case, we want to be able to schedule the imported default expressions here. instance.ResolveNewVariableDefaultsDuringDynamicUpdate(activityExecutor, addedPrivateVariableIndexes, true); } if (envMap.HasArgumentEntries && TryGatherSchedulableExpressions(envMap.ArgumentEntries, out addedArgumentIndexes)) { // schedule added arguments instance.ResolveNewArgumentsDuringDynamicUpdate(activityExecutor, addedArgumentIndexes); } } } }
internal void Update(EnvironmentUpdateMap map, Activity activity) { // arguments public variables private variables RuntimeDelegateArguments // Locations array: AAAAAAAAAA VVVVVVVVVVVVVVVVVVVVVV PPPPPPPPPPPPPPPPPPP DDDDDDDDDDDDDDDDDDDDDDDDDDDDDD int actualRuntimeDelegateArgumentCount = activity.HandlerOf == null ? 0 : activity.HandlerOf.RuntimeDelegateArguments.Count; if (map.NewArgumentCount != activity.RuntimeArguments.Count || map.NewVariableCount != activity.RuntimeVariables.Count || map.NewPrivateVariableCount != activity.ImplementationVariables.Count || map.RuntimeDelegateArgumentCount != actualRuntimeDelegateArgumentCount) { throw FxTrace.Exception.AsError(new InstanceUpdateException(SR.InvalidUpdateMap( SR.WrongEnvironmentCount(activity, map.NewArgumentCount, map.NewVariableCount, map.NewPrivateVariableCount, map.RuntimeDelegateArgumentCount, activity.RuntimeArguments.Count, activity.RuntimeVariables.Count, activity.ImplementationVariables.Count, actualRuntimeDelegateArgumentCount)))); } int expectedLocationCount = map.OldArgumentCount + map.OldVariableCount + map.OldPrivateVariableCount + map.RuntimeDelegateArgumentCount; int actualLocationCount; if (this.locations == null) { if (this.singleLocation == null) { // we can hit this condition when the root activity instance has zero symbol. actualLocationCount = 0; } else { actualLocationCount = 1; // temporarily normalize to locations array for the sake of environment update processing this.locations = new Location[] { this.singleLocation }; this.singleLocation = null; } } else { Fx.Assert(this.singleLocation == null, "locations and singleLocations cannot be non-null at the same time."); actualLocationCount = this.locations.Length; } if (expectedLocationCount != actualLocationCount) { throw FxTrace.Exception.AsError(new InstanceUpdateException(SR.InvalidUpdateMap( SR.WrongOriginalEnvironmentCount(activity, map.OldArgumentCount, map.OldVariableCount, map.OldPrivateVariableCount, map.RuntimeDelegateArgumentCount, expectedLocationCount, actualLocationCount)))); } Location[] newLocations = null; // If newTotalLocations == 0, update will leave us with an empty LocationEnvironment, // which is something the runtime would normally never create. This is harmless, but it // is a loosening of normal invariants. int newTotalLocations = map.NewArgumentCount + map.NewVariableCount + map.NewPrivateVariableCount + map.RuntimeDelegateArgumentCount; if (newTotalLocations > 0) { newLocations = new Location[newTotalLocations]; } UpdateArguments(map, newLocations); UnregisterRemovedVariables(map); UpdatePublicVariables(map, newLocations, activity); UpdatePrivateVariables(map, newLocations, activity); CopyRuntimeDelegateArguments(map, newLocations); Location newSingleLocation = null; if (newTotalLocations == 1) { newSingleLocation = newLocations[0]; newLocations = null; } this.singleLocation = newSingleLocation; this.locations = newLocations; }
void ActivityInstanceMap.IActivityReferenceWithEnvironment.UpdateEnvironment(EnvironmentUpdateMap map, Activity activity) { // LocationEnvironment.Update() is invoked through this path when this is a seondary root's environment(and in its parent chain) whose owner has already completed. this.Update(map, activity); }