From 93eb96d6891e2c8bb2bff47ef93746543fe191d6 Mon Sep 17 00:00:00 2001 From: yuri-kiss <135030944+yuri-kiss@users.noreply.github.com> Date: Mon, 3 Feb 2025 15:30:13 -0500 Subject: [PATCH 1/5] Use a function instead --- src/compiler/jsgen.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index 914e5cc72b1..23a9e8be865 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -1333,7 +1333,7 @@ class JSGenerator { for (const inputName of Object.keys(node.inputs)) { const input = node.inputs[inputName]; const compiledInput = this.descendInput(input).asSafe(); - result += `"${sanitize(inputName)}":${compiledInput},`; + result += `"${sanitize(inputName)}":(function*(){ return( ${compiledInput} ); }),`; } for (const fieldName of Object.keys(node.fields)) { const field = node.fields[fieldName]; @@ -1445,7 +1445,8 @@ JSGenerator.unstable_exports = { ConstantInput, VariableInput, Frame, - sanitize + sanitize, + jsexecute }; // Test hook used by automated snapshot testing. From f1c0746d38c6f16fc6cda49efb1640222a63f9e9 Mon Sep 17 00:00:00 2001 From: yuri-kiss <135030944+yuri-kiss@users.noreply.github.com> Date: Mon, 3 Feb 2025 15:40:31 -0500 Subject: [PATCH 2/5] Allow reevaluation of arguments --- src/compiler/jsexecute.js | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/compiler/jsexecute.js b/src/compiler/jsexecute.js index b7bff8956ad..fc3f6cd7871 100644 --- a/src/compiler/jsexecute.js +++ b/src/compiler/jsexecute.js @@ -135,6 +135,7 @@ const isPromise = value => ( typeof value.then === 'function' ); const executeInCompatibilityLayer = function*(inputs, blockFunction, isWarp, useFlags, blockId, branchInfo) { + const inputNames = new Set(Object.keys(inputs)); const thread = globalState.thread; const blockUtility = globalState.blockUtility; const stackFrame = branchInfo ? branchInfo.stackFrame : {}; @@ -151,12 +152,32 @@ const executeInCompatibilityLayer = function*(inputs, blockFunction, isWarp, use return returnValue; }; - const executeBlock = () => { + const inputCache = {}; + let firstRun = true; + const executeBlock = function*() { + let callInputs, reEvaluate = new Set(); + if (firstRun || blockUtility._forceRevaluationOfArguments) { + firstRun = false; + if (blockUtility._forceRevaluationOfArguments) { + if (Array.isArray(blockUtility._forceRevaluationOfArguments)) { + reEvaluate = new Set(blockUtility._forceRevaluationOfArguments); + } else { + reEvaluate = inputNames; + } + blockUtility._forceRevaluationOfArguments = false; + callInputs = {}; + } + for (const inputName of reEvaluate) { + const inputValue = yield* (inputs[inputName]()); + inputCache[inputName] = inputValue; + if (callInputs) callInputs[inputName] = inputValue; + } + } blockUtility.init(thread, blockId, stackFrame); - return blockFunction(inputs, blockUtility); + return blockFunction(callInputs || inputCache, blockUtility); }; - let returnValue = executeBlock(); + let returnValue = yield* executeBlock(); if (isPromise(returnValue)) { returnValue = finish(yield* waitPromise(returnValue)); if (useFlags) hasResumedFromPromise = true; @@ -183,7 +204,7 @@ const executeInCompatibilityLayer = function*(inputs, blockFunction, isWarp, use yield; } - returnValue = executeBlock(); + returnValue = yield* executeBlock(); if (isPromise(returnValue)) { returnValue = finish(yield* waitPromise(returnValue)); if (useFlags) hasResumedFromPromise = true; From 25dbff394383cbe14d97c9ecb1b3e47e90de0596 Mon Sep 17 00:00:00 2001 From: yuri-kiss <135030944+yuri-kiss@users.noreply.github.com> Date: Mon, 3 Feb 2025 15:41:24 -0500 Subject: [PATCH 3/5] Add _forceRevaluationOfArguments --- src/compiler/compat-block-utility.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/compat-block-utility.js b/src/compiler/compat-block-utility.js index 6fedba1d9d2..b42c09aa09d 100644 --- a/src/compiler/compat-block-utility.js +++ b/src/compiler/compat-block-utility.js @@ -33,6 +33,7 @@ class CompatibilityLayerBlockUtility extends BlockUtility { this.thread = thread; this.sequencer = thread.target.runtime.sequencer; this._startedBranch = null; + this._forceRevaluationOfArguments = false; thread.stack[0] = fakeBlockId; thread.compatibilityStackFrame = stackFrame; } From 8deeadb32c9c1c263856a2e1c8b8520c84721ac6 Mon Sep 17 00:00:00 2001 From: yuri-kiss <135030944+yuri-kiss@users.noreply.github.com> Date: Mon, 3 Feb 2025 16:22:23 -0500 Subject: [PATCH 4/5] Fix initial run not caching --- src/compiler/jsexecute.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/compiler/jsexecute.js b/src/compiler/jsexecute.js index fc3f6cd7871..ee3d623e706 100644 --- a/src/compiler/jsexecute.js +++ b/src/compiler/jsexecute.js @@ -157,7 +157,11 @@ const executeInCompatibilityLayer = function*(inputs, blockFunction, isWarp, use const executeBlock = function*() { let callInputs, reEvaluate = new Set(); if (firstRun || blockUtility._forceRevaluationOfArguments) { - firstRun = false; + if (firstRun) { + blockUtility._forceRevaluationOfArguments = false; + reEvaluate = inputNames; + firstRun = false; + } if (blockUtility._forceRevaluationOfArguments) { if (Array.isArray(blockUtility._forceRevaluationOfArguments)) { reEvaluate = new Set(blockUtility._forceRevaluationOfArguments); @@ -168,6 +172,7 @@ const executeInCompatibilityLayer = function*(inputs, blockFunction, isWarp, use callInputs = {}; } for (const inputName of reEvaluate) { + if (!inputNames.has(inputName)) continue; const inputValue = yield* (inputs[inputName]()); inputCache[inputName] = inputValue; if (callInputs) callInputs[inputName] = inputValue; From b3f9ea6188ea1cc26ff980000262acb3ea08b644 Mon Sep 17 00:00:00 2001 From: yuri-kiss <135030944+yuri-kiss@users.noreply.github.com> Date: Mon, 3 Feb 2025 16:50:37 -0500 Subject: [PATCH 5/5] Only re-evaluate an argument if it is a function --- src/compiler/jsexecute.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compiler/jsexecute.js b/src/compiler/jsexecute.js index ee3d623e706..18ac1edabc4 100644 --- a/src/compiler/jsexecute.js +++ b/src/compiler/jsexecute.js @@ -173,7 +173,9 @@ const executeInCompatibilityLayer = function*(inputs, blockFunction, isWarp, use } for (const inputName of reEvaluate) { if (!inputNames.has(inputName)) continue; - const inputValue = yield* (inputs[inputName]()); + const inputValue = ( + typeof inputs[inputName] === 'function' + ) ? (yield* (inputs[inputName]())) : inputs[inputName]; inputCache[inputName] = inputValue; if (callInputs) callInputs[inputName] = inputValue; }