Discussion:
question about javascript functions
Béatrice Philippe
2005-02-04 13:22:48 UTC
Permalink
Hello !

i'm currently trying to replace an old javascript function with a new one in
the global object like this:
1) i create a new javascript function (say 'myfun') and compile it.
2) i delete the old property of the name 'myfun'
3) i add a new property with my new javascript function 'myfun' created and
compile in step 1.

these steps work well. But when i want to call a function 'fun1' that calls
my new function 'myfun', it seems to be lost.
am i forgetting something ?

Thank you.

example:
" function fun1() {
....
myfun(); //crash !
return;
}

function myfun(){
//this is my new function that replaced the old one with the same name.
}"
Ludovic Delabre
2005-02-07 23:21:52 UTC
Permalink
Hello!
I'm not sure I understand what you want so ... Somethin' like this ?
(played with the jsshell)

js> function myfun() { return "Original"; }
js> function fun1() { return myfun(); }
js> fun1()
Original
js> delete myfun
false
js> function myfun() { return "NewOne"; }
js> fun1()
NewOne
js>

Ludovic.
Post by Béatrice Philippe
Hello !
i'm currently trying to replace an old javascript function with a new one in
1) i create a new javascript function (say 'myfun') and compile it.
2) i delete the old property of the name 'myfun'
3) i add a new property with my new javascript function 'myfun' created and
compile in step 1.
these steps work well. But when i want to call a function 'fun1' that calls
my new function 'myfun', it seems to be lost.
am i forgetting something ?
Thank you.
" function fun1() {
....
myfun(); //crash !
return;
}
function myfun(){
//this is my new function that replaced the old one with the same name.
}"
Béatrice Philippe
2005-02-08 13:56:00 UTC
Permalink
yes, your example is working !
but i'm trying to do this in my C++ application, using jsapi. And here is
the problem...

I'm interrested in modifying the body of an existing javascript function in
its global object.
So for the moment, i'm currently trying to delete my old function 'fun1'
with 'js_deleteProperty()' in the global object, and then i create a new
function with 'js_compileFunction()' method with the same name 'fun1'.
If my application tries to call the new fun1 with 'js_callFunction..()',
it's working. But if the new fun1 function is called by others existing
functions, it crashes.
I think when i try to delete a function fun1 with 'js_deleteProperty()', all
functions that referenced this function fun1 are not notified about this
change. They don't know fun1 was deleted and replaced by a new fun1
function.

My question is:
is there any way to change dynamically the body of an existing function in a
C++ application, using jsapi ?
or if no, is there any solution to create a new function that would replace
the old one ?

Thank you very much for your help.
--
Béatrice Philippe-Derbez
Post by Ludovic Delabre
Hello!
I'm not sure I understand what you want so ... Somethin' like this ?
(played with the jsshell)
js> function myfun() { return "Original"; }
js> function fun1() { return myfun(); }
js> fun1()
Original
js> delete myfun
false
js> function myfun() { return "NewOne"; }
js> fun1()
NewOne
js>
Ludovic.
Post by Béatrice Philippe
Hello !
i'm currently trying to replace an old javascript function with a new one
1) i create a new javascript function (say 'myfun') and compile it.
2) i delete the old property of the name 'myfun'
3) i add a new property with my new javascript function 'myfun' created
and compile in step 1.
these steps work well. But when i want to call a function 'fun1' that
calls my new function 'myfun', it seems to be lost.
am i forgetting something ?
Thank you.
" function fun1() {
....
myfun(); //crash !
return;
}
function myfun(){
//this is my new function that replaced the old one with the same name.
}"
Ludovic Delabre
2005-02-08 19:43:19 UTC
Permalink
Post by Béatrice Philippe
yes, your example is working !
but i'm trying to do this in my C++ application, using jsapi. And here is
the problem...
Yeah I understood you wanted to play with jsapi but I first needed to
get your problem... :-p
Post by Béatrice Philippe
I'm interrested in modifying the body of an existing javascript function in
its global object.
I just played a bit with jsapi using JS_CompileFunction() to dynamically
changes a function at runtime and ... no problem !?
BTW, it also works fine for me without calling deleteProperty()...
Post by Béatrice Philippe
So for the moment, i'm currently trying to delete my old function 'fun1'
with 'js_deleteProperty()' in the global object, and then i create a new
function with 'js_compileFunction()' method with the same name 'fun1'.
If my application tries to call the new fun1 with 'js_callFunction..()',
it's working. But if the new fun1 function is called by others existing
functions, it crashes.
I think when i try to delete a function fun1 with 'js_deleteProperty()', all
functions that referenced this function fun1 are not notified about this
change. They don't know fun1 was deleted and replaced by a new fun1
function.
From what I know, there're no hidden reference lying around, everythin'
is evaluated at runtime (but I might be mistaken?).
Post by Béatrice Philippe
is there any way to change dynamically the body of an existing function in a
C++ application, using jsapi ?
or if no, is there any solution to create a new function that would replace
the old one ?
Thank you very much for your help.
Well I don't know why it doesn't work for you when it works fine for
me... What are you doing exactly ?

See ya,
Ludovic.
Béatrice Philippe
2005-02-08 21:02:21 UTC
Permalink
what i'm doing is :
1. reading each function body
2. if a function contains some javascript statements my app doesn't want, my
app modifies the javascript function body (that's what i try to).

The purpose is :
when my app changes the body of a javascript function, this function must be
called everywhere and works.

I tried this example :
here are two functions :
function fun1() {
var i = 'hello';
return i.toString();
}

function fun2() {
var j = 'hello from fun2';
var x = fun1();
return x.toString();
}
somwhere in the html document:
<A href=..... onclick="javascript:fun1();".....>
if we do : 'js_evaluateScript()' for the onclick event: it works.

now, my app wants to change fun1 like this:
JSstring aBody = js_decompileFunctionBody(...);
char * aBody_char = js_GetStringBytes(...aBody);
.... here we change the content of aBody_char....
JSFunction *new_fun = js_compileFunction(contextOfGlobalObject,
GlobalObject, aBody_char, strlen(aBody_char),.....);
JSObject * childObject = JS_GetFunctionObject(new_fun);
JS_AddRoot(contextOfGlobalObject,&childObject);

jsval rval = OBJECT_TO_JSVAL(childObject);
JSObject *clonedFunc = JS_CloneFunctionObject(contextOfGlobalObject,
childObject, GlobalObject);
JS_DefineProperty(contextOfGlobalObject, GlobalObject, "fun1",
OBJECT_TO_JSVAL(childObject), nsnull, nsnull,
JSPROP_ENUMERATE | JSPROP_PERMANENT));

here, the function fun1 has been changed. Now, We can' t use
js_evaluateScript() anymore to play the 'onclick' event, but we must use
js_callFunctionValue() (or js_callFunction()) to call fun1 (and for that, we
must know that the onclick event is a function call :-)). This solution
works.

BUT: if we want to call fun2 function: it crashes since fun1 has changed and
spidermonkey cannot resolve
"x=fun1()" statement in fun2. Why ????? pointer lost ?
if we don't change fun1 body, calling fun2 works well ! strange !!!!

Any idea ?
Thank you.
--
Béatrice Philippe-Derbez
Post by Béatrice Philippe
yes, your example is working !
but i'm trying to do this in my C++ application, using jsapi. And here is
the problem...
Yeah I understood you wanted to play with jsapi but I first needed to get
your problem... :-p
Post by Béatrice Philippe
I'm interrested in modifying the body of an existing javascript function
in its global object.
I just played a bit with jsapi using JS_CompileFunction() to dynamically
changes a function at runtime and ... no problem !?
BTW, it also works fine for me without calling deleteProperty()...
Post by Béatrice Philippe
So for the moment, i'm currently trying to delete my old function 'fun1'
with 'js_deleteProperty()' in the global object, and then i create a new
function with 'js_compileFunction()' method with the same name 'fun1'.
If my application tries to call the new fun1 with 'js_callFunction..()',
it's working. But if the new fun1 function is called by others existing
functions, it crashes.
I think when i try to delete a function fun1 with 'js_deleteProperty()',
all functions that referenced this function fun1 are not notified about
this change. They don't know fun1 was deleted and replaced by a new fun1
function.
From what I know, there're no hidden reference lying around, everythin' is
evaluated at runtime (but I might be mistaken?).
Post by Béatrice Philippe
is there any way to change dynamically the body of an existing function
in a C++ application, using jsapi ?
or if no, is there any solution to create a new function that would
replace the old one ?
Thank you very much for your help.
Well I don't know why it doesn't work for you when it works fine for me...
What are you doing exactly ?
See ya,
Ludovic.
Ludovic Delabre
2005-02-09 00:15:03 UTC
Permalink
Well if I try from what you gave me, I got:
Assertion failure: root_points_to_gcArenaPool, at
\js-1.5-rc6a\js\src\jsgc.c:972
Is that it ?

I can get rid of the crash by taking out the call to JS_AddRoot()...

hum... but somehow I got the idea working using "only" JS_CompileFunction ?
And from what I read from spidermonkey's source, the define property is
already done there... so why all the extra code ?

But maybe I miss somethin'... :-)

And why can't you call evaluateScript() anymore ? Works fine here...

Good night,
Ludovic
Post by Béatrice Philippe
1. reading each function body
2. if a function contains some javascript statements my app doesn't want, my
app modifies the javascript function body (that's what i try to).
when my app changes the body of a javascript function, this function must be
called everywhere and works.
function fun1() {
var i = 'hello';
return i.toString();
}
function fun2() {
var j = 'hello from fun2';
var x = fun1();
return x.toString();
}
<A href=..... onclick="javascript:fun1();".....>
if we do : 'js_evaluateScript()' for the onclick event: it works.
JSstring aBody = js_decompileFunctionBody(...);
char * aBody_char = js_GetStringBytes(...aBody);
.... here we change the content of aBody_char....
JSFunction *new_fun = js_compileFunction(contextOfGlobalObject,
GlobalObject, aBody_char, strlen(aBody_char),.....);
JSObject * childObject = JS_GetFunctionObject(new_fun);
JS_AddRoot(contextOfGlobalObject,&childObject);
jsval rval = OBJECT_TO_JSVAL(childObject);
JSObject *clonedFunc = JS_CloneFunctionObject(contextOfGlobalObject,
childObject, GlobalObject);
JS_DefineProperty(contextOfGlobalObject, GlobalObject, "fun1",
OBJECT_TO_JSVAL(childObject), nsnull, nsnull,
JSPROP_ENUMERATE | JSPROP_PERMANENT));
here, the function fun1 has been changed. Now, We can' t use
js_evaluateScript() anymore to play the 'onclick' event, but we must use
js_callFunctionValue() (or js_callFunction()) to call fun1 (and for that, we
must know that the onclick event is a function call :-)). This solution
works.
BUT: if we want to call fun2 function: it crashes since fun1 has changed and
spidermonkey cannot resolve
"x=fun1()" statement in fun2. Why ????? pointer lost ?
if we don't change fun1 body, calling fun2 works well ! strange !!!!
Any idea ?
Thank you.
Béatrice Philippe
2005-02-14 21:22:27 UTC
Permalink
Thank you.
i still don't understand why i can't use "evaluateScript()" instead of
"callFunctionValue()" since i change a javascript function in the global
object.

Another question : is there any way to get argument names of a each
javascript function stored in the global object ? i saw i could get the
number of arguments but no names....

Thanks and good night too !
--
Béatrice Philippe-Derbez
Post by Ludovic Delabre
Assertion failure: root_points_to_gcArenaPool, at
\js-1.5-rc6a\js\src\jsgc.c:972
Is that it ?
I can get rid of the crash by taking out the call to JS_AddRoot()...
hum... but somehow I got the idea working using "only" JS_CompileFunction ?
And from what I read from spidermonkey's source, the define property is
already done there... so why all the extra code ?
But maybe I miss somethin'... :-)
And why can't you call evaluateScript() anymore ? Works fine here...
Good night,
Ludovic
Post by Béatrice Philippe
1. reading each function body
2. if a function contains some javascript statements my app doesn't want,
my app modifies the javascript function body (that's what i try to).
when my app changes the body of a javascript function, this function must
be called everywhere and works.
function fun1() {
var i = 'hello';
return i.toString();
}
function fun2() {
var j = 'hello from fun2';
var x = fun1();
return x.toString();
}
<A href=..... onclick="javascript:fun1();".....>
if we do : 'js_evaluateScript()' for the onclick event: it works.
JSstring aBody = js_decompileFunctionBody(...);
char * aBody_char = js_GetStringBytes(...aBody);
.... here we change the content of aBody_char....
JSFunction *new_fun = js_compileFunction(contextOfGlobalObject,
GlobalObject, aBody_char, strlen(aBody_char),.....);
JSObject * childObject = JS_GetFunctionObject(new_fun);
JS_AddRoot(contextOfGlobalObject,&childObject);
jsval rval = OBJECT_TO_JSVAL(childObject);
JSObject *clonedFunc = JS_CloneFunctionObject(contextOfGlobalObject,
childObject, GlobalObject);
JS_DefineProperty(contextOfGlobalObject, GlobalObject, "fun1",
OBJECT_TO_JSVAL(childObject), nsnull, nsnull,
JSPROP_ENUMERATE | JSPROP_PERMANENT));
here, the function fun1 has been changed. Now, We can' t use
js_evaluateScript() anymore to play the 'onclick' event, but we must use
js_callFunctionValue() (or js_callFunction()) to call fun1 (and for that,
we must know that the onclick event is a function call :-)). This
solution works.
BUT: if we want to call fun2 function: it crashes since fun1 has changed
and spidermonkey cannot resolve
"x=fun1()" statement in fun2. Why ????? pointer lost ?
if we don't change fun1 body, calling fun2 works well ! strange !!!!
Any idea ?
Thank you.
Matthew Mondor
2005-02-15 00:39:22 UTC
Permalink
On Mon, 14 Feb 2005 22:22:27 +0100
Post by Béatrice Philippe
Another question : is there any way to get argument names of a each
javascript function stored in the global object ? i saw i could get
the number of arguments but no names....
Hmm I just ran a little test through the js shell to see if function
arguments would be considered properties and could be iterated though:

function test(arg1, arg2)
{
for (;;) ;
}

for (i in test)
print(i + ' = ' + test[i] + "\n");

This suggests that a C function running through the properties after a
JS_Enumerate() could retreive the argument names of a function, if
working on the function JSObject... A function similar to the one I
posted above in the "Iterating through all Array elements from C" would
most probably work. Unfortunately, the JSIdArray structure is supposed
to be considered private API, according to the reference documentation I
read
(http://www.mozilla.org/js/spidermonkey/apidoc/gen/api-JSIdArray.html)
but it worked for me and I needed the functionality.

Matt
Béatrice Philippe
2005-02-16 14:43:19 UTC
Permalink
Thank you Matt, you are right !!
with js_enumerate in c++, we can retrieve all parameter names of the
function (parameters appear at the top of the enumeration).
Now, i just need to give parameter values to my js_callFunctionValue(). I
think js_convert() should be
the right solution ?!

Thank you again.
--
Béatrice Philippe-Derbez
Post by Matthew Mondor
On Mon, 14 Feb 2005 22:22:27 +0100
Post by Béatrice Philippe
Another question : is there any way to get argument names of a each
javascript function stored in the global object ? i saw i could get
the number of arguments but no names....
Hmm I just ran a little test through the js shell to see if function
function test(arg1, arg2)
{
for (;;) ;
}
for (i in test)
print(i + ' = ' + test[i] + "\n");
This suggests that a C function running through the properties after a
JS_Enumerate() could retreive the argument names of a function, if
working on the function JSObject... A function similar to the one I
posted above in the "Iterating through all Array elements from C" would
most probably work. Unfortunately, the JSIdArray structure is supposed
to be considered private API, according to the reference documentation I
read
(http://www.mozilla.org/js/spidermonkey/apidoc/gen/api-JSIdArray.html)
but it worked for me and I needed the functionality.
Matt
Matthew Mondor
2005-02-18 22:07:33 UTC
Permalink
On Wed, 16 Feb 2005 15:43:19 +0100
Post by Béatrice Philippe
Thank you Matt, you are right !!
with js_enumerate in c++, we can retrieve all parameter names of the
function (parameters appear at the top of the enumeration).
Now, i just need to give parameter values to my
js_callFunctionValue(). I think js_convert() should be
the right solution ?!
Hmm I'm not sure I understand... So you obtain the arguments and their
types of a user created function, using JS_Evaluate(), so that you can
then call that user/script function with the proper arguments from C?

I guess that JS_ConvertArguments() could serve perhaps, if it's what you
meant, but the arguments are simply passed as an array of jsval, of
course (argv) with the number of elements of the array in argc. It
appears that in javascript the value types can easily be converted as
well automatically in many cases... This is also true with SpiderMonkey
when using JS_ValueTo*() functions rather than strict JSVAL_IS_*()
followed by conditional JSVAL_TO_*() macros (which are probably good for
performance and to ensure proper types though).

Also, you can attempt to call a JS function from C which is assumed to
have been defined with the expected arguments. Very possibly there is a
simple way to then detect if the function wasn't declared as it had to
be when doing so (I would have to write a little test and see to confirm
this though).

Sorry if I'm way off, I couldn't clearly understand the question

Matt
Béatrice Philippe
2005-02-21 09:27:47 UTC
Permalink
Well, if i try to change a user javascript function, then i can't use
js_evaluate() anymore (i can use js_evaluate only if nothing is changed by
my C++ application).
so what i have to do is calling the modified function with
js_callFunctionValue() and to perform this, i must know wich arguments i
have to give to the function (my c++ app scans all javascript functions in
the web page, so it doesn't know what kind of function it's scanning).
I had a look in js_convert...() : i think it's not the right way to give
arguments to js_callFunctionValue().
I'll try js_valueto...() function ....

Thanks.
Béatrice.
Post by Matthew Mondor
On Wed, 16 Feb 2005 15:43:19 +0100
Post by Béatrice Philippe
Thank you Matt, you are right !!
with js_enumerate in c++, we can retrieve all parameter names of the
function (parameters appear at the top of the enumeration).
Now, i just need to give parameter values to my
js_callFunctionValue(). I think js_convert() should be
the right solution ?!
Hmm I'm not sure I understand... So you obtain the arguments and their
types of a user created function, using JS_Evaluate(), so that you can
then call that user/script function with the proper arguments from C?
I guess that JS_ConvertArguments() could serve perhaps, if it's what you
meant, but the arguments are simply passed as an array of jsval, of
course (argv) with the number of elements of the array in argc. It
appears that in javascript the value types can easily be converted as
well automatically in many cases... This is also true with SpiderMonkey
when using JS_ValueTo*() functions rather than strict JSVAL_IS_*()
followed by conditional JSVAL_TO_*() macros (which are probably good for
performance and to ensure proper types though).
Also, you can attempt to call a JS function from C which is assumed to
have been defined with the expected arguments. Very possibly there is a
simple way to then detect if the function wasn't declared as it had to
be when doing so (I would have to write a little test and see to confirm
this though).
Sorry if I'm way off, I couldn't clearly understand the question
Matt
Continue reading on narkive:
Loading...