therubyracer 0.8.2 → 0.9.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 (53) hide show
  1. data/Changelog.md +1 -1
  2. data/ext/v8/rr.cpp +14 -7
  3. data/ext/v8/rr.h +1 -0
  4. data/ext/v8/v8.cpp +27 -25
  5. data/ext/v8/v8_array.cpp +7 -9
  6. data/ext/v8/v8_callbacks.cpp +1 -1
  7. data/ext/v8/{v8_cxt.cpp → v8_context.cpp} +11 -11
  8. data/ext/v8/{v8_cxt.h → v8_context.h} +1 -1
  9. data/ext/v8/v8_date.cpp +6 -6
  10. data/ext/v8/v8_exception.cpp +10 -11
  11. data/ext/v8/v8_external.cpp +7 -24
  12. data/ext/v8/v8_external.h +0 -1
  13. data/ext/v8/{v8_func.cpp → v8_function.cpp} +14 -14
  14. data/ext/v8/{v8_func.h → v8_function.h} +1 -2
  15. data/ext/v8/v8_handle.cpp +119 -0
  16. data/ext/v8/v8_handle.h +27 -0
  17. data/ext/v8/{v8_msg.cpp → v8_message.cpp} +8 -9
  18. data/ext/v8/{v8_msg.h → v8_message.h} +1 -1
  19. data/ext/v8/{v8_obj.cpp → v8_object.cpp} +51 -29
  20. data/ext/v8/{v8_obj.h → v8_object.h} +3 -4
  21. data/ext/v8/v8_script.cpp +5 -5
  22. data/ext/v8/{v8_str.cpp → v8_string.cpp} +9 -11
  23. data/ext/v8/{v8_str.h → v8_string.h} +1 -1
  24. data/ext/v8/v8_template.cpp +113 -98
  25. data/ext/v8/v8_try_catch.cpp +1 -1
  26. data/ext/v8/v8_v8.cpp +7 -0
  27. data/ext/v8/v8_value.cpp +44 -36
  28. data/ext/v8/v8_value.h +2 -2
  29. data/ext/v8/v8_weakref.cpp +51 -0
  30. data/ext/v8/v8_weakref.h +30 -0
  31. data/lib/v8.rb +6 -1
  32. data/lib/v8/context.rb +13 -3
  33. data/lib/v8/error.rb +1 -1
  34. data/lib/v8/portal.rb +26 -277
  35. data/lib/v8/portal/caller.rb +36 -0
  36. data/lib/v8/portal/constructor.rb +98 -0
  37. data/lib/v8/portal/function.rb +48 -0
  38. data/lib/v8/portal/interceptors.rb +153 -0
  39. data/lib/v8/portal/proxies.rb +102 -0
  40. data/lib/v8/portal/templates.rb +73 -0
  41. data/lib/v8/version.rb +1 -1
  42. data/spec/ext/array_spec.rb +15 -0
  43. data/spec/ext/cxt_spec.rb +4 -4
  44. data/spec/ext/ext_spec_helper.rb +43 -0
  45. data/spec/ext/mem_spec.rb +42 -0
  46. data/spec/ext/object_spec.rb +22 -0
  47. data/spec/redjs/jsapi_spec.rb +4 -4
  48. data/spec/spec_helper.rb +1 -1
  49. data/spec/v8/portal/proxies_spec.rb +189 -0
  50. metadata +38 -42
  51. data/ext/v8/v8_ref.cpp +0 -37
  52. data/ext/v8/v8_ref.h +0 -28
  53. data/lib/v8/portal/functions.rb +0 -45
@@ -3,8 +3,8 @@
3
3
 
4
4
  #include "rr.h"
5
5
 
6
- extern VALUE rr_cV8_C_Value;
7
- extern VALUE rr_cV8_C_Empty;
8
6
  void rr_init_value();
9
7
  VALUE rr_wrap_v8_value(v8::Handle<v8::Value>& value);
8
+ VALUE rr_v8_value_class();
9
+ VALUE rr_v8_value_empty();
10
10
  #endif
@@ -0,0 +1,51 @@
1
+ #include "v8.h"
2
+ #include "v8_weakref.h"
3
+
4
+ using namespace v8;
5
+
6
+ v8_weakref::v8_weakref(VALUE object) {
7
+ this->external = Persistent<External>::New(External::New((void *)this));
8
+ this->external.MakeWeak(this, v8_weakref_dispose);
9
+ this->set(object);
10
+ }
11
+
12
+ void v8_weakref::set(VALUE value) {
13
+ this->object_id = rb_obj_id(value);
14
+ VALUE data = Data_Wrap_Struct(rb_cObject, 0, 0, this);
15
+ VALUE finalizer = rb_proc_new((VALUE (*)(...))v8_weakref_finalize, data);
16
+ rb_funcall(v8_weakref_objectspace(), rb_intern("define_finalizer"), 2, value, finalizer);
17
+ }
18
+
19
+ VALUE v8_weakref::get() {
20
+ if (this->object_id) {
21
+ return rb_rescue((VALUE (*)(...))v8_weakref_id2ref, this->object_id, (VALUE (*)(...))v8_weakref_nil, Qnil);
22
+ } else {
23
+ return Qnil;
24
+ }
25
+ }
26
+
27
+ VALUE v8_weakref_finalize(VALUE object_id, VALUE data) {
28
+ v8_weakref* weakref = 0;
29
+ Data_Get_Struct(data, struct v8_weakref, weakref);
30
+ weakref->object_id = Qnil;
31
+ return Qnil;
32
+ }
33
+
34
+ void v8_weakref_dispose(Persistent<Value> value, void* weakref) {
35
+ value.Dispose();
36
+ value.Clear();
37
+ delete (v8_weakref*)weakref;
38
+ }
39
+
40
+ VALUE v8_weakref_nil(VALUE nil, VALUE exception) {
41
+ return nil;
42
+ }
43
+
44
+ VALUE v8_weakref_objectspace() {
45
+ return rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
46
+ }
47
+
48
+ VALUE v8_weakref_id2ref(VALUE id) {
49
+ return rb_funcall(v8_weakref_objectspace(), rb_intern("_id2ref"), 1, id);
50
+ }
51
+
@@ -0,0 +1,30 @@
1
+ #ifndef _RR_V8_WEAKREF_
2
+ #define _RR_V8_WEAKREF_
3
+
4
+ #include <v8.h>
5
+ #include "ruby.h"
6
+ #include "ruby/version.h"
7
+
8
+ struct v8_weakref {
9
+ v8_weakref(VALUE object);
10
+ VALUE get();
11
+ void set(VALUE object);
12
+ void retain();
13
+ void release();
14
+
15
+ VALUE object_id;
16
+ v8::Persistent<v8::External> external;
17
+ };
18
+
19
+ void v8_weakref_dispose(v8::Persistent<v8::Value> value, void* weakref);
20
+ VALUE v8_weakref_finalize(VALUE self, VALUE object_id);
21
+ VALUE v8_weakref_objectspace();
22
+ VALUE v8_weakref_nil(VALUE nil, VALUE exception);
23
+ VALUE v8_weakref_id2ref(VALUE id);
24
+
25
+
26
+ #if RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8
27
+ extern "C" VALUE rb_proc_new(VALUE (*)(ANYARGS/* VALUE yieldarg[, VALUE procarg] */), VALUE);
28
+ #endif
29
+
30
+ #endif
data/lib/v8.rb CHANGED
@@ -5,7 +5,12 @@ module V8
5
5
  require 'v8/version'
6
6
  require 'v8/v8' #native glue
7
7
  require 'v8/portal'
8
- require 'v8/portal/functions'
8
+ require 'v8/portal/caller'
9
+ require 'v8/portal/proxies'
10
+ require 'v8/portal/templates'
11
+ require 'v8/portal/function'
12
+ require 'v8/portal/constructor'
13
+ require 'v8/portal/interceptors'
9
14
  require 'v8/context'
10
15
  require 'v8/object'
11
16
  require 'v8/array'
@@ -7,11 +7,21 @@ module V8
7
7
  def initialize(opts = {})
8
8
  @access = Access.new
9
9
  @to = Portal.new(self, @access)
10
- @native = opts[:with] ? C::Context::New(@to.rubytemplate) : C::Context::New()
10
+ with = opts[:with]
11
+ constructor = nil
12
+ template = if with
13
+ constructor = @to.templates.to_constructor(with.class)
14
+ constructor.disable()
15
+ constructor.template.InstanceTemplate()
16
+ else
17
+ C::ObjectTemplate::New()
18
+ end
19
+ @native = opts[:with] ? C::Context::New(template) : C::Context::New()
11
20
  @native.enter do
12
21
  @global = @native.Global()
22
+ @to.proxies.register_javascript_proxy @global, :for => with if with
23
+ constructor.enable() if constructor
13
24
  @scope = @to.rb(@global)
14
- @global.SetHiddenValue(C::String::New("TheRubyRacer::RubyObject"), C::External::New(opts[:with])) if opts[:with]
15
25
  @global.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyContext"), C::External::New(self))
16
26
  end
17
27
  yield(self) if block_given?
@@ -58,7 +68,7 @@ module V8
58
68
 
59
69
  def self.stack(limit = 99)
60
70
  if native = C::Context::GetEntered()
61
- global = native.Global().instance_eval {@native}
71
+ global = native.Global()
62
72
  cxt = global.GetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyContext")).Value()
63
73
  cxt.instance_eval {@to.rb(C::StackTrace::CurrentStackTrace(limit))}
64
74
  else
@@ -106,7 +106,7 @@ module V8
106
106
  #in these instances, we have to pull it out of the Message object
107
107
  #in the TryCatch. Is there a better way to detect a syntax error
108
108
  def syntax_error?(try)
109
- ex = try.Exception()
109
+ ex = @to.rb(try.Exception())
110
110
  if ex && ex.kind_of?(V8::Object)
111
111
  type = ex["constructor"]
112
112
  type && type.kind_of?(V8::Function) && type.name == "SyntaxError"
@@ -1,73 +1,14 @@
1
1
 
2
2
  module V8
3
3
  class Portal
4
- attr_reader :context
4
+ attr_reader :context, :access, :proxies, :templates, :interceptors, :caller
5
5
 
6
6
  def initialize(context, access)
7
7
  @context, @access = context, access
8
- @named_property_getter = Interceptor(NamedPropertyGetter)
9
- @named_property_setter = Interceptor(NamedPropertySetter)
10
- @named_property_query = nil
11
- @named_property_deleter = nil
12
- @named_property_enumerator = Interceptor(NamedPropertyEnumerator)
13
-
14
- @indexed_property_getter = Interceptor(IndexedPropertyGetter)
15
- @indexed_property_setter = Interceptor(IndexedPropertySetter)
16
- @indexed_property_query = nil
17
- @indexed_property_deleter = nil
18
- @indexed_property_enumerator = Interceptor(IndexedPropertyEnumerator)
19
-
20
- @constructors = Hash.new do |h, cls|
21
- h[cls] = template = C::FunctionTemplate::New() do |arguments|
22
- unless arguments.Length() == 1 && arguments[0].kind_of?(C::External)
23
- C::ThrowException(C::Exception::Error(C::String::New("cannot call native constructor from javascript")))
24
- else
25
- arguments.This().tap do |this|
26
- this.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"), arguments[0])
27
- end
28
- end
29
- end
30
- template.tap do
31
- setuptemplate(template.InstanceTemplate())
32
- if cls != ::Object && cls.superclass != ::Object && cls.superclass != ::Class
33
- template.Inherit(@constructors[cls.superclass])
34
- end
35
- if cls.name && cls.name =~ /(::)?(\w+?)$/
36
- template.SetClassName(C::String::NewSymbol("rb::" + $2))
37
- else
38
- template.SetClassName("Ruby")
39
- end
40
- end
41
- end
42
-
43
- @instances = Hash.new do |h, obj|
44
- args = C::Array::New(1)
45
- args.Set(0, C::External::New(obj))
46
- h[obj] = @constructors[obj.class].GetFunction().NewInstance(args)
47
- end
48
-
49
- @functions = Functions.new(self)
50
-
51
- @embedded_constructors = Hash.new do |h, cls|
52
- template = @constructors[cls]
53
- template.SetCallHandler() do |arguments|
54
- wrap = nil
55
- if arguments.Length() > 0 && arguments[0].kind_of?(C::External)
56
- wrap = arguments[0]
57
- else
58
- rbargs = []
59
- for i in 0..arguments.Length() - 1
60
- rbargs << rb(arguments[i])
61
- end
62
- instance = rubysend(cls, :new, *rbargs)
63
- wrap = C::External::New(instance)
64
- end
65
- arguments.This().tap do |this|
66
- this.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"), wrap)
67
- end
68
- end
69
- h[cls] = template
70
- end
8
+ @proxies = Proxies.new
9
+ @templates = Templates.new(self)
10
+ @interceptors = Interceptors.new(self)
11
+ @caller = Caller.new(self)
71
12
  end
72
13
 
73
14
  def open
@@ -77,16 +18,18 @@ module V8
77
18
  end
78
19
 
79
20
  def rb(value)
80
- case value
81
- when V8::C::Function then peer(value) {V8::Function}
82
- when V8::C::Array then peer(value) {V8::Array}
83
- when V8::C::Object then peer(value) {V8::Object}
84
- when V8::C::String then value.Utf8Value.tap {|s| return s.respond_to?(:force_encoding) ? s.force_encoding("UTF-8") : s}
85
- when V8::C::Date then Time.at(value.NumberValue() / 1000)
86
- when V8::C::StackTrace then V8::StackTrace.new(self, value)
87
- when V8::C::Value then nil if value.IsEmpty()
88
- else
89
- value
21
+ @proxies.js2rb(value) do
22
+ case value
23
+ when V8::C::Function then V8::Function.new(value, self)
24
+ when V8::C::Array then V8::Array.new(value, self)
25
+ when V8::C::Object then V8::Object.new(value, self)
26
+ when V8::C::String then value.Utf8Value.tap {|s| return s.respond_to?(:force_encoding) ? s.force_encoding("UTF-8") : s}
27
+ when V8::C::Date then Time.at(value.NumberValue() / 1000)
28
+ when V8::C::StackTrace then V8::StackTrace.new(self, value)
29
+ when V8::C::Value then nil if value.IsEmpty()
30
+ else
31
+ value
32
+ end
90
33
  end
91
34
  end
92
35
 
@@ -99,7 +42,9 @@ module V8
99
42
  when Symbol
100
43
  C::String::NewSymbol(value.to_s)
101
44
  when Proc,Method,UnboundMethod
102
- @functions[value]
45
+ @proxies.rb2js(value) do
46
+ @templates.to_function(value).function
47
+ end
103
48
  when ::Array
104
49
  C::Array::New(value.length).tap do |a|
105
50
  value.each_with_index do |item, i|
@@ -115,212 +60,16 @@ module V8
115
60
  when ::Time
116
61
  C::Date::New(value.to_f * 1000)
117
62
  when ::Class
118
- @embedded_constructors[value].GetFunction().tap do |f|
119
- f.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"), C::External::New(value))
120
- #set the function's prototype object to the object that will have the named property handlers
121
- prototype = rubytemplate.NewInstance()
122
- #set *that* object's prototype to an empty function so that it will look and behave like a function.
123
- prototype.SetPrototype(C::FunctionTemplate::New() {}.GetFunction())
124
- f.SetPrototype(prototype)
63
+ @proxies.rb2js(value) do
64
+ constructor = @templates.to_constructor(value)
65
+ constructor.exposed = true
66
+ constructor.function
125
67
  end
126
68
  when nil,Numeric,TrueClass,FalseClass, C::Value
127
69
  value
128
70
  else
129
- @instances[value]
130
- end
131
- end
132
-
133
- def rubyprotect
134
- begin
135
- v8 yield
136
- rescue Exception => e
137
- case e
138
- when SystemExit, NoMemoryError
139
- raise e
140
- else
141
- error = V8::C::Exception::Error(V8::C::String::New(e.message))
142
- error.SetHiddenValue("TheRubyRacer::Cause", C::External::New(e))
143
- V8::C::ThrowException(error)
144
- end
145
- end
146
- end
147
-
148
- def rubycall(rubycode, *args, &block)
149
- rubyprotect do
150
- rubycode.call(*args, &block)
151
- end
152
- end
153
-
154
- def rubysend(obj, message, *args, &block)
155
- rubyprotect do
156
- obj.send(message, *args, &block)
157
- end
158
- end
159
-
160
- def rubytemplate
161
- C::ObjectTemplate::New().tap do |t|
162
- setuptemplate(t)
163
- end
164
- end
165
-
166
- def setuptemplate(t)
167
- t.SetNamedPropertyHandler(
168
- @named_property_getter,
169
- @named_property_setter,
170
- nil,
171
- nil,
172
- @named_property_enumerator
173
- )
174
- t.SetIndexedPropertyHandler(
175
- @indexed_property_getter,
176
- @indexed_property_setter,
177
- nil,
178
- nil,
179
- @indexed_property_enumerator
180
- )
181
- end
182
-
183
- private
184
-
185
- def peer(value)
186
- external = value.GetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"))
187
- if external && !external.IsEmpty()
188
- external.Value()
189
- else
190
- yield.new(value, self).tap do |object|
191
- value.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"), C::External::New(object))
192
- end
193
- end
194
- end
195
-
196
- class Interceptor
197
- def initialize(portal, access)
198
- @to, @access = portal, access
199
- end
200
-
201
- def intercept(info, retval = nil, &code)
202
- obj = @to.rb(info.This())
203
- intercepts = true
204
- result = @to.rubyprotect do
205
- dontintercept = proc do
206
- intercepts = false
207
- end
208
- code.call(obj, dontintercept)
209
- end
210
- intercepts ? (retval || result) : C::Empty
211
- end
212
-
213
- end
214
-
215
- def Interceptor(cls)
216
- cls.new self, @access
217
- end
218
-
219
- class PropertyAttributes
220
- attr_reader :flags
221
- def initialize
222
- @flags = 0
223
- end
224
-
225
- def read_only
226
- tap do
227
- @flags |= V8::C::ReadOnly
228
- end
229
- end
230
-
231
- def dont_enum
232
- tap do
233
- @flags |= V8::C::DontEnum
234
- end
235
- end
236
-
237
- def dont_delete
238
- tap do
239
- @flags |= V8::C::DontDelete
240
- end
241
- end
242
- end
243
-
244
- class NamedPropertyGetter < Interceptor
245
- def call(property, info)
246
- intercept(info) do |obj, dontintercept|
247
- @access.get(obj, @to.rb(property), &dontintercept)
248
- end
249
- end
250
- end
251
-
252
- class NamedPropertySetter < Interceptor
253
- def call(property, value, info)
254
- intercept(info, value) do |obj, dontintercept|
255
- @access.set(obj, @to.rb(property), @to.rb(value), &dontintercept)
256
- end
257
- end
258
- end
259
-
260
- class NamedPropertyQuery
261
- def call(property, info)
262
- attributes = PropertyAttributes.new
263
- result = intercept(info) do |obj, dontintercept|
264
- @access.query(obj, @to.rb(property), attributes, &dontintercept)
265
- end
266
- return result == C::Empty ? result : C::Integer::New(attributes.flags)
267
- end
268
- end
269
-
270
- class NamedPropertyEnumerator < Interceptor
271
- def call(info)
272
- intercept(info) do |obj, dontintercept|
273
- @access.names(obj, &dontintercept).to_a
274
- end
275
- end
276
- end
277
-
278
- class NamedPropertyDeleter < Interceptor
279
- def call(property, info)
280
- intercept(info) do |obj, dontintercept|
281
- @access.delete(obj, property, &dontintercept)
282
- end
283
- end
284
- end
285
-
286
- class IndexedPropertyGetter < Interceptor
287
- def call(index, info)
288
- intercept(info) do |obj, dontintercept|
289
- @access.iget(obj, index, &dontintercept)
290
- end
291
- end
292
- end
293
-
294
- class IndexedPropertySetter < Interceptor
295
- def call(index, value, info)
296
- intercept(info, value) do |obj, dontintercept|
297
- @access.iset(obj, index, @to.rb(value), &dontintercept)
298
- end
299
- end
300
- end
301
-
302
- class IndexedPropertyQuery < Interceptor
303
- def call(property, info)
304
- attributes = PropertyAttributes.new
305
- result = intercept(info) do |obj, dontintercept|
306
- @access.indices(obj, &dontintercept)
307
- end
308
- result == C::Empty ? C::Empty : C::Integer::New(attributes.flags)
309
- end
310
- end
311
-
312
- class IndexedPropertyDeleter < Interceptor
313
- def call(index, info)
314
- intercept(info) do |obj, dontintercept|
315
- @access.idelete(obj, index, &dontintercept)
316
- end
317
- end
318
- end
319
-
320
- class IndexedPropertyEnumerator < Interceptor
321
- def call(info)
322
- intercept(info) do |obj, dontintercept|
323
- @access.indices(obj, &dontintercept)
71
+ @proxies.rb2js(value) do
72
+ @templates.to_constructor(value.class).allocate(value)
324
73
  end
325
74
  end
326
75
  end