therubyracer 0.10.2 → 0.11.0beta1

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.

Files changed (159) hide show
  1. data/.gitignore +21 -11
  2. data/.travis.yml +2 -1
  3. data/Changelog.md +46 -0
  4. data/Gemfile +16 -1
  5. data/README.md +31 -13
  6. data/Rakefile +42 -23
  7. data/benchmarks.rb +217 -0
  8. data/ext/v8/accessor.cc +181 -0
  9. data/ext/v8/array.cc +26 -0
  10. data/ext/v8/backref.cc +56 -0
  11. data/ext/v8/build.rb +51 -0
  12. data/ext/v8/constants.cc +34 -0
  13. data/ext/v8/constraints.cc +52 -0
  14. data/ext/v8/context.cc +130 -0
  15. data/ext/v8/date.cc +18 -0
  16. data/ext/v8/exception.cc +38 -0
  17. data/ext/v8/extconf.rb +14 -18
  18. data/ext/v8/external.cc +43 -0
  19. data/ext/v8/function.cc +58 -0
  20. data/ext/v8/gc.cc +43 -0
  21. data/ext/v8/handles.cc +34 -0
  22. data/ext/v8/heap.cc +31 -0
  23. data/ext/v8/init.cc +39 -0
  24. data/ext/v8/invocation.cc +86 -0
  25. data/ext/v8/locker.cc +77 -0
  26. data/ext/v8/message.cc +51 -0
  27. data/ext/v8/object.cc +334 -0
  28. data/ext/v8/primitive.cc +8 -0
  29. data/ext/v8/rr.cc +83 -0
  30. data/ext/v8/rr.h +878 -36
  31. data/ext/v8/script.cc +80 -0
  32. data/ext/v8/signature.cc +18 -0
  33. data/ext/v8/stack.cc +75 -0
  34. data/ext/v8/string.cc +47 -0
  35. data/ext/v8/template.cc +175 -0
  36. data/ext/v8/trycatch.cc +86 -0
  37. data/ext/v8/v8.cc +87 -0
  38. data/ext/v8/value.cc +239 -0
  39. data/lib/v8.rb +30 -22
  40. data/lib/v8/access.rb +5 -87
  41. data/lib/v8/access/indices.rb +40 -0
  42. data/lib/v8/access/invocation.rb +47 -0
  43. data/lib/v8/access/names.rb +65 -0
  44. data/lib/v8/array.rb +19 -10
  45. data/lib/v8/context.rb +85 -78
  46. data/lib/v8/conversion.rb +35 -0
  47. data/lib/v8/conversion/array.rb +11 -0
  48. data/lib/v8/conversion/class.rb +120 -0
  49. data/lib/v8/conversion/code.rb +38 -0
  50. data/lib/v8/conversion/fundamental.rb +11 -0
  51. data/lib/v8/conversion/hash.rb +11 -0
  52. data/lib/v8/conversion/indentity.rb +31 -0
  53. data/lib/v8/conversion/method.rb +26 -0
  54. data/lib/v8/conversion/object.rb +28 -0
  55. data/lib/v8/conversion/primitive.rb +7 -0
  56. data/lib/v8/conversion/proc.rb +5 -0
  57. data/lib/v8/conversion/reference.rb +16 -0
  58. data/lib/v8/conversion/string.rb +12 -0
  59. data/lib/v8/conversion/symbol.rb +7 -0
  60. data/lib/v8/conversion/time.rb +13 -0
  61. data/lib/v8/error.rb +18 -123
  62. data/lib/v8/error/protect.rb +20 -0
  63. data/lib/v8/error/try.rb +15 -0
  64. data/lib/v8/function.rb +18 -34
  65. data/lib/v8/object.rb +48 -52
  66. data/lib/v8/util/weakcell.rb +29 -0
  67. data/lib/v8/version.rb +2 -2
  68. data/spec/c/array_spec.rb +17 -0
  69. data/spec/c/constants_spec.rb +20 -0
  70. data/spec/c/exception_spec.rb +26 -0
  71. data/spec/c/external_spec.rb +9 -0
  72. data/spec/c/function_spec.rb +46 -0
  73. data/spec/c/handles_spec.rb +35 -0
  74. data/spec/c/locker_spec.rb +38 -0
  75. data/spec/c/object_spec.rb +46 -0
  76. data/spec/c/script_spec.rb +28 -0
  77. data/spec/c/string_spec.rb +16 -0
  78. data/spec/c/template_spec.rb +30 -0
  79. data/spec/c/trycatch_spec.rb +51 -0
  80. data/spec/mem/blunt_spec.rb +42 -0
  81. data/spec/redjs_spec.rb +10 -0
  82. data/spec/spec_helper.rb +40 -4
  83. data/spec/threading_spec.rb +52 -0
  84. data/spec/v8/context_spec.rb +19 -0
  85. data/spec/v8/conversion_spec.rb +9 -0
  86. data/spec/v8/error_spec.rb +15 -125
  87. data/spec/v8/function_spec.rb +9 -0
  88. data/therubyracer.gemspec +15 -24
  89. metadata +102 -135
  90. data/.gitmodules +0 -3
  91. data/.rspec +0 -1
  92. data/.yardopts +0 -1
  93. data/bin/therubyracer +0 -11
  94. data/ext/v8/rr.cpp +0 -189
  95. data/ext/v8/v8.cpp +0 -48
  96. data/ext/v8/v8_array.cpp +0 -48
  97. data/ext/v8/v8_array.h +0 -8
  98. data/ext/v8/v8_callbacks.cpp +0 -81
  99. data/ext/v8/v8_callbacks.h +0 -8
  100. data/ext/v8/v8_context.cpp +0 -92
  101. data/ext/v8/v8_context.h +0 -6
  102. data/ext/v8/v8_date.cpp +0 -34
  103. data/ext/v8/v8_date.h +0 -6
  104. data/ext/v8/v8_debug.cpp +0 -17
  105. data/ext/v8/v8_debug.h +0 -6
  106. data/ext/v8/v8_exception.cpp +0 -133
  107. data/ext/v8/v8_exception.h +0 -11
  108. data/ext/v8/v8_external.cpp +0 -70
  109. data/ext/v8/v8_external.h +0 -8
  110. data/ext/v8/v8_function.cpp +0 -69
  111. data/ext/v8/v8_function.h +0 -11
  112. data/ext/v8/v8_handle.cpp +0 -186
  113. data/ext/v8/v8_handle.h +0 -48
  114. data/ext/v8/v8_locker.cpp +0 -139
  115. data/ext/v8/v8_locker.h +0 -6
  116. data/ext/v8/v8_message.cpp +0 -67
  117. data/ext/v8/v8_message.h +0 -10
  118. data/ext/v8/v8_object.cpp +0 -122
  119. data/ext/v8/v8_object.h +0 -10
  120. data/ext/v8/v8_script.cpp +0 -36
  121. data/ext/v8/v8_script.h +0 -8
  122. data/ext/v8/v8_string.cpp +0 -52
  123. data/ext/v8/v8_string.h +0 -9
  124. data/ext/v8/v8_template.cpp +0 -344
  125. data/ext/v8/v8_template.h +0 -8
  126. data/ext/v8/v8_try_catch.cpp +0 -70
  127. data/ext/v8/v8_try_catch.h +0 -5
  128. data/ext/v8/v8_v8.cpp +0 -35
  129. data/ext/v8/v8_v8.h +0 -6
  130. data/ext/v8/v8_value.cpp +0 -175
  131. data/ext/v8/v8_value.h +0 -10
  132. data/ext/v8/v8_weakref.cpp +0 -61
  133. data/ext/v8/v8_weakref.h +0 -29
  134. data/lib/v8/c/locker.rb +0 -18
  135. data/lib/v8/cli.rb +0 -133
  136. data/lib/v8/portal.rb +0 -86
  137. data/lib/v8/portal/caller.rb +0 -37
  138. data/lib/v8/portal/constructor.rb +0 -98
  139. data/lib/v8/portal/function.rb +0 -63
  140. data/lib/v8/portal/interceptors.rb +0 -152
  141. data/lib/v8/portal/proxies.rb +0 -151
  142. data/lib/v8/portal/templates.rb +0 -73
  143. data/lib/v8/stack.rb +0 -66
  144. data/lib/v8/tap.rb +0 -9
  145. data/spec/ext/array_spec.rb +0 -15
  146. data/spec/ext/cxt_spec.rb +0 -57
  147. data/spec/ext/ext_spec_helper.rb +0 -27
  148. data/spec/ext/func_spec.rb +0 -64
  149. data/spec/ext/object_spec.rb +0 -10
  150. data/spec/ext/string_spec.rb +0 -11
  151. data/spec/ext/try_catch_spec.rb +0 -60
  152. data/spec/redjs_helper.rb +0 -3
  153. data/spec/v8/portal/proxies_spec.rb +0 -106
  154. data/specmem/handle_memspec.rb +0 -41
  155. data/specmem/object_memspec.rb +0 -14
  156. data/specmem/proxies_memspec.rb +0 -49
  157. data/specmem/spec_helper.rb +0 -24
  158. data/specthread/spec_helper.rb +0 -2
  159. data/specthread/threading_spec.rb +0 -13
data/lib/v8/portal.rb DELETED
@@ -1,86 +0,0 @@
1
-
2
- module V8
3
- class Portal
4
- attr_reader :context, :access, :proxies, :templates, :interceptors, :caller
5
-
6
- def initialize(context, access)
7
- @context, @access = context, access
8
- @proxies = Proxies.new
9
- @templates = Templates.new(self)
10
- @interceptors = Interceptors.new(self)
11
- @caller = Caller.new(self)
12
- end
13
-
14
- def lock
15
- lock = V8::C::Locker.new
16
- yield
17
- ensure
18
- lock.delete
19
- end
20
-
21
- def open
22
- lock do
23
- @context.native.enter do
24
- yield(self)
25
- end if block_given?
26
- end
27
- end
28
-
29
- def rb(value)
30
- @proxies.js2rb(value) do
31
- case value
32
- when V8::C::Function then V8::Function.new(value, self)
33
- when V8::C::Array then V8::Array.new(value, self)
34
- when V8::C::Object then V8::Object.new(value, self)
35
- when V8::C::String then value.Utf8Value.tap {|s| return s.respond_to?(:force_encoding) ? s.force_encoding("UTF-8") : s}
36
- when V8::C::Date then Time.at(value.NumberValue() / 1000)
37
- when V8::C::StackTrace then V8::StackTrace.new(self, value)
38
- when V8::C::Value then nil if value.IsEmpty()
39
- else
40
- value
41
- end
42
- end
43
- end
44
-
45
- def v8(value)
46
- case value
47
- when V8::Object
48
- value.instance_eval {@native}
49
- when String
50
- C::String::New(value)
51
- when Symbol
52
- C::String::NewSymbol(value.to_s)
53
- when Proc,Method,UnboundMethod
54
- @proxies.rb2js(value) do
55
- @templates.to_function(value).function
56
- end
57
- when ::Array
58
- C::Array::New(value.length).tap do |a|
59
- value.each_with_index do |item, i|
60
- a.Set(i, v8(item))
61
- end
62
- end
63
- when ::Hash
64
- C::Object::New().tap do |o|
65
- value.each do |key, val|
66
- o.Set(v8(key), v8(val))
67
- end
68
- end
69
- when ::Time
70
- C::Date::New(value.to_f * 1000)
71
- when ::Class
72
- @proxies.rb2js(value) do
73
- constructor = @templates.to_constructor(value)
74
- constructor.exposed = true
75
- constructor.function
76
- end
77
- when nil,Numeric,TrueClass,FalseClass, C::Value
78
- value
79
- else
80
- @proxies.rb2js(value) do
81
- @templates.to_constructor(value.class).allocate(value)
82
- end
83
- end
84
- end
85
- end
86
- end
@@ -1,37 +0,0 @@
1
-
2
- module V8
3
- class Portal
4
- class Caller
5
-
6
- def initialize(portal)
7
- @portal = portal
8
- end
9
-
10
- def raw
11
- yield
12
- rescue Exception => e
13
- case e
14
- when SystemExit, NoMemoryError
15
- raise e
16
- else
17
- error = V8::C::Exception::Error(V8::C::String::New(e.message))
18
- #TODO: This is almost certainly a crash here.
19
- #we need to hold onto `error` while it bubbles up the javascript stack.
20
- error.SetHiddenValue("TheRubyRacer::Cause", C::External::New(e))
21
- V8::C::ThrowException(error)
22
- end
23
- end
24
-
25
- def protect(*args, &block)
26
- @portal.v8 raw(*args, &block)
27
- end
28
-
29
- def invoke(code, *args, &block)
30
- protect do
31
- args = args.slice(0, code.arity) if code.arity >= 0
32
- code.call(*args, &block)
33
- end
34
- end
35
- end
36
- end
37
- end
@@ -1,98 +0,0 @@
1
-
2
- module V8
3
- class Portal
4
- class ConstructorAdapter
5
- attr_reader :template, :exposed
6
- alias_method :exposed?, :exposed
7
-
8
- def initialize(templates, class_id)
9
- @exposed = false
10
- @class_id = class_id
11
- @templates = templates
12
- @invoke = method(:invoke)
13
- @template = C::FunctionTemplate::New(@invoke)
14
- portal.interceptors.setup(@template.InstanceTemplate())
15
- cls = self.ruby_class
16
- superclass = cls.superclass
17
- if cls != ::Object && superclass != ::Object && superclass != ::Class
18
- @template.Inherit(templates.to_constructor(superclass).template)
19
- end
20
- if cls.name && cls.name =~ /(::)?(\w+?)$/
21
- template.SetClassName(C::String::NewSymbol("rb::" + $2))
22
- else
23
- template.SetClassName("Ruby")
24
- end
25
- end
26
-
27
- def function
28
- @template.GetFunction()
29
- end
30
-
31
- def allocate(object)
32
- arguments = C::Array::New(1)
33
- arguments.Set(0, C::External::New(object))
34
- function.NewInstance(arguments)
35
- end
36
-
37
- def disable
38
- @disabled = true
39
- end
40
-
41
- def enable
42
- @disabled = nil
43
- end
44
-
45
- def invoke(arguments)
46
- return if @disabled
47
- if !@exposed
48
- unless arguments.Length() == 1 && arguments[0].kind_of?(C::External)
49
- C::ThrowException(C::Exception::Error(C::String::New("cannot call native constructor from javascript")))
50
- else
51
- object = arguments[0].Value()
52
- proxies.register_javascript_proxy arguments.This(), :for => object
53
- end
54
- else
55
- instance = nil
56
- if arguments.Length() > 0 && arguments[0].kind_of?(C::External)
57
- instance = arguments[0].Value()
58
- else
59
- rbargs = []
60
- for i in 0..arguments.Length() - 1
61
- rbargs << @templates.portal.rb(arguments[i])
62
- end
63
- instance = portal.caller.raw do
64
- self.ruby_class.new(*rbargs)
65
- end
66
- end
67
- proxies.register_javascript_proxy arguments.This(), :for => instance
68
- end
69
- end
70
-
71
- def exposed=(exposed)
72
- if exposed && !@augmented
73
- #create a prototype so that this constructor also acts like a ruby object
74
- prototype_template = C::ObjectTemplate::New()
75
- portal.interceptors.setup(prototype_template)
76
- prototype = prototype_template.NewInstance()
77
- #set *that* object's prototype to an empty function so that it will look and behave like a function.
78
- prototype.SetPrototype(C::FunctionTemplate::New().GetFunction())
79
- template.GetFunction().SetPrototype(prototype)
80
- @augmented = true
81
- end
82
- @exposed = exposed
83
- end
84
-
85
- def ruby_class
86
- ObjectSpace._id2ref(@class_id)
87
- end
88
-
89
- def proxies
90
- @templates.proxies
91
- end
92
-
93
- def portal
94
- @templates.portal
95
- end
96
- end
97
- end
98
- end
@@ -1,63 +0,0 @@
1
- module V8
2
- class Portal
3
- class FunctionAdapter
4
-
5
- attr_reader :template
6
-
7
- def initialize(portal, code)
8
- @portal = portal
9
- @caller = case code
10
- when Method then BoundCall.new(portal)
11
- when UnboundMethod then BindAndCall.new(portal)
12
- else Call.new(portal)
13
- end
14
- @code = code
15
- @template = V8::C::FunctionTemplate::New(@caller, @code)
16
- end
17
-
18
- def function
19
- @template.GetFunction()
20
- end
21
-
22
- class Call
23
- def initialize(portal)
24
- @portal = portal
25
- end
26
-
27
- def call(arguments)
28
- proc = arguments.Data()
29
- rbargs = [@portal.rb(arguments.This())]
30
- for i in 0..arguments.Length() - 1
31
- rbargs << @portal.rb(arguments[i])
32
- end
33
- @portal.caller.invoke(proc, *rbargs)
34
- end
35
- end
36
-
37
- class BoundCall < Call
38
- def call(arguments)
39
- proc = arguments.Data()
40
- rbargs = []
41
- for i in 0..arguments.Length() - 1
42
- rbargs << @portal.rb(arguments[i])
43
- end
44
- @portal.caller.invoke(proc, *rbargs)
45
- end
46
- end
47
-
48
- class BindAndCall < Call
49
- def call(arguments)
50
- method = arguments.Data()
51
- rbargs = []
52
- for i in 0..arguments.Length() - 1
53
- rbargs << @portal.rb(arguments[i])
54
- end
55
- this = @portal.rb(arguments.This())
56
- @portal.caller.protect do
57
- method.bind(this).call(*rbargs)
58
- end
59
- end
60
- end
61
- end
62
- end
63
- end
@@ -1,152 +0,0 @@
1
- module V8
2
- class Portal
3
- class Interceptors
4
- def initialize(portal)
5
- @getter = NamedPropertyGetter.new(portal)
6
- @setter = NamedPropertySetter.new(portal)
7
- @query = nil
8
- @deleter = nil
9
- @enumerator = NamedPropertyEnumerator.new(portal)
10
- @igetter = IndexedPropertyGetter.new(portal)
11
- @isetter = IndexedPropertySetter.new(portal)
12
- @iquery = nil
13
- @ideleter = nil
14
- @ienumerator = IndexedPropertyEnumerator.new(portal)
15
- end
16
-
17
- def setup(template)
18
- template.SetNamedPropertyHandler(@getter,@setter,@query,@deleter,@enumerator, nil)
19
- template.SetIndexedPropertyHandler(@igetter,@isetter,@iquery,@ideleter,@ienumerator, nil)
20
- end
21
-
22
- class PropertyAttributes
23
- attr_reader :flags
24
- def initialize
25
- @flags = 0
26
- end
27
-
28
- def read_only
29
- tap do
30
- @flags |= V8::C::ReadOnly
31
- end
32
- end
33
-
34
- def dont_enum
35
- tap do
36
- @flags |= V8::C::DontEnum
37
- end
38
- end
39
-
40
- def dont_delete
41
- tap do
42
- @flags |= V8::C::DontDelete
43
- end
44
- end
45
- end
46
-
47
- class Interceptor
48
-
49
- def initialize(portal)
50
- @to, @access = portal, portal.access
51
- end
52
-
53
- def intercept(info, retval = nil, &code)
54
- obj = @to.rb(info.This())
55
- intercepts = true
56
- result = @to.caller.protect do
57
- dontintercept = proc do
58
- intercepts = false
59
- end
60
- code.call(obj, dontintercept)
61
- end
62
- intercepts ? (retval || result) : C::Empty
63
- end
64
- end
65
-
66
- class NamedPropertyGetter < Interceptor
67
- def call(property, info)
68
- intercept(info) do |obj, dontintercept|
69
- @access.get(obj, @to.rb(property), &dontintercept)
70
- end
71
- end
72
- end
73
-
74
- class NamedPropertySetter < Interceptor
75
- def call(property, value, info)
76
- intercept(info, value) do |obj, dontintercept|
77
- @access.set(obj, @to.rb(property), @to.rb(value), &dontintercept)
78
- end
79
- end
80
- end
81
-
82
- class NamedPropertyQuery
83
- def call(property, info)
84
- attributes = PropertyAttributes.new
85
- result = intercept(info) do |obj, dontintercept|
86
- @access.query(obj, @to.rb(property), attributes, &dontintercept)
87
- end
88
- return result == C::Empty ? result : C::Integer::New(attributes.flags)
89
- end
90
- end
91
-
92
- class NamedPropertyEnumerator < Interceptor
93
- def call(info)
94
- intercept(info) do |obj, dontintercept|
95
- @access.names(obj, &dontintercept).to_a
96
- end
97
- end
98
- end
99
-
100
- class NamedPropertyDeleter < Interceptor
101
- def call(property, info)
102
- intercept(info) do |obj, dontintercept|
103
- @access.delete(obj, property, &dontintercept)
104
- end
105
- end
106
- end
107
-
108
- class IndexedPropertyGetter < Interceptor
109
- def call(index, info)
110
- intercept(info) do |obj, dontintercept|
111
- @access.iget(obj, index, &dontintercept)
112
- end
113
- end
114
- end
115
-
116
- class IndexedPropertySetter < Interceptor
117
- def call(index, value, info)
118
- intercept(info, value) do |obj, dontintercept|
119
- @access.iset(obj, index, @to.rb(value), &dontintercept)
120
- end
121
- end
122
- end
123
-
124
- class IndexedPropertyQuery < Interceptor
125
- def call(property, info)
126
- attributes = PropertyAttributes.new
127
- result = intercept(info) do |obj, dontintercept|
128
- @access.indices(obj, &dontintercept)
129
- end
130
- result == C::Empty ? C::Empty : C::Integer::New(attributes.flags)
131
- end
132
- end
133
-
134
- class IndexedPropertyDeleter < Interceptor
135
- def call(index, info)
136
- intercept(info) do |obj, dontintercept|
137
- @access.idelete(obj, index, &dontintercept)
138
- end
139
- end
140
- end
141
-
142
- class IndexedPropertyEnumerator < Interceptor
143
- def call(info)
144
- intercept(info) do |obj, dontintercept|
145
- @access.indices(obj, &dontintercept)
146
- end
147
- end
148
- end
149
- end
150
- end
151
- end
152
-
@@ -1,151 +0,0 @@
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