473,888 Members | 1,558 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Recursive functions and arguments.calle e.caller

Inside a function, I'd like to know the call stack. By this I mean
that I'd like to know the function that called this one, that one's
caller and so on.

So I thought to do:
<script type='text/javascript'>
function myFunc(lev) {
// if (lev) return myFunc(lev-1);
var aStack=[];
nextFunc = arguments.calle e;
while (nextFunc) {
aStack.push(nex tFunc.name ? nextFunc.name : nextFunc.toStri ng());
nextFunc = nextFunc.caller ;
}
return aStack;
}
function foo() { return myFunc(1); }
function bar() { return foo("frob"); }
alert (bar("baz"));
</script>
This works as expected (on FF 1.5+ / IE 6 on my WinXP Pro). However,
if I uncomment the first line of myFunc to make it recursive (making
sure I don't have any unsaved work or other browser windows open), the
function stalls out because arguments.calle e.caller==argum ents.callee,
so the script goes into an infinite loop.

In other words, myFunc at the lowest level knows it was called by
myFunc (hence I can detect recursion), but I don't see how to determine
how many levels deep myFunc is, nor its original caller. Anyone know
an alternate approach?

Thanks,
Csaba Gabor from Vienna

I did try an approach of getting to the arguments.calle e of the caller
(since arguments.calle e.caller in [the outer call, ] myFunc(1) is
correct, returning foo), but no dice. I got the same results (of an
infinite loop) after adding the following two lines after nextFunc =
nextFunc.caller ;

if (!nextFunc) break;
var nextFunc = nextFunc.argume nts.callee;

Mar 19 '06 #1
9 16858
Csaba Gabor said on 20/03/2006 8:10 AM AEST:
Inside a function, I'd like to know the call stack. By this I mean
that I'd like to know the function that called this one, that one's
caller and so on.

So I thought to do:
<script type='text/javascript'>
function myFunc(lev) {
// if (lev) return myFunc(lev-1);
var aStack=[];
nextFunc = arguments.calle e;
while (nextFunc) {
aStack.push(nex tFunc.name ? nextFunc.name : nextFunc.toStri ng());
nextFunc = nextFunc.caller ;
}
return aStack;
}
function foo() { return myFunc(1); }
function bar() { return foo("frob"); }
alert (bar("baz"));
</script>
This works as expected (on FF 1.5+ / IE 6 on my WinXP Pro). However,
if I uncomment the first line of myFunc to make it recursive (making
sure I don't have any unsaved work or other browser windows open), the
function stalls out because arguments.calle e.caller==argum ents.callee,
so the script goes into an infinite loop.

In other words, myFunc at the lowest level knows it was called by
myFunc (hence I can detect recursion), but I don't see how to determine
how many levels deep myFunc is, nor its original caller. Anyone know
an alternate approach?

Thanks,
Csaba Gabor from Vienna

I did try an approach of getting to the arguments.calle e of the caller
(since arguments.calle e.caller in [the outer call, ] myFunc(1) is
correct, returning foo), but no dice. I got the same results (of an
infinite loop) after adding the following two lines after nextFunc =
nextFunc.caller ;
Not all browsers give function objects a caller property, and I think
the name property of function objects is unique to Gecko. So whatever
you get to work in Firefox/Mozilla/Netscape probably will not work
elsewhere.

if (!nextFunc) break;
var nextFunc = nextFunc.argume nts.callee;


The script below is a bit dirty, it works in Firefox but not IE.

I've used the function object's name property but it isn't widely
supported, nor is the name property of arguments.calle e (which I guess
is the same thing as arguments.calle e is a reference to the current
function object).

You could use toString() and just parse out the function name to get
around lack of support for fnObj.name, it's a bit harder to get around
lack of support for the caller property, but not impossible.
function callFoo(){ foo(); }
function foo(){ bar(); }

function bar()
{
var callObj = arguments.calle e;
var callName = callObj.name;
var callChain = [callName];

while ('string' == typeof callName) {
if ( (callObj = callObj.caller) ){
callName = callObj.name;
callChain.push( callName);
} else {
callName = null;
}
}

// Gives top-down order, leave as-is if bottom-up is required
callChain.rever se();
alert(callChain .join('\n'));
}

callFoo();

The bar() function could be turned into a showCallChain() function by
passing it arguments.calle e and using that as the initial value of callObj.

It seems to me you are better off having each function call the next
with its arguments.calle e.name property as a parameter - again,
callee.name may not be (in fact probably isn't) supported in all browsers.
--
Rob
Mar 20 '06 #2
RobG said on 20/03/2006 3:51 PM AEST:
Csaba Gabor said on 20/03/2006 8:10 AM AEST:
Inside a function, I'd like to know the call stack. By this I mean
that I'd like to know the function that called this one, that one's
caller and so on.

Sorry for my above answer, I missed your point. The problem is that for
recursive functions, the callee and caller properties refer to the same
object.

Try this, loopMe() recurses 'depth' times, then compares callee to caller:

function loopMe(depth, idx){
if (idx<depth){
loopMe(depth, ++idx);
} else {
var obj = arguments.calle e;
alert(idx + ': ' + (obj == obj.caller));
}
}

loopMe(5, 0);
You can even do something like:

alert(arguments .callee.caller. caller.caller.c aller.name)
after two loops, you'll keep getting 'loopMe'. To keep track of
recursion depth, you'll need to pass ++idx to recursive calls. Once you
enter a recursive function, probably the only way to get the scope chain
using your while algorithm is to pass a reference to the function that
calls the recursive function and start from there.
The ECMAScript Section 10.1.8 says:

"A property is created with name callee and property
attributes { DontEnum }. The initial value of this property
is the Function object being executed. This allows anonymous
functions to be recursive."
And Section 10.2.3 on function code:

"The scope chain is initialised to contain the activation
object followed by the objects in the scope chain stored
in the [[Scope]] property of the Function object."

Based on that and testing, it seems that callee and caller refer to the
original function object, not the activation object that actually calls
the function. This makes sense if you want to use a recursive function
because you want a new 'copy' of the original function object.

Note that arguments.calle r was deprecated in Netsacpe's JavaScript
version 1.3, but the function object's caller property is still supported.

The following links offer minimal help:

MSDN:
<URL:
http://msdn.microsoft.com/library/de...489f180ce1.asp
MozDev:
<URL:
http://developer.mozilla.org/en/docs...unction:caller

--
Rob
Mar 20 '06 #3
RobG wrote:
RobG said on 20/03/2006 3:51 PM AEST:
Csaba Gabor said on 20/03/2006 8:10 AM AEST:
Inside a function, I'd like to know the call stack. By this I mean
that I'd like to know the function that called this one, that one's
caller and so on.
....
The ECMAScript Section 10.1.8 says:

"A property is created with name callee and property
attributes { DontEnum }. The initial value of this property
is the Function object being executed. This allows anonymous
functions to be recursive."

And Section 10.2.3 on function code:

"The scope chain is initialised to contain the activation
object followed by the objects in the scope chain stored
in the [[Scope]] property of the Function object."

Based on that and testing, it seems that callee and caller refer to the
original function object, not the activation object that actually calls
the function. This makes sense if you want to use a recursive function
because you want a new 'copy' of the original function object.


Thanks for your comments, Rob. I didn't follow your conclusion about
it making sense and wanting the copies. Are you saying that it makes
sense as is? Seems to me, I should expect to be able to backtrack up
the call stack. I didn't find any references to
arguments.calle e.caller coupled with recursive functions in my
searches, but I did see mentioned __caller__ in one old FF bug report
(https://bugzilla.mozilla.org/show_bug.cgi?id=65683), but I didn't get
so much as "peep" in trying to use it.

So I'm really wondering whether I'm missing an angle on this, cause I
just don't see the rationale. It's does not seem to be a security
issue because arguments.calle e.caller of the first call into the
recursive function can reach out to its caller. By the same token,
it's not a (stack) space issue since that stack exists anyway (since
each function higher up the stack has its own, extant and distinct
arguments object). And it's also not on account of possible tail
recursion optimisation because in separate testing I inserted code to
forestall tail recursion.

Csaba Gabor from Vienna

Mar 20 '06 #4
Csaba Gabor said on 21/03/2006 4:03 AM AEST:
RobG wrote:
RobG said on 20/03/2006 3:51 PM AEST:
Csaba Gabor said on 20/03/2006 8:10 AM AEST:

Inside a function, I'd like to know the call stack. By this I mean
that I'd like to know the function that called this one, that one's
caller and so on.

...
The ECMAScript Section 10.1.8 says:

"A property is created with name callee and property
attributes { DontEnum }. The initial value of this property
is the Function object being executed. This allows anonymous
functions to be recursive."

And Section 10.2.3 on function code:

"The scope chain is initialised to contain the activation
object followed by the objects in the scope chain stored
in the [[Scope]] property of the Function object."

Based on that and testing, it seems that callee and caller refer to the
original function object, not the activation object that actually calls
the function. This makes sense if you want to use a recursive function
because you want a new 'copy' of the original function object.

Thanks for your comments, Rob. I didn't follow your conclusion about
it making sense and wanting the copies. Are you saying that it makes
sense as is? Seems to me, I should expect to be able to backtrack up
the call stack. I didn't find any references to
arguments.calle e.caller coupled with recursive functions in my
searches, but I did see mentioned __caller__ in one old FF bug report
(https://bugzilla.mozilla.org/show_bug.cgi?id=65683), but I didn't get
so much as "peep" in trying to use it.


Ah, I think that holds the key. The caller property references the
function object, not the activation object that the now removed
__caller__ property referred to.
Following is a Brendan Eich comment on Mozilla 0.9 (2001-01-10):

"All traces of a caller property were removed a while ago,
to follow ECMA-262 and to avoid any chance of a security exploit.
The removal seems to me to have been overzealous, because it axed
the caller property of function objects *and* the
much-more-exploitable caller (or __caller__) property of
activation objects.

"Confirming , we should consider restoring the caller property
of function objects for old time's sake (JScript imitated it
faithfully in cloning JS1.1, where it originated)."
I suppose that for a recursive function, each recursion has the same
function object but different activation object. If you could reference
the activation object, then you could climb any stack. But Brendan's
comment says that support for __caller__ was removed long ago.

So I'm really wondering whether I'm missing an angle on this, cause I
just don't see the rationale. It's does not seem to be a security
issue because arguments.calle e.caller of the first call into the
recursive function can reach out to its caller.


I think getting a reference to the activation object was seen as a
potential security exploit, hence caller was reinstated but not __caller__.

[...]
--
Rob
Mar 21 '06 #5
VK

RobG wrote:
Following is a Brendan Eich comment on Mozilla 0.9 (2001-01-10):

"All traces of a caller property were removed a while ago,
to follow ECMA-262 and to avoid any chance of a security exploit.
The removal seems to me to have been overzealous, because it axed
the caller property of function objects *and* the
much-more-exploitable caller (or __caller__) property of
activation objects.

"Confirming , we should consider restoring the caller property
of function objects for old time's sake (JScript imitated it
faithfully in cloning JS1.1, where it originated)."
I suppose that for a recursive function, each recursion has the same
function object but different activation object. If you could reference
the activation object, then you could climb any stack. But Brendan's
comment says that support for __caller__ was removed long ago.

So I'm really wondering whether I'm missing an angle on this, cause I
just don't see the rationale. It's does not seem to be a security
issue because arguments.calle e.caller of the first call into the
recursive function can reach out to its caller.


I think getting a reference to the activation object was seen as a
potential security exploit, hence caller was reinstated but not __caller__.


A year or so ago I was writing a similar caller chain tracing program
but for another purpose (to get the literal name of the instance). Some
discrepancies and bizarrities I had to bypass for that how have some
explanation grace to Rob.

Given a function f(), "arguments" object with all its properties is
created not for the function f() itself, but for the given
instance/heap of the function f() - that is what confusingly reffered
in ECMAScript as Activation object.
I would stay with the "heap" term here because "instance" implies wrong
analogies with the higher level mechanics, while here it is merely a
lower level execution stack mechanics.
There can be multiple heaps created by the same function existing at
once, each with its own argument object. In this heap arguments.calle r
either blocked or looped to the "creator" (function f). Otherwise
indeed one could penetrate right into execution stack using caller as
starting point with all possible security problems.
It is interesting to notice that in this concerne:

function f() {
f.caller != arguments.calle r;
}

f.caller refers to the function forced function f to create the current
heap. It is really should be explained better than I did - and
definitely better than it's done in ECMA Books.

Some code:

<html>
<head>
<title>callee , caller and stuff...</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<style type="text/css">
body {
margin: 0px 0px;
padding: 10px 10px;
color: #000000;
background-color: #FFFFFF}
</style>

<script type="text/javascript">
var output = null;
function init() {
output = document.forms['frm01'].elements['output'];
}
window.onload = init;

function test1(caller) {
var out = 'Function in intrinsic event handler:\n\n'
out+= (caller)? caller : 'undefined';
output.value = out;
}

function test2(caller) {
var out = 'test2(): function reference behavior:\n\n'
out+= 'arguments.call ee = ' + arguments.calle e + '\n\n';
out+= 'test2.toString () = ' + test2.toString( );
output.value = out;
}

function test3() {
var out = 'arguments.call er = ' + arguments.calle r + '\n\n';
out+= 'test3.caller = ' + test3.caller + '\n\n';
out+= (arguments.call er == test3.caller) + '\n\n';
out+= arguments.calle r.callee;
output.value = out;
}
function test3_helper() {
test3();
} test3_helper.fi d = true;

</script>

</head>

<body>

<form name="frm01" action="">
<fieldset>
<legend>Test</legend><br>
<textarea name="output" id="output"
cols="64" rows="10"></textarea><br>
<input type="button" value="Test 1"
onClick="test1( arguments.calle e)">
<input type="button" value="Test 2"
onClick="test2( arguments.calle e)">
<input type="button" value="Test 3" onClick="test3_ helper()">
</fieldset>
</form>

</body>
</html>

Mar 21 '06 #6
VK wrote:
function f() {
f.caller != arguments.calle r;
}

f.caller refers to the function forced function f to
create the current heap.
No, it does not. There is only one heap for the entire program.
It is really should be explained better than I did -
Which is not too hard.
and definitely better than it's done in ECMA Books.


There are no ECMA Books.
PointedEars
Mar 21 '06 #7
RobG wrote:
Csaba Gabor said on 21/03/2006 4:03 AM AEST:
RobG said on 20/03/2006 3:51 PM AEST:
Csaba Gabor said on 20/03/2006 8:10 AM AEST:
>Inside a function, I'd like to know the call stack. By this I mean
>that I'd like to know the function that called this one, that one's
>caller and so on.

...

Ah, I think that holds the key. The caller property references the
function object, not the activation object that the now removed
__caller__ property referred to.

Following is a Brendan Eich comment on Mozilla 0.9 (2001-01-10):

"All traces of a caller property were removed a while ago,
to follow ECMA-262 and to avoid any chance of a security exploit.
The removal seems to me to have been overzealous, because it axed
the caller property of function objects *and* the
much-more-exploitable caller (or __caller__) property of
activation objects.

"Confirming , we should consider restoring the caller property
of function objects for old time's sake (JScript imitated it
faithfully in cloning JS1.1, where it originated)."
I suppose that for a recursive function, each recursion has the same
function object but different activation object. If you could reference
the activation object, then you could climb any stack. But Brendan's
comment says that support for __caller__ was removed long ago.

So I'm really wondering whether I'm missing an angle on this, cause I
just don't see the rationale. It's does not seem to be a security
issue because arguments.calle e.caller of the first call into the
recursive function can reach out to its caller.


I think getting a reference to the activation object was seen as a
potential security exploit, hence caller was reinstated but not __caller__.


To be clear on what is happening [it is as you say], arguments.calle e
returns the original function object (and by that I mean the reference
that you get when you define:
function foo(...) {...}
I tested this by calling a function and in the function doing
arguments.calle e.funcProp="fro b" and checking foo.funcProp after
finishing the function call and sure enough, there was "frob".

The implication is that each time a call is made the function object
has a property, .caller, placed on it that points to the calling
function object ** for the duration of that call **. Sure enough, this
checks out too.

Frankly, this seems like a really whacked out way to go. I haven't
seen anything so far to give me notions to the contrary. Appears to me
that what is needed is a property of arguments that is essentially
..parent, which would point to the arguments object of the activation
object that called this one. In this fashion there would not even need
to be a .caller property anymore, considering that .caller on the
original function object is a crutch anyway (ie. the interpreter is not
making use of it).

Csaba

By the way, Eric Lippert has a really interesting read about activation
objects, execution variables, scopes, this, and more at:
http://blogs.msdn.com/ericlippert/ar...04/414684.aspx

Mar 23 '06 #8
VK

Csaba Gabor wrote:
To be clear on what is happening [it is as you say], arguments.calle e
returns the original function object (and by that I mean the reference
that you get when you define:
function foo(...) {...}


Right in opposite order ;-)

arguments.calle r returns a reference to the current running instance of
the function (and its functionality and reliability is partially locked
for security reasons). FunctionName.ca ller returns the reference to the
original function. Read my previous post again, it has some code to
play with.

Also you may try this (narrowed to illustrate this particular issue):

<html>
<head>
<title>callee , caller and stuff</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script type="text/javascript">

var out = null;

function init() {
out = document.forms[0].elements['out'];
test();
}
// adding a property to init function object:
init.marker = true;

function test() {
if (arguments.call er) {
var s = 'arguments.call er.marker = '
+ arguments.calle r.marker + '\n\n';
s+= 'init.marker = ' + init.marker + '\n\n';
out.value = s;
}
}
</script>
</head>

<body onLoad="init()" >

<form action="">
<fieldset>
<legend>Outpu t</legend>
<textarea name="out" cols="64" rows="32"></textarea>
</fieldset>
</form>

</body>
</html>

Mar 25 '06 #9
VK

VK wrote:
arguments.calle r returns a reference to the current running instance of
the function (and its functionality and reliability is partially locked
for security reasons). FunctionName.ca ller returns the reference to the
original function. Read my previous post again, it has some code to
play with.

Also you may try this (narrowed to illustrate this particular issue):
<snip> s+= 'init.marker = ' + init.marker + '\n\n';

<snip>

Hum... Either I'm in everyone's ban list already, or everyone found
some sense in it I'm not aware of :-) Sorry I actually grabbed a wrong
demo file - I produced a lot of them while trying to study this
question. The right code (what I meant in my post is):

<html>
<head>
<title>callee , caller and stuff</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script type="text/javascript">

var out = null;

function init() {
out = document.forms[0].elements['out'];
test();
}

// adding a property to init function object:
init.marker = true;

function test() {
if (arguments.call er) {
var s = 'arguments.call er.marker = '
+ arguments.calle r.marker + '\n\n';
// HERE IS THE CHANGE:
s+= 'test.caller.ma rker = ' + test.caller.mar ker + '\n\n';
out.value = s;
}
}

</script>
</head>

<body onLoad="init()" >

<form action="">
<fieldset>
<legend>Outpu t</legend>
<textarea name="out" cols="64" rows="32"></textarea>
</fieldset>
</form>

</body>
</html>

IE6 (JScript was not patched for caller) gives me:

arguments.calle r.marker = undefined
test.caller.mar ker = true

Mar 27 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
6134
by: Aloo | last post by:
Dear friends, If we declare a recursive function as 'inline' then does it actually convert to an iterative form during compilation ( the executable code is iterative)? Is it possible ? Please reply.
6
3120
by: jeniffer | last post by:
Please give an example of 2 simple mutually recursive functions in C .
7
3232
by: VK | last post by:
I was getting this effect N times but each time I was in rush to just make it work, and later I coudn't recall anymore what was the original state I was working around. This time I nailed the bastard so posting it before I forgot again... By taking this minimum code: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <head>
12
3493
by: -Lost | last post by:
What in the world is functionName.name good for? That is: function functionName() { return functionName.name; } I mean, I already had to write out the function's name so it seems that it is not very useful or efficient. To me, this.name seems most appropriate, but of course that does not work within the context of a function unless defined as a class, which of course then the name property does not apply to the calling function.
41
3411
by: Harry | last post by:
Hi all, 1)I need your help to solve a problem. I have a function whose prototype is int reclen(char *) This function has to find the length of the string passed to it.But the conditions are that no local variable or global variable should be used.I have to use recursive functions.
5
4953
by: Digital Puer | last post by:
I got this on an interview: Is it possible to write inline recursive functions? I said yes, but there is no guarantee that the compiler will definitely inline your code even if you write "inline". Is this a right answer? It seems to be independent of whether or not the function is recursive. Another question: how can you tell if the compiler has inlined your
34
4531
by: Jorge | last post by:
Why is it listed here : http://www.crockford.com/javascript/recommend.html under "deprecation" ? Without it, how is an anonymous function() going to call itself (recursively) ? I use to write timers like this :
0
9961
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9800
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
11182
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10778
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
10439
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7990
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5824
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
6014
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
4245
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.