mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
extract memory specs into separate folder. Memory is notorious to test, and is unreliable depending on the platform.
This commit is contained in:
parent
3a1b0cfddf
commit
d2017c673d
9 changed files with 171 additions and 158 deletions
|
@ -1,9 +1,8 @@
|
|||
|
||||
module V8::ExtSpec
|
||||
|
||||
|
||||
def self.included(object)
|
||||
object.class_eval do
|
||||
before(:all) {c::V8::SetFlagsFromString("--expose-gc")}
|
||||
before do
|
||||
@cxt = c::Context::New()
|
||||
@cxt.Enter()
|
||||
|
@ -14,7 +13,7 @@ module V8::ExtSpec
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def v8_eval(script, sourcename = "<eval>")
|
||||
c::Script::New(c::String::New(script), c::String::New(sourcename)).Run()
|
||||
end
|
||||
|
@ -22,22 +21,5 @@ module V8::ExtSpec
|
|||
def c
|
||||
V8::C
|
||||
end
|
||||
|
||||
def ruby_gc
|
||||
if GC.respond_to?(:stress)
|
||||
current = GC.stress
|
||||
GC.stress = true
|
||||
end
|
||||
yield
|
||||
ensure
|
||||
if GC.respond_to?(:stess)
|
||||
GC.stress = current
|
||||
end
|
||||
end
|
||||
|
||||
def v8_gc
|
||||
while !c::V8::IdleNotification();end
|
||||
v8_eval('gc()', 'gc.js')
|
||||
end
|
||||
|
||||
end
|
|
@ -1,42 +0,0 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe "Memory:" do
|
||||
include V8::ExtSpec
|
||||
context "A JavaScript Object reflected into Ruby" do
|
||||
|
||||
before do
|
||||
@weakref_callback = WeakrefCallback.new
|
||||
end
|
||||
|
||||
it "has a strong reference from the ruby side, which is not released until the Ruby reference goes away" do
|
||||
handle = c::Handle::New(object = c::Object::New())
|
||||
handle.MakeWeak(nil, @weakref_callback)
|
||||
ruby_gc do
|
||||
v8_gc
|
||||
@weakref_callback.should_not have_been_invoked
|
||||
handle.should_not be_dead
|
||||
end
|
||||
ruby_gc do
|
||||
object = nil
|
||||
v8_gc
|
||||
@weakref_callback.should have_been_invoked
|
||||
handle.should be_dead
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
class WeakrefCallback
|
||||
|
||||
def call(value, parameters)
|
||||
@invoked = true
|
||||
end
|
||||
|
||||
def has_been_invoked?
|
||||
@invoked
|
||||
end
|
||||
end
|
||||
end
|
||||
#These don't work in 1.8.7. Can't determine why not. I'll probably have to come back to this.
|
||||
end if RUBY_VERSION >= '1.9.2'
|
|
@ -7,16 +7,4 @@ describe V8::C::Object do
|
|||
v8_eval('var o = new Object()')
|
||||
v8_eval('o').should be(v8_eval('o'))
|
||||
end
|
||||
|
||||
it "will return a new peer and not barf if the old peer has been garbage collected" do
|
||||
v8_eval('var o = {foo: "bar"}')
|
||||
o = v8_eval('o')
|
||||
old_id = o.object_id
|
||||
ruby_gc do
|
||||
o = nil
|
||||
v8_eval('o').Get(c::String::New("foo")).Utf8Value().should == "bar"
|
||||
v8_eval('o').object_id.should_not be(old_id)
|
||||
end
|
||||
#can't quite get this to work in 1.8. I'm questioning if it's worth the effort
|
||||
end if RUBY_VERSION >= "1.9.2"
|
||||
end
|
|
@ -2,6 +2,7 @@
|
|||
require 'v8'
|
||||
require 'erb'
|
||||
require Pathname(__FILE__).dirname.join('ext/ext_spec_helper')
|
||||
require Pathname(__FILE__).dirname.join('../specmem/spec_helper')
|
||||
def rputs(msg)
|
||||
puts "<pre>#{ERB::Util.h(msg)}</pre>"
|
||||
$stdout.flush
|
||||
|
|
|
@ -2,7 +2,7 @@ require 'spec_helper'
|
|||
|
||||
describe V8::Portal::Proxies do
|
||||
include V8::ExtSpec
|
||||
# include V8::MemSpec
|
||||
|
||||
|
||||
context "for Ruby objects which are embedded into javascript" do
|
||||
|
||||
|
@ -27,26 +27,6 @@ describe V8::Portal::Proxies do
|
|||
subject.register_javascript_proxy c::Object::New(), :for => rb_object
|
||||
expect {subject.register_javascript_proxy c::Object::New(), :for => rb_object}.should raise_error(V8::Portal::Proxies::DoubleProxyError)
|
||||
end
|
||||
|
||||
context "Memory Management" do
|
||||
it "holds a hard reference to any ruby object which is linked to a javascript proxy" do
|
||||
rb_object = Object.new
|
||||
check_not_finalized(rb_object)
|
||||
subject.register_javascript_proxy c::Object::New(), :for => rb_object
|
||||
rb_object = nil
|
||||
end
|
||||
|
||||
it "releases the hard reference if its corresponding javascript object has been garbage collected" do
|
||||
rb_object = Object.new
|
||||
js_proxy = c::Object::New()
|
||||
check_finalized(rb_object)
|
||||
subject.register_javascript_proxy js_proxy, :for => rb_object
|
||||
rb_object = nil
|
||||
ruby_gc do
|
||||
v8_gc()
|
||||
end
|
||||
end
|
||||
end if RUBY_VERSION >= "1.9.2"
|
||||
end
|
||||
|
||||
context "for a JavaScript objects which are embedded into Ruby" do
|
||||
|
@ -73,27 +53,6 @@ describe V8::Portal::Proxies do
|
|||
subject.rb2js(target).should be(proxy)
|
||||
end
|
||||
|
||||
context "Memory Management" do
|
||||
|
||||
it "holds a hard reference to any JavaScript object which is linked to a Ruby proxy" do
|
||||
js_object = c::Object::New()
|
||||
check_not_finalized(js_object)
|
||||
subject.register_ruby_proxy Object.new, :for => js_object
|
||||
js_object = nil
|
||||
end
|
||||
|
||||
it "clears any strong references to the JavaScript object when it's Ruby proxy is garbage collected" do
|
||||
js_object = c::Object::New()
|
||||
rb_proxy = Object.new
|
||||
subject.register_ruby_proxy rb_proxy, :for => js_object
|
||||
check_finalized(js_object)
|
||||
js_object = rb_proxy = nil
|
||||
ruby_gc do
|
||||
v8_gc
|
||||
end
|
||||
end
|
||||
end if RUBY_VERSION >= "1.9.2"
|
||||
|
||||
context "looking up a Ruby object from a random JavaScript object" do
|
||||
it "checks first if it's a native Ruby object with a javascript proxy" do
|
||||
target = Object.new
|
||||
|
@ -143,47 +102,5 @@ describe V8::Portal::Proxies do
|
|||
subject.rb2js(rb).should be(proxy)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def finalize(object_id)
|
||||
@finalized ||= {}
|
||||
@finalized[object_id] = true
|
||||
end
|
||||
|
||||
def check_finalized(object)
|
||||
@finalized ||= {}
|
||||
ObjectSpace.define_finalizer(object, method(:finalize))
|
||||
id_to_check = object.object_id
|
||||
object = nil
|
||||
afterwards do
|
||||
@finalized[id_to_check].should be_true
|
||||
end
|
||||
end
|
||||
|
||||
def check_not_finalized(object)
|
||||
@finalized ||= {}
|
||||
ObjectSpace.define_finalizer(object, method(:finalize))
|
||||
id_to_check = object.object_id
|
||||
object = nil
|
||||
afterwards do
|
||||
@finalized[id_to_check].should be_false
|
||||
end
|
||||
end
|
||||
|
||||
def afterwards(&block)
|
||||
@after ||= []
|
||||
@after << block if block_given?
|
||||
end
|
||||
|
||||
after do
|
||||
ruby_gc do
|
||||
@after.each do |proc|
|
||||
proc.call
|
||||
end if @after
|
||||
end
|
||||
end if RUBY_VERSION >= '1.9.2'
|
||||
|
||||
end
|
||||
|
|
41
specmem/handle_memspec.rb
Normal file
41
specmem/handle_memspec.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe V8::C::Handle do
|
||||
include V8::MemSpec
|
||||
context "A JavaScript Object reflected into Ruby" do
|
||||
|
||||
before do
|
||||
@weakref_callback = WeakrefCallback.new
|
||||
end
|
||||
|
||||
it "has a strong reference from the ruby side, which is not released until the Ruby reference goes away" do
|
||||
handle = c::Handle::New(object = c::Object::New())
|
||||
handle.MakeWeak(nil, @weakref_callback)
|
||||
ruby_gc do
|
||||
v8_gc
|
||||
@weakref_callback.should_not have_been_invoked
|
||||
handle.should_not be_dead
|
||||
end
|
||||
ruby_gc do
|
||||
object = nil
|
||||
v8_gc
|
||||
@weakref_callback.should have_been_invoked
|
||||
handle.should be_dead
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
class WeakrefCallback
|
||||
|
||||
def call(value, parameters)
|
||||
@invoked = true
|
||||
end
|
||||
|
||||
def has_been_invoked?
|
||||
@invoked
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
16
specmem/object_memspec.rb
Normal file
16
specmem/object_memspec.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe V8::C::Object do
|
||||
include V8::MemSpec
|
||||
it "will return a new peer and not barf if the old peer has been garbage collected" do
|
||||
v8_eval('var o = {foo: "bar"}')
|
||||
o = v8_eval('o')
|
||||
old_id = o.object_id
|
||||
ruby_gc do
|
||||
o = nil
|
||||
v8_eval('o').Get(c::String::New("foo")).Utf8Value().should == "bar"
|
||||
v8_eval('o').object_id.should_not be(old_id)
|
||||
end
|
||||
end
|
||||
end
|
86
specmem/proxies_memspec.rb
Normal file
86
specmem/proxies_memspec.rb
Normal file
|
@ -0,0 +1,86 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe V8::Portal::Proxies do
|
||||
include V8::MemSpec
|
||||
|
||||
context "A Ruby object embedded into JavaScript" do
|
||||
it "holds a hard reference to any ruby object which is linked to a javascript proxy" do
|
||||
rb_object = Object.new
|
||||
check_not_finalized(rb_object)
|
||||
subject.register_javascript_proxy c::Object::New(), :for => rb_object
|
||||
rb_object = nil
|
||||
end
|
||||
|
||||
it "releases the hard reference if its corresponding javascript object has been garbage collected" do
|
||||
rb_object = Object.new
|
||||
js_proxy = c::Object::New()
|
||||
check_finalized(rb_object)
|
||||
subject.register_javascript_proxy js_proxy, :for => rb_object
|
||||
rb_object = nil
|
||||
ruby_gc do
|
||||
v8_gc()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "A JavaScript object embedded into Ruby" do
|
||||
it "holds a hard reference to any JavaScript object which is linked to a Ruby proxy" do
|
||||
js_object = c::Object::New()
|
||||
check_not_finalized(js_object)
|
||||
subject.register_ruby_proxy Object.new, :for => js_object
|
||||
js_object = nil
|
||||
end
|
||||
|
||||
it "clears any strong references to the JavaScript object when it's Ruby proxy is garbage collected" do
|
||||
js_object = c::Object::New()
|
||||
rb_proxy = Object.new
|
||||
subject.register_ruby_proxy rb_proxy, :for => js_object
|
||||
check_finalized(js_object)
|
||||
js_object = rb_proxy = nil
|
||||
ruby_gc do
|
||||
v8_gc
|
||||
GC.start
|
||||
v8_gc
|
||||
end
|
||||
end
|
||||
end
|
||||
private
|
||||
|
||||
def finalize(object_id)
|
||||
@finalized ||= {}
|
||||
@finalized[object_id] = true
|
||||
end
|
||||
|
||||
def check_finalized(object)
|
||||
@finalized ||= {}
|
||||
ObjectSpace.define_finalizer(object, method(:finalize))
|
||||
id_to_check = object.object_id
|
||||
object = nil
|
||||
afterwards do
|
||||
@finalized[id_to_check].should be_true
|
||||
end
|
||||
end
|
||||
|
||||
def check_not_finalized(object)
|
||||
@finalized ||= {}
|
||||
ObjectSpace.define_finalizer(object, method(:finalize))
|
||||
id_to_check = object.object_id
|
||||
object = nil
|
||||
afterwards do
|
||||
@finalized[id_to_check].should be_false
|
||||
end
|
||||
end
|
||||
|
||||
def afterwards(&block)
|
||||
@after ||= []
|
||||
@after << block if block_given?
|
||||
end
|
||||
|
||||
after do
|
||||
ruby_gc do
|
||||
@after.each do |proc|
|
||||
proc.call
|
||||
end if @after
|
||||
end
|
||||
end
|
||||
end
|
24
specmem/spec_helper.rb
Normal file
24
specmem/spec_helper.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
require Pathname(__FILE__).dirname.join('../spec/spec_helper')
|
||||
|
||||
module V8::MemSpec
|
||||
|
||||
def self.included(cls)
|
||||
cls.class_eval do
|
||||
include V8::ExtSpec
|
||||
before(:all) {V8::C::V8::SetFlagsFromString("--expose-gc")}
|
||||
end
|
||||
end
|
||||
|
||||
def ruby_gc
|
||||
current = GC.stress
|
||||
GC.stress = true
|
||||
yield
|
||||
ensure
|
||||
GC.stress = current
|
||||
end
|
||||
|
||||
def v8_gc
|
||||
while !c::V8::IdleNotification();end
|
||||
v8_eval('gc()', 'gc.js')
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue