How to get the original type on a native c++ object from v8::Object's internal fields?

134 views
Skip to first unread message

Zac Hansen

unread,
Feb 5, 2016, 12:09:54 AM2/5/16
to v8-users
I'm in a FunctionTemplate callback and about to call a function that expects parameters of a certain type and I want to make sure that the variable backing the object is of the right type.  I know the type the function wants (T), but you can't call dynamic_cast<T>(my_void_ptr).   

Unless I'm missing something (which is entirely possible), it seems like it would be nice if v8::External were templated to take a pointer type.   So I could say v8::External<T>::New(my_t_ptr) and then have my_local_external->Value() return a T* instead of a void *.   I'm not a template master, but I think you could make void * the default to not have any behavior change in the default case.

I think a workaround for this is to make a templated wrapping class that inherits from a non-templated base class.. so I can say dynamic_cast<WrapperClass<T>>((WrapperBaseClass*)void_from_external) == nullptr  and find out that way, but it doesn't seem like that workaround should be necessary.

Anyone have a better way to do this (like something already in V8 I don't know about) or any thoughts on if v8::External could be made templated?   I'd be willing to write the patch, as it seems pretty trivial.


Thank you!

--Zac

Louis Santillan

unread,
Feb 5, 2016, 12:41:30 AM2/5/16
to v8-u...@googlegroups.com
First, is the Function callback calling a C++ native function, a JS
function or another C++ defined Function callback? Providing some
code might make the issue more obvious.

Second, v8.h has all the JS ("container") types defined. Start there
when defining variables. You can often use the v8 type when going
between JS-land and C++-land. Things like:
```
v8::Array arr = Array::New( isolate, len );
v8::Integer i = Integer::New( isolate, ivalue );
```

If you're converting the callback's parameters to a native type:
```
String::Utf8Value str( args[ 0 ] );
char* ascii = *str; // * is overloaded to return an ASCII C string
int n = ( int )( args[ 1 ]->Int32Value() );
```

Once you have the parameter in the v8 type or C++ type, you can pass
them appropriately.

If you're hard up for the wrapper approach, then Stephen Beal had an
extensive template based solution that is probably 18-24 months
out-of-date (read: extensively out of date) and then there's node.js'
wrapper object approach.

-L
> --
> --
> v8-users mailing list
> v8-u...@googlegroups.com
> http://groups.google.com/group/v8-users
> ---
> You received this message because you are subscribed to the Google Groups
> "v8-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to v8-users+u...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Zac Hansen

unread,
Feb 5, 2016, 1:23:14 AM2/5/16
to v8-users
Very pseudocode-y:

class Foo {};

function f(Foo * f){}

static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   void * internal_field = args[0].GetInternalField(0); // this skips a bunch of casts and such



}

// create the function called "foo"
ft = FunctionTemplate( callback);
context->Global->Set("foo", ft);

// Create an object backed by a C++ Foo object and call it "o"
o = v8::Object::New();
o.SetInternalField(new Foo());
context->Global->Set("o", o);

then in javascript:

foo(o);

Zac Hansen

unread,
Feb 5, 2016, 1:24:19 AM2/5/16
to v8-users

Crap, that last reply was early.. I hit tab/space anda it went to "POST"... 

 
Very pseudocode-y:

class Foo {};

function f(Foo * f){}

static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   void * internal_field = args[0].GetInternalField(0); // this skips a bunch of casts and such

  // How to find out if internal_field is convertible to Foo *?

Zac Hansen

unread,
Feb 5, 2016, 2:02:52 AM2/5/16
to v8-users
Thinking more about this problem, I realize it's actually quite involved.   Without some sort of type information about what's being stored, it doesn't seem possible to see if something is a derived class of an arbitrary type.

Also, introducing some sort of templated pointer type to External would require the whole stack to suddenly be templatized adn the concept of the callback info object wouldn't work since it wouldn't be returning an array of objects of the same type in it's operator[].

I've settled on simply testing to see if it's exactly the right type as what I'm trying to convert it to by wrapping it in a templated class with a known base type and testing if the base type is dynamic_cast'able to the specific type I want.   but that stops me from using parameters with derived types which should be allowed.

--Zac

Jochen Eisinger

unread,
Feb 5, 2016, 3:12:02 AM2/5/16
to v8-users
In Blink, we store a pointer to a wrapper type info, and the void* on the object. The wrapper type info struct is used to determine the type of the void*. We also have some code that decides when you actually want to have type S* but the void* points to a T* whether it's safe to cast from T* to S*.

hth
-jochen

--

Zac Hansen

unread,
Feb 5, 2016, 5:32:23 AM2/5/16
to v8-u...@googlegroups.com
can you point me to that code?

You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/rr4CkYpoZBY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.

Zac Hansen

unread,
Feb 5, 2016, 7:53:23 AM2/5/16
to v8-u...@googlegroups.com
I think I did find it in WrapperTypeInfo.h.   And while I don't understand exactly how it works, I'm guessing it requires each class that contains a static WrapperTypeInfo to configure it in such a way that it can retrieve information like what derived classes are and such?

I'm trying to write something that can work with arbitrary classes.. my current solution is to allow users to make an explicit list if which classes can be substituted in when a certain type is wanted.   It uses sfinae to make sure the specified types are derived types.   

Basically wrap_class_for_js<MyClass>().add_compatible_types<MyClassChild, MyClassGrandChild>();   

so when you say "some_function(new MyClassChild())" in javascript, my callback says "Is the GetInternalField of the v8::Object a MyClass?   No?  Then let me try the compatible types.   Is it a MyClassChild?  Yes.  Ok, send the pointer in".   If it makes it to the end of the compatible type list without a match, it throws an exception (which is wrapped in a isoalte->ThrowException() before control returns to V8).   

The thing I put int the InternalField v8::External is actually an "AnyBase*" which is a base class of all Any<T> objects.. so I can use dynamic_cast to do the testing of whether the type is a desired type or not.

Jochen Eisinger

unread,
Feb 15, 2016, 5:04:52 AM2/15/16
to v8-u...@googlegroups.com
ah yes, in chromium (and v8) we compile without RTTI, so we can't rely on dynamic_cast. But yes, you can store a AnyBase* in the internal field and then use a huge type switch to figure out the actual class.

Note that you still need a function that knows about all types you possible have in your system (the typeswitch)..

--

Jochen Eisinger

unread,
Feb 15, 2016, 5:06:31 AM2/15/16
to v8-u...@googlegroups.com
we have a light-weight wrapper library in chromium called gin: https://code.google.com/p/chromium/codesearch#chromium/src/gin/wrappable_unittest.cc&sq=package:chromium has some examples on how to use it.

Maybe you can build something similar with RTTI

Zac Hansen

unread,
Feb 15, 2016, 5:06:45 AM2/15/16
to v8-u...@googlegroups.com
Thanks :)   Yeah, I create that function that knows about the types in my system at compile time from types provided by the user, so it ends up pretty flexible.

--Zac

You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/rr4CkYpoZBY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.

Zac Hansen

unread,
Feb 15, 2016, 5:07:37 AM2/15/16
to v8-u...@googlegroups.com
I'll check it out, thanks :)

--Zac

You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/rr4CkYpoZBY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages