Fix funarg analysis to cope with escaping kids of a named function expression that use that lambda by name (545980, r=jorendorff).

This commit is contained in:
Brendan Eich 2010-02-18 16:32:15 -08:00
parent 4fb42b4c2a
commit c4b4c765a4
2 changed files with 64 additions and 2 deletions

View File

@ -1993,7 +1993,8 @@ JSCompiler::markFunArgs(JSFunctionBox *funbox, uintN tcflags)
if (!lexdep->isFreeVar() &&
!lexdep->isFunArg() &&
lexdep->kind() == JSDefinition::FUNCTION) {
(lexdep->kind() == JSDefinition::FUNCTION ||
PN_OP(lexdep) == JSOP_CALLEE)) {
/*
* Mark this formerly-Algol-like function as an escaping
* function (i.e., as a funarg), because it is used from a
@ -2006,7 +2007,26 @@ JSCompiler::markFunArgs(JSFunctionBox *funbox, uintN tcflags)
*/
lexdep->setFunArg();
JSFunctionBox *afunbox = lexdep->pn_funbox;
JSFunctionBox *afunbox;
if (PN_OP(lexdep) == JSOP_CALLEE) {
/*
* A named function expression will not appear to be a
* funarg if it is immediately applied. However, if its
* name is used in an escaping function nested within
* it, then it must become flagged as a funarg again.
* See bug 545980.
*/
afunbox = funbox;
uintN calleeLevel = UPVAR_FRAME_SKIP(lexdep->pn_cookie);
uintN staticLevel = afunbox->level + 1U;
while (staticLevel != calleeLevel) {
afunbox = afunbox->parent;
--staticLevel;
}
afunbox->node->setFunArg();
} else {
afunbox = lexdep->pn_funbox;
}
queue.push(afunbox);
/*

View File

@ -0,0 +1,42 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var gTestfile = 'regress-545980.js';
var BUGNUMBER = 518103;
var summary = 'partial flat closures must not reach across funargs';
var actual = "no crash";
var expect = actual;
function Timer(){}
Timer.prototype = { initWithCallback: function (o) {Timer.q.push(o)} };
Timer.q = [];
var later;
var ac = {startSearch: function(q,s,n,o){later=o}};
var bm = {insertBookmark: function(){}, getIdForItemAt: function(){}};
function run_test() {
var tagIds = [];
(function doSearch(query) {
ac.startSearch(query, "", null, {
onSearchResult: function() {
var num = tagIds.length;
var timer = new Timer;
var next = query.slice(1);
timer.initWithCallback({ notify: function() doSearch(next) });
}
});
})("title");
}
run_test();
later.onSearchResult();
for (var i in Timer.q)
Timer.q[i].notify();
reportCompare(expect, actual, summary);