therubyracer-xcode 0.12.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.travis.yml +14 -0
- data/Changelog.md +263 -0
- data/Gemfile +12 -0
- data/README.md +227 -0
- data/Rakefile +42 -0
- data/benchmarks.rb +218 -0
- data/ext/v8/accessor.cc +181 -0
- data/ext/v8/array.cc +26 -0
- data/ext/v8/backref.cc +45 -0
- data/ext/v8/constants.cc +34 -0
- data/ext/v8/constraints.cc +52 -0
- data/ext/v8/context.cc +130 -0
- data/ext/v8/date.cc +18 -0
- data/ext/v8/exception.cc +38 -0
- data/ext/v8/extconf.rb +34 -0
- data/ext/v8/external.cc +43 -0
- data/ext/v8/function.cc +58 -0
- data/ext/v8/gc.cc +43 -0
- data/ext/v8/handles.cc +34 -0
- data/ext/v8/heap.cc +35 -0
- data/ext/v8/init.cc +39 -0
- data/ext/v8/invocation.cc +86 -0
- data/ext/v8/locker.cc +77 -0
- data/ext/v8/message.cc +51 -0
- data/ext/v8/object.cc +335 -0
- data/ext/v8/primitive.cc +8 -0
- data/ext/v8/rr.cc +83 -0
- data/ext/v8/rr.h +934 -0
- data/ext/v8/script.cc +115 -0
- data/ext/v8/signature.cc +18 -0
- data/ext/v8/stack.cc +76 -0
- data/ext/v8/string.cc +47 -0
- data/ext/v8/template.cc +175 -0
- data/ext/v8/trycatch.cc +87 -0
- data/ext/v8/v8.cc +87 -0
- data/ext/v8/value.cc +239 -0
- data/lib/therubyracer.rb +1 -0
- data/lib/v8/access/indices.rb +40 -0
- data/lib/v8/access/invocation.rb +47 -0
- data/lib/v8/access/names.rb +65 -0
- data/lib/v8/access.rb +5 -0
- data/lib/v8/array.rb +26 -0
- data/lib/v8/context.rb +258 -0
- data/lib/v8/conversion/array.rb +11 -0
- data/lib/v8/conversion/class.rb +119 -0
- data/lib/v8/conversion/code.rb +38 -0
- data/lib/v8/conversion/fixnum.rb +11 -0
- data/lib/v8/conversion/fundamental.rb +11 -0
- data/lib/v8/conversion/hash.rb +11 -0
- data/lib/v8/conversion/indentity.rb +31 -0
- data/lib/v8/conversion/method.rb +26 -0
- data/lib/v8/conversion/object.rb +28 -0
- data/lib/v8/conversion/primitive.rb +7 -0
- data/lib/v8/conversion/proc.rb +5 -0
- data/lib/v8/conversion/reference.rb +16 -0
- data/lib/v8/conversion/string.rb +12 -0
- data/lib/v8/conversion/symbol.rb +7 -0
- data/lib/v8/conversion/time.rb +13 -0
- data/lib/v8/conversion.rb +36 -0
- data/lib/v8/error.rb +169 -0
- data/lib/v8/function.rb +28 -0
- data/lib/v8/object.rb +79 -0
- data/lib/v8/stack.rb +85 -0
- data/lib/v8/version.rb +3 -0
- data/lib/v8/weak.rb +82 -0
- data/lib/v8.rb +30 -0
- data/spec/c/array_spec.rb +19 -0
- data/spec/c/constants_spec.rb +22 -0
- data/spec/c/exception_spec.rb +28 -0
- data/spec/c/external_spec.rb +11 -0
- data/spec/c/function_spec.rb +48 -0
- data/spec/c/handles_spec.rb +31 -0
- data/spec/c/locker_spec.rb +36 -0
- data/spec/c/object_spec.rb +47 -0
- data/spec/c/script_spec.rb +30 -0
- data/spec/c/string_spec.rb +18 -0
- data/spec/c/template_spec.rb +31 -0
- data/spec/c/trycatch_spec.rb +52 -0
- data/spec/mem/blunt_spec.rb +42 -0
- data/spec/redjs_spec.rb +10 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/threading_spec.rb +64 -0
- data/spec/v8/context_spec.rb +19 -0
- data/spec/v8/conversion_spec.rb +52 -0
- data/spec/v8/error_spec.rb +167 -0
- data/spec/v8/function_spec.rb +9 -0
- data/spec/v8/object_spec.rb +15 -0
- data/thefrontside.png +0 -0
- data/therubyracer.gemspec +22 -0
- metadata +186 -0
data/lib/v8/stack.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
module V8
|
3
|
+
|
4
|
+
class StackTrace
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(native)
|
8
|
+
@context = V8::Context.current
|
9
|
+
@native = native
|
10
|
+
end
|
11
|
+
|
12
|
+
def length
|
13
|
+
@context.enter do
|
14
|
+
@native ? @native.GetFrameCount() : 0
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def each
|
19
|
+
return unless @native
|
20
|
+
@context.enter do
|
21
|
+
for i in 0..length - 1
|
22
|
+
yield V8::StackFrame.new(@native.GetFrame(i), @context)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
@native ? map(&:to_s).join("\n") : ""
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class StackFrame
|
33
|
+
|
34
|
+
def initialize(native, context)
|
35
|
+
@context = context
|
36
|
+
@native = native
|
37
|
+
end
|
38
|
+
|
39
|
+
def script_name
|
40
|
+
@context.enter do
|
41
|
+
@context.to_ruby(@native.GetScriptName())
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def function_name
|
46
|
+
@context.enter do
|
47
|
+
@context.to_ruby(@native.GetFunctionName())
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def line_number
|
52
|
+
@context.enter do
|
53
|
+
@native.GetLineNumber()
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def column
|
58
|
+
@context.enter do
|
59
|
+
@native.GetColumn()
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def eval?
|
64
|
+
@context.enter do
|
65
|
+
@native.IsEval()
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def constructor?
|
70
|
+
@context.enter do
|
71
|
+
@native.IsConstructor()
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_s
|
76
|
+
@context.enter do
|
77
|
+
"at " + if !function_name.empty?
|
78
|
+
"#{function_name} (#{script_name}:#{line_number}:#{column})"
|
79
|
+
else
|
80
|
+
"#{script_name}:#{line_number}:#{column}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/v8/version.rb
ADDED
data/lib/v8/weak.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
module V8
|
2
|
+
module Weak
|
3
|
+
# weak refs are broken on MRI 1.9 and merely slow on 1.8
|
4
|
+
# so we mitigate this by using the 'ref' gem. However, this
|
5
|
+
# only mitigates the problem. Under heavy load, you will still
|
6
|
+
# get different or terminated objects being returned. bad stuff.
|
7
|
+
#
|
8
|
+
# If you are having problems with this, an upgrade to 2.0 is *highly*
|
9
|
+
# recommended.
|
10
|
+
#
|
11
|
+
# for other platforms we just use the stdlib 'weakref'
|
12
|
+
# implementation
|
13
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' && RUBY_VERSION < '2.0.0'
|
14
|
+
require 'ref'
|
15
|
+
Ref = ::Ref::WeakReference
|
16
|
+
WeakValueMap = ::Ref::WeakValueMap
|
17
|
+
else
|
18
|
+
require 'weakref'
|
19
|
+
class Ref
|
20
|
+
def initialize(object)
|
21
|
+
@ref = ::WeakRef.new(object)
|
22
|
+
end
|
23
|
+
def object
|
24
|
+
@ref.__getobj__
|
25
|
+
rescue ::WeakRef::RefError
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class WeakValueMap
|
31
|
+
def initialize
|
32
|
+
@values = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def [](key)
|
36
|
+
if ref = @values[key]
|
37
|
+
ref.object
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def []=(key, value)
|
42
|
+
ref = V8::Weak::Ref.new(value)
|
43
|
+
ObjectSpace.define_finalizer(value, self.class.ensure_cleanup(@values, key, ref))
|
44
|
+
|
45
|
+
@values[key] = ref
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.ensure_cleanup(values,key,ref)
|
49
|
+
proc {
|
50
|
+
values.delete(key) if values[key] == ref
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module Cell
|
57
|
+
def weakcell(name, &block)
|
58
|
+
unless storage = instance_variable_get("@#{name}")
|
59
|
+
storage = instance_variable_set("@#{name}", Storage.new)
|
60
|
+
end
|
61
|
+
storage.access(&block)
|
62
|
+
end
|
63
|
+
class Storage
|
64
|
+
def access(&block)
|
65
|
+
if @ref
|
66
|
+
@ref.object || populate(block)
|
67
|
+
else
|
68
|
+
populate(block)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def populate(block)
|
75
|
+
occupant = block.call()
|
76
|
+
@ref = V8::Weak::Ref.new(occupant)
|
77
|
+
return occupant
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/v8.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "v8/version"
|
2
|
+
|
3
|
+
require 'v8/weak'
|
4
|
+
require 'v8/init'
|
5
|
+
require 'v8/error'
|
6
|
+
require 'v8/stack'
|
7
|
+
require 'v8/conversion/fundamental'
|
8
|
+
require 'v8/conversion/indentity'
|
9
|
+
require 'v8/conversion/reference'
|
10
|
+
require 'v8/conversion/primitive'
|
11
|
+
require 'v8/conversion/code'
|
12
|
+
require 'v8/conversion/class'
|
13
|
+
require 'v8/conversion/object'
|
14
|
+
require 'v8/conversion/time'
|
15
|
+
require 'v8/conversion/hash'
|
16
|
+
require 'v8/conversion/array'
|
17
|
+
require 'v8/conversion/proc'
|
18
|
+
require 'v8/conversion/method'
|
19
|
+
require 'v8/conversion/symbol'
|
20
|
+
require 'v8/conversion/string'
|
21
|
+
require 'v8/conversion/fixnum'
|
22
|
+
require 'v8/conversion'
|
23
|
+
require 'v8/access/names'
|
24
|
+
require 'v8/access/indices'
|
25
|
+
require 'v8/access/invocation'
|
26
|
+
require 'v8/access'
|
27
|
+
require 'v8/context'
|
28
|
+
require 'v8/object'
|
29
|
+
require 'v8/array'
|
30
|
+
require 'v8/function'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe V8::C::Array do
|
4
|
+
requires_v8_context
|
5
|
+
|
6
|
+
it "can store and retrieve a value" do
|
7
|
+
o = V8::C::Object::New()
|
8
|
+
a = V8::C::Array::New()
|
9
|
+
a.Length().should eql 0
|
10
|
+
a.Set(0, o)
|
11
|
+
a.Length().should eql 1
|
12
|
+
a.Get(0).Equals(o).should be_truthy
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can be initialized with a length" do
|
16
|
+
a = V8::C::Array::New(5)
|
17
|
+
a.Length().should eql 5
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe V8::C do
|
4
|
+
requires_v8_context
|
5
|
+
|
6
|
+
it "has constant methods for Undefined, Null, True and False" do
|
7
|
+
[:Undefined, :Null, :True, :False].each do |name|
|
8
|
+
constant = V8::C.send(name)
|
9
|
+
constant.should_not be_nil
|
10
|
+
V8::C.send(name).should be constant
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "has a value for the Empty handle" do
|
15
|
+
V8::C::Value::Empty.should_not be_nil
|
16
|
+
V8::C::Value::Empty.should be V8::C::Value::Empty
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can access the V8 version" do
|
20
|
+
V8::C::V8::GetVersion().should match /^3\.16/
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe V8::C::Exception do
|
4
|
+
requires_v8_context
|
5
|
+
|
6
|
+
it "can be thrown from Ruby" do
|
7
|
+
t = V8::C::FunctionTemplate::New(method(:explode))
|
8
|
+
@cxt.Global().Set("explode", t.GetFunction())
|
9
|
+
script = V8::C::Script::New(<<-JS, '<eval>')
|
10
|
+
(function() {
|
11
|
+
try {
|
12
|
+
explode()
|
13
|
+
} catch (e) {
|
14
|
+
return e.message
|
15
|
+
}
|
16
|
+
})()
|
17
|
+
JS
|
18
|
+
result = script.Run()
|
19
|
+
result.should_not be_nil
|
20
|
+
result.should be_kind_of(V8::C::String)
|
21
|
+
result.Utf8Value().should eql 'did not pay syntax'
|
22
|
+
end
|
23
|
+
|
24
|
+
def explode(arguments)
|
25
|
+
error = V8::C::Exception::SyntaxError('did not pay syntax')
|
26
|
+
V8::C::ThrowException(error)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe V8::C::Function do
|
4
|
+
requires_v8_context
|
5
|
+
|
6
|
+
it "can be called" do
|
7
|
+
fn = run '(function() {return "foo"})'
|
8
|
+
fn.Call(@cxt.Global(), []).Utf8Value().should eql "foo"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "can be called with arguments and context" do
|
12
|
+
fn = run '(function(one, two, three) {this.one = one; this.two = two; this.three = three})'
|
13
|
+
one = V8::C::Object::New()
|
14
|
+
two = V8::C::Object::New()
|
15
|
+
fn.Call(@cxt.Global(), [one, two, 3])
|
16
|
+
@cxt.Global().Get("one").should eql one
|
17
|
+
@cxt.Global().Get("two").should eql two
|
18
|
+
@cxt.Global().Get("three").should eql 3
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can be called as a constructor" do
|
22
|
+
fn = run '(function() {this.foo = "foo"})'
|
23
|
+
fn.NewInstance().Get(V8::C::String::New('foo')).Utf8Value().should eql "foo"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can be called as a constructor with arguments" do
|
27
|
+
fn = run '(function(foo) {this.foo = foo})'
|
28
|
+
object = fn.NewInstance([V8::C::String::New("bar")])
|
29
|
+
object.Get(V8::C::String::New('foo')).Utf8Value().should eql "bar"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "doesn't kill the world if invoking it throws a javascript exception" do
|
33
|
+
V8::C::TryCatch() do
|
34
|
+
fn = run '(function() { throw new Error("boom!")})'
|
35
|
+
fn.Call(@cxt.Global(), [])
|
36
|
+
fn.NewInstance([])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def run(source)
|
42
|
+
source = V8::C::String::New(source.to_s)
|
43
|
+
filename = V8::C::String::New("<eval>")
|
44
|
+
script = V8::C::Script::New(source, filename)
|
45
|
+
result = script.Run()
|
46
|
+
result.kind_of?(V8::C::String) ? result.Utf8Value() : result
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "setting up handles scopes" do
|
4
|
+
around(:each) do |example|
|
5
|
+
V8::C::Locker() do
|
6
|
+
cxt = V8::C::Context::New()
|
7
|
+
begin
|
8
|
+
cxt.Enter()
|
9
|
+
example.run
|
10
|
+
ensure
|
11
|
+
cxt.Exit()
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "can allocate handle scopes" do
|
17
|
+
V8::C::HandleScope() do
|
18
|
+
V8::C::Object::New()
|
19
|
+
end.class.should eql V8::C::Object
|
20
|
+
end
|
21
|
+
|
22
|
+
it "isn't the end of the world if a ruby exception is raised inside a HandleScope" do
|
23
|
+
begin
|
24
|
+
V8::C::HandleScope() do
|
25
|
+
raise "boom!"
|
26
|
+
end
|
27
|
+
rescue StandardError => e
|
28
|
+
e.message.should eql "boom!"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe V8::C::Locker do
|
4
|
+
it "can lock and unlock the VM" do
|
5
|
+
V8::C::Locker::IsLocked().should be_falsey
|
6
|
+
V8::C::Locker() do
|
7
|
+
V8::C::Locker::IsLocked().should be_truthy
|
8
|
+
V8::C::Unlocker() do
|
9
|
+
V8::C::Locker::IsLocked().should be_falsey
|
10
|
+
end
|
11
|
+
end
|
12
|
+
V8::C::Locker::IsLocked().should be_falsey
|
13
|
+
end
|
14
|
+
|
15
|
+
it "properly unlocks if an exception is thrown inside a lock block" do
|
16
|
+
begin
|
17
|
+
V8::C::Locker() do
|
18
|
+
raise "boom!"
|
19
|
+
end
|
20
|
+
rescue
|
21
|
+
V8::C::Locker::IsLocked().should be_falsey
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "properly re-locks if an exception is thrown inside an un-lock block" do
|
26
|
+
V8::C::Locker() do
|
27
|
+
begin
|
28
|
+
V8::C::Unlocker() do
|
29
|
+
raise "boom!"
|
30
|
+
end
|
31
|
+
rescue
|
32
|
+
V8::C::Locker::IsLocked().should be_truthy
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe V8::C::Object do
|
4
|
+
requires_v8_context
|
5
|
+
|
6
|
+
it "can store and retrieve a value" do
|
7
|
+
o = V8::C::Object::New()
|
8
|
+
key = V8::C::String::New("foo")
|
9
|
+
value = V8::C::String::New("bar")
|
10
|
+
o.Set(key, value)
|
11
|
+
o.Get(key).Utf8Value().should eql "bar"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can retrieve all property names" do
|
15
|
+
o = V8::C::Object::New()
|
16
|
+
o.Set(V8::C::String::New("foo"), V8::C::String::New("bar"))
|
17
|
+
o.Set(V8::C::String::New("baz"), V8::C::String::New("bang"))
|
18
|
+
names = o.GetPropertyNames()
|
19
|
+
names.Length().should eql 2
|
20
|
+
names.Get(0).Utf8Value().should eql "foo"
|
21
|
+
names.Get(1).Utf8Value().should eql "baz"
|
22
|
+
end
|
23
|
+
it "can set an accessor from ruby" do
|
24
|
+
o = V8::C::Object::New()
|
25
|
+
property = V8::C::String::New("statement")
|
26
|
+
callback_data = V8::C::String::New("I am Legend")
|
27
|
+
left = V8::C::String::New("Yo! ")
|
28
|
+
getter = proc do |name, info|
|
29
|
+
info.This().StrictEquals(o).should be_truthy
|
30
|
+
info.Holder().StrictEquals(o).should be_truthy
|
31
|
+
V8::C::String::Concat(left, info.Data())
|
32
|
+
end
|
33
|
+
setter = proc do |name, value, info|
|
34
|
+
left = value
|
35
|
+
end
|
36
|
+
o.SetAccessor(property, getter, setter, callback_data)
|
37
|
+
o.Get(property).Utf8Value().should eql "Yo! I am Legend"
|
38
|
+
o.Set(property, V8::C::String::New("Bro! "))
|
39
|
+
o.Get(property).Utf8Value().should eql "Bro! I am Legend"
|
40
|
+
end
|
41
|
+
it "always returns the same ruby object for the same V8 object" do
|
42
|
+
one = V8::C::Object::New()
|
43
|
+
two = V8::C::Object::New()
|
44
|
+
one.Set("two", two)
|
45
|
+
one.Get("two").should be two
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe V8::C::Script do
|
5
|
+
requires_v8_context
|
6
|
+
|
7
|
+
it "can run a script and return a polymorphic result" do
|
8
|
+
source = V8::C::String::New("(new Array())")
|
9
|
+
filename = V8::C::String::New("<eval>")
|
10
|
+
script = V8::C::Script::New(source, filename)
|
11
|
+
result = script.Run()
|
12
|
+
result.should be_kind_of V8::C::Array
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can accept precompiled script data" do
|
16
|
+
source = "7 * 6"
|
17
|
+
name = V8::C::String::New("<spec>")
|
18
|
+
origin = V8::C::ScriptOrigin.new(name)
|
19
|
+
data = V8::C::ScriptData::PreCompile(source, source.length)
|
20
|
+
data.HasError().should be_falsey
|
21
|
+
script = V8::C::Script::New(V8::C::String::New(source), origin, data)
|
22
|
+
script.Run().should eql 42
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can detect errors in the script data" do
|
26
|
+
source = "^ = ;"
|
27
|
+
data = V8::C::ScriptData::PreCompile(source, source.length)
|
28
|
+
data.HasError().should be_truthy
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe V8::C::String do
|
4
|
+
requires_v8_context
|
5
|
+
|
6
|
+
it "can hold Unicode values outside the Basic Multilingual Plane" do
|
7
|
+
string = V8::C::String::New("\u{100000}")
|
8
|
+
string.Utf8Value().should eql "\u{100000}"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "can naturally translate ruby strings into v8 strings" do
|
12
|
+
V8::C::String::Concat(V8::C::String::New("Hello "), "World").Utf8Value().should eql "Hello World"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can naturally translate ruby objects into v8 strings" do
|
16
|
+
V8::C::String::Concat(V8::C::String::New("forty two is "), 42).Utf8Value().should eql "forty two is 42"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe V8::C::Template do
|
4
|
+
requires_v8_context
|
5
|
+
|
6
|
+
describe V8::C::FunctionTemplate do
|
7
|
+
it "can be created with no arguments" do
|
8
|
+
t = V8::C::FunctionTemplate::New()
|
9
|
+
t.GetFunction().Call(@cxt.Global(),[]).StrictEquals(@cxt.Global()).should be_truthy
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can be created with a callback" do
|
13
|
+
receiver = V8::C::Object::New()
|
14
|
+
f = nil
|
15
|
+
callback = lambda do |arguments|
|
16
|
+
arguments.Length().should be(2)
|
17
|
+
arguments[0].Utf8Value().should eql 'one'
|
18
|
+
arguments[1].Utf8Value().should eql 'two'
|
19
|
+
arguments.Callee().StrictEquals(f).should be_truthy
|
20
|
+
arguments.This().StrictEquals(receiver).should be_truthy
|
21
|
+
arguments.Holder().StrictEquals(receiver).should be_truthy
|
22
|
+
arguments.IsConstructCall().should be_falsey
|
23
|
+
arguments.Data().Value().should be(42)
|
24
|
+
V8::C::String::New("result")
|
25
|
+
end
|
26
|
+
t = V8::C::FunctionTemplate::New(callback, V8::C::External::New(42))
|
27
|
+
f = t.GetFunction()
|
28
|
+
f.Call(receiver, [V8::C::String::New('one'), V8::C::String::New('two')]).Utf8Value().should eql "result"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe V8::C::External do
|
4
|
+
requires_v8_context
|
5
|
+
|
6
|
+
it "can catch javascript exceptions" do
|
7
|
+
V8::C::V8::SetCaptureStackTraceForUncaughtExceptions(true, 99, V8::C::StackTrace::kDetailed)
|
8
|
+
V8::C::TryCatch() do |trycatch|
|
9
|
+
source = V8::C::String::New(<<-JS)
|
10
|
+
function one() {
|
11
|
+
two()
|
12
|
+
}
|
13
|
+
function two() {
|
14
|
+
three()
|
15
|
+
}
|
16
|
+
function three() {
|
17
|
+
boom()
|
18
|
+
}
|
19
|
+
function boom() {
|
20
|
+
throw new Error('boom!')
|
21
|
+
}
|
22
|
+
eval('one()')
|
23
|
+
JS
|
24
|
+
filename = V8::C::String::New("<eval>")
|
25
|
+
script = V8::C::Script::New(source, filename)
|
26
|
+
result = script.Run()
|
27
|
+
trycatch.HasCaught().should be_truthy
|
28
|
+
trycatch.CanContinue().should be_truthy
|
29
|
+
exception = trycatch.Exception()
|
30
|
+
exception.should_not be_nil
|
31
|
+
exception.IsNativeError().should be_truthy
|
32
|
+
trycatch.StackTrace().Utf8Value().should match /boom.*three.*two.*one/m
|
33
|
+
message = trycatch.Message();
|
34
|
+
message.should_not be_nil
|
35
|
+
message.Get().Utf8Value().should eql "Uncaught Error: boom!"
|
36
|
+
message.GetSourceLine().Utf8Value().should eql " throw new Error('boom!')"
|
37
|
+
message.GetScriptResourceName().Utf8Value().should eql "<eval>"
|
38
|
+
message.GetLineNumber().should eql 11
|
39
|
+
stack = message.GetStackTrace()
|
40
|
+
stack.should_not be_nil
|
41
|
+
stack.GetFrameCount().should eql 6
|
42
|
+
frame = stack.GetFrame(0)
|
43
|
+
frame.GetLineNumber().should eql 11
|
44
|
+
frame.GetColumn().should eql 15
|
45
|
+
frame.GetScriptName().Utf8Value().should eql "<eval>"
|
46
|
+
frame.GetScriptNameOrSourceURL().Utf8Value().should eql "<eval>"
|
47
|
+
frame.IsEval().should be_falsey
|
48
|
+
stack.GetFrame(4).IsEval().should be_truthy
|
49
|
+
frame.IsConstructor().should be_falsey
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "A Very blunt test to make sure that we aren't doing stupid leaks", :memory => true do
|
4
|
+
before do
|
5
|
+
if Object.const_defined?(:RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
|
6
|
+
pending 'need to figure out how to do memory sanity checks on rbx'
|
7
|
+
end
|
8
|
+
#allocate a single context to make sure that v8 loads its snapshot and
|
9
|
+
#we pay the overhead.
|
10
|
+
V8::Context.new
|
11
|
+
@start_memory = process_memory
|
12
|
+
GC.stress = true
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
GC.stress = false
|
17
|
+
end
|
18
|
+
it "won't increase process memory by more than 50% no matter how many contexts we create" do
|
19
|
+
500.times do
|
20
|
+
V8::Context.new
|
21
|
+
run_v8_gc
|
22
|
+
end
|
23
|
+
process_memory.should <= @start_memory * 1.5
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can eval simple value passing statements repeatedly without significantly increasing memory" do
|
27
|
+
V8::C::Locker() do
|
28
|
+
cxt = V8::Context.new
|
29
|
+
500.times do
|
30
|
+
cxt.eval('7 * 6')
|
31
|
+
run_v8_gc
|
32
|
+
end
|
33
|
+
end
|
34
|
+
process_memory.should <= @start_memory * 1.1
|
35
|
+
end
|
36
|
+
|
37
|
+
def process_memory
|
38
|
+
/\w*[ ]*#{Process.pid}[ ]*([.,\d]*)[ ]*([.,\d]*)[ ]*([\d]*)[ ]*([\d]*)/.match(`ps aux`)[4].to_i
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
data/spec/redjs_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'v8'
|
2
|
+
|
3
|
+
def run_v8_gc
|
4
|
+
V8::C::V8::LowMemoryNotification()
|
5
|
+
while !V8::C::V8::IdleNotification() do
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def rputs(msg)
|
10
|
+
puts "<pre>#{ERB::Util.h(msg)}</pre>"
|
11
|
+
$stdout.flush
|
12
|
+
end
|
13
|
+
|
14
|
+
module V8ContextHelpers
|
15
|
+
module GroupMethods
|
16
|
+
def requires_v8_context
|
17
|
+
around(:each) do |example|
|
18
|
+
bootstrap_v8_context(&example)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def bootstrap_v8_context
|
24
|
+
V8::C::Locker() do
|
25
|
+
V8::C::HandleScope() do
|
26
|
+
@cxt = V8::C::Context::New()
|
27
|
+
begin
|
28
|
+
@cxt.Enter()
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
@cxt.Exit()
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
RSpec.configure do |c|
|
39
|
+
c.include V8ContextHelpers
|
40
|
+
c.extend V8ContextHelpers::GroupMethods
|
41
|
+
end
|