therubyracer-freebsd 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/.gitignore +13 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +8 -0
  4. data/.yardopts +1 -0
  5. data/Changelog.md +231 -0
  6. data/Gemfile +3 -0
  7. data/README.md +167 -0
  8. data/Rakefile +26 -0
  9. data/bin/therubyracer +11 -0
  10. data/ext/v8/extconf.rb +26 -0
  11. data/ext/v8/rr.cpp +189 -0
  12. data/ext/v8/rr.h +41 -0
  13. data/ext/v8/v8.cpp +48 -0
  14. data/ext/v8/v8_array.cpp +48 -0
  15. data/ext/v8/v8_array.h +8 -0
  16. data/ext/v8/v8_callbacks.cpp +81 -0
  17. data/ext/v8/v8_callbacks.h +8 -0
  18. data/ext/v8/v8_context.cpp +92 -0
  19. data/ext/v8/v8_context.h +6 -0
  20. data/ext/v8/v8_date.cpp +40 -0
  21. data/ext/v8/v8_date.h +6 -0
  22. data/ext/v8/v8_debug.cpp +17 -0
  23. data/ext/v8/v8_debug.h +6 -0
  24. data/ext/v8/v8_exception.cpp +133 -0
  25. data/ext/v8/v8_exception.h +11 -0
  26. data/ext/v8/v8_external.cpp +70 -0
  27. data/ext/v8/v8_external.h +8 -0
  28. data/ext/v8/v8_function.cpp +69 -0
  29. data/ext/v8/v8_function.h +11 -0
  30. data/ext/v8/v8_handle.cpp +186 -0
  31. data/ext/v8/v8_handle.h +48 -0
  32. data/ext/v8/v8_locker.cpp +139 -0
  33. data/ext/v8/v8_locker.h +6 -0
  34. data/ext/v8/v8_message.cpp +67 -0
  35. data/ext/v8/v8_message.h +10 -0
  36. data/ext/v8/v8_object.cpp +122 -0
  37. data/ext/v8/v8_object.h +10 -0
  38. data/ext/v8/v8_script.cpp +36 -0
  39. data/ext/v8/v8_script.h +8 -0
  40. data/ext/v8/v8_string.cpp +52 -0
  41. data/ext/v8/v8_string.h +9 -0
  42. data/ext/v8/v8_template.cpp +344 -0
  43. data/ext/v8/v8_template.h +8 -0
  44. data/ext/v8/v8_try_catch.cpp +70 -0
  45. data/ext/v8/v8_try_catch.h +5 -0
  46. data/ext/v8/v8_v8.cpp +34 -0
  47. data/ext/v8/v8_v8.h +6 -0
  48. data/ext/v8/v8_value.cpp +175 -0
  49. data/ext/v8/v8_value.h +10 -0
  50. data/ext/v8/v8_weakref.cpp +61 -0
  51. data/ext/v8/v8_weakref.h +29 -0
  52. data/lib/v8.rb +23 -0
  53. data/lib/v8/access.rb +92 -0
  54. data/lib/v8/array.rb +17 -0
  55. data/lib/v8/c/locker.rb +18 -0
  56. data/lib/v8/cli.rb +133 -0
  57. data/lib/v8/context.rb +111 -0
  58. data/lib/v8/error.rb +130 -0
  59. data/lib/v8/function.rb +44 -0
  60. data/lib/v8/object.rb +69 -0
  61. data/lib/v8/portal.rb +86 -0
  62. data/lib/v8/portal/caller.rb +37 -0
  63. data/lib/v8/portal/constructor.rb +98 -0
  64. data/lib/v8/portal/function.rb +63 -0
  65. data/lib/v8/portal/interceptors.rb +152 -0
  66. data/lib/v8/portal/proxies.rb +151 -0
  67. data/lib/v8/portal/templates.rb +73 -0
  68. data/lib/v8/stack.rb +66 -0
  69. data/lib/v8/tap.rb +9 -0
  70. data/lib/v8/version.rb +3 -0
  71. data/spec/ext/array_spec.rb +15 -0
  72. data/spec/ext/cxt_spec.rb +57 -0
  73. data/spec/ext/ext_spec_helper.rb +27 -0
  74. data/spec/ext/func_spec.rb +64 -0
  75. data/spec/ext/object_spec.rb +10 -0
  76. data/spec/ext/string_spec.rb +11 -0
  77. data/spec/ext/try_catch_spec.rb +60 -0
  78. data/spec/redjs_spec.rb +9 -0
  79. data/spec/spec_helper.rb +9 -0
  80. data/spec/v8/error_spec.rb +131 -0
  81. data/spec/v8/portal/proxies_spec.rb +106 -0
  82. data/specmem/handle_memspec.rb +41 -0
  83. data/specmem/object_memspec.rb +14 -0
  84. data/specmem/proxies_memspec.rb +49 -0
  85. data/specmem/spec_helper.rb +24 -0
  86. data/specthread/spec_helper.rb +2 -0
  87. data/specthread/threading_spec.rb +13 -0
  88. data/thefrontside.png +0 -0
  89. data/therubyracer.gemspec +27 -0
  90. metadata +183 -0
@@ -0,0 +1,11 @@
1
+ #ifndef _RUBY_V8_FUNCTION_
2
+ #define _RUBY_V8_FUNCTION_
3
+
4
+ #include "rr.h"
5
+ #include "v8.h"
6
+
7
+ void rr_init_function();
8
+
9
+ VALUE rr_reflect_v8_function(v8::Handle<v8::Value> value);
10
+
11
+ #endif
@@ -0,0 +1,186 @@
1
+
2
+ #include "rr.h"
3
+ #include "v8_handle.h"
4
+
5
+ using namespace v8;
6
+
7
+ /**
8
+ * Creates a new Persistent storage cell for `handle`
9
+ * so that we can reference it from Ruby. Ruby metadat
10
+ * is contained on the handle object, and then the actual
11
+ * v8 references are contain in an instance of `Payload`
12
+ */
13
+ v8_handle::v8_handle(Handle<void> object) {
14
+ this->weakref_callback = Qnil;
15
+ this->weakref_callback_parameters = Qnil;
16
+ this->dead = false;
17
+ this->payload = new Payload(object);
18
+ }
19
+
20
+ v8_handle::~v8_handle() {}
21
+
22
+ /**
23
+ * Construct a new handle payload.
24
+ *
25
+ * Each payload contains a Ruby object wrapper so that it
26
+ * can be enqueued for V8 GC (the GC queue is a ruby Array)
27
+ * the wrapper is pre-allocated at payload creation time
28
+ * so that no Ruby objects are allocated during Ruby GC.
29
+ */
30
+ v8_handle::Payload::Payload(Handle<void> object) {
31
+ rb_gc_register_address(&wrapper);
32
+ handle = Persistent<void>::New(object);
33
+ wrapper = Data_Wrap_Struct(rb_cObject, 0, destroy, this);
34
+ }
35
+
36
+ v8_handle::Payload::~Payload() {
37
+ rb_gc_unregister_address(&wrapper);
38
+ }
39
+
40
+ void v8_handle::Payload::release() {
41
+ handle.Dispose();
42
+ handle.Clear();
43
+ }
44
+
45
+ void v8_handle::Payload::destroy(v8_handle::Payload* payload) {
46
+ delete payload;
47
+ }
48
+
49
+ namespace {
50
+ /**
51
+ * Holds dead references, that are no longer being held in Ruby, so that they can be garbage collected
52
+ * inside of V8
53
+ */
54
+ VALUE handle_queue;
55
+
56
+ /**
57
+ * Invoked by the Ruby garbage collector whenever it determines that this handle is
58
+ * still reachable. We in turn, mark our weak callback parameters, so that it knows
59
+ * they are reachable too.
60
+ */
61
+ void v8_handle_mark(v8_handle* handle) {
62
+ rb_gc_mark(handle->weakref_callback);
63
+ rb_gc_mark(handle->weakref_callback_parameters);
64
+ }
65
+
66
+ /**
67
+ * Whenver a V8::C::Handle becomes garbage collected, we do not free it immediately.
68
+ * instead, we put them into a "zombie" queue, where its corresponding V8 storage cell
69
+ * can be released safely while the V8 engine is running. A zombie Ruby object is
70
+ * created to wrap it so that it can be stored in the queue.
71
+ */
72
+ void v8_handle_enqueue(v8_handle* handle) {
73
+ handle->dead = true;
74
+ rb_ary_unshift(handle_queue, handle->payload->wrapper);
75
+ }
76
+
77
+ /**
78
+ * Drains the dead handle queue, and releases them from V8
79
+ *
80
+ * This implements the V8 `GCPrologueCallback` and is registered to run before
81
+ * each invocation of the V8 garbage collector. It empties the queue of dead handles
82
+ * and disposes of them. It is important to do this operations inside V8 so that
83
+ * Ruby garbage collection is never locked, and never touches V8.
84
+ */
85
+ void v8_handle_dequeue(GCType type, GCCallbackFlags flags) {
86
+ for (VALUE handle = rb_ary_pop(handle_queue); RTEST(handle); handle = rb_ary_pop(handle_queue)) {
87
+ v8_handle::Payload* payload = NULL;
88
+ Data_Get_Struct(handle, struct v8_handle::Payload, payload);
89
+ payload->release();
90
+ }
91
+ }
92
+
93
+ VALUE New(VALUE self, VALUE handle) {
94
+ if (RTEST(handle)) {
95
+ Persistent<void> that = rr_v8_handle<void>(handle);
96
+ return rr_v8_handle_new(self, that);
97
+ } else {
98
+ return rr_v8_handle_new(self, Handle<void>());
99
+ }
100
+ }
101
+
102
+ VALUE IsEmpty(VALUE self) {
103
+ return rr_v82rb(rr_v8_handle<void>(self).IsEmpty());
104
+ }
105
+
106
+ VALUE Clear(VALUE self) {
107
+ rr_v8_handle<void>(self).Clear();
108
+ return Qnil;
109
+ }
110
+
111
+ VALUE Dispose(VALUE self) {
112
+ rr_v8_handle<void>(self).Dispose();
113
+ return Qnil;
114
+ }
115
+
116
+ void RubyWeakReferenceCallback(Persistent<Value> value, void* parameter) {
117
+ VALUE self = (VALUE)parameter;
118
+ v8_handle* handle = rr_v8_handle_raw(self);
119
+ VALUE callback = handle->weakref_callback;
120
+ VALUE parameters = handle->weakref_callback_parameters;
121
+ if (RTEST(callback)) {
122
+ rb_funcall(callback, rb_intern("call"), 2, self, parameters);
123
+ }
124
+ value.Dispose();
125
+ handle->payload->release();
126
+ handle->dead = true;
127
+
128
+ }
129
+
130
+ VALUE MakeWeak(VALUE self, VALUE parameters, VALUE callback) {
131
+ v8_handle* handle = rr_v8_handle_raw(self);
132
+ handle->weakref_callback = callback;
133
+ handle->weakref_callback_parameters = parameters;
134
+ rr_v8_handle<void>(self).MakeWeak((void*)self, RubyWeakReferenceCallback);
135
+ return Qnil;
136
+ }
137
+
138
+ VALUE ClearWeak(VALUE self) {
139
+ rr_v8_handle<void>(self).ClearWeak();
140
+ return Qnil;
141
+ }
142
+
143
+ VALUE IsNearDeath(VALUE self) {
144
+ return rr_v82rb(rr_v8_handle<void>(self).IsNearDeath());
145
+ }
146
+
147
+ VALUE IsWeak(VALUE self) {
148
+ return rr_v82rb(rr_v8_handle<void>(self).IsWeak());
149
+ }
150
+
151
+ VALUE dead_p(VALUE self) {
152
+ return rr_v8_handle_raw(self)->dead ? Qtrue : Qfalse;
153
+ }
154
+ }
155
+
156
+ void rr_init_handle() {
157
+ VALUE HandleClass = rr_define_class("Handle");
158
+ rr_define_method(HandleClass, "dead?", dead_p, 0);
159
+ rr_define_singleton_method(HandleClass, "New", New, 1);
160
+ rr_define_method(HandleClass, "IsEmpty", IsEmpty, 0);
161
+ rr_define_method(HandleClass, "Clear", Clear, 0);
162
+ rr_define_method(HandleClass, "Dispose", Dispose, 0);
163
+ rr_define_method(HandleClass, "MakeWeak", MakeWeak, 2);
164
+ rr_define_method(HandleClass, "ClearWeak", ClearWeak, 0);
165
+ rr_define_method(HandleClass, "IsNearDeath", IsNearDeath, 0);
166
+ rr_define_method(HandleClass, "IsWeak", IsWeak, 0);
167
+
168
+ rb_gc_register_address(&handle_queue);
169
+ handle_queue = rb_ary_new();
170
+ V8::AddGCPrologueCallback(v8_handle_dequeue);
171
+ }
172
+
173
+ VALUE rr_v8_handle_new(VALUE klass, v8::Handle<void> handle) {
174
+ v8_handle* new_handle = new v8_handle(handle);
175
+ return Data_Wrap_Struct(klass, v8_handle_mark, v8_handle_enqueue, new_handle);
176
+ }
177
+
178
+ VALUE rr_v8_handle_class() {
179
+ return rr_define_class("Handle");
180
+ }
181
+
182
+ v8_handle* rr_v8_handle_raw(VALUE value) {
183
+ v8_handle* handle = 0;
184
+ Data_Get_Struct(value, struct v8_handle, handle);
185
+ return handle;
186
+ }
@@ -0,0 +1,48 @@
1
+ #ifndef _RR_V8_HANDLE_
2
+ #define _RR_V8_HANDLE_
3
+
4
+ #include <v8.h>
5
+ #include "ruby.h"
6
+
7
+ /**
8
+ * Holds a reference to a V8 heap object. This serves as the base
9
+ * class for all of the low-level proxies that reference into V8.
10
+ */
11
+ struct v8_handle {
12
+
13
+ /**
14
+ * Contains the *actual* V8 references. This object is kept
15
+ * separate so that it can be "detached" from the handle when
16
+ * it is garbage collected, and enqueued separately and
17
+ * collected in the context of a V8 thread.
18
+ */
19
+
20
+ struct Payload {
21
+ Payload(v8::Handle<void> object);
22
+ virtual ~Payload();
23
+ void release();
24
+ static void destroy(v8_handle::Payload* payload);
25
+ v8::Persistent<void> handle;
26
+ VALUE wrapper;
27
+ };
28
+
29
+ v8_handle(v8::Handle<void> object);
30
+ virtual ~v8_handle();
31
+
32
+ Payload* payload;
33
+ bool dead;
34
+ VALUE weakref_callback;
35
+ VALUE weakref_callback_parameters;
36
+ };
37
+
38
+ void rr_init_handle();
39
+
40
+ v8_handle* rr_v8_handle_raw(VALUE value);
41
+
42
+ template <class T> v8::Persistent<T>& rr_v8_handle(VALUE value) {
43
+ return (v8::Persistent<T>&)(rr_v8_handle_raw(value)->payload->handle);
44
+ }
45
+ VALUE rr_v8_handle_new(VALUE rbclass, v8::Handle<void> handle);
46
+ VALUE rr_v8_handle_class();
47
+
48
+ #endif
@@ -0,0 +1,139 @@
1
+ #include "rr.h"
2
+ #include "v8_locker.h"
3
+
4
+ using namespace v8;
5
+
6
+ namespace {
7
+ namespace Lock {
8
+
9
+ /**
10
+ * Document-method: V8::C::Locker#new
11
+ *
12
+ * Allocates and returns a new `v8::Locker` object. The thread that instantiated
13
+ * this object will hold the V8 interpreter lock until it is released with a
14
+ * corresponding call to {#delete}.
15
+ *
16
+ * It critical that you call {#delete} to deallocate it, preferably within the same method.
17
+ * If you don't, two bad things will happen:
18
+ *
19
+ * 1. You'll leak the underlying C++ object
20
+ * 1. Worse, you'll leave the V8 vm locked to this thread forever
21
+ *
22
+ * It's dangerous! Be sure to `ensure`.
23
+ *
24
+ * for detailed semantics see the locking {API http://izs.me/v8-docs/classv8_1_1Unlocker.html}
25
+ *
26
+ * @return [V8::C::Locker] the new locker
27
+ */
28
+
29
+ VALUE New(VALUE LockerClass) {
30
+ Locker* locker = new Locker();
31
+ return Data_Wrap_Struct(LockerClass, 0, 0, (void*)locker);
32
+ }
33
+
34
+ /**
35
+ * Document-method: V8::C::Locker#delete
36
+ *
37
+ * Pop this lock off the stack for this thread. For a full run down of V8 locking
38
+ * semantics see the locking {API http://izs.me/v8-docs/classv8_1_1Unlocker.html}
39
+ * @return nil
40
+ */
41
+ VALUE Delete(VALUE self) {
42
+ Locker* locker = 0;
43
+ Data_Get_Struct(self, class Locker, locker);
44
+ delete locker;
45
+ }
46
+ }
47
+
48
+ namespace Unlock {
49
+ /**
50
+ * Document-method: V8::C::Unlocker#new
51
+ *
52
+ * Allocates and returns a new `v8::UnLocker` object, temporarily releasing any locks that
53
+ * this thread is holding. It will reaquire all of the locksto {#delete}.
54
+ *
55
+ * This is a great thing to do when you want to call out to some code that might do some
56
+ * waiting, sleeping, and you want to politely let other threads use this VM.
57
+ *
58
+ * It critical that you call {#delete} to deallocate it, preferably within the same method.
59
+ * If you don't, two bad things will happen:
60
+ *
61
+ * 1. You'll leak the underlying C++ object
62
+ * 1. You won't restore the locks to your current thread, and will mess things up horribly
63
+ *
64
+ * It's dangerous! Be sure to `ensure`.
65
+ *
66
+ * For details on V8 locking semantics, see the locking {API http://izs.me/v8-docs/classv8_1_1Unlocker.html}
67
+ * @return [V8::C::Unocker] the new locker
68
+ */
69
+ VALUE New(VALUE UnlockerClass) {
70
+ Unlocker* unlocker = new Unlocker();
71
+ return Data_Wrap_Struct(UnlockerClass, 0, 0, (void*)unlocker);
72
+ }
73
+
74
+ /**
75
+ * Document-method: V8::C::Unlocker#delete
76
+ *
77
+ * Restore any locks to the stack that were temporarily removed by this `Unlocker`.
78
+ * For a full run down, see semantics see the locking {API http://izs.me/v8-docs/classv8_1_1Unlocker.html}
79
+ * @return nil
80
+ */
81
+ VALUE Delete(VALUE self) {
82
+ Unlocker* unlocker;
83
+ Data_Get_Struct(self, class Unlocker, unlocker);
84
+ delete unlocker;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Document-method: V8::C::Locker#StartPreemption
90
+ * Start preemption.
91
+ * When preemption is started, a timer is fired every n milli seconds that will switch between
92
+ * multiple threads that are in contention for the V8 lock.
93
+ *
94
+ * @param [Integer] every_n_ms
95
+ * @return nil
96
+ */
97
+ VALUE StartPreemption(VALUE self, VALUE every_n_ms) {
98
+ Locker::StartPreemption(NUM2INT(rb_to_int(every_n_ms)));
99
+ return Qnil;
100
+ }
101
+
102
+ /**
103
+ * Document-method: V8::C::Locker#StartPreemption
104
+ * Stop preemption
105
+ */
106
+ VALUE StopPreemption(VALUE self) {
107
+ Locker::StopPreemption();
108
+ return Qnil;
109
+ }
110
+
111
+ /**
112
+ * Document-method: V8::C::Locker#IsLocked
113
+ * Returns whether or not the locker is locked by the current thread.
114
+ */
115
+ VALUE IsLocked(VALUE self) {
116
+ return rr_v82rb(Locker::IsLocked());
117
+ }
118
+
119
+ /**
120
+ * Document-method: V8::C::Locker#IsActive
121
+ * Returns whether v8::Locker is being used by this V8 instance.
122
+ */
123
+ VALUE IsActive(VALUE self) {
124
+ return rr_v82rb(Locker::IsActive());
125
+ }
126
+ }
127
+
128
+ void rr_init_v8_locker() {
129
+ VALUE LockerClass = rr_define_class("Locker");
130
+ VALUE UnlockerClass = rr_define_class("Unlocker");
131
+ rr_define_singleton_method(LockerClass, "new", Lock::New, 0);
132
+ rr_define_method(LockerClass, "delete", Lock::Delete, 0);
133
+ rr_define_singleton_method(UnlockerClass, "new", Unlock::New, 0);
134
+ rr_define_method(UnlockerClass, "delete", Unlock::Delete, 0);
135
+ rr_define_singleton_method(LockerClass, "StartPreemption", StartPreemption, 1);
136
+ rr_define_singleton_method(LockerClass, "StopPreemption", StopPreemption, 0);
137
+ rr_define_singleton_method(LockerClass, "IsLocked", IsLocked, 0);
138
+ rr_define_singleton_method(LockerClass, "IsActive", IsActive, 0);
139
+ }
@@ -0,0 +1,6 @@
1
+ #ifndef _RUBY_V8_LOCKER
2
+ #define _RUBY_V8_LOCKER
3
+
4
+ void rr_init_v8_locker();
5
+
6
+ #endif
@@ -0,0 +1,67 @@
1
+ #include "v8_message.h"
2
+ #include "v8_handle.h"
3
+
4
+ using namespace v8;
5
+
6
+ namespace {
7
+ VALUE MessageClass;
8
+
9
+ Persistent<Message>& unwrap(VALUE self) {
10
+ return rr_v8_handle<Message>(self);
11
+ }
12
+
13
+ VALUE Get(VALUE self) {
14
+ return rr_v82rb(unwrap(self)->Get());
15
+ }
16
+
17
+ VALUE GetSourceLine(VALUE self) {
18
+ return rr_v82rb(unwrap(self)->GetSourceLine());
19
+ }
20
+
21
+ VALUE GetScriptResourceName(VALUE self) {
22
+ return rr_v82rb(unwrap(self)->GetScriptResourceName());
23
+ }
24
+
25
+ VALUE GetStackTrace(VALUE self) {
26
+ Handle<StackTrace> trace = unwrap(self)->GetStackTrace();
27
+ return trace.IsEmpty() ? Qnil : rr_v82rb(trace);
28
+ }
29
+
30
+ VALUE GetLineNumber(VALUE self) {
31
+ return rr_v82rb(unwrap(self)->GetLineNumber());
32
+ }
33
+
34
+ VALUE GetStartPosition(VALUE self) {
35
+ return rr_v82rb(unwrap(self)->GetStartPosition());
36
+ }
37
+
38
+ VALUE GetEndPosition(VALUE self) {
39
+ return rr_v82rb(unwrap(self)->GetEndPosition());
40
+ }
41
+
42
+ VALUE GetStartColumn(VALUE self) {
43
+ return rr_v82rb(unwrap(self)->GetStartColumn());
44
+ }
45
+
46
+ VALUE GetEndColumn(VALUE self) {
47
+ return rr_v82rb(unwrap(self)->GetEndColumn());
48
+ }
49
+ }
50
+
51
+ void rr_init_message() {
52
+ MessageClass = rr_define_class("Message", rr_v8_handle_class());
53
+ rr_define_method(MessageClass, "Get", Get, 0);
54
+ rr_define_method(MessageClass, "GetSourceLine", GetSourceLine, 0);
55
+ rr_define_method(MessageClass, "GetScriptResourceName", GetScriptResourceName, 0);
56
+ rr_define_method(MessageClass, "GetStackTrace", GetStackTrace, 0);
57
+ rr_define_method(MessageClass, "GetLineNumber", GetLineNumber, 0);
58
+ rr_define_method(MessageClass, "GetStartPosition", GetStartPosition, 0);
59
+ rr_define_method(MessageClass, "GetEndPosition", GetEndPosition, 0);
60
+ rr_define_method(MessageClass, "GetStartColumn", GetStartColumn, 0);
61
+ rr_define_method(MessageClass, "GetEndColumn", GetEndColumn, 0);
62
+ }
63
+
64
+ VALUE rr_reflect_v8_message(Handle<Message> value) {
65
+ return rr_v8_handle_new(MessageClass, value);
66
+ }
67
+