Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Pavel Medvedev
    @pmed
    @xiolec thanks, didn't think this way to use object as array
    Pavel Medvedev
    @pmed

    I didn't catch about default get/set method. do you need to have a default conversion to string for a wrapped C++ object in JS? As I remember, there should be a toString() function in object prototype on JS side:

    struct Some
    {
        std::string to_string() const { return "I am Some"; }
    };
    
    v8pp:class_<Some> some_js_class(isolate);
    some_js_class.set("toString", &some::to_string);

    In javascript it should work as:

    var some = new Some();
    var s = "" + some; // implicit call some.toString()
    s == "I am Some"
    Pavel Medvedev
    @pmed
    xiolec
    @xiolec
    ah okay thanks. Do you know if there's anyway to display missing named methods/attributes for an object. Say I have a document object and java tries to access the "something" method. i.e. document.something. It doesn't say that the method doesn't exist. It only gives an error if the document object is missing. anyway to change the behaviour?
    xiolec
    @xiolec
    actually I think I found the code I'm looking for in the shell.cc example
    xiolec
    @xiolec
    nvm that doesn't show missing methods
    xiolec
    @xiolec
    Is there anyway to transfer an object from the current context to a new context? like get the window object and all variables that were created on the window object and then apply those variables to the new context.
    Pavel Medvedev
    @pmed
    I don't know such a way, never used several contexts
    xiolec
    @xiolec
    something like this seems to be working.
    using namespace v8;
        V8::InitializeICU();
        Platform* platform = platform::CreateDefaultPlatform();
        V8::InitializePlatform(platform);
        V8::Initialize();
    
        // Create a new Isolate and make it the current one.
        ArrayBufferAllocator allocator;
        Isolate::CreateParams create_params;
        create_params.array_buffer_allocator = &allocator;
        Isolate* isolate = Isolate::New(create_params);
        {
            Isolate::Scope isolate_scope(isolate);
    
            // Create a stack-allocated handle scope.
            HandleScope handle_scope(isolate);
    
            // Create a new context.
            Local<Context> context = Context::New(isolate);
            context->SetSecurityToken(v8pp::to_v8(isolate, "test"));
            // Enter the context for compiling and running the hello world script.
            Context::Scope context_scope(context);
    
            // Create a string containing the JavaScript source code.
            Local<String> source =
                String::NewFromUtf8(isolate, "var x = 'hello'; x;",
                NewStringType::kNormal).ToLocalChecked();
    
            // Compile the source code.
            Local<Script> script = Script::Compile(context, source).ToLocalChecked();
    
            // Run the script to get the result.
            Local<Value> result = script->Run(context).ToLocalChecked();
    
            // Convert the result to an UTF8 string and print it.
            String::Utf8Value utf8(result);
            printf("%s\n", *utf8);
            //Context::New()
            Local<Context> context2 = Context::New(isolate);
            Context::Scope context_scope2(context2);
            context2->Enter();
            context2->SetSecurityToken(context->GetSecurityToken());
            context2->Global()->Set(v8pp::to_v8(isolate, "window"), context->Global());
            Local<String> source2 =
                String::NewFromUtf8(isolate, "window.x;",
                NewStringType::kNormal).ToLocalChecked();
            Local<Script> script2 = Script::Compile(context2, source2).ToLocalChecked();
            v8::TryCatch try_catch(isolate);
            v8::Local<v8::Value> result2;
            // Run the script to get the result.
            if (!script2->Run(context2).ToLocal(&result2)) {
                assert(try_catch.HasCaught());
                // Print errors that happened during execution.
                ReportException(isolate, &try_catch);
                return false;
            }
    
            // Convert the result to an UTF8 string and print it.
            String::Utf8Value utf82(result2);
            printf("%s\n", *utf82);
        }
    I'm going to try to modify the v8pp context so that it can use multiple contexts. Though for some reason context.cpp keeps crashing visual studio. Well just the c++ package server for that file. Has that happened to you before?
    Pavel Medvedev
    @pmed
    No, I had no such issue with v8pp. But on other project I got package server crashes in VS2012 and resolved them by deleting *.sdf file
    Pavel Medvedev
    @pmed

    You can create multiple v8pp::context instances in the same v8::Isolate. Constructor of v8pp::context may accept existing v8::Isolate objects to re-use it.

    Probably you may add another optional parameter for security token in v8pp::context ctor to call v8::Conext::SetSecurityToken()with it. So the code above would look like this:

    // V8 init boilerplate
        using namespace v8;
        V8::InitializeICU();
        Platform* platform = platform::CreateDefaultPlatform();
        V8::InitializePlatform(platform);
        V8::Initialize();
    
        Isolate* isolate = nullptr; // would be created in first context
       char const* const security_token = "test";
    
        v8pp::context context(nullptr, security_token); // create Isolate, context, enter there
       isolate = context.isolate();
    
        Local<Value> result =context.run_script("var x = 'hello'; x").ToLocalChecked();
    
       // create and enttr to another context with the same isolate and security token
       v8pp::context context2(context.isolate(), security_token);
    
       context2.set("window", context.global()); // TODO: add v8pp::context.global() to return the Global object
    
        Local<Value> result2 =context.run_script("window.x").ToLocalChecked();
    xiolec
    @xiolec
    ah okay. That makes things much easier. Yeah I'll probably do that then.
    xiolec
    @xiolec
    Do you know the exact purpose of the scope classes? is it just for the get current isolate calls and such? I noticed that you only use the handle scope in the context class and not isolate scope or context scope. is there any benefit in doing that? Anything to watch out for when not using the other two scopes?
    xiolec
    @xiolec
    found the context/isolate scope in v8.h. they only enter/exit when the class is created/destroyed.
    so what does the handle scope do? and why not keep it active at all times for the isolate(as a global var in the v8pp context class)?
    xiolec
    @xiolec
    oh and since the v8pp context is entered at all times do you know of what kind of conflicts I would have if I was to use multiple v8pp contexts at the same time? Like if I was to have one main context then a couple of other contexts that I would create from the main one. From what I can see from the v8 embedders guide just having one child would be find, but what happens with multiple children? Should I manually control the entering and exiting of the context for the children contexts?
    xiolec
    @xiolec
    and what does Reset do in this situation? on the context constructor
    v8::Handle<v8::Context> impl = v8::Context::New(isolate_, nullptr, global);
        impl->Enter();
        impl_.Reset(isolate_, impl);
    Pavel Medvedev
    @pmed
    v8::HandleScope allows to cleanup local handles on exit from the scope, documentation: https://developers.google.com/v8/embed#handles-and-garbage-collection
    v8::Context and v8::Isolate have scope classes for automatic call Enter() and Exit() functions. This is the common way in C++ named RAII: https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
    Pavel Medvedev
    @pmed
    impl_.Reset(..) is just an assignment of local handle to persistent handle to save it after exit from the function
    I don't know how to deal with multiple contexts. Maybe in v8 users group someone will help you with it: https://groups.google.com/forum/#!forum/v8-users
    Pavel Medvedev
    @pmed
    Maybe you need to create one Isolate, enter into it and then create v8pp::conext instances as dynamic objects. Either to add a pair of functions enter()/exit() to manually enter and exit required context.
    xiolec
    @xiolec

    ah okay. I was thinking of just changing the v8pp context code to not enter a child context automatically and then just save a variable saying that it's a child and that would enter/exit when needed. Probably also add enter/exit functions so that it can be entered when doing a group of similar calls? or maybe that is not even needed because in the v8.h documentation it says that the enter function would only be used for compiling and running code. You wouldn't happen to know if anything else besides compiling/running requires a context to be entered?

    anyways I'm going to try that and hope everything works lol. also I tried to delete the .sdf file to stop the crashing, but it didn't work :( I'm using vs 2013

    I removed the get_external_data and set_external_data functions from function.hpp and that stopped it from crashing. or maybe just disabled the problem further down the line. I couldn't see anything wrong with the functions. so no idea why it's crashing for me.

    xiolec
    @xiolec

    got it to work using this code

    v8pp::context test_context(nullptr);
        test_context.set_security_token("test");
        v8::HandleScope handle_scope(test_context.isolate());
    
        v8pp::context child_context(test_context.isolate(), "test");
        child_context.set_security_token(test_context);
    
        std::string script = "var x = 'hello'; x;";
    
        Local<Value> result = test_context.run_script(script);
        String::Utf8Value utf8(result);
        printf("%s\n", *utf8);
    
        v8pp::context child_context2(test_context.isolate(), "test");
        child_context2.set_security_token(test_context);
    
        child_context.set("window", test_context);
        script = "window.x;";
        result = child_context.run_script(script);
        String::Utf8Value utf82(result);
        printf("%s\n", *utf82);
    
        child_context2.set("window", test_context);
        script = "window.x;";
        result = child_context2.run_script(script);
        String::Utf8Value utf83(result);
        printf("%s\n", *utf83);

    so set security token creates a new handle<value> to set as the token then there's an overloaded function that will transfer the security token. I couldn't get it to work with just using the same string as the value. I guess it needs to use the same handle<value>?

    then I added a new set overload that adds another context global object to the calling contexts global object.

    and added a check to see if it has its own isolate in run script and enter/exit if it doesnt.

    I didn't test if it would screw up if the context was always entered when it was created
    Pavel Medvedev
    @pmed
    Visual Studio crashes are strange. I used the same version with no issues.
    Pavel Medvedev
    @pmed

    I thought security token has a string type. Since it's a v8::Value you might store security token inv8pp::context as a persistent handle, either to get it from v8::context:

    Here's possible implementation:

    
    v8::Handle<v8::Object> v8pp::context::global()
    {
    /* Note the comment from v8.h:
    Returns the global proxy object.
       *
       * Global proxy object is a thin wrapper whose prototype points to actual
       * context's global object with the properties like Object, etc. This is done
       * that way for security reasons (for more details see
       * https://wiki.mozilla.org/Gecko:SplitWindow).
       *
       * Please note that changes to global proxy object prototype most probably
       * would break VM---v8 expects only global object as a prototype of global
       * proxy object.
    */
         return v8pp::to_local(isolate_, impl_)->Global();
    }
    
    v8::Handle<v8::Value> v8pp::context::security_token()
    {
         return v8pp::to_local(isolate_, impl_)->GetSecurityToken();
    }
    
    void v8pp::context::set_security_token(v8::Handle<v8::Value> value)
    {
         return v8pp::to_local(isolate_, impl_)->SetSecurityToken(value);
    }
    xiolec
    @xiolec
    Yeah, what I was trying to do was set the token by a string each time (without getting the handle<value> from the other context to use as the token). Since that would be easier for initialization, but that didn't work.
    Pavel Medvedev
    @pmed

    If you need to have a context clone, maybe you need to use a copy constructor:

    v8pp::context::context(context const& src)
        : own_isolate_(false)
       , isolate_(src)
    {
            v8::HandleScope scope(isolate_);
    
            v8::Local<v8::ObjectTemplate> src_templ = to_local(isolate_, src.templ_);
            v8::Local<v8::Object> src_global = to_local(isolate_, src.impl_)->Global();
    
            v8::Local<v8::Context> impl = v8::Context::New(isolate_, nullptr, src_templ, src_global);
            impl->Enter();
            impl_.Reset(isolate_, impl);
    }

    It requires to store an ObjectTemplate used to create v8::Context as a persistent handle in v8pp::context instance.

    Having copy ctor you may quik create many contexts (but they will be in initial state):

    v8pp::context parent; // create, enter to parent
    {
        v8pp::context child = parent; // copy initial global from parent, enter to child context
        {
                v8pp::context child2 = child;
               ... 
        } // exit from child 2, enter to child
    
    } // exit from child, enter to parent

    Copy ctor maybe not so goo idea, because v8pp::context becomes copy constructible with side effect (enterin into the V8 context). I'd rather would have a static function, say static v8pp::context v8pp::context::clone_and_enter(v8pp::context& src)

    xiolec
    @xiolec
    hmm, interesting.
    Is there any way to remove set name/values from a context? or would just setting a new value to the same name delete the old one and create a new one?
    xiolec
    @xiolec
    okay I found the delete variable by name in v8.h. So, I can do that. What about overriding a value? does that delete and replace or should I just call delete first?
    Pavel Medvedev
    @pmed
    do you mean to set/delete properties in V8 objects? as i understand context is only a container for global object. didn't tried this, but maybe set_option(isolate, obj, "name", v8::Undefined) would delete the property in some object.
    xiolec
    @xiolec
    Yeah, just wondering if it would delete the object if it was replaced.
    xiolec
    @xiolec
    Is there anyway to turn a pre-existing object into a class and import a reference to that class? Like if I wanted the global object to have a base class. So the class
    methods could be called from the global object as though it was one of the classes
    or what would the best way of having the global object have access to those class methods?
    Pavel Medvedev
    @pmed
    I think there is no such way. You can create a v8pp::module from existing v8::ObjectTemplate and add into this v8pp::module C++ functions, objects and v8pp::class_es. And then use that object template in v8::Context::New:
    using namespace v8;
    Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
    
    v8pp::module global(isolate, global_template);
    v8pp::class_<Some> some_class;
    ...
    global.set("aa", 123);
    global.set('rand", &rand);
    global.set("MyClass", some_class);
    
    Local<Context> context = v8::Context::New(isolate, global_template);
    Either it would be better to have a v8pp::context constructor overload with v8pp::module to use as the global object template.
    xiolec
    @xiolec

    hmm, well I ended up just adding some static functions to create the class object for the global object then set it to an internal pointer and unwrapped it from the contexts global object on the call.

    I was looking at the v8pp class functions and I was wondering if there would be a way for the global object to be recognized as that class then automatically unwrapped when those class functions were called. I wasn't exactly sure what was being done for an object to be recognized as a v8pp class.

    hia3
    @hia3
    Hello there! I'm wondering what would happen if a native method wrapped by v8pp will throw C++ exception? I'm assuming it is not allowed for C++ exception to propagate through v8. I was expecting std::current_exception (C++11) to be used in v8pp to store the exception to rethrow it later (outside of v8).
    Pavel Medvedev
    @pmed

    Hi @hia3! All wrapped native functions (both free and class members) are being called from inside of try .. catch block (see forward_function).

    Such a catched std::exception (as well all its derived types) would be converted to v8::Exception and set as the result value for the V8 function callback.

    Other C++ exception types are not supported and the program behaviour is undefined, since I don't know how V8 handles exceptions thrown out of a function callback.

    hia3
    @hia3
    @pmed Thanks for your answer! But ideally it should catch (...), store std::current_exception, ask v8 to interrupt the script (idk if it is possible in v8) returning to calling code and rethrow stored exception. Because there are exceptions like boost::thread_interrupted and boost::coroutines::detail::forced_unwind that do not inherint from std::exception and should not be ignored.
    I mean, catch (...) additionaly to catch (std::exception).
    hia3
    @hia3
    And, btw, imagine native function is throwing somethin like boost::exception (inherints from std::exception) ( http://www.boost.org/doc/libs/1_59_0/libs/exception/doc/motivation.html ) with a lot of properties attached. It is ok to use what() in forward_function if javascript actually catches this exception. But if javascript does not catch the exception, then C++ code at upper layer better get that original boost::exception. What do you think?
    Pavel Medvedev
    @pmed

    Well this try .. catch block in forward_function is a simple trap for unhandled exceptions which may be thrown from a wrapped C++ function. I'm not sure how to deal with exceptions correctly in such situations because a C++ exception may occur in the middle of V8 code flow:

    some V8 code ...
              our wrapped C++ function
    ... rest of V8 code

    The current solution with v8::Exception return allows to use try catch block in JavaScript and to resume the JS script execution there.

    Maybe I should add catch(...) block into the forward_function and return some v8::Exception("uknown") value from that catch.

    But in general, I think exception handling should be in your code, since v8pp library knows nothing about your application. In this situation you can use try catch block inside of the wrapped C++ function to manage all exceptional cases you need.

    xiolec
    @xiolec
    I was looking into exception handling a few days ago. For try catch to be properly wrapped it should grab the object that was thrown in the c++ try catch and then throw that to javascript. I.e. if I wanted to have a dom_exception class that has a member variable "code" wrapped in javascript. That would allow javascript to know which error code happened. I could just throw that in c++ then v8pp should catch it and unwrap the object.
    Haven't really tried to implement it yet though. I did change how pointers are handled when they are returned and are nullptrs though. Now in my code they return null instead of undefined. As that should be the expected return when a function fails. Instead of when it just doesn't exist.
    xiolec
    @xiolec
    the only options for doing what hia3 wants to do is to find out if there is a way to save the position of execution in the v8 script. then exit out of the stack with the position saved. Then resume after everything is running again. Other than that you would have to send an extra function to v8pp in order for it to call that function to handle the error.
    second option would be possible if you had a static object that holds the information on the type of error then checks to see how that error is handled and calls a function based on that error, but doing that is still tricky. So, best option is to ask around to see if code execution can be saved and resumed.