therubyracer 0.9.0 → 0.9.1beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of therubyracer might be problematic. Click here for more details.

data/.gitignore CHANGED
@@ -8,9 +8,6 @@ v8.so
8
8
  *.rbc
9
9
  *.log
10
10
  *~
11
- docs/cpp/html/*
12
-
13
- ext/v8/upstream/build
14
-
15
11
  pkg/
16
- tmp/
12
+ tmp/
13
+ .yardoc/
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ lib/**/*.rb ext/**/*.cpp
data/ext/v8/v8_handle.cpp CHANGED
@@ -4,28 +4,72 @@
4
4
 
5
5
  using namespace v8;
6
6
 
7
+ /**
8
+ * Creates a new Persistent storage cell for `handle`
9
+ * so that we can reference it from Ruby.
10
+ */
7
11
  v8_handle::v8_handle(Handle<void> handle) : handle(Persistent<void>::New(handle)) {
8
12
  this->weakref_callback = Qnil;
9
13
  this->weakref_callback_parameters = Qnil;
10
14
  this->dead = false;
11
15
  }
12
16
 
13
- v8_handle::~v8_handle() {
14
- handle.Dispose();
15
- handle.Clear();
16
- dead = true;
17
- }
17
+ v8_handle::~v8_handle() {}
18
18
 
19
19
  namespace {
20
+ /**
21
+ * Holds dead references, that are no longer being held in Ruby, so that they can be garbage collected
22
+ * inside of V8
23
+ */
24
+ VALUE handle_queue;
25
+
26
+ /**
27
+ * Invoked by the Ruby garbage collector whenever it determines that this handle is
28
+ * still reachable. We in turn, mark our weak callback parameters, so that it knows
29
+ * they are reachable too.
30
+ */
20
31
  void v8_handle_mark(v8_handle* handle) {
21
32
  rb_gc_mark(handle->weakref_callback);
22
33
  rb_gc_mark(handle->weakref_callback_parameters);
23
34
  }
24
35
 
36
+ /**
37
+ * Deallocates this handle. This function is invoked on Zombie handles after they have
38
+ * been released from V8 and finally
39
+ */
25
40
  void v8_handle_free(v8_handle* handle) {
26
41
  delete handle;
27
42
  }
28
43
 
44
+ /**
45
+ * Whenver a V8::C::Handle becomes garbage collected, we do not free it immediately.
46
+ * instead, we put them into a "zombie" queue, where its corresponding V8 storage cell
47
+ * can be released safely while the V8 engine is running. A zombie Ruby object is
48
+ * created to wrap it so that it can be stored in the queue.
49
+ */
50
+ void v8_handle_enqueue(v8_handle* handle) {
51
+ handle->dead = true;
52
+ VALUE zombie = Data_Wrap_Struct(rr_v8_handle_class(), 0, v8_handle_free, handle);
53
+ rb_ary_unshift(handle_queue, zombie);
54
+ }
55
+
56
+ /**
57
+ * Drains the dead handle queue, and releases them from V8
58
+ *
59
+ * This implements the V8 `GCPrologueCallback` and is registered to run before
60
+ * each invocation of the V8 garbage collector. It empties the queue of dead handles
61
+ * and disposes of them. It is important to do this operations inside V8 so that
62
+ * Ruby garbage collection is never locked, and never touches V8.
63
+ */
64
+ void v8_handle_dequeue(GCType type, GCCallbackFlags flags) {
65
+ for (VALUE handle = rb_ary_pop(handle_queue); RTEST(handle); handle = rb_ary_pop(handle_queue)) {
66
+ v8_handle* dead = NULL;
67
+ Data_Get_Struct(handle, struct v8_handle, dead);
68
+ dead->handle.Dispose();
69
+ dead->handle.Clear();
70
+ }
71
+ }
72
+
29
73
  VALUE New(VALUE self, VALUE handle) {
30
74
  if (RTEST(handle)) {
31
75
  Persistent<void> that = rr_v8_handle<void>(handle);
@@ -101,11 +145,15 @@ void rr_init_handle() {
101
145
  rr_define_method(HandleClass, "ClearWeak", ClearWeak, 0);
102
146
  rr_define_method(HandleClass, "IsNearDeath", IsNearDeath, 0);
103
147
  rr_define_method(HandleClass, "IsWeak", IsWeak, 0);
148
+
149
+ handle_queue = rb_ary_new();
150
+ rb_gc_register_address(&handle_queue);
151
+ V8::AddGCPrologueCallback(v8_handle_dequeue);
104
152
  }
105
153
 
106
154
  VALUE rr_v8_handle_new(VALUE klass, v8::Handle<void> handle) {
107
155
  v8_handle* new_handle = new v8_handle(handle);
108
- return Data_Wrap_Struct(klass, v8_handle_mark, v8_handle_free, new_handle);
156
+ return Data_Wrap_Struct(klass, v8_handle_mark, v8_handle_enqueue, new_handle);
109
157
  }
110
158
 
111
159
  VALUE rr_v8_handle_class() {
data/ext/v8/v8_handle.h CHANGED
@@ -4,6 +4,10 @@
4
4
  #include <v8.h>
5
5
  #include "ruby.h"
6
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
+ */
7
11
  struct v8_handle {
8
12
  v8_handle(v8::Handle<void> object);
9
13
  virtual ~v8_handle();
data/ext/v8/v8_locker.cpp CHANGED
@@ -4,38 +4,136 @@
4
4
  using namespace v8;
5
5
 
6
6
  namespace {
7
- VALUE Lock(VALUE self) {
8
- Locker locker;
9
- return rb_yield(Qnil);
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
+ }
10
46
  }
11
- VALUE Unlock(VALUE self) {
12
- Unlocker unlocker;
13
- return rb_yield(Qnil);
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
+ }
14
86
  }
15
- VALUE StartPreemption(VALUE self, VALUE thread_id) {
16
- Locker::StartPreemption(NUM2INT(rb_to_int(thread_id)));
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)));
17
99
  return Qnil;
18
100
  }
101
+
102
+ /**
103
+ * Document-method: V8::C::Locker#StartPreemption
104
+ * Stop preemption
105
+ */
19
106
  VALUE StopPreemption(VALUE self) {
20
107
  Locker::StopPreemption();
21
108
  return Qnil;
22
109
  }
110
+
111
+ /**
112
+ * Document-method: V8::C::Locker#IsLocked
113
+ * Returns whether or not the locker is locked by the current thread.
114
+ */
23
115
  VALUE IsLocked(VALUE self) {
24
116
  return rr_v82rb(Locker::IsLocked());
25
117
  }
118
+
119
+ /**
120
+ * Document-method: V8::C::Locker#IsActive
121
+ * Returns whether v8::Locker is being used by this V8 instance.
122
+ */
26
123
  VALUE IsActive(VALUE self) {
27
124
  return rr_v82rb(Locker::IsActive());
28
125
  }
29
126
  }
30
127
 
31
128
  void rr_init_v8_locker() {
32
- VALUE V8 = rb_define_module("V8");
33
- VALUE V8_C = rb_define_module_under(V8, "C");
34
- VALUE LockerModule = rb_define_module_under(V8_C, "Locker");
35
- rr_define_singleton_method(V8_C, "Locker", Lock, 0);
36
- rr_define_singleton_method(V8_C, "Unlocker", Unlock, 0);
37
- rr_define_singleton_method(LockerModule, "StartPreemption", StartPreemption, 1);
38
- rr_define_singleton_method(LockerModule, "StopPreemption", StopPreemption, 0);
39
- rr_define_singleton_method(LockerModule, "IsLocked", IsLocked, 0);
40
- rr_define_singleton_method(LockerModule, "IsActive", IsActive, 0);
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);
41
139
  }
data/lib/v8.rb CHANGED
@@ -4,6 +4,7 @@ $:.unshift(File.dirname(__FILE__)) unless
4
4
  module V8
5
5
  require 'v8/version'
6
6
  require 'v8/v8' #native glue
7
+ require 'v8/c/locker'
7
8
  require 'v8/portal'
8
9
  require 'v8/portal/caller'
9
10
  require 'v8/portal/proxies'
@@ -0,0 +1,18 @@
1
+ module V8
2
+ module C
3
+ # Shim to support the old style locking syntax. We don't currently
4
+ # deprecate this because it might make a comeback at some point.
5
+ #
6
+ # to synchronize access to V8, and to associate V8 with this thread:
7
+ #
8
+ # Locker() do
9
+ # #... interact with v8
10
+ # end
11
+ def self.Locker
12
+ lock = Locker.new
13
+ yield
14
+ ensure
15
+ lock.delete
16
+ end
17
+ end
18
+ end
@@ -43,7 +43,6 @@ module V8
43
43
  @js_proxies_js2rb[proxy] = target
44
44
  @js_proxies_rb2js[target] = proxy
45
45
  proxy.MakeWeak(nil, @clear_js_proxy)
46
- V8::C::V8::AdjustAmountOfExternalAllocatedMemory(16 * 1024)
47
46
  end
48
47
 
49
48
  # Lookup the JavaScript proxy for a natively Ruby object
@@ -66,7 +65,6 @@ module V8
66
65
  @rb_proxies_rb2js[proxy.object_id] = target
67
66
  @rb_proxies_js2rb[target] = proxy.object_id
68
67
  ObjectSpace.define_finalizer(proxy, @clear_rb_proxy)
69
- V8::C::V8::AdjustAmountOfExternalAllocatedMemory(8 * 1024)
70
68
  end
71
69
 
72
70
  # Looks up the Ruby proxy for an object that is natively JavaScript
@@ -115,7 +113,6 @@ module V8
115
113
  rb = @js2rb[proxy]
116
114
  @js2rb.delete(proxy)
117
115
  @rb2js.delete(rb)
118
- V8::C::V8::AdjustAmountOfExternalAllocatedMemory(-16 * 1024)
119
116
  end
120
117
  end
121
118
 
@@ -146,7 +143,6 @@ module V8
146
143
  if js = @rb2js[proxy_id]
147
144
  @rb2js.delete(proxy_id)
148
145
  @js2rb.delete(js)
149
- V8::C::V8::AdjustAmountOfExternalAllocatedMemory(-8 * 1024)
150
146
  end
151
147
  end
152
148
  end
data/lib/v8/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module V8
2
- VERSION = "0.9.0"
2
+ VERSION = "0.9.1beta1"
3
3
  end
@@ -0,0 +1,2 @@
1
+ require Pathname(__FILE__).dirname.join('../spec/spec_helper')
2
+
@@ -0,0 +1,13 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ describe "using v8 from multiple threads" do
5
+
6
+ it "is possible" do
7
+ Thread.new do
8
+ require 'v8'
9
+ V8::Context.new
10
+ end.join
11
+ V8::Context.new
12
+ end
13
+ end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: therubyracer
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.9.0
4
+ prerelease: 5
5
+ version: 0.9.1beta1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Charles Lowell
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2011-06-10 00:00:00 -05:00
14
+ date: 2011-06-15 00:00:00 -05:00
15
15
  default_executable:
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
@@ -70,6 +70,7 @@ files:
70
70
  - .gitignore
71
71
  - .gitmodules
72
72
  - .rspec
73
+ - .yardopts
73
74
  - Changelog.md
74
75
  - Gemfile
75
76
  - README.md
@@ -120,6 +121,7 @@ files:
120
121
  - lib/v8.rb
121
122
  - lib/v8/access.rb
122
123
  - lib/v8/array.rb
124
+ - lib/v8/c/locker.rb
123
125
  - lib/v8/cli.rb
124
126
  - lib/v8/context.rb
125
127
  - lib/v8/error.rb
@@ -150,6 +152,8 @@ files:
150
152
  - specmem/object_memspec.rb
151
153
  - specmem/proxies_memspec.rb
152
154
  - specmem/spec_helper.rb
155
+ - specthread/spec_helper.rb
156
+ - specthread/threading_spec.rb
153
157
  - therubyracer.gemspec
154
158
  - spec/redjs/.gitignore
155
159
  - spec/redjs/README.txt
@@ -170,19 +174,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
170
174
  requirements:
171
175
  - - ">="
172
176
  - !ruby/object:Gem::Version
173
- hash: -3759778087038355586
177
+ hash: -227927920256907833
174
178
  segments:
175
179
  - 0
176
180
  version: "0"
177
181
  required_rubygems_version: !ruby/object:Gem::Requirement
178
182
  none: false
179
183
  requirements:
180
- - - ">="
184
+ - - ">"
181
185
  - !ruby/object:Gem::Version
182
- hash: -3759778087038355586
183
- segments:
184
- - 0
185
- version: "0"
186
+ version: 1.3.1
186
187
  requirements: []
187
188
 
188
189
  rubyforge_project: therubyracer