therubyracer-freebsd 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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