From 89873308531b8be701292fbbe8af65546fc17279 Mon Sep 17 00:00:00 2001 From: Tim Mickel Date: Thu, 15 Sep 2016 13:51:40 -0400 Subject: [PATCH] Cleanly handle deleting running scripts (#162) * Cleanly handle deleting running scripts * Turn off glow request on retire thread; add null check --- src/engine/blocks.js | 4 ++++ src/engine/execute.js | 7 +++++++ src/engine/runtime.js | 17 ++++++++++++++++- src/engine/sequencer.js | 1 + 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/engine/blocks.js b/src/engine/blocks.js index b3d87e49f..99f52477d 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -185,6 +185,10 @@ Blocks.prototype.blocklyListen = function (e, isFlyout, opt_runtime) { if (this._blocks[e.blockId].shadow) { return; } + // Inform any runtime to forget about glows on this script. + if (opt_runtime && this._blocks[e.blockId].topLevel) { + opt_runtime.quietGlow(e.blockId); + } this.deleteBlock({ id: e.blockId }); diff --git a/src/engine/execute.js b/src/engine/execute.js index 2dfc075f5..7754852e9 100644 --- a/src/engine/execute.js +++ b/src/engine/execute.js @@ -22,6 +22,13 @@ var execute = function (sequencer, thread) { var currentBlockId = thread.peekStack(); var currentStackFrame = thread.peekStackFrame(); + // Verify that the block still exists. + if (!target || + typeof target.blocks.getBlock(currentBlockId) === 'undefined') { + // No block found: stop the thread; script no longer exists. + sequencer.retireThread(thread); + return; + } // Query info about the block. var opcode = target.blocks.getOpcode(currentBlockId); var blockFunction = runtime.getOpcodeFunction(opcode); diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 6c5f36eb1..b085dd3d9 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -383,7 +383,9 @@ Runtime.prototype._updateScriptGlows = function () { if (thread.requestScriptGlowInFrame && target == this._editingTarget) { var blockForThread = thread.peekStack() || thread.topBlock; var script = target.blocks.getTopLevelScript(blockForThread); - requestedGlowsThisFrame.push(script); + if (script) { + requestedGlowsThisFrame.push(script); + } } } // Compare to previous frame. @@ -408,6 +410,19 @@ Runtime.prototype._updateScriptGlows = function () { this._scriptGlowsPreviousFrame = finalScriptGlows; }; +/** + * "Quiet" a script's glow: stop the VM from generating glow/unglow events + * about that script. Use when a script has just been deleted, but we may + * still be tracking glow data about it. + * @param {!string} scriptBlockId Id of top-level block in script to quiet. + */ +Runtime.prototype.quietGlow = function (scriptBlockId) { + var index = this._scriptGlowsPreviousFrame.indexOf(scriptBlockId); + if (index > -1) { + this._scriptGlowsPreviousFrame.splice(index, 1); + } +}; + /** * Emit feedback for block glowing (used in the sequencer). * @param {?string} blockId ID for the block to update glow diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js index 11b134b53..a515095bc 100644 --- a/src/engine/sequencer.js +++ b/src/engine/sequencer.js @@ -173,6 +173,7 @@ Sequencer.prototype.proceedThread = function (thread) { Sequencer.prototype.retireThread = function (thread) { thread.stack = []; thread.stackFrame = []; + thread.requestScriptGlowInFrame = false; thread.setStatus(Thread.STATUS_DONE); };