diff --git a/src/Engine/ProtoAssociative/CodeGen.cs b/src/Engine/ProtoAssociative/CodeGen.cs index 44730a17558..63132231905 100644 --- a/src/Engine/ProtoAssociative/CodeGen.cs +++ b/src/Engine/ProtoAssociative/CodeGen.cs @@ -5415,11 +5415,24 @@ private void EmitBinaryExpressionNode(AssociativeNode node, ref ProtoCore.Type i if (bnode.IsInputExpression) { + + // Emit the following instructions: + // pop lx + // <-- mark this pc as graphnode's start pc if pushed value is a primitive + // push lx + StackValue regLX = StackValue.BuildRegister(Registers.LX); EmitInstrConsole(kw.pop, kw.regLX); EmitPopUpdateInstruction(regLX, bnode.OriginalAstID); - graphNode.updateBlock.updateRegisterStartPC = pc; + // In the case of the RHS being a primitive, we can skip executing instructions + // to push the updated value and pop it to the register as the register is directly updated. + // In the case of a non-primitive, we let these instructions execute, so that the + // updated result from the VM can be pushed and popped to update the register. + if (CoreUtils.IsPrimitiveASTNode(bnode.RightNode)) + { + graphNode.updateBlock.updateRegisterStartPC = pc; + } EmitInstrConsole(kw.push, kw.regLX); EmitPushUpdateInstruction(regLX, bnode.OriginalAstID); diff --git a/src/Engine/ProtoScript/Runners/LiveRunner.cs b/src/Engine/ProtoScript/Runners/LiveRunner.cs index 81ecc4b1429..cf5f5b8d8e7 100644 --- a/src/Engine/ProtoScript/Runners/LiveRunner.cs +++ b/src/Engine/ProtoScript/Runners/LiveRunner.cs @@ -261,8 +261,8 @@ private void ApplyChangeSetForceExecute(ChangeSetData changeSet) if (changeSet.ForceExecuteASTList.Count > 0) { // Mark all graphnodes dirty which are associated with the force exec ASTs - ProtoCore.AssociativeGraph.GraphNode firstDirtyNode = ProtoCore.AssociativeEngine.Utils.MarkGraphNodesDirtyAtGlobalScope -(runtimeCore, changeSet.ForceExecuteASTList); + var firstDirtyNode = ProtoCore.AssociativeEngine.Utils.MarkGraphNodesDirtyAtGlobalScope( + runtimeCore, changeSet.ForceExecuteASTList); Validity.Assert(firstDirtyNode != null); // If the only ASTs to execute are force exec, then set the entrypoint here. @@ -755,18 +755,19 @@ private void UpdateCachedASTList(Subtree st, List modifiedASTLi } else { + var unmodifiedASTs = GetUnmodifiedASTList(oldSubTree.AstNodes, st.AstNodes); if (st.ForceExecution) { // Get the cached AST and append it to the changeSet - csData.ForceExecuteASTList.AddRange(GetUnmodifiedASTList(oldSubTree.AstNodes, st.AstNodes)); + csData.ForceExecuteASTList.AddRange(unmodifiedASTs); } // Update the cached AST to reflect the change List newCachedASTList = new List(); - // Get all the unomodified ASTs and append them to the cached ast list - newCachedASTList.AddRange(GetUnmodifiedASTList(oldSubTree.AstNodes, st.AstNodes)); + // Get all the unmodified ASTs and append them to the cached ast list + newCachedASTList.AddRange(unmodifiedASTs); // Append all the modified ASTs to the cached ast list newCachedASTList.AddRange(modifiedASTList); @@ -809,6 +810,7 @@ private IEnumerable GetDeltaAstListModified(List modif if (!modifiedSubTree.IsInput) { redefinitionAllowed = false; + break; } } diff --git a/test/DynamoCoreTests/UpdateInputNodeModelTest.cs b/test/DynamoCoreTests/UpdateInputNodeModelTest.cs new file mode 100644 index 00000000000..f04602bfe9d --- /dev/null +++ b/test/DynamoCoreTests/UpdateInputNodeModelTest.cs @@ -0,0 +1,51 @@ +using NUnit.Framework; +using System.Collections.Generic; +using System.IO; + +namespace Dynamo.Tests +{ + [TestFixture] + internal class UpdateInputNodeModelTest : DynamoModelTestBase + { + protected override void GetLibrariesToPreload(List libraries) + { + libraries.Add("DesignScriptBuiltin.dll"); + libraries.Add("DSCoreNodes.dll"); + + base.GetLibrariesToPreload(libraries); + } + + [Test] + public void TestUpdateInputNodeModel() + { + // DYN file contains nodemodel node that reads an image from hardcoded file name and returns a bitmap + string openPath = Path.Combine(TestDirectory, @"core\astbuilder\updateInputNodeModel.dyn"); + RunModel(openPath); + + // Assert on one of the color values belonging to the image read + var guid = "313bc594-8879-492b-aa99-8efc61c5707a"; + AssertPreviewValue(guid, 91); + + // Create backup of original file + var originalFile = Path.Combine(TestDirectory, @"core\astbuilder\hardcoded_image_file.jpg"); + var backupFile = Path.Combine(TestDirectory, @"core\astbuilder\hardcoded_image_file - Copy.jpg"); + File.Copy(originalFile, backupFile); + + // Overwrite the file "harcoded_image_file.jpg" with the file "harcoded_image_file2.jpg" + var path = Path.Combine(TestDirectory, @"core\astbuilder\hardcoded_image_file2.jpg"); + File.Copy(path, originalFile, true); + + // Force re-execute the nodemodel node + var guid2 = "a787e45f-f6ed-439f-9eb3-60008b4c8a72"; + var nodeModel = CurrentDynamoModel.CurrentWorkspace.NodeFromWorkspace(guid2); + nodeModel.OnNodeModified(true); + + File.Delete(originalFile); + // restore the file, "harcoded_image_file.jpg" + File.Move(backupFile, originalFile); + + // Assert that the same color value has changed as the file is now pointing to a different image + AssertPreviewValue(guid, 41); + } + } +} diff --git a/test/TestUINodes/TestUINodes.cs b/test/TestUINodes/TestUINodes.cs index 31fd30eecc8..ac1c02d7d3b 100644 --- a/test/TestUINodes/TestUINodes.cs +++ b/test/TestUINodes/TestUINodes.cs @@ -1,9 +1,13 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Drawing; using Autodesk.DesignScript.Runtime; using Dynamo.Graph.Nodes; using Newtonsoft.Json; using ProtoCore.AST.AssociativeAST; +using DSCore.IO; namespace TestUINodes { @@ -28,4 +32,52 @@ public override IEnumerable BuildOutputAst(List inPorts, IEnumerable outPorts) : base(inPorts, outPorts) + { + } + + public override IEnumerable BuildOutputAst(List inputAstNodes) + { + var executingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + var directory = new DirectoryInfo(executingDirectory); + var testDirectory = Path.Combine(directory.Parent.Parent.Parent.Parent.FullName, "test/core/astbuilder"); + + string imagePath = Path.Combine(testDirectory, "hardcoded_image_file.jpg"); + var func1 = + AstFactory.BuildFunctionCall( + new Func(FileSystem.FileFromPath), + new List { AstFactory.BuildStringNode(imagePath) }); + + var func2 = AstFactory.BuildFunctionCall( + new Func(DSCore.IO.Image.ReadFromFile), new List { func1 }); + + // returns an identifier that is assigned to a bitmap upon the call to Image.ReadFromFile. + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), func2), + + }; + } + } } diff --git a/test/TestUINodes/TestUINodes.csproj b/test/TestUINodes/TestUINodes.csproj index bc1cf28f82d..b5c1d0256cc 100644 --- a/test/TestUINodes/TestUINodes.csproj +++ b/test/TestUINodes/TestUINodes.csproj @@ -33,6 +33,7 @@ False DynamoCore + {6E0A079E-85F1-45A1-AD5B-9855E4344809} Units diff --git a/test/core/astbuilder/hardcoded_image_file.JPG b/test/core/astbuilder/hardcoded_image_file.JPG new file mode 100644 index 00000000000..14ec935e43d Binary files /dev/null and b/test/core/astbuilder/hardcoded_image_file.JPG differ diff --git a/test/core/astbuilder/hardcoded_image_file2.JPG b/test/core/astbuilder/hardcoded_image_file2.JPG new file mode 100644 index 00000000000..f6621b5fd4c Binary files /dev/null and b/test/core/astbuilder/hardcoded_image_file2.JPG differ diff --git a/test/core/astbuilder/updateInputNodeModel.dyn b/test/core/astbuilder/updateInputNodeModel.dyn new file mode 100644 index 00000000000..6d3c8434ade --- /dev/null +++ b/test/core/astbuilder/updateInputNodeModel.dyn @@ -0,0 +1,336 @@ +{ + "Uuid": "502d8b9f-05a3-41df-bc80-1a1b0c29ebf1", + "IsCustomNode": false, + "Description": "", + "Name": "updateInputNodeModel", + "ElementResolver": { + "ResolutionMap": {} + }, + "Inputs": [], + "Outputs": [], + "Nodes": [ + { + "ConcreteType": "TestUINodes.TestSelectionNode, TestUINodes", + "NodeType": "ExtensionNode", + "Id": "a787e45ff6ed439f9eb360008b4c8a72", + "Inputs": [], + "Outputs": [ + { + "Id": "dfcd893f19b5426397b4ef310290de4e", + "Name": "File", + "Description": "The selected file.", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Replication": "Disabled", + "Description": "A test selection node." + }, + { + "ConcreteType": "CoreNodeModels.WatchImageCore, CoreNodeModels", + "NodeType": "ExtensionNode", + "Id": "4d5f199ce95644e4a687d7cd096f1e20", + "Inputs": [ + { + "Id": "3d9d5d1b316f436d9b7893d3adb8099e", + "Name": "image", + "Description": "Image for visualization", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Outputs": [ + { + "Id": "9e271acee2e049a9bf536de17fb8647a", + "Name": "image", + "Description": "Image for visualization", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Replication": "Disabled", + "Description": "Previews an image" + }, + { + "ConcreteType": "Dynamo.Graph.Nodes.ZeroTouch.DSFunction, DynamoCore", + "NodeType": "FunctionNode", + "FunctionSignature": "DSCore.IO.Image.Pixels@var,int,int", + "Id": "7be24c8b4762488484ee4ddd38d07aa5", + "Inputs": [ + { + "Id": "c050353a2f9c4d4a9d38931ed48c8869", + "Name": "image", + "Description": "Image object to get pixel colors from\n\nvar", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + }, + { + "Id": "635e1ca0d6544a1c9b617c436f0b1b3e", + "Name": "xSamples", + "Description": "Number of sample grid points in the X direction.\n\nint", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + }, + { + "Id": "dec0cfda0e834a129c6004c93eb68501", + "Name": "ySamples", + "Description": "Number of sample grid points in the Y direction.\n\nint", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Outputs": [ + { + "Id": "45baaad36aca4d9cbbfc504dbee7f26d", + "Name": "colors", + "Description": "Colors at the specified grid points", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Replication": "Auto", + "Description": "Reads an image file and returns the color values at the specified grid locations.\n\nImage.Pixels (image: var, xSamples: int, ySamples: int): Color[][]" + }, + { + "ConcreteType": "Dynamo.Graph.Nodes.CodeBlockNodeModel, DynamoCore", + "NodeType": "CodeBlockNode", + "Code": "2;", + "Id": "8376d15688054d2d81cdc2f858b35c35", + "Inputs": [], + "Outputs": [ + { + "Id": "c6e500c7defc4d8b8ba4f2db87f908ad", + "Name": "", + "Description": "Value of expression at line 1", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Replication": "Disabled", + "Description": "Allows for DesignScript code to be authored directly" + }, + { + "ConcreteType": "Dynamo.Graph.Nodes.CodeBlockNodeModel, DynamoCore", + "NodeType": "CodeBlockNode", + "Code": "a[0][0];", + "Id": "47713c3eb6174119877aac2c6052b35f", + "Inputs": [ + { + "Id": "727aeb4604604fd0ac2276d99ea76d3e", + "Name": "a", + "Description": "a", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Outputs": [ + { + "Id": "cfb85ae489604913b30d258673260373", + "Name": "", + "Description": "Value of expression at line 1", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Replication": "Disabled", + "Description": "Allows for DesignScript code to be authored directly" + }, + { + "ConcreteType": "Dynamo.Graph.Nodes.ZeroTouch.DSFunction, DynamoCore", + "NodeType": "FunctionNode", + "FunctionSignature": "DSCore.Color.Red", + "Id": "313bc5948879492baa998efc61c5707a", + "Inputs": [ + { + "Id": "457fad8c8ace482699772bbd30292524", + "Name": "color", + "Description": "DSCore.Color", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Outputs": [ + { + "Id": "10f6ef45b5884967b8d486b4b2fdecd5", + "Name": "int", + "Description": "Red value for RGB color model, int between 0 and 255 inclusive.", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Replication": "Auto", + "Description": "Find the red component of a color, 0 to 255.\n\nColor.Red: int" + } + ], + "Connectors": [ + { + "Start": "dfcd893f19b5426397b4ef310290de4e", + "End": "3d9d5d1b316f436d9b7893d3adb8099e", + "Id": "50f98659721645439f5cf1adb3790860", + "IsHidden": "False" + }, + { + "Start": "9e271acee2e049a9bf536de17fb8647a", + "End": "c050353a2f9c4d4a9d38931ed48c8869", + "Id": "cb50a403c3a94d82ac51ef64794ea771", + "IsHidden": "False" + }, + { + "Start": "45baaad36aca4d9cbbfc504dbee7f26d", + "End": "727aeb4604604fd0ac2276d99ea76d3e", + "Id": "841c086d1ff44a3da084cb50e475bf11", + "IsHidden": "False" + }, + { + "Start": "c6e500c7defc4d8b8ba4f2db87f908ad", + "End": "635e1ca0d6544a1c9b617c436f0b1b3e", + "Id": "5e0be313ff40483bb99783554681455d", + "IsHidden": "False" + }, + { + "Start": "c6e500c7defc4d8b8ba4f2db87f908ad", + "End": "dec0cfda0e834a129c6004c93eb68501", + "Id": "f0ab6b17b65f4e17a1faf81ba6cda68c", + "IsHidden": "False" + }, + { + "Start": "cfb85ae489604913b30d258673260373", + "End": "457fad8c8ace482699772bbd30292524", + "Id": "6295fb4c46fb45e19f80f362def9fb68", + "IsHidden": "False" + } + ], + "Dependencies": [], + "NodeLibraryDependencies": [], + "Thumbnail": "", + "GraphDocumentationURL": null, + "ExtensionWorkspaceData": [ + { + "ExtensionGuid": "28992e1d-abb9-417f-8b1b-05e053bee670", + "Name": "Properties", + "Version": "2.16", + "Data": {} + } + ], + "Author": "", + "Linting": { + "activeLinter": "None", + "activeLinterId": "7b75fb44-43fd-4631-a878-29f4d5d8399a", + "warningCount": 0, + "errorCount": 0 + }, + "Bindings": [], + "View": { + "Dynamo": { + "ScaleFactor": 1.0, + "HasRunWithoutCrash": true, + "IsVisibleInDynamoLibrary": true, + "Version": "2.16.0.2070", + "RunType": "Automatic", + "RunPeriod": "1000" + }, + "Camera": { + "Name": "Background Preview", + "EyeX": -17.0, + "EyeY": 24.0, + "EyeZ": 50.0, + "LookX": 12.0, + "LookY": -13.0, + "LookZ": -58.0, + "UpX": 0.0, + "UpY": 1.0, + "UpZ": 0.0 + }, + "ConnectorPins": [], + "NodeViews": [ + { + "Name": "Test Selection Node", + "ShowGeometry": true, + "Id": "a787e45ff6ed439f9eb360008b4c8a72", + "IsSetAsInput": true, + "IsSetAsOutput": false, + "Excluded": false, + "X": -1586.2977129538247, + "Y": -361.78956205231162 + }, + { + "Name": "Watch Image", + "ShowGeometry": true, + "Id": "4d5f199ce95644e4a687d7cd096f1e20", + "IsSetAsInput": false, + "IsSetAsOutput": false, + "Excluded": false, + "X": -1316.8458459770434, + "Y": -366.14455060208917 + }, + { + "Name": "Image.Pixels", + "ShowGeometry": true, + "Id": "7be24c8b4762488484ee4ddd38d07aa5", + "IsSetAsInput": false, + "IsSetAsOutput": false, + "Excluded": false, + "X": -322.27598640213671, + "Y": -4.3990790919472147 + }, + { + "Name": "Code Block", + "ShowGeometry": true, + "Id": "8376d15688054d2d81cdc2f858b35c35", + "IsSetAsInput": false, + "IsSetAsOutput": false, + "Excluded": false, + "X": -593.16362103833194, + "Y": 117.04036421725289 + }, + { + "Name": "Code Block", + "ShowGeometry": true, + "Id": "47713c3eb6174119877aac2c6052b35f", + "IsSetAsInput": false, + "IsSetAsOutput": false, + "Excluded": false, + "X": 5.9021652486715084, + "Y": 25.643674731481269 + }, + { + "Name": "Color.Red", + "ShowGeometry": true, + "Id": "313bc5948879492baa998efc61c5707a", + "IsSetAsInput": false, + "IsSetAsOutput": false, + "Excluded": false, + "X": 316.30659336161148, + "Y": 28.955493733475237 + } + ], + "Annotations": [], + "X": 997.73265257897538, + "Y": 377.75657373516856, + "Zoom": 0.61005739633638678 + } +} \ No newline at end of file