Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating custom Error classes from C++ code in V8

I want to create custom exceptions in a native NodeJS (0.11.5) extension. I'm trying to create subclasses of the builtin Error class in V8 (3.20.11).

Basically I'm looking for a C++ equivalent of the following Javascript code:

function MyError(message) {
  Error.apply(this, arguments);
  this.message = message;
}
MyError.prototype = new Error;
MyError.prototype.name = MyError.name;

new MyError("message")

I tried digging in the V8 source and I found the following helper method that appears to do part of what I want:

Handle<Object> Factory::NewError(const char* constructor,
                                 Handle<String> message)

Unfortunately it looks like it's a private API and I don't understand enough V8 to figure out how to construct something similar myself. It would be great to be able to write a method that I could use in a similar way as creating a built-in Error instance, for example:

ThrowException(v8::Exception::Error(v8::String::New(msg)))
// becomes...
ThrowException(MyError(v8::String::New(msg)))

I'm looking for a solution that is as close as possible to a subclass of the builtin Error class. It should probably satisfy the following:

var e = new MyError("message");
assert(e instanceof MyError);
assert(e instanceof Error);
assert(e.name === "MyError");
assert(e.message === "message");

Any suggestions where to start?

like image 301
molf Avatar asked Nov 01 '22 16:11

molf


1 Answers

I don't know much about NodeJS, but one possibility might be to throw whatever C++ exception makes sense, catch it at the extension boundary, use standard V8 calls to construct the appropriate JavaScript exception, and call v8::ThrowException(). This approach may not be an option if NodeJS doesn't give your extension direct access to V8.

Here's a sample program that shows how to set up the custom error class and instantiate it from C++. Hopefully NodeJS gives you enough V8 access to do something similar:

#include "v8.h"
#include <iostream>

static void Print(v8::Handle<v8::Value> value)
{
    std::cout << *v8::String::Utf8Value(value) << std::endl;
}

static v8::Local<v8::Value> RunScript(const char* code)
{
    return v8::Script::Compile(v8::String::New(code))->Run();
}

static void RunTest(v8::Isolate* isolate)
{
    // setup
    v8::Locker locker(isolate);
    v8::Isolate::Scope isolateScope(isolate);
    v8::HandleScope handleScope(isolate);
    auto context = v8::Context::New(isolate);
    v8::Context::Scope contextScope(context);

    // create custom error class/function
    auto code =
        "function MyError(message) {"
            "Error.apply(this, arguments);"
            "this.message = message;"
        "}"
        "MyError.prototype = new Error;"
        "MyError.prototype.name = MyError.name;"
        "MyError";
    auto errorFunc = RunScript(code)->ToObject();

    // create custom error instance
    auto message = v8::String::New("message");
    v8::Handle<v8::Value> args[] = { message };
    auto error = errorFunc->CallAsConstructor(1, args);

    // validate custom error instance
    context->Global()->Set(v8::String::New("e"), error);
    Print(RunScript("e instanceof MyError"));
    Print(RunScript("e instanceof Error"));
    Print(RunScript("e.name === 'MyError'"));
    Print(RunScript("e.message === 'message'"));
}

void main(void)
{
    auto isolate = v8::Isolate::New();
    RunTest(isolate);
    isolate->Dispose();
}
like image 91
BitCortex Avatar answered Nov 04 '22 09:11

BitCortex