Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Get a variable in the scope chain

14 views
Skip to first unread message

franck.fr

unread,
Nov 18, 2009, 10:24:48 AM11/18/09
to
Hello.

I am trying to access a variable value in the current scope chain:

function foo() {
var myVar = 123;
function bar() {
Print( EvalVarByName('myVar') );
};
bar();
};
foo();

EvalVarByName native function is define as:
...
JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
JSBool found;
JSObject *scope = JS_GetFrameScopeChain(cx, fp);
for ( ; scope; scope = JS_GetParent(cx, scope) ) {

JS_HasProperty(cx, scope, name, &found);
if ( found )
return JS_GetProperty(cx, scope, name, rval);
}
...
(src: http://code.google.com/p/jslibs/source/browse/trunk/src/tools/jsTest.cpp?spec=svn2940&r=2940#1)

note1: if I remove the outer function foo, EvalVarByName('myVar')
returns 123.
note2: using JS_GetScopeChain(cx) give the same result.

Is there a better method to access myVar without using eval-like
functions ?

Franck.

John J. Barton

unread,
Nov 18, 2009, 10:50:14 AM11/18/09
to
franck.fr wrote:
> Hello.
>
> I am trying to access a variable value in the current scope chain:
>
> function foo() {
> var myVar = 123;
> function bar() {
> Print( EvalVarByName('myVar') );
> };
> bar();
> };
> foo();
>
> EvalVarByName native function is define as:
> ...
> JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
> JSBool found;
> JSObject *scope = JS_GetFrameScopeChain(cx, fp);
> for ( ; scope; scope = JS_GetParent(cx, scope) ) {
>
> JS_HasProperty(cx, scope, name, &found);
> if ( found )
> return JS_GetProperty(cx, scope, name, rval);
> }
> ...
> (src: http://code.google.com/p/jslibs/source/browse/trunk/src/tools/jsTest.cpp?spec=svn2940&r=2940#1)
>
> note1: if I remove the outer function foo, EvalVarByName('myVar')
> returns 123.

That suggests that your code works for the global scope but fails for
the closure.

If you add a dummy EvalVarByName JS function, put the code in to
Firebug, and set a breakpoint in EvalVarByName you can look at the
scopes in the Watch side panel.

jjb

franck.fr

unread,
Nov 18, 2009, 10:57:56 AM11/18/09
to
On Nov 18, 4:50 pm, "John J. Barton" <johnjbar...@johnjbarton.com>
wrote:

> franck.fr wrote:
> > Hello.
>
> > I am trying to access a variable value in the current scope chain:
>
> > function foo() {
> >   var myVar = 123;
> >   function bar() {
> >     Print( EvalVarByName('myVar') );
> >   };
> >   bar();
> > };
> > foo();
>
> > EvalVarByName native function is define as:
> > ...
> > JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
> > JSBool found;
> > JSObject *scope = JS_GetFrameScopeChain(cx, fp);
> > for ( ; scope; scope = JS_GetParent(cx, scope) ) {
>
> >   JS_HasProperty(cx, scope, name, &found);
> >   if ( found )
> >     return JS_GetProperty(cx, scope, name, rval);
> > }
> > ...
> > (src:http://code.google.com/p/jslibs/source/browse/trunk/src/tools/jsTest....)

>
> > note1: if I remove the outer function foo, EvalVarByName('myVar')
> > returns 123.
>
> That suggests that your code works for the global scope but fails for
> the closure.
>
> If you add a dummy EvalVarByName JS function, put the code in to
> Firebug, and set a breakpoint in EvalVarByName you can look at the
> scopes in the Watch side panel.
>
> jjb

Oh, I understand my mistake.
I have to search in the scope chain of the caller of EvalVarByName,
not EvalVarByName itself.
Thanks.

Franck.

Jason Orendorff

unread,
Nov 18, 2009, 2:33:15 PM11/18/09
to franck.fr
On 11/18/2009 09:24 AM, franck.fr wrote:
> I am trying to access a variable value in the current scope chain:
>
> function foo() {
> var myVar = 123;
> function bar() {
> Print( EvalVarByName('myVar') );
> };
> bar();
> };
> foo();

I see what's happening here. You're running into a JS optimization.

The debugger APIs can detect some optimizations that are otherwise
transparent. Here the JS compiler sees that bar does not actually close
on any local variables in foo, so its scope chain does not include foo's
locals. Only the debugger APIs can tell the difference.

If the function did actually use myVar, that part of the scope chain
would be retained.

> Is there a better method to access myVar without using eval-like
> functions ?

I don't think so. What are you trying to do?

Later, you wrote:
> Oh, I understand my mistake.
> I have to search in the scope chain of the caller of EvalVarByName,
> not EvalVarByName itself.

Alas, I think this comment is mistaken. JS_GetScriptedCaller already
skips the (non-scripted) stack frame of EvalVarByName itself. Try this:

function foo() {
var myVar = 123;

return function bar() {


Print( EvalVarByName('myVar') );
};
}

var bar = foo();
bar();

I don't think this will work for you.

-j

franck.fr

unread,
Nov 18, 2009, 5:47:09 PM11/18/09
to
Thank you for the clarification.

> > Is there a better method to access myVar without using eval-like
> > functions ?
>
> I don't think so. What are you trying to do?
>

I try to enable my Expand() function to use the scope chain. eg:
var a = 'a';
function foo() {
var b = 'b';
function bar() {
var c = 'c';
Print( Expand('$(a)$(b)$(c)') );
};
bar();
};
foo();

Franck.

franck.fr

unread,
Nov 18, 2009, 6:06:20 PM11/18/09
to
If I use the following code to get variables value, a, b and c are
properly detected by JS_HasProperty but JS_GetProperty say that b has
undefined (JSVAL_VOID) value:

JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);

for ( JSObject *scope = JS_GetFrameScopeChain(cx, fp); scope; scope =


JS_GetParent(cx, scope) ) {
JS_HasProperty(cx, scope, name, &found);

if ( found ) {
JS_GetProperty(cx, scope, name, vp);
return JS_TRUE;
}
}

Franck.

Puneet Sharma

unread,
Nov 20, 2009, 7:00:12 AM11/20/09
to dev-tech-...@lists.mozilla.org

Hi,

I have recently moved to JS 1.8rc1 from JS 1.5. Thanks to SM, for
maintaining its backward compatibility for such a long time.
But, now JS 1.8 is reporting out of memory for same scenarios which
were used to be OK for JS 1.5.

I am using spidermonkey API's in below sequence:
1. JS_NewRuntime(1 << 14); maxbytes : 1 << 14 bytes
2. JS_NewContext(rt, 1<<13)
3. JS_NewObject() : Create class object
4. JS_InitStandardClasses

I debugged this issue and got to know that JS 1.8 is reporting "out of
memory" in InitStandardClasses API. To get rid of this, I tried increasing
size of runtime, so it didn't work with "1<<15", but got initialized with
1<<16.

Memory required for initialization in JS 1.8 is about 4 times the size of
JS 1.5 took. Or these is something which I need do along with current set of
API. Or it has something to do with Garbage collector. I tried using
JS_GetGCParameter API, but it also specifies same values which JS_NewRuntime
specifies.

Now, memory requirement has increased subsequently, is there any way to
curb this memory consumption which is getting huge in initialization itself.

Regards,
Puneet

Jason Orendorff

unread,
Nov 20, 2009, 10:32:40 AM11/20/09
to
On 11/18/2009 05:06 PM, franck.fr wrote:
> If I use the following code to get variables value, a, b and c are
> properly detected by JS_HasProperty but JS_GetProperty say that b has
> undefined (JSVAL_VOID) value:

Franck, this is hopeless. The JS engine is not going to keep around
apparently-dead variables on the off chance that someone might call a
native function that uses the debugger APIs to read them off the stack.
The debugger APIs don't work that way. You can use eval:

var a = 'a';
function foo() {
var b = 'b';
function bar() {
var c = 'c';

Print(eval(Expand('$(a)$(b)$(c)')));
}
bar();
}
foo();

where Expand('$(a)$(b)$(c)') returns the string '""+(a)+(b)+(c)'.

Or you can run your JS code through the C preprocessor before passing it
to SpiderMonkey, and use something like

#define Expand(s) eval(__expand(s))

-j

0 new messages