Debugging wrapped C++ object

126 views
Skip to first unread message

Anoop R. S.

unread,
May 8, 2018, 12:35:12 AM5/8/18
to v8-users
Hi All,
I am trying out a debugger prototype using the remote debugger protocol. 
Going by the standard example in Embedder's Guide:
C++ class:
-------------
class Point {
 public:
  Point(int x, int y) : x_(x), y_(y) { }
  int x_, y_;
}

Usage in JavaScript:
---------------------------
var p = Point(1,2);

Has anyone tried debugging a wrapped C++ object that is being returned to Javascript? Is it possible? 

regards,
Anoop R. S.

Zac Hansen

unread,
May 8, 2018, 1:00:48 AM5/8/18
to v8-users
I believe you can only interact with it on a javascript-basis from the javascript debugger.   I don't know of any way to treat it special from the javascript debugger.

I often end up setting two breakpoints - first in JS, then another in the native callback I registered for the javascript object/operation I'm about to call.

--Zac

Zac Hansen

unread,
May 8, 2018, 1:04:01 AM5/8/18
to v8-users
..the second breakpoint being in a native debugger like gdb/lldb/etc.

ibon

unread,
May 9, 2018, 8:14:12 AM5/9/18
to v8-users
Hey, I do this all the time with android studio.
I have an android app with embedded v8, and debug both native c++ and javascript seamlessly.

Anoop R. S.

unread,
May 9, 2018, 10:05:59 AM5/9/18
to v8-users
Thank you all for your replies. 
But my intention is different. Let me be more specific:
I want others to debug the JavaScript code but not the c++ part. They will use chrome devtools to do that. So, when they encounter any c++ object that is made available to Javascript, I would like to display some custom information about it.

While wrapping the object, I implimented GenericNamedPropertyGetterCallback and called SetHandler to set it to the ObjectTemplate using function NamedPropertyHandlerConfiguration

point_object_template->SetHandler(
 v8
::NamedPropertyHandlerConfiguration(AccessorGetterCallbackFunction,0, NamedPropertyQueryCallbackFunction));

The function is implemented as follows:
void AccessorGetterCallbackFunction(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& info)
{
 
auto pointPtr = UnwrapPoint(info.Holder());
 
bool bIsString = property->IsString();
 std
::string accessed_property;
 
auto value = v8::Local<v8::String>::Cast(property);
 v8
::String::Utf8Value utf8_value(v8::Local<v8::String>::Cast(property));
 accessed_property
= *utf8_value;
 
if (accessed_property == "x")
 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), pointPtr->x_));
 else if (accessed_property == "y")
 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), pointPtr->y_));
}

The content of p is coming as {} as shown below. 

Are there any callbacks are available to set the content that is displayed as value of p? Also, other than x and y, which are members of Point, another property named splice is showing up. When is this property accessed? 
Please let me know if you have any information.

regards,
Anoop R. S.
Message has been deleted
Message has been deleted

Anoop R. S.

unread,
May 10, 2018, 2:42:17 AM5/10/18
to v8-users
Ok. I figured out that if v8::IndexedPropertyHandlerConfiguration is set, and IndexedPropertyEnumeratorCallback is implemented, I can configure what is displayed on mouse over action (Debugger.evaluateOnCallFrame is  passed from devtools on doing that operation.) 

The implementation is provided below. 
void IndexedPropertyEnumeratorCallbackFunction(
 
const v8::PropertyCallbackInfo<v8::Array>& p_callbackInfo)
{
 v8
::Local<v8::Array> IndexArray = v8::Array::New(p_callbackInfo.GetIsolate(), 2);
 
IndexArray->Set(
 v8
::Integer::New(p_callbackInfo.GetIsolate(), 0),
 v8
::String::NewFromUtf8(p_callbackInfo.GetIsolate(), u8"x"));
 
IndexArray->Set(
 v8
::Integer::New(p_callbackInfo.GetIsolate(), 1),
 v8
::String::NewFromUtf8(p_callbackInfo.GetIsolate(), u8"y"));
 p_callbackInfo
.GetReturnValue().Set(IndexArray);
}

From reading the embedder's guide, my understanding is that 
indexed property interceptors - called when accessing indexed properties. An example of this, in a browser environment, is document.forms.elements[0].

Why is it called on evaluateOnCallFrame action? Also, I tried with other callback s of v8::IndexedPropertyHandlerConfiguration, but they are not called. Can I know why? Also, since the signature of callback is as below :

void (*IndexedPropertyEnumeratorCallback)( const PropertyCallbackInfo<Array>& info);

I can set only arrays into the result and nothing else. 
I am not an expert in v8, hence these questions. Please let me know about it/ point me to some documentation regarding this.

regards,
Anoop R. S.

Ben Noordhuis

unread,
May 10, 2018, 3:40:03 AM5/10/18
to v8-users
IndexedPropertyEnumeratorCallback - is called for Object.keys()-like
operations; i.e., to list the enumerable properties of the object but
not non-enumerable or prototype properties. The 'Indexed' refers to
the fact that it's intended for numeric keys, i.e., array-like
objects. Instead of v8::IndexedPropertyHandlerConfiguration, you may
want to use v8::NamedPropertyHandlerConfiguration.

evaluateOnCallFrame - V8 cannot know whether your callback has any
side effects (it could create objects, call into JS code, etc.), hence
it evaluates it as if it were a snippet of regular JS code. Newer
versions of V8 let you register callbacks with kHasNoSideEffect but as
far as I know that has no effect (hah!) on whether or not
evaluateOnCallFrame is used. Maybe in the future.
Message has been deleted

Anoop R. S.

unread,
May 10, 2018, 5:18:39 AM5/10/18
to v8-users
Thank you for the reply, Ben.
Instead of v8::IndexedPropertyHandlerConfiguration, you may 
want to use v8::NamedPropertyHandlerConfiguration. 

I am already using it. What I noticed is that, when I run the code without devtools debugging, only the callback GenericNamedPropertyGetterCallback, (of NamedPropertyHandlerConfigurationis invoked. IndexedPropertyHandlerConfiguration callbacks are not called even though they are implemented. But when I run the code through the debugger, I can see the IndexedPropertyHandlerConfiguration callback is called and whatever I am populating inside it, is visible in the debugger. After that, GenericNamedPropertyGetterCallback, (of NamedPropertyHandlerConfiguration) is called, for resolving the names which I am putting into the array in GenericNamedPropertyGetterCallback implementation. 

Based on this behaviour, I would assume that evaluateOnCallFrame (similar behaviour is shown by the message Runtime.getProperties also, which I think fetches the variable values for the overlay display) treats the variable as an indexed property. 

regards,
Anoop R. S.
Message has been deleted

Ben Noordhuis

unread,
May 11, 2018, 8:38:29 AM5/11/18
to v8-users
On Thu, May 10, 2018 at 11:18 AM, Anoop R. S. <anoo...@gmail.com> wrote:
> Thank you for the reply, Ben.
>>
>> Instead of v8::IndexedPropertyHandlerConfiguration, you may
>> want to use v8::NamedPropertyHandlerConfiguration.
>
> I am already using it. What I noticed is that, when I run the code without
> devtools debugging, only the callback GenericNamedPropertyGetterCallback,
> (of NamedPropertyHandlerConfiguration) is invoked.
> IndexedPropertyHandlerConfiguration callbacks are not called even though
> they are implemented. But when I run the code through the debugger, I can
> see the IndexedPropertyHandlerConfiguration callback is called and whatever
> I am populating inside it, is visible in the debugger. After that,
> GenericNamedPropertyGetterCallback, (of NamedPropertyHandlerConfiguration)
> is called, for resolving the names which I am putting into the array in
> GenericNamedPropertyGetterCallback implementation.

Just to make sure we're on the same page:
IndexedPropertyHandlerConfiguration is for number-as-key operations,
i.e., obj[42]; obj.x and obj['x'] on the other hand are named property
operations.

What the debugger does is (mostly) equivalent to `Object.keys(obj)`
and `Object.getOwnPropertyNames(obj)`, operations that include
enumerable element indices _and_ enumerable named properties in their
output. That's why you observe your IndexedPropertyEnumeratorCallback
getting invoked. It's asked to list the object's enumerable element
indices.

Interceptor callbacks need to conform to some fairly strict semantics
(that isn't always explained well in v8.h), otherwise you can get
unintuitive behavior. If unsure, take a look at
test/cctest/test-api-interceptors.cc.

Anoop R. S.

unread,
May 21, 2018, 12:40:45 AM5/21/18
to v8-users
Hi All,
I noticed another behaviour. If the callback SetCallAsFunctionHandler() is implemented for the ObjectTemplate, the value of the object is displayed as f anonymous() as shown below. 

it seems to be overriding the callbacks NamedPropertyHandlerConfiguration and IndexedPropertyHandlerConfiguration (with respect to how it is displayed only). 

Is there any way to override this behaviour? 

I tried tracking where it is getting populated as function, but ended up in CALL_GENERATED_CODE called in Invoke() in execution.cc


regards,
Anoop R. S.

On Tuesday, 8 May 2018 10:05:12 UTC+5:30, Anoop R. S. wrote:

ibon

unread,
May 21, 2018, 4:33:25 AM5/21/18
to v8-users
Have you tried setting the class name in the FunctionTemplate ?

interface_template->SetClassName( v8::String )

This names my objects as expected. I also get [object MyObject] instead of [object Object] when calling Object's prototype toString.
You also might want to name the prototype by setting the GetToStringTag symbol in the prototype object template.

Anoop R. S.

unread,
May 22, 2018, 12:33:11 AM5/22/18
to v8-users
Thank you for your reply, ibon.
I am using FunctionTemplate to expose the keyword 'Point'. So, it will call the function registered with the FunctionTemplate. In that function, I am using ObjectTemplate to wrap the C++ object and return. For the ObjectTemplate, I am setting the handlers. (v8::NamedPropertyHandlerConfiguration and v8::IndexedPropertyHandlerConfiguration)
I tried using SetClassName() on the FunctionTemplate. That worked in a different way. Now, when I do mouse over on 'Point', it is displaying the string I am populating.


Where as, if SetClassName() is not called, it is displayed as anonymous. 


My aim is to change the value being displayed for the variable p, to which I am returning an ObjectTemplate
Or, is it that I can use a FunctionTemplate to return? In that case, how can I set the handlers? 

Maybe I am not doing it properly here. The Embedder's guide says:
Each function template has an associated object template. This is used to configure objects created with this function as their constructor.
But it seems I am using an unrelated ObjectTemplate to wrap C++ object. Please correct me if I am wrong. I am inferring that you are using the associated ObjectTemplate of the of the FunctionTemplate to wrap the C++ object. 
Also, from v8.h:

/**
* Set the class name of the FunctionTemplate. This is used for
* printing objects created with the function created from the
* FunctionTemplate as its constructor.
*/

void SetClassName(Local<String> name);
This also leads me to believe that I am not using the ObjectTemplate as intended. 

regards,
Anoop R. S.

Anoop R. S.

unread,
May 22, 2018, 1:56:26 AM5/22/18
to v8-users
Hi,
I read around a bit and did some changes. 
Instead of using an ObjectTemplate directly, for wrapping the C++ object, I created a FunctionTemplate first, used SetClassName() and then called InstanceTemplate() to create an ObjectTemplate from it. All handlers were set on this ObjectTemplate. Now  the name is getting displayed for the returned object. :)
However, there is a catch. When I set the callback SetCallAsFunctionHandler() on the ObjectTemplate, it stops working and starts showing up as f anonymous(). I need this because I want to further call the object as a function. 
ibon, can you please check if SetCallAsFunctionHandler() is set for your ObjectTemplate?

regards,
Anoop R. S.

ibon

unread,
May 22, 2018, 5:19:55 AM5/22/18
to v8-users
On my side, I don't do anything in the object template with SetCallAsFunctionHandler.
I have tested setting my object template SetCallAsFunctionHandler and as you say, instant tooltip in DevTools shows the object as anonymous, but still prints as [object MyStuff] in the console.
so I am afraid I can't be of any more help :(

best
- i

Anoop R. S.

unread,
May 22, 2018, 6:08:20 AM5/22/18
to v8-users
Yes, same behaviour is observed here. In console, it is printed as 
 ƒ [object customValue ]

Thank you for your help, ibon. :)

regards,
Anoop R. S.
Reply all
Reply to author
Forward
0 new messages