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,151 @@
1
+ module V8
2
+ class Portal
3
+ class Proxies
4
+
5
+ def initialize
6
+ @js_proxies_rb2js = {}
7
+ @js_proxies_js2rb = {}
8
+ @rb_proxies_rb2js = {}
9
+ @rb_proxies_js2rb = {}
10
+ @clear_js_proxy = ClearJSProxy.new(@js_proxies_rb2js, @js_proxies_js2rb)
11
+ @clear_rb_proxy = ClearRubyProxy.new(@rb_proxies_rb2js, @rb_proxies_js2rb)
12
+ end
13
+
14
+ def js2rb(js)
15
+ if rb = js_proxy_2_rb_object(js)
16
+ return rb
17
+ elsif rb = js_object_2_rb_proxy(js)
18
+ return rb
19
+ else
20
+ proxy = block_given? ? yield(js) : Object.new
21
+ register_ruby_proxy proxy, :for => js if proxy && js && js.kind_of?(V8::C::Handle)
22
+ return proxy
23
+ end
24
+ end
25
+
26
+ def rb2js(rb)
27
+ if js = rb_proxy_2_js_object(rb)
28
+ return js
29
+ elsif js = rb_object_2_js_proxy(rb)
30
+ return js
31
+ else
32
+ proxy = block_given? ? yield(rb) : V8::C::Object::New()
33
+ register_javascript_proxy proxy, :for => rb unless @js_proxies_rb2js[rb]
34
+ return proxy
35
+ end
36
+ end
37
+
38
+ def register_javascript_proxy(proxy, options = {})
39
+ target = options[:for] or fail ArgumentError, "must specify the object that you're proxying with the :for => param"
40
+ fail ArgumentError, "javascript proxy must be a V8::C::Handle, not #{proxy.class}" unless proxy.kind_of?(V8::C::Handle)
41
+ fail DoubleProxyError, "target already has a registered proxy" if @js_proxies_rb2js[target]
42
+
43
+ @js_proxies_js2rb[proxy] = target
44
+ @js_proxies_rb2js[target] = proxy
45
+ proxy.MakeWeak(nil, @clear_js_proxy)
46
+ end
47
+
48
+ # Lookup the JavaScript proxy for a natively Ruby object
49
+ # @param [Object] object the Ruby object
50
+ # @return [V8::C::Handle] the JavaScript proxy representing `object`
51
+ def rb_object_2_js_proxy(object)
52
+ @js_proxies_rb2js[object]
53
+ end
54
+
55
+ # Look up a natively Ruby object given its JavaScript proxy
56
+ # @param [V8::C::Handle] proxy the JavaScript proxy
57
+ # @return [Object] the Ruby object represented by `proxy`
58
+ def js_proxy_2_rb_object(proxy)
59
+ @js_proxies_js2rb[proxy]
60
+ end
61
+
62
+ def register_ruby_proxy(proxy, options = {})
63
+ target = options[:for] or fail ArgumentError, "must specify the object that you're proxying with the :for => param"
64
+ fail ArgumentError, "'#{proxy.inspect}' is not a Handle to an actual V8 object" unless target.kind_of?(V8::C::Handle)
65
+ @rb_proxies_rb2js[proxy.object_id] = target
66
+ @rb_proxies_js2rb[target] = proxy.object_id
67
+ ObjectSpace.define_finalizer(proxy, @clear_rb_proxy)
68
+ end
69
+
70
+ # Looks up the Ruby proxy for an object that is natively JavaScript
71
+ # @param [V8::C::Handle] object the JavaScript whose proxy we want
72
+ # @return [Object] the Ruby proxy for `object`
73
+ def js_object_2_rb_proxy(object)
74
+ if id = @rb_proxies_js2rb[object]
75
+ ObjectSpace._id2ref id
76
+ end
77
+ rescue RangeError
78
+ # sometimes, the Ruby proxy has been garbage collected, but
79
+ # the finalizer which runs has not been called. That's OK
80
+ # we just clear out the entry, and return nil so that a new
81
+ # proxy can be created.
82
+ @clear_rb_proxy.call(id)
83
+ return nil
84
+ end
85
+
86
+ # Looks up a native JavaScript object by its Ruby proxy
87
+ # @param [Object] proxy the Ruby proxy
88
+ # @return [V8::C::Handle] the native JavaScript object
89
+ def rb_proxy_2_js_object(proxy)
90
+ @rb_proxies_rb2js[proxy.object_id]
91
+ end
92
+
93
+ def js_empty?
94
+ @js_proxies_rb2js.empty? && @js_proxies_js2rb.empty?
95
+ end
96
+
97
+ def rb_empty?
98
+ @rb_proxies_rb2js.empty? && @rb_proxies_js2rb.empty?
99
+ end
100
+
101
+ def empty?
102
+ js_empty? && rb_empty?
103
+ end
104
+ DoubleProxyError = Class.new(StandardError)
105
+
106
+ class ClearJSProxy
107
+
108
+ def initialize(rb2js, js2rb)
109
+ @rb2js, @js2rb = rb2js, js2rb
110
+ end
111
+
112
+ def call(proxy, parameter)
113
+ rb = @js2rb[proxy]
114
+ @js2rb.delete(proxy)
115
+ @rb2js.delete(rb)
116
+ end
117
+ end
118
+
119
+ # @Private
120
+ # Remove the linkage between a Ruby proxy and a native
121
+ # JavaScript object. In general, this object is registered
122
+ # as a finalizer on the Ruby proxy itself, so that when it is
123
+ # garbage collected, it releases the back reference to the
124
+ # native JavaScript object.
125
+ #
126
+ # It is important to do this as soon as is reasonably possible
127
+ # so that the native JavaScript object can itself be garbage
128
+ # collected (provided there are no other references to it)
129
+ class ClearRubyProxy
130
+ def initialize(rb2js, js2rb)
131
+ @rb2js, @js2rb = rb2js, js2rb
132
+ end
133
+
134
+ # takes the object id of a Ruby proxy that has been garbage collected
135
+ # and releases the reference to the native JavaScript object that
136
+ # it was bound to.
137
+ # @param[Fixnum] proxy_id the proxy id of the garbage collected Ruby proxy
138
+ def call(proxy_id)
139
+ # TODO: this if-check should be synchronized, so that if called manually
140
+ # it will not conflict with the finalization thread. It's not so heinous
141
+ # if the refererence gets cleared twice, but we definiteily dont't want
142
+ # to double-decrement the v8 GC hint.
143
+ if js = @rb2js[proxy_id]
144
+ @rb2js.delete(proxy_id)
145
+ @js2rb.delete(js)
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,73 @@
1
+
2
+ module V8
3
+ class Portal
4
+ class Templates
5
+
6
+ attr_reader :portal
7
+
8
+ def initialize(portal)
9
+ @portal = portal
10
+ @constructors = {}
11
+ @methods = {}
12
+ @procs = {}
13
+ @releases = {}
14
+ end
15
+
16
+ def to_constructor(ruby_class)
17
+ class_id = ruby_class.object_id
18
+ if constructor = @constructors[class_id]
19
+ return constructor
20
+ else
21
+ constructor = @constructors[class_id] = ConstructorAdapter.new(self, class_id)
22
+ ObjectSpace.define_finalizer(ruby_class, release(@constructors, class_id))
23
+ return constructor
24
+ end
25
+ end
26
+
27
+ def to_function(code)
28
+ case code
29
+ when Method, UnboundMethod
30
+ if fn = @methods[code.to_s]
31
+ return fn
32
+ else
33
+ function = @methods[code.to_s] = FunctionAdapter.new(@portal, code)
34
+ #TODO: test this weak behavior
35
+ function.template.MakeWeak(0, release(@methods, code.to_s))
36
+ return function
37
+ end
38
+ else
39
+ if fn = @procs[code]
40
+ return fn
41
+ else
42
+ function = @procs[code] = FunctionAdapter.new(@portal, code)
43
+ #TODO: test this weak behavior
44
+ function.template.MakeWeak(0, release(@procs, code))
45
+ return function
46
+ end
47
+ end
48
+ end
49
+
50
+ def proxies
51
+ @portal.proxies
52
+ end
53
+
54
+ def release(refs, id)
55
+ release = Release.new(@releases, refs, id)
56
+ @releases[release] = true
57
+ return release
58
+ end
59
+
60
+ class Release
61
+ def initialize(releases, refs, id)
62
+ @releases, @refs, @id = releases, refs, id
63
+ end
64
+
65
+ def call(*args)
66
+ @refs.delete(@id)
67
+ @releases.delete(self)
68
+ end
69
+
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,66 @@
1
+
2
+ module V8
3
+
4
+ class StackTrace
5
+ include Enumerable
6
+
7
+ def initialize(to, native)
8
+ @to = to
9
+ @native = native
10
+ end
11
+
12
+ def length
13
+ @native.GetFrameCount()
14
+ end
15
+
16
+ def each
17
+ for i in 0..length - 1
18
+ yield V8::StackFrame.new(@to, @native.GetFrame(i))
19
+ end
20
+ end
21
+
22
+ def to_s
23
+ map {|f|"at #{f}"}.join("\n")
24
+ end
25
+ end
26
+
27
+ class StackFrame
28
+
29
+ def initialize(portal, native)
30
+ @to = portal
31
+ @native = native
32
+ end
33
+
34
+ def script_name
35
+ @to.rb(@native.GetScriptName())
36
+ end
37
+
38
+ def function_name
39
+ @to.rb(@native.GetFunctionName())
40
+ end
41
+
42
+ def line_number
43
+ @native.GetLineNumber()
44
+ end
45
+
46
+ def column
47
+ @native.GetColumn()
48
+ end
49
+
50
+ def eval?
51
+ @native.IsEval()
52
+ end
53
+
54
+ def constructor?
55
+ @native.IsConstructor()
56
+ end
57
+
58
+ def to_s
59
+ if @native.GetFunctionName()
60
+ "#{function_name} (#{script_name}:#{line_number}:#{column})"
61
+ else
62
+ "#{script_name}:#{line_number}:#{column}"
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+
2
+ unless Object.method_defined?(:tap)
3
+ class Object
4
+ def tap
5
+ yield self
6
+ return self
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module V8
2
+ VERSION = "0.10.1"
3
+ end
@@ -0,0 +1,15 @@
1
+ require "spec_helper"
2
+
3
+ describe V8::C::Array do
4
+ include V8::ExtSpec
5
+
6
+ it "can be instantiated" do
7
+ a = c::Array::New()
8
+ a.Length().should eql(0)
9
+ end
10
+
11
+ it "maintains referential integrity" do
12
+ v8_eval('a = []')
13
+ v8_eval('a').should be(v8_eval('a'))
14
+ end
15
+ end
@@ -0,0 +1,57 @@
1
+
2
+ require "#{File.dirname(__FILE__)}/../spec_helper.rb"
3
+
4
+ include V8
5
+
6
+ describe C::Context do
7
+
8
+ before {@lock = C::Locker.new}
9
+ after {@lock.delete}
10
+
11
+ it "should not have a current context if no context is open" do
12
+ C::Context::GetEntered().should be_nil
13
+ end
14
+
15
+ it "can javascript properties on the global scope via ruby when the default scope is a ruby object" do
16
+ V8::Context.new(:with => Object.new) do |cxt|
17
+ cxt['foo'] = 'bar'
18
+ cxt.eval('foo').should eql('bar')
19
+ end
20
+ end
21
+
22
+ it "can get the current javascript execution stack" do
23
+ V8::Context.new do |cxt|
24
+ trace = nil
25
+ cxt['getTrace'] = lambda do
26
+ trace = V8::Context.stack
27
+ end
28
+ cxt.eval(<<-JS, 'trace.js')
29
+ function one() {
30
+ return two();
31
+ }
32
+
33
+ function two() {
34
+ return three();
35
+ }
36
+
37
+ function three() {
38
+ return getTrace()
39
+ }
40
+ one();
41
+ JS
42
+ trace.length.should be(4)
43
+ trace.to_a[0].tap do |frame|
44
+ frame.line_number.should == 10
45
+ frame.column.should == 16
46
+ frame.script_name.should == 'trace.js'
47
+ frame.function_name.should == 'three'
48
+ frame.should_not be_eval
49
+ frame.should_not be_constructor
50
+ end
51
+ end
52
+ end
53
+
54
+ it "has an empty stack if there is no enterned context" do
55
+ V8::Context.stack.should be_empty
56
+ end
57
+ end
@@ -0,0 +1,27 @@
1
+
2
+ module V8::ExtSpec
3
+
4
+ def self.included(object)
5
+ object.class_eval do
6
+ before do
7
+ @lock = c::Locker.new
8
+ @cxt = c::Context::New()
9
+ @cxt.Enter()
10
+ end
11
+ after do
12
+ @cxt.Exit()
13
+ @cxt.Dispose()
14
+ @lock.delete
15
+ end
16
+ end
17
+ end
18
+
19
+ def v8_eval(script, sourcename = "<eval>")
20
+ c::Script::New(c::String::New(script), c::String::New(sourcename)).Run()
21
+ end
22
+
23
+ def c
24
+ V8::C
25
+ end
26
+
27
+ end
@@ -0,0 +1,64 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper.rb"
2
+
3
+ include V8
4
+
5
+ describe C::Function do
6
+ it "is callable" do
7
+ Context.new do |cxt|
8
+ f = cxt.eval('(function() {return "Hello World"})', '<eval>');
9
+ f.call().should == "Hello World"
10
+ end
11
+ end
12
+
13
+ it "receives proper argument length from ruby" do
14
+ Context.new do |cxt|
15
+ f = cxt.eval('(function() {return arguments.length})', 'eval')
16
+ f.call(1, 2, 3).should == 3
17
+ end
18
+ end
19
+
20
+ it "maps all arguments from ruby" do
21
+ Context.new do |cxt|
22
+ f = cxt.eval('(function(one, two, three) {return one + two + three})', 'eval')
23
+ f.call(1,2,3).should == 6
24
+ end
25
+ end
26
+
27
+ it "properly maps ruby objects back and forth from arguments to return value" do
28
+ Context.new do |cxt|
29
+ Object.new.tap do |this|
30
+ f = cxt.eval('(function() {return this})', 'eval')
31
+ f.methodcall(this).should be(this)
32
+ end
33
+ end
34
+ end
35
+
36
+ it "can be called outside of a context" do
37
+ Context.new do |cxt|
38
+ @f = cxt.eval('(function() {return "Call Me"})', 'eval')
39
+ end
40
+ @f.call().should == "Call Me"
41
+ end
42
+
43
+ it "is reflected properly" do
44
+ Context.new do |cxt|
45
+ cxt['say'] = lambda {|this, word, times| word * times}
46
+ cxt.eval('say("Hello", 3)').should == "HelloHelloHello"
47
+ end
48
+ end
49
+
50
+ it "has a name" do
51
+ Context.new do |cxt|
52
+ f = cxt.eval('(function hi() {return "Hello World"})', '<eval>')
53
+ f.name.should == "hi"
54
+ end
55
+ end
56
+
57
+ it "can have its name set" do
58
+ Context.new do |cxt|
59
+ f = cxt.eval('(function () {return "Goodbye World"})', '<eval>')
60
+ f.name = 'bye'
61
+ f.name.should == 'bye'
62
+ end
63
+ end
64
+ end