Object creation in SpiderMonkey 45

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

Object creation in SpiderMonkey 45

Mihai Dobrescu
Hello,

What changed concerning custom global objects?
I have defined some with "toString" function. In version 38, when instantiating them with JS_NewObject, "toString" was called successfully.
Now, this happens for objects created by the SpiderMonkey itself, but my code that uses JS_NewObject seems to skip assigning the "toString" method, as it is not called anymore. What could be the reason?

Thanks.
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Mihai Dobrescu
On Wednesday, May 4, 2016 at 7:48:10 PM UTC+3, Mihai Dobrescu wrote:
> Hello,
>
> What changed concerning custom global objects?
> I have defined some with "toString" function. In version 38, when instantiating them with JS_NewObject, "toString" was called successfully.
> Now, this happens for objects created by the SpiderMonkey itself, but my code that uses JS_NewObject seems to skip assigning the "toString" method, as it is not called anymore. What could be the reason?
>
> Thanks.

I've tried to debug, but still, no success.

For the following javascript:

var ap1 = new AIRealPoint(3, 3); --> (h, v), both of type AIReal

print(ap1);
print(ap1.h);

I get:

{ h: 3, v: 3 } --> my toString implementation
[object AIReal] --> default toString implementation, should have been my custom toString, having the output of "3"

For the following code:

var r = new AIReal(3);
print(r);

I get the expected custom toString output:

3

The h and v properties are defined using a templated function, basically creating a custom object of type AIReal (in this case) to return, using JS_NewObject. It surely does it, as the toString output states "[object AIReal]", but for some reason it doesn't call the custom toString when it is created this way. Any hints?

BTW, the print function uses JS::ToString to access object's toString method.
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Boris Zbarsky
On 5/5/16 8:56 AM, Mihai Dobrescu wrote:
> but for some reason it doesn't call the custom toString when it is
> created this way. Any hints?

Where does the custom toString live?  In your examples:

var ap1 = new AIRealPoint(3, 3);
var r = new AIReal(3);

is it the case that Object.getPrototypeOf(r) ==
Object.getPrototypeOf(ap1.h)?

Or put another way, when you say "h and v properties are defined using a
templated function, basically creating a custom object of type AIReal
(in this case) to return, using JS_NewObject", how _exactly_ are you
doing this?  What does the JS_NewObject callsite look like?

-Boris
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Mihai Dobrescu
On Thursday, May 5, 2016 at 6:06:29 PM UTC+3, Boris Zbarsky wrote:

> On 5/5/16 8:56 AM, Mihai Dobrescu wrote:
> > but for some reason it doesn't call the custom toString when it is
> > created this way. Any hints?
>
> Where does the custom toString live?  In your examples:
>
> var ap1 = new AIRealPoint(3, 3);
> var r = new AIReal(3);
>
> is it the case that Object.getPrototypeOf(r) ==
> Object.getPrototypeOf(ap1.h)?
>
> Or put another way, when you say "h and v properties are defined using a
> templated function, basically creating a custom object of type AIReal
> (in this case) to return, using JS_NewObject", how _exactly_ are you
> doing this?  What does the JS_NewObject callsite look like?
>
> -Boris

I have a construction as follows:

const JSFunctionSpec jsAIReal::fFunctions[] = {
    JS_FN("toString", jsAIReal::ToString, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
    ...

    JS_FS_END
}

passed to JS_InitClass (in a template class...):

static void DefineClass(JSContext *cx, JS::Handle<JSObject*> global)
    {
        try
        {

jsType::fProtoObj = JS_InitClass(cx, global,
                nullptr, &fClass,
                Constructor, jsType::fConstructorNumberOfArguments,
                jsType::fProperties, jsType::fFunctions, jsType::fStaticProperties, jsType::fStaticFunctions);

            if (!jsType::fProtoObj)
            {
                throw new jsEngineException("jsEngine error at definiton of %s.", fClass.name);
            }
}
        catch (...)
        {
            throw new jsEngineException("jsEngine error at definiton of %s.", fClass.name);
        }
    }

A property getter looks like:

template<typename jsType, typename jsPropertyType, typename jsPropertyType::PrivateType PrivateType::*Property>
    static bool GetProperty(JSContext *cx, unsigned argc, JS::Value *vp)
    {
        JS::CallArgs args = CallArgsFromVp(argc, vp);

        PrivateType* data = (PrivateType*)(JS_GetPrivate(&args.thisv().toObject()));

        if (!data)
            return false; // +throw error...

        JSObject *obj = JS_NewObject(cx, &jsDataClass<jsPropertyType>::fClass);

        JS_SetPrivate(obj, new jsPropertyType::PrivateType(data->*Property));

        args.rval().setObject(*obj);

        return true;
    }

used as follows:

const JSPropertySpec jsAIRealPoint::fProperties[] = {
        CLASS_JS_PSGS_PROPERTY(jsAIRealPoint, jsAIReal, h),
        CLASS_JS_PSGS_PROPERTY(jsAIRealPoint, jsAIReal, v),

    JS_PS_END
};

where I have:

#define CLASS_JS_PSGS_PROPERTY(JS_TYPE, JS_PROPERTY_TYPE, PROPERTY) \
JS_PSGS(#PROPERTY, (JS_TYPE::GetProperty<JS_TYPE, JS_PROPERTY_TYPE, &JS_TYPE::PrivateType::PROPERTY>), \
                   (JS_TYPE::SetProperty<JS_TYPE, JS_PROPERTY_TYPE, &JS_TYPE::PrivateType::PROPERTY>), JSPROP_PERMANENT | JSPROP_ENUMERATE)

A bit hard to read this...sorry.

Note, it worked fine in 38.
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Mihai Dobrescu
On Thursday, May 5, 2016 at 6:19:24 PM UTC+3, Mihai Dobrescu wrote:

> On Thursday, May 5, 2016 at 6:06:29 PM UTC+3, Boris Zbarsky wrote:
> > On 5/5/16 8:56 AM, Mihai Dobrescu wrote:
> > > but for some reason it doesn't call the custom toString when it is
> > > created this way. Any hints?
> >
> > Where does the custom toString live?  In your examples:
> >
> > var ap1 = new AIRealPoint(3, 3);
> > var r = new AIReal(3);
> >
> > is it the case that Object.getPrototypeOf(r) ==
> > Object.getPrototypeOf(ap1.h)?
> >
> > Or put another way, when you say "h and v properties are defined using a
> > templated function, basically creating a custom object of type AIReal
> > (in this case) to return, using JS_NewObject", how _exactly_ are you
> > doing this?  What does the JS_NewObject callsite look like?
> >
> > -Boris
>
> I have a construction as follows:
>
> const JSFunctionSpec jsAIReal::fFunctions[] = {
>     JS_FN("toString", jsAIReal::ToString, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
>     ...
>
>     JS_FS_END
> }
>
> passed to JS_InitClass (in a template class...):
>
> static void DefineClass(JSContext *cx, JS::Handle<JSObject*> global)
>     {
>         try
>         {
>
> jsType::fProtoObj = JS_InitClass(cx, global,
>                 nullptr, &fClass,
>                 Constructor, jsType::fConstructorNumberOfArguments,
>                 jsType::fProperties, jsType::fFunctions, jsType::fStaticProperties, jsType::fStaticFunctions);
>
>             if (!jsType::fProtoObj)
>             {
>                 throw new jsEngineException("jsEngine error at definiton of %s.", fClass.name);
>             }
> }
>         catch (...)
>         {
>             throw new jsEngineException("jsEngine error at definiton of %s.", fClass.name);
>         }
>     }
>
> A property getter looks like:
>
> template<typename jsType, typename jsPropertyType, typename jsPropertyType::PrivateType PrivateType::*Property>
>     static bool GetProperty(JSContext *cx, unsigned argc, JS::Value *vp)
>     {
>         JS::CallArgs args = CallArgsFromVp(argc, vp);
>
>         PrivateType* data = (PrivateType*)(JS_GetPrivate(&args.thisv().toObject()));
>
>         if (!data)
>             return false; // +throw error...
>
>         JSObject *obj = JS_NewObject(cx, &jsDataClass<jsPropertyType>::fClass);
>
>         JS_SetPrivate(obj, new jsPropertyType::PrivateType(data->*Property));
>
>         args.rval().setObject(*obj);
>
>         return true;
>     }
>
> used as follows:
>
> const JSPropertySpec jsAIRealPoint::fProperties[] = {
> CLASS_JS_PSGS_PROPERTY(jsAIRealPoint, jsAIReal, h),
> CLASS_JS_PSGS_PROPERTY(jsAIRealPoint, jsAIReal, v),
>
>     JS_PS_END
> };
>
> where I have:
>
> #define CLASS_JS_PSGS_PROPERTY(JS_TYPE, JS_PROPERTY_TYPE, PROPERTY) \
> JS_PSGS(#PROPERTY, (JS_TYPE::GetProperty<JS_TYPE, JS_PROPERTY_TYPE, &JS_TYPE::PrivateType::PROPERTY>), \
>                    (JS_TYPE::SetProperty<JS_TYPE, JS_PROPERTY_TYPE, &JS_TYPE::PrivateType::PROPERTY>), JSPROP_PERMANENT | JSPROP_ENUMERATE)
>
> A bit hard to read this...sorry.
>
> Note, it worked fine in 38.

Initially, I have set 0 for the functions flags (now, out of curiousity, I have JSPROP_PERMANENT | JSPROP_ENUMERATE, which is just for testing).
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Boris Zbarsky
In reply to this post by Mihai Dobrescu
On 5/5/16 11:19 AM, Mihai Dobrescu wrote:
>          JSObject *obj = JS_NewObject(cx, &jsDataClass<jsPropertyType>::fClass);

Here's your problem.  You didn't give it the right prototype.

Things used to default to "if you pass no prototype and just the class
we'll do some fragile lookup to try to figure out the right prototype",
but that went away in https://bugzilla.mozilla.org/show_bug.cgi?id=1125567

So you need to pass in the right prototype object here.

-Boris
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Mihai Dobrescu
On Thursday, May 5, 2016 at 7:27:05 PM UTC+3, Boris Zbarsky wrote:

> On 5/5/16 11:19 AM, Mihai Dobrescu wrote:
> >          JSObject *obj = JS_NewObject(cx, &jsDataClass<jsPropertyType>::fClass);
>
> Here's your problem.  You didn't give it the right prototype.
>
> Things used to default to "if you pass no prototype and just the class
> we'll do some fragile lookup to try to figure out the right prototype",
> but that went away in https://bugzilla.mozilla.org/show_bug.cgi?id=1125567
>
> So you need to pass in the right prototype object here.
>
> -Boris

I don't understand what you mean. It is 45, not 38.
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Mihai Dobrescu
On Thursday, May 5, 2016 at 7:38:32 PM UTC+3, Mihai Dobrescu wrote:

> On Thursday, May 5, 2016 at 7:27:05 PM UTC+3, Boris Zbarsky wrote:
> > On 5/5/16 11:19 AM, Mihai Dobrescu wrote:
> > >          JSObject *obj = JS_NewObject(cx, &jsDataClass<jsPropertyType>::fClass);
> >
> > Here's your problem.  You didn't give it the right prototype.
> >
> > Things used to default to "if you pass no prototype and just the class
> > we'll do some fragile lookup to try to figure out the right prototype",
> > but that went away in https://bugzilla.mozilla.org/show_bug.cgi?id=1125567
> >
> > So you need to pass in the right prototype object here.
> >
> > -Boris
>
> I don't understand what you mean. It is 45, not 38.

+ I used to pass nullptr for prototype, in 38, and it worked.
I would expect that after initialization of classes, all the stuff to work as their definitions are loaded, including their functions.
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Boris Zbarsky
On 5/5/16 12:50 PM, Mihai Dobrescu wrote:

> On Thursday, May 5, 2016 at 7:38:32 PM UTC+3, Mihai Dobrescu wrote:
>> On Thursday, May 5, 2016 at 7:27:05 PM UTC+3, Boris Zbarsky wrote:
>>> Things used to default to "if you pass no prototype and just the class
>>> we'll do some fragile lookup to try to figure out the right prototype",
>>> but that went away in https://bugzilla.mozilla.org/show_bug.cgi?id=1125567
>>>
>>> So you need to pass in the right prototype object here.
>>>
>>> -Boris
>>
>> I don't understand what you mean. It is 45, not 38.
>
> + I used to pass nullptr for prototype, in 38, and it worked.

Sure.  It worked because JS_NewObject saw you passed null for the proto
but a non-default class, took the class name, looked it up as a property
on the global, assumed the result was the constructor for your class,
got its .prototype and used that as the prototype.

That whole "look up the name on the global and hope it has something to
do with us" thing was removed in the bug I link to above, which was
fixed in Firefox 40.  Notably, 38 < 40 <= 45.

> I would expect that after initialization of classes, all the stuff to work as their definitions are loaded, including their functions.

The definitions are "loaded".  The functions are defined on the
prototype object for your class.  But the object you're creating doesn't
have that on its proto chain, because of the behavior change above.

-Boris


_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Mihai Dobrescu
On Thursday, May 5, 2016 at 8:21:04 PM UTC+3, Boris Zbarsky wrote:

> On 5/5/16 12:50 PM, Mihai Dobrescu wrote:
> > On Thursday, May 5, 2016 at 7:38:32 PM UTC+3, Mihai Dobrescu wrote:
> >> On Thursday, May 5, 2016 at 7:27:05 PM UTC+3, Boris Zbarsky wrote:
> >>> Things used to default to "if you pass no prototype and just the class
> >>> we'll do some fragile lookup to try to figure out the right prototype",
> >>> but that went away in https://bugzilla.mozilla.org/show_bug.cgi?id=1125567
> >>>
> >>> So you need to pass in the right prototype object here.
> >>>
> >>> -Boris
> >>
> >> I don't understand what you mean. It is 45, not 38.
> >
> > + I used to pass nullptr for prototype, in 38, and it worked.
>
> Sure.  It worked because JS_NewObject saw you passed null for the proto
> but a non-default class, took the class name, looked it up as a property
> on the global, assumed the result was the constructor for your class,
> got its .prototype and used that as the prototype.
>
> That whole "look up the name on the global and hope it has something to
> do with us" thing was removed in the bug I link to above, which was
> fixed in Firefox 40.  Notably, 38 < 40 <= 45.
>
> > I would expect that after initialization of classes, all the stuff to work as their definitions are loaded, including their functions.
>
> The definitions are "loaded".  The functions are defined on the
> prototype object for your class.  But the object you're creating doesn't
> have that on its proto chain, because of the behavior change above.
>
> -Boris

My mind just blown up. What is the status now in 45? Is it a bug, or should I do things differently? If so, how?
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Boris Zbarsky
On 5/5/16 1:47 PM, Mihai Dobrescu wrote:
> My mind just blown up. What is the status now in 45? Is it a bug, or should I do things differently? If so, how?

You should do things differently.  You need to pass the correct proto to
the JS_NewObject call, as I said two or three times already.

-Boris
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Mihai Dobrescu
On Thursday, May 5, 2016 at 8:57:54 PM UTC+3, Boris Zbarsky wrote:
> On 5/5/16 1:47 PM, Mihai Dobrescu wrote:
> > My mind just blown up. What is the status now in 45? Is it a bug, or should I do things differently? If so, how?
>
> You should do things differently.  You need to pass the correct proto to
> the JS_NewObject call, as I said two or three times already.
>
> -Boris

If I understand well, should I replace the call to JS_NewObject by JS_NewObjectWithGivenProto?

JSObject *
JS_NewObject(JSContext *cx, const JSClass *clasp);

by

bool
JS_NewObjectWithGivenProto(JSContext *cx, const JSClass *clasp, JS::Handle<JSObject*> proto);
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Boris Zbarsky
On 5/5/16 2:11 PM, Mihai Dobrescu wrote:
> If I understand well, should I replace the call to JS_NewObject by JS_NewObjectWithGivenProto?

Yes.

-Boris
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Mihai Dobrescu
On Thursday, May 5, 2016 at 9:25:23 PM UTC+3, Boris Zbarsky wrote:
> On 5/5/16 2:11 PM, Mihai Dobrescu wrote:
> > If I understand well, should I replace the call to JS_NewObject by JS_NewObjectWithGivenProto?
>
> Yes.
>
> -Boris

Thank you, Boris.

Now, what could be done with the JS_NewObject as long as it couldn't do this job? What is its purpose?
_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine
Reply | Threaded
Open this post in threaded view
|

Re: Object creation in SpiderMonkey 45

Boris Zbarsky
On 5/5/16 2:58 PM, Mihai Dobrescu wrote:
> Now, what could be done with the JS_NewObject as long as it couldn't do this job? What is its purpose?

It's a slightly more convenient API for JS_NewObjectWithGivenProto(cx,
clasp, JS_GetObjectPrototype(cx)).

-Boris

_______________________________________________
dev-tech-js-engine mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-js-engine