summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjmoenig <jens@moenig.org>2014-11-25 12:24:20 +0100
committerjmoenig <jens@moenig.org>2014-11-25 12:24:20 +0100
commit75849a59a2ac594c2c78a7cf6ef1e8be6c1eec57 (patch)
treefb13a87c2b95ae03a266778b136b8077bb92d6f5
parent4be96bb240ea8518fa95218cba7111846af93baa (diff)
downloadsnap-75849a59a2ac594c2c78a7cf6ef1e8be6c1eec57.tar.gz
snap-75849a59a2ac594c2c78a7cf6ef1e8be6c1eec57.zip
Evaluator optimizations
reducing the stack size for reporters
-rwxr-xr-xhistory.txt6
-rw-r--r--threads.js127
2 files changed, 67 insertions, 66 deletions
diff --git a/history.txt b/history.txt
index 964686e..22215e9 100755
--- a/history.txt
+++ b/history.txt
@@ -2342,7 +2342,7 @@ ______
-------
* Threads: Fix “stop this block” primitive for tail-call-elimination
-1411214
+1411224
-------
* Threads: Fixed #318
* Objects: Fixed #416
@@ -2353,3 +2353,7 @@ ______
* snap.html, favicon.ico: new Favicon, thanks, Michael!
* Threads: improved whitespace detection for “split” primitive, thanks, Michael!
* Threads: tail-call-elimination for reporters experiment (commented out, under construction)
+
+1411225
+-------
+* Threads: Evaluator optimizations (reducing the stack size for reporters)
diff --git a/threads.js b/threads.js
index a6b824b..aef13a1 100644
--- a/threads.js
+++ b/threads.js
@@ -83,7 +83,7 @@ ArgLabelMorph, localize, XML_Element, hex_sha512*/
// Global stuff ////////////////////////////////////////////////////////
-modules.threads = '2014-November-24';
+modules.threads = '2014-November-25';
var ThreadManager;
var Process;
@@ -218,11 +218,10 @@ ThreadManager.prototype.resumeAll = function (stage) {
};
ThreadManager.prototype.step = function () {
-/*
- run each process until it gives up control, skipping processes
- for sprites that are currently picked up, then filter out any
- processes that have been terminated
-*/
+ // run each process until it gives up control, skipping processes
+ // for sprites that are currently picked up, then filter out any
+ // processes that have been terminated
+
this.processes.forEach(function (proc) {
if (!proc.homeContext.receiver.isPickedUp() && !proc.isDead) {
proc.runStep();
@@ -384,13 +383,13 @@ Process.prototype.isRunning = function () {
// Process entry points
Process.prototype.runStep = function () {
-/*
- a step is an an uninterruptable 'atom', it can consist
- of several contexts, even of several blocks
-*/
+ // a step is an an uninterruptable 'atom', it can consist
+ // of several contexts, even of several blocks
+
if (this.isPaused) { // allow pausing in between atomic steps:
return this.pauseStep();
}
+
this.readyToYield = false;
while (!this.readyToYield
&& this.context
@@ -459,6 +458,9 @@ Process.prototype.pauseStep = function () {
Process.prototype.evaluateContext = function () {
var exp = this.context.expression;
this.frameCount += 1;
+ if (this.context.tag === 'exit') {
+ this.expectReport();
+ }
if (exp instanceof Array) {
return this.evaluateSequence(exp);
}
@@ -482,7 +484,7 @@ Process.prototype.evaluateContext = function () {
Process.prototype.evaluateBlock = function (block, argCount) {
// check for special forms
- if (contains(['reportOr', 'reportAnd'], block.selector)) {
+ if (contains(['reportOr', 'reportAnd', 'doReport'], block.selector)) {
return this[block.selector](block);
}
@@ -548,33 +550,29 @@ Process.prototype.reportAnd = function (block) {
}
};
-/*
- tail-call-elimination for reporters
- -----------------------------------
- currently under construction, commented out for now
- to activate add 'doReport' to the list of special forms
- selectors in evaluateBlock() and comment out / remove
- the current 'doReport' primitive in the "return"
- section of the code
-
Process.prototype.doReport = function (block) {
-
-// if (this.context.expression.partOfCustomCommand) {
-// return this.doStopCustomBlock();
-// }
-
+ if (this.context.expression.partOfCustomCommand) {
+ this.doStopCustomBlock();
+ this.popContext();
+ return;
+ }
var outer = this.context.outerContext;
- while (this.context && this.context.expression !== 'exitReporter') {
+ while (this.context && this.context.tag !== 'exit') {
if (this.context.expression === 'doStopWarping') {
this.doStopWarping();
} else {
this.popContext();
}
}
- this.popContext();
+ if (this.context.expression === 'expectReport') {
+ // pop off inserted top-level exit context
+ this.popContext();
+ } else {
+ // un-tag and preserve original caller
+ this.context.tag = null;
+ }
this.pushContext(block.inputs()[0], outer);
};
-*/
// Process: Non-Block evaluation
@@ -724,9 +722,8 @@ Process.prototype.doYield = function () {
}
};
-Process.prototype.exitReporter = function () {
- // catch-tag for REPORT and STOP BLOCK primitives
- this.handleError(new Error("missing 'report' statement in reporter"));
+Process.prototype.expectReport = function () {
+ this.handleError(new Error("reporter didn't report"));
};
// Process Exception Handling
@@ -831,9 +828,10 @@ Process.prototype.evaluate = function (
}
var outer = new Context(null, null, context.outerContext),
+ caller = this.context.parentContext,
+ exit,
runnable,
extra,
- exit,
parms = args.asArray(),
i,
value;
@@ -904,17 +902,22 @@ Process.prototype.evaluate = function (
if (runnable.expression instanceof CommandBlockMorph) {
runnable.expression = runnable.expression.blockSequence();
-
- // insert a reporter exit tag for the
- // CALL SCRIPT primitive variant
if (!isCommand) {
- exit = new Context(
- runnable.parentContext,
- 'exitReporter',
- outer,
- outer.receiver
- );
- runnable.parentContext = exit;
+ if (caller) {
+ // tag caller, so "report" can catch it later
+ caller.tag = 'exit';
+ } else {
+ // top-level context, insert a tagged exit context
+ // which "report" can catch later
+ exit = new Context(
+ runnable.parentContext,
+ 'expectReport',
+ outer,
+ outer.receiver
+ );
+ exit.tag = 'exit';
+ runnable.parentContext = exit;
+ }
}
}
};
@@ -993,21 +996,7 @@ Process.prototype.fork = function (context, args) {
stage.threads.processes.push(proc);
};
-// Process "return" primitives
-
-Process.prototype.doReport = function (value) {
- if (this.context.expression.partOfCustomCommand) {
- return this.doStopCustomBlock();
- }
- while (this.context && this.context.expression !== 'exitReporter') {
- if (this.context.expression === 'doStopWarping') {
- this.doStopWarping();
- } else {
- this.popContext();
- }
- }
- return value;
-};
+// Process stopping blocks primitives
Process.prototype.doStopBlock = function () {
var target = this.context.expression.exitTag;
@@ -1119,13 +1108,21 @@ Process.prototype.evaluateCustomBlock = function () {
// insert a reporter exit tag for the
// CALL SCRIPT primitive variant
if (this.context.expression.definition.type !== 'command') {
- exit = new Context(
- runnable.parentContext,
- 'exitReporter',
- outer,
- outer.receiver
- );
- runnable.parentContext = exit;
+ if (caller) {
+ // tag caller, so "report" can catch it later
+ caller.tag = 'exit';
+ } else {
+ // top-level context, insert a tagged exit context
+ // which "report" can catch later
+ exit = new Context(
+ runnable.parentContext,
+ 'expectReport',
+ outer,
+ outer.receiver
+ );
+ exit.tag = 'exit';
+ runnable.parentContext = exit;
+ }
} else {
// tag all "stop this block" blocks with the current
// procedureCount as exitTag, and mark all "report" blocks
@@ -2925,7 +2922,7 @@ Context.prototype.continuation = function () {
} else {
return new Context(null, 'doStop');
}
- if (cont.expression === 'exitReporter') {
+ if (cont.expression === 'expectReport') {
return cont.continuation();
}
cont = cont.copyForContinuation();