Skip to content
This repository was archived by the owner on Dec 4, 2023. It is now read-only.

Commit 5a1632a

Browse files
committed
Merge pull request #379 from cowboyd/4.5/try-catch-throw
add support for TryCatch along with StackTrace
2 parents e567976 + c9b43ff commit 5a1632a

18 files changed

+687
-10
lines changed

ext/v8/class_builder.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ namespace rr {
4141
return *this;
4242
}
4343

44+
ClassBuilder& ClassBuilder::defineConstMethod(const char* name, VALUE value) {
45+
VALUE symbol = rb_funcall(rb_str_cat2(rb_str_new2("@"), name), rb_intern("to_sym"), 0);
46+
VALUE singleton_class = rb_funcall(this->value, rb_intern("singleton_class"), 0);
47+
rb_ivar_set(this->value, SYM2ID(symbol), value);
48+
rb_funcall(singleton_class, rb_intern("attr_reader"), 1, ID2SYM(rb_intern(name)));
49+
return *this;
50+
}
51+
4452
ClassBuilder& ClassBuilder::defineMethod(const char* name, VALUE (*impl)(int, VALUE*, VALUE)) {
4553
rb_define_method(this->value, name, (VALUE (*)(...))impl, -1);
4654
return *this;

ext/v8/class_builder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace rr {
1616
ClassBuilder(const char* name, const char* supername);
1717

1818
ClassBuilder& defineConst(const char* name, VALUE value);
19+
ClassBuilder& defineConstMethod(const char* name, VALUE value);
1920

2021
ClassBuilder& defineMethod(const char* name, VALUE (*impl)(int, VALUE*, VALUE));
2122
ClassBuilder& defineMethod(const char* name, VALUE (*impl)(VALUE));

ext/v8/equiv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ namespace rr {
2323
* Internally, `Equiv`s are always stored as a Ruby `VALUE`, and so
2424
* part of the job of the subclass is to have an appropriate
2525
* constructor that converts the C/C++ type to a `VALUE`
26+
*
27+
* It is handy to have a class to do the conversions instead of
28+
* preprocessor macros like `NUM2INT`, et al. because classes can be
29+
* easily used in C++ templates.
2630
*/
2731
class Equiv {
2832
public:

ext/v8/exception.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// -*- mode: c++ -*-
2+
#ifndef RR_EXCEPTION_H
3+
#define RR_EXCEPTION_H
4+
#include "rr.h"
5+
6+
namespace rr {
7+
class Exception {
8+
public:
9+
static inline void Init() {
10+
ClassBuilder("Exception").
11+
defineSingletonMethod("RangeError", &RangeError).
12+
defineSingletonMethod("ReferenceError", &ReferenceError).
13+
defineSingletonMethod("SyntaxError", &SyntaxError).
14+
defineSingletonMethod("TypeError", &TypeError).
15+
defineSingletonMethod("Error", &Error);
16+
}
17+
18+
static VALUE RangeError(VALUE self, VALUE rb_message) {
19+
String message(rb_message);
20+
Locker lock(message);
21+
return Value(message, v8::Exception::RangeError(message));
22+
}
23+
24+
static VALUE ReferenceError(VALUE self, VALUE rb_message) {
25+
String message(rb_message);
26+
Locker lock(message);
27+
return Value(message, v8::Exception::ReferenceError(message));
28+
}
29+
30+
static VALUE SyntaxError(VALUE self, VALUE rb_message) {
31+
String message(rb_message);
32+
Locker lock(message);
33+
return Value(message, v8::Exception::SyntaxError(message));
34+
}
35+
36+
static VALUE TypeError(VALUE self, VALUE rb_message) {
37+
String message(rb_message);
38+
Locker lock(message);
39+
return Value(message, v8::Exception::TypeError(message));
40+
}
41+
42+
static VALUE Error(VALUE self, VALUE rb_message) {
43+
String message(rb_message);
44+
Locker lock(message);
45+
return Value(message, v8::Exception::Error(message));
46+
}
47+
};
48+
}
49+
50+
#endif /* RR_EXCEPTION_H */

ext/v8/init.cc

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,15 @@ extern "C" {
4343
ObjectTemplate::Init();
4444
FunctionTemplate::Init();
4545
Signature::Init();
46+
StackFrame::Init();
47+
StackTrace::Init();
48+
Message::Init();
49+
Exception::Init();
50+
TryCatch::Init();
4651

4752
// Invocation::Init();
48-
// Signature::Init();
49-
// Date::Init();
5053
// Constants::Init();
5154
// Template::Init();
52-
// Stack::Init();
53-
// Message::Init();
54-
// TryCatch::Init();
55-
// Exception::Init();
5655
// ResourceConstraints::Init();
5756
// HeapStatistics::Init();
5857
}

ext/v8/int.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// -*- mode: c++ -*-
2+
#ifndef RR_INT_H
3+
#define RR_INT_H
4+
5+
6+
namespace rr {
7+
/**
8+
* Converts between Ruby `Number` and the C/C++ `int`.
9+
*
10+
* This allows you to easily pass in `int` values whenever a
11+
* Ruby VALUE is expected (such as a method call) E.g.
12+
*
13+
* int myInt = 5;
14+
* rb_funcall(Uint32_t(myInt), rb_intern("to_s")); //=> <String "5">
15+
*
16+
* It also converts a Ruby `VALUE` into its corresponding
17+
* `int`:
18+
*
19+
* intt myInt = Int(rb_eval_string("5")); //=> 5
20+
*
21+
* Like all `Equiv`s, it stores itself internally as a Ruby `VALUE`
22+
*/
23+
class Int : public Equiv {
24+
public:
25+
/**
26+
* Use to convert methods that return Maybe<int> to a Ruby
27+
* VALUE
28+
*
29+
* return Int::Maybe(stack_trace->GetStartColumn(context));
30+
*/
31+
typedef Equiv::Maybe<int, Int> Maybe;
32+
33+
/**
34+
* Construct an Int from a Ruby `VALUE`
35+
*/
36+
Int(VALUE val) : Equiv(val) {}
37+
38+
/**
39+
* Construct an Int from a `int` by converting it into its
40+
* corresponding `VALUE`.
41+
*/
42+
Int(int i) : Equiv(INT2FIX(i)) {}
43+
44+
/**
45+
* Coerce the Ruby `VALUE` into an `int`.
46+
*/
47+
inline operator int() {
48+
return RTEST(value) ? NUM2UINT(value) : 0;
49+
}
50+
};
51+
52+
}
53+
54+
#endif

ext/v8/isolate.cc

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// -*- mode: c++ -*-
22
#include "rr.h"
3-
#include "isolate.h"
43

54
namespace rr {
65

@@ -10,7 +9,8 @@ namespace rr {
109
rb_eval_string("require 'v8/retained_objects'");
1110
ClassBuilder("Isolate").
1211
defineSingletonMethod("New", &New).
13-
12+
defineMethod("ThrowException", &ThrowException).
13+
defineMethod("SetCaptureStackTraceForUncaughtExceptions", &SetCaptureStackTraceForUncaughtExceptions).
1414
defineMethod("IdleNotificationDeadline", &IdleNotificationDeadline).
1515

1616
store(&Class);
@@ -33,6 +33,23 @@ namespace rr {
3333
return Isolate(isolate);
3434
}
3535

36+
VALUE Isolate::ThrowException(VALUE self, VALUE error) {
37+
Isolate isolate(self);
38+
Locker lock(isolate);
39+
return Value(isolate, isolate->ThrowException(Value(error)));
40+
}
41+
42+
VALUE Isolate::SetCaptureStackTraceForUncaughtExceptions(VALUE self, VALUE capture, VALUE stack_limit, VALUE options) {
43+
Isolate isolate(self);
44+
Locker lock(isolate);
45+
46+
isolate->SetCaptureStackTraceForUncaughtExceptions(
47+
Bool(capture),
48+
RTEST(stack_limit) ? NUM2INT(stack_limit) : 10,
49+
Enum<v8::StackTrace::StackTraceOptions>(options, v8::StackTrace::kOverview));
50+
return Qnil;
51+
}
52+
3653

3754
VALUE Isolate::IdleNotificationDeadline(VALUE self, VALUE deadline_in_seconds) {
3855
Isolate isolate(self);

ext/v8/isolate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ namespace rr {
3030
static void Init();
3131

3232
static VALUE New(VALUE self);
33+
static VALUE SetCaptureStackTraceForUncaughtExceptions(VALUE self, VALUE capture, VALUE stack_limit, VALUE options);
34+
static VALUE ThrowException(VALUE self, VALUE error);
3335

3436
inline Isolate(IsolateData* data_) : data(data_) {}
3537
inline Isolate(v8::Isolate* isolate) :

ext/v8/message.h

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// -*- mode: c++ -*-
2+
3+
#ifndef RR_MESSAGE_H
4+
#define RR_MESSAGE_H
5+
#include "rr.h"
6+
7+
namespace rr {
8+
class Message : public Ref<v8::Message> {
9+
public:
10+
Message(VALUE self) : Ref<v8::Message>(self) {}
11+
Message(v8::Isolate* isolate, v8::Local<v8::Message> msg) :
12+
Ref<v8::Message>(isolate, msg) {}
13+
14+
static VALUE Get(VALUE self) {
15+
Message message(self);
16+
Locker lock(message);
17+
return String(message, message->Get());
18+
}
19+
static VALUE GetSourceLine(VALUE self, VALUE cxt) {
20+
Message message(self);
21+
Locker lock(message);
22+
return String::Maybe(message, message->GetSourceLine(Context(cxt)));
23+
}
24+
static VALUE GetScriptOrigin(VALUE self) {
25+
Message message(self);
26+
Locker lock(message);
27+
return ScriptOrigin(message, message->GetScriptOrigin());
28+
}
29+
static VALUE GetScriptResourceName(VALUE self) {
30+
Message message(self);
31+
Locker lock(message);
32+
return Value(message, message->GetScriptResourceName());
33+
}
34+
static VALUE GetStackTrace(VALUE self) {
35+
Message message(self);
36+
Locker lock(message);
37+
return StackTrace(message, message->GetStackTrace());
38+
}
39+
static VALUE GetLineNumber(VALUE self, VALUE cxt) {
40+
Message message(self);
41+
Locker lock(message);
42+
return Int::Maybe(message->GetLineNumber(Context(cxt)));
43+
}
44+
static VALUE GetStartPosition(VALUE self) {
45+
Message message(self);
46+
Locker lock(message);
47+
return Int(message->GetStartPosition());
48+
}
49+
static VALUE GetEndPosition(VALUE self) {
50+
Message message(self);
51+
Locker lock(message);
52+
return Int(message->GetEndPosition());
53+
}
54+
static VALUE GetStartColumn(VALUE self, VALUE cxt) {
55+
Message message(self);
56+
Locker lock(message);
57+
return Int::Maybe(message->GetStartColumn(Context(cxt)));
58+
}
59+
static VALUE GetEndColumn(VALUE self, VALUE cxt) {
60+
Message message(self);
61+
Locker lock(message);
62+
return Int::Maybe(message->GetEndColumn(Context(cxt)));
63+
}
64+
static VALUE IsOpaque(VALUE self) {
65+
Message message(self);
66+
Locker lock(message);
67+
return Bool(message->IsOpaque());
68+
}
69+
static VALUE IsSharedCrossOrigin(VALUE self) {
70+
Message message(self);
71+
Locker lock(message);
72+
return Bool(message->IsSharedCrossOrigin());
73+
}
74+
75+
static inline void Init() {
76+
ClassBuilder("Message").
77+
defineMethod("Get", &Get).
78+
defineMethod("GetSourceLine", &GetSourceLine).
79+
defineMethod("GetScriptOrigin", &GetScriptOrigin).
80+
defineMethod("GetScriptResourceName", &GetScriptResourceName).
81+
defineMethod("GetStackTrace", &GetStackTrace).
82+
defineMethod("GetLineNumber", &GetLineNumber).
83+
defineMethod("GetStartPosition", &GetStartPosition).
84+
defineMethod("GetEndPosition", &GetEndPosition).
85+
defineMethod("GetStartColumn", &GetStartColumn).
86+
defineMethod("GetEndColumn", &GetEndColumn).
87+
defineMethod("IsSharedCrossOrigin", &IsSharedCrossOrigin).
88+
defineMethod("IsOpaque", &IsOpaque).
89+
store(&Class);
90+
}
91+
};
92+
}
93+
94+
95+
#endif /* RR_MESSAGE_H */

ext/v8/rr.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ inline VALUE not_implemented(const char* message) {
2323

2424
#include "equiv.h"
2525
#include "bool.h"
26+
#include "int.h"
2627
#include "uint32_t.h"
2728
#include "pointer.h"
2829
#include "wrapper.h"
@@ -68,4 +69,10 @@ inline VALUE not_implemented(const char* message) {
6869
#include "function-template.h"
6970
#include "object-template.h"
7071

72+
#include "stack-frame.h"
73+
#include "stack-trace.h"
74+
#include "message.h"
75+
#include "exception.h"
76+
#include "try-catch.h"
77+
7178
#endif

0 commit comments

Comments
 (0)