1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

Re-enabling garbage collection of tempvars, only at function boundaries.

This commit is contained in:
Jeremy Ashkenas 2010-10-06 21:19:05 -04:00
parent d4dac214ab
commit 69d2048ccc
7 changed files with 69 additions and 29 deletions

View file

@ -2,6 +2,6 @@
lunch = eat food for food in ['toast', 'cheese', 'wine']
# Naive collision detection.
for roid, index in asteroids
for roid, pos in asteroids
for roid2 in asteroids when roid isnt roid2
roid.explode() if roid.overlaps roid2

View file

@ -1,4 +1,4 @@
var _i, _j, _len, _len2, _len3, _ref, _result, food, index, lunch, roid, roid2;
var _i, _len, _len2, _ref, _result, food, lunch, pos, roid, roid2;
lunch = (function() {
_result = []; _ref = ['toast', 'cheese', 'wine'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@ -7,10 +7,10 @@ lunch = (function() {
}
return _result;
})();
for (index = 0, _len2 = asteroids.length; index < _len2; index++) {
roid = asteroids[index];
for (_j = 0, _len3 = asteroids.length; _j < _len3; _j++) {
roid2 = asteroids[_j];
for (pos = 0, _len = asteroids.length; pos < _len; pos++) {
roid = asteroids[pos];
for (_i = 0, _len2 = asteroids.length; _i < _len2; _i++) {
roid2 = asteroids[_i];
if (roid !== roid2) {
if (roid.overlaps(roid2)) {
roid.explode();

View file

@ -829,10 +829,10 @@ lyrics = (function() {
lunch <span class="Keyword">=</span> eat food <span class="Keyword">for</span> food <span class="Keyword">in</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>]
<span class="Comment"><span class="Comment">#</span> Naive collision detection.</span>
<span class="Keyword">for</span> roid, index <span class="Keyword">in</span> asteroids
<span class="Keyword">for</span> roid, pos <span class="Keyword">in</span> asteroids
<span class="Keyword">for</span> roid2 <span class="Keyword">in</span> asteroids <span class="Keyword">when</span> roid <span class="Keyword">isnt</span> roid2
roid.explode() <span class="Keyword">if</span> roid.overlaps roid2
</pre><pre class="idle"><span class="Storage">var</span> _i, _j, _len, _len2, _len3, _ref, _result, food, index, lunch, roid, roid2;
</pre><pre class="idle"><span class="Storage">var</span> _i, _len, _len2, _ref, _result, food, lunch, pos, roid, roid2;
lunch <span class="Keyword">=</span> (<span class="Storage">function</span>() {
_result <span class="Keyword">=</span> []; _ref <span class="Keyword">=</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>];
<span class="Keyword">for</span> (_i <span class="Keyword">=</span> <span class="Number">0</span>, _len <span class="Keyword">=</span> _ref.<span class="LibraryConstant">length</span>; _i <span class="Keyword">&lt;</span> _len; _i<span class="Keyword">++</span>) {
@ -841,10 +841,10 @@ lunch <span class="Keyword">=</span> (<span class="Storage">function</span>() {
}
<span class="Keyword">return</span> _result;
})();
<span class="Keyword">for</span> (index <span class="Keyword">=</span> <span class="Number">0</span>, _len2 <span class="Keyword">=</span> asteroids.<span class="LibraryConstant">length</span>; index <span class="Keyword">&lt;</span> _len2; index<span class="Keyword">++</span>) {
roid <span class="Keyword">=</span> asteroids[index];
<span class="Keyword">for</span> (_j <span class="Keyword">=</span> <span class="Number">0</span>, _len3 <span class="Keyword">=</span> asteroids.<span class="LibraryConstant">length</span>; _j <span class="Keyword">&lt;</span> _len3; _j<span class="Keyword">++</span>) {
roid2 <span class="Keyword">=</span> asteroids[_j];
<span class="Keyword">for</span> (pos <span class="Keyword">=</span> <span class="Number">0</span>, _len <span class="Keyword">=</span> asteroids.<span class="LibraryConstant">length</span>; pos <span class="Keyword">&lt;</span> _len; pos<span class="Keyword">++</span>) {
roid <span class="Keyword">=</span> asteroids[pos];
<span class="Keyword">for</span> (_i <span class="Keyword">=</span> <span class="Number">0</span>, _len2 <span class="Keyword">=</span> asteroids.<span class="LibraryConstant">length</span>; _i <span class="Keyword">&lt;</span> _len2; _i<span class="Keyword">++</span>) {
roid2 <span class="Keyword">=</span> asteroids[_i];
<span class="Keyword">if</span> (roid <span class="Keyword">!</span><span class="Keyword">==</span> roid2) {
<span class="Keyword">if</span> (roid.overlaps(roid2)) {
roid.explode();

View file

@ -785,7 +785,7 @@
ObjectNode.prototype.children = ['properties'];
ObjectNode.prototype.topSensitive = YES;
ObjectNode.prototype.compileNode = function(o) {
var _i, _len, _len2, _ref2, _ref3, _result, _result2, i, indent, join, lastNoncom, nonComments, obj, prop, props, top;
var _i, _len, _ref2, _result, i, indent, join, lastNoncom, nonComments, obj, prop, props, top;
top = del(o, 'top');
o.indent = this.idt(1);
nonComments = (function() {
@ -800,10 +800,10 @@
}).call(this);
lastNoncom = last(nonComments);
props = (function() {
_result2 = []; _ref3 = this.properties;
for (i = 0, _len2 = _ref3.length; i < _len2; i++) {
prop = _ref3[i];
_result2.push((function() {
_result = []; _ref2 = this.properties;
for (i = 0, _len = _ref2.length; i < _len; i++) {
prop = _ref2[i];
_result.push((function() {
join = ",\n";
if ((prop === lastNoncom) || (prop instanceof CommentNode)) {
join = "\n";
@ -820,7 +820,7 @@
return indent + prop.compile(o) + join;
}).call(this));
}
return _result2;
return _result;
}).call(this);
props = props.join('');
obj = '{' + (props ? '\n' + props + '\n' + this.idt() : '') + '}';
@ -1102,7 +1102,7 @@
__extends(CodeNode, BaseNode);
CodeNode.prototype.children = ['params', 'body'];
CodeNode.prototype.compileNode = function(o) {
var _i, _j, _len, _len2, _len3, _ref2, _ref3, _result, close, code, empty, func, i, open, param, params, sharedScope, splat, top, value;
var _i, _len, _len2, _ref2, _ref3, _result, close, code, empty, func, i, open, param, params, sharedScope, splat, top, value;
sharedScope = del(o, 'sharedScope');
top = del(o, 'top');
o.scope = sharedScope || new Scope(o.scope, this.body, this);
@ -1139,6 +1139,7 @@
}
}
}
o.scope.startLevel();
params = (function() {
_result = [];
for (_i = 0, _len2 = params.length; _i < _len2; _i++) {
@ -1150,8 +1151,8 @@
if (!(empty)) {
this.body.makeReturn();
}
for (_j = 0, _len3 = params.length; _j < _len3; _j++) {
param = params[_j];
for (_i = 0, _len2 = params.length; _i < _len2; _i++) {
param = params[_i];
(o.scope.parameter(param));
}
if (this.className) {
@ -1161,6 +1162,7 @@
open = this.className ? ("(function() {\n" + (this.idt(1)) + "return function " + (this.className) + "(") : "function(";
close = this.className ? ("" + (code && this.idt(1)) + "};\n" + (this.tab) + "})()") : ("" + (code && this.tab) + "}");
func = ("" + open + (params.join(', ')) + ") {" + code + close);
o.scope.endLevel();
if (this.bound) {
return ("" + (utility('bind')) + "(" + func + ", " + (this.context) + ")");
}

View file

@ -11,13 +11,31 @@
this.variables = {
'arguments': 'arguments'
};
if (!(this.parent)) {
if (this.parent) {
this.garbage = this.parent.garbage;
} else {
this.garbage = [];
Scope.root = this;
}
return this;
};
})();
Scope.root = null;
Scope.prototype.startLevel = function() {
return this.garbage.push([]);
};
Scope.prototype.endLevel = function() {
var _i, _len, _ref2, _result, name, vars;
vars = this.variables;
_result = []; _ref2 = this.garbage.pop();
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
name = _ref2[_i];
if (vars[name] === 'var') {
_result.push(vars[name] = 'reuse');
}
}
return _result;
};
Scope.prototype.find = function(name, options) {
if (this.check(name, options)) {
return true;
@ -54,10 +72,13 @@
Scope.prototype.freeVariable = function(type) {
var index, temp;
index = 0;
while (this.check(temp = this.temporary(type, index))) {
while (this.check(temp = this.temporary(type, index)) && this.variables[temp] !== 'reuse') {
index++;
}
this.variables[temp] = 'var';
if (this.garbage.length) {
last(this.garbage).push(temp);
}
return temp;
};
Scope.prototype.assign = function(name, value) {
@ -68,7 +89,7 @@
};
Scope.prototype.hasDeclarations = function(body) {
return body === this.expressions && this.any(function(k, val) {
return val === 'var';
return ('var' === val || 'reuse' === val);
});
};
Scope.prototype.hasAssignments = function(body) {
@ -83,7 +104,7 @@
for (key in _ref2) {
if (!__hasProp.call(_ref2, key)) continue;
val = _ref2[key];
if (val === 'var') {
if (('var' === val || 'reuse' === val)) {
_result.push(key);
}
}

View file

@ -984,6 +984,7 @@ exports.CodeNode = class CodeNode extends BaseNode
@body.unshift(splat)
else
params.push param
o.scope.startLevel()
params = (param.compile(o) for param in params)
@body.makeReturn() unless empty
(o.scope.parameter(param)) for param in params
@ -992,6 +993,7 @@ exports.CodeNode = class CodeNode extends BaseNode
open = if @className then "(function() {\n#{@idt(1)}return function #{@className}(" else "function("
close = if @className then "#{code and @idt(1)}};\n#{@tab}})()" else "#{code and @tab}}"
func = "#{open}#{ params.join(', ') }) {#{code}#{close}"
o.scope.endLevel()
return "#{utility 'bind'}(#{func}, #{@context})" if @bound
if top then "(#{func})" else func

View file

@ -19,7 +19,21 @@ exports.Scope = class Scope
# it wraps.
constructor: (@parent, @expressions, @method) ->
@variables = {'arguments'}
Scope.root = this unless @parent
if @parent
@garbage = @parent.garbage
else
@garbage = []
Scope.root = this
# Create a new garbage level
startLevel: ->
@garbage.push []
# Return to the previous garbage level and erase referenced temporary
# variables in current level from scope.
endLevel: ->
vars = @variables
(vars[name] = 'reuse') for name in @garbage.pop() when vars[name] is 'var'
# Look up a variable name in lexical scope, and declare it if it does not
# already exist.
@ -57,8 +71,9 @@ exports.Scope = class Scope
# compiler-generated variable. `_var`, `_var2`, and so on...
freeVariable: (type) ->
index = 0
index++ while @check(temp = @temporary type, index)
index++ while @check(temp = @temporary type, index) and @variables[temp] isnt 'reuse'
@variables[temp] = 'var'
last(@garbage).push temp if @garbage.length
temp
# Ensure that an assignment is made at the top of this scope
@ -69,7 +84,7 @@ exports.Scope = class Scope
# Does this scope reference any variables that need to be declared in the
# given function body?
hasDeclarations: (body) ->
body is @expressions and @any (k, val) -> val is 'var'
body is @expressions and @any (k, val) -> val in ['var', 'reuse']
# Does this scope reference any assignments that need to be declared at the
# top of the given function body?
@ -78,7 +93,7 @@ exports.Scope = class Scope
# Return the list of variables first declared in this scope.
declaredVariables: ->
(key for key, val of @variables when val is 'var').sort()
(key for key, val of @variables when val in ['var', 'reuse']).sort()
# Return the list of assignments that are supposed to be made at the top
# of this scope.