therubyracer 0.11.0beta8-x86-freebsd-9

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 (92) hide show
  1. data/.gitignore +23 -0
  2. data/.travis.yml +10 -0
  3. data/Changelog.md +242 -0
  4. data/Gemfile +16 -0
  5. data/README.md +185 -0
  6. data/Rakefile +42 -0
  7. data/benchmarks.rb +218 -0
  8. data/ext/v8/accessor.cc +181 -0
  9. data/ext/v8/array.cc +26 -0
  10. data/ext/v8/backref.cc +45 -0
  11. data/ext/v8/build.rb +52 -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 +25 -0
  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/init.so +0 -0
  25. data/ext/v8/invocation.cc +86 -0
  26. data/ext/v8/locker.cc +77 -0
  27. data/ext/v8/message.cc +51 -0
  28. data/ext/v8/object.cc +334 -0
  29. data/ext/v8/primitive.cc +8 -0
  30. data/ext/v8/rr.cc +83 -0
  31. data/ext/v8/rr.h +932 -0
  32. data/ext/v8/script.cc +80 -0
  33. data/ext/v8/signature.cc +18 -0
  34. data/ext/v8/stack.cc +76 -0
  35. data/ext/v8/string.cc +47 -0
  36. data/ext/v8/template.cc +175 -0
  37. data/ext/v8/trycatch.cc +87 -0
  38. data/ext/v8/v8.cc +87 -0
  39. data/ext/v8/value.cc +239 -0
  40. data/lib/v8.rb +30 -0
  41. data/lib/v8/access.rb +5 -0
  42. data/lib/v8/access/indices.rb +40 -0
  43. data/lib/v8/access/invocation.rb +47 -0
  44. data/lib/v8/access/names.rb +65 -0
  45. data/lib/v8/array.rb +26 -0
  46. data/lib/v8/context.rb +245 -0
  47. data/lib/v8/conversion.rb +36 -0
  48. data/lib/v8/conversion/array.rb +11 -0
  49. data/lib/v8/conversion/class.rb +119 -0
  50. data/lib/v8/conversion/code.rb +38 -0
  51. data/lib/v8/conversion/fixnum.rb +11 -0
  52. data/lib/v8/conversion/fundamental.rb +11 -0
  53. data/lib/v8/conversion/hash.rb +11 -0
  54. data/lib/v8/conversion/indentity.rb +31 -0
  55. data/lib/v8/conversion/method.rb +26 -0
  56. data/lib/v8/conversion/object.rb +28 -0
  57. data/lib/v8/conversion/primitive.rb +7 -0
  58. data/lib/v8/conversion/proc.rb +5 -0
  59. data/lib/v8/conversion/reference.rb +16 -0
  60. data/lib/v8/conversion/string.rb +12 -0
  61. data/lib/v8/conversion/symbol.rb +7 -0
  62. data/lib/v8/conversion/time.rb +13 -0
  63. data/lib/v8/error.rb +166 -0
  64. data/lib/v8/function.rb +28 -0
  65. data/lib/v8/object.rb +79 -0
  66. data/lib/v8/stack.rb +85 -0
  67. data/lib/v8/version.rb +3 -0
  68. data/lib/v8/weak.rb +70 -0
  69. data/spec/c/array_spec.rb +17 -0
  70. data/spec/c/constants_spec.rb +20 -0
  71. data/spec/c/exception_spec.rb +26 -0
  72. data/spec/c/external_spec.rb +9 -0
  73. data/spec/c/function_spec.rb +46 -0
  74. data/spec/c/handles_spec.rb +35 -0
  75. data/spec/c/locker_spec.rb +38 -0
  76. data/spec/c/object_spec.rb +46 -0
  77. data/spec/c/script_spec.rb +28 -0
  78. data/spec/c/string_spec.rb +16 -0
  79. data/spec/c/template_spec.rb +30 -0
  80. data/spec/c/trycatch_spec.rb +51 -0
  81. data/spec/mem/blunt_spec.rb +42 -0
  82. data/spec/redjs_spec.rb +10 -0
  83. data/spec/spec_helper.rb +45 -0
  84. data/spec/threading_spec.rb +52 -0
  85. data/spec/v8/context_spec.rb +19 -0
  86. data/spec/v8/conversion_spec.rb +52 -0
  87. data/spec/v8/error_spec.rb +165 -0
  88. data/spec/v8/function_spec.rb +9 -0
  89. data/spec/v8/object_spec.rb +15 -0
  90. data/thefrontside.png +0 -0
  91. data/therubyracer.gemspec +20 -0
  92. metadata +164 -0
@@ -0,0 +1,65 @@
1
+ require 'set'
2
+ class V8::Access
3
+ module Names
4
+ def names(obj)
5
+ accessible_names(obj)
6
+ end
7
+
8
+ def get(obj, name, &dontintercept)
9
+ methods = accessible_names(obj)
10
+ if methods.include?(name)
11
+ method = obj.method(name)
12
+ method.arity == 0 ? method.call : method.unbind
13
+ elsif obj.respond_to?(:[]) && !special?(name)
14
+ obj.send(:[], name, &dontintercept)
15
+ else
16
+ yield
17
+ end
18
+ end
19
+
20
+ def set(obj, name, value, &dontintercept)
21
+ setter = name + "="
22
+ methods = accessible_names(obj, true)
23
+ if methods.include?(setter)
24
+ obj.send(setter, value)
25
+ elsif obj.respond_to?(:[]=) && !special?(name)
26
+ obj.send(:[]=, name, value, &dontintercept)
27
+ else
28
+ yield
29
+ end
30
+ end
31
+
32
+ def query(obj, name, attributes, &dontintercept)
33
+ if obj.respond_to?(name)
34
+ attributes.dont_delete
35
+ unless obj.respond_to?(name + "=")
36
+ attributes.read_only
37
+ end
38
+ else
39
+ yield
40
+ end
41
+ end
42
+
43
+ def delete(obj, name, &dontintercept)
44
+ yield
45
+ end
46
+
47
+ def accessible_names(obj, special_methods = false)
48
+ obj.public_methods(false).map {|m| m.to_s}.to_set.tap do |methods|
49
+ ancestors = obj.class.ancestors.dup
50
+ while ancestor = ancestors.shift
51
+ break if ancestor == ::Object
52
+ methods.merge(ancestor.public_instance_methods(false).map {|m| m.to_s})
53
+ end
54
+ methods.reject!(&special?) unless special_methods
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def special?(name = nil)
61
+ @special ||= lambda {|m| m == "[]" || m == "[]=" || m =~ /=$/}
62
+ name.nil? ? @special : @special[name]
63
+ end
64
+ end
65
+ end
data/lib/v8/array.rb ADDED
@@ -0,0 +1,26 @@
1
+ class V8::Array < V8::Object
2
+
3
+ def initialize(native_or_length = nil)
4
+ super do
5
+ if native_or_length.is_a?(Numeric)
6
+ V8::C::Array::New(native_or_length)
7
+ elsif native_or_length.is_a?(V8::C::Array)
8
+ native_or_length
9
+ else
10
+ V8::C::Array::New()
11
+ end
12
+ end
13
+ end
14
+
15
+ def each
16
+ @context.enter do
17
+ 0.upto(@native.Length() - 1) do |i|
18
+ yield @context.to_ruby(@native.Get(i))
19
+ end
20
+ end
21
+ end
22
+
23
+ def length
24
+ @native.Length()
25
+ end
26
+ end
data/lib/v8/context.rb ADDED
@@ -0,0 +1,245 @@
1
+ require 'stringio'
2
+ module V8
3
+ # All JavaScript must be executed in a context. This context consists of a global scope containing the
4
+ # standard JavaScript objects¨and functions like Object, String, Array, as well as any objects or
5
+ # functions from Ruby which have been embedded into it from the containing enviroment. E.g.
6
+ #
7
+ # V8::Context.new do |cxt|
8
+ # cxt['num'] = 5
9
+ # cxt.eval('num + 5') #=> 10
10
+ # end
11
+ #
12
+ # The same object may appear in any number of contexts, but only one context may be executing JavaScript code
13
+ # in any given thread. If a new context is opened in a thread in which a context is already opened, the second
14
+ # context will "mask" the old context e.g.
15
+ #
16
+ # six = 6
17
+ # Context.new do |cxt|
18
+ # cxt['num'] = 5
19
+ # cxt.eval('num') # => 5
20
+ # Context.new do |cxt|
21
+ # cxt['num'] = 10
22
+ # cxt.eval('num') # => 10
23
+ # cxt.eval('++num') # => 11
24
+ # end
25
+ # cxt.eval('num') # => 5
26
+ # end
27
+ class Context
28
+ include V8::Error::Try
29
+
30
+ # @!attribute [r] conversion
31
+ # @return [V8::Conversion] conversion behavior for this context
32
+ attr_reader :conversion
33
+
34
+ # @!attrribute [r] access
35
+ # @return [V8::Access] Ruby access behavior for this context
36
+ attr_reader :access
37
+
38
+ # @!attribute [r] native
39
+ # @return [V8::C::Context] the underlying C++ object
40
+ attr_reader :native
41
+
42
+ # Creates a new context.
43
+ #
44
+ # If passed the `:with` option, that object will be used as
45
+ # the global scope of the newly creating context. e.g.
46
+ #
47
+ # scope = Object.new
48
+ # def scope.hello; "Hi"; end
49
+ # V8::Context.new(:with => scope) do |cxt|
50
+ # cxt['hello'] #=> 'Hi'
51
+ # end
52
+ #
53
+ # @param [Hash<Symbol, Object>] options initial context configuration
54
+ # * :with scope serves as the global scope of the new context
55
+ # @yield [V8::Context] the newly created context
56
+ def initialize(options = {})
57
+ @conversion = Conversion.new
58
+ @access = Access.new
59
+ if global = options[:with]
60
+ Context.new.enter do
61
+ global_template = global.class.to_template.InstanceTemplate()
62
+ @native = V8::C::Context::New(nil, global_template)
63
+ end
64
+ enter {link global, @native.Global()}
65
+ else
66
+ V8::C::Locker() do
67
+ @native = V8::C::Context::New()
68
+ end
69
+ end
70
+ yield self if block_given?
71
+ end
72
+
73
+ # Compile and execute a string of JavaScript source.
74
+ #
75
+ # If `source` is an IO object it will be read fully before being evaluated
76
+ #
77
+ # @param [String,IO] source the source code to compile and execute
78
+ # @param [String] filename the name to use for this code when generating stack traces
79
+ # @param [Integer] line the line number to start with
80
+ # @return [Object] the result of the evaluation
81
+ def eval(source, filename = '<eval>', line = 1)
82
+ if IO === source || StringIO === source
83
+ source = source.read
84
+ end
85
+ enter do
86
+ script = try { V8::C::Script::New(source.to_s, filename.to_s) }
87
+ to_ruby try {script.Run()}
88
+ end
89
+ end
90
+
91
+ # Read a value from the global scope of this context
92
+ #
93
+ # @param [Object] key the name of the value to read
94
+ # @return [Object] value the value at `key`
95
+ def [](key)
96
+ enter do
97
+ to_ruby(@native.Global().Get(to_v8(key)))
98
+ end
99
+ end
100
+
101
+ # Binds `value` to the name `key` in the global scope of this context.
102
+ #
103
+ # @param [Object] key the name to bind to
104
+ # @param [Object] value the value to bind
105
+ def []=(key, value)
106
+ enter do
107
+ @native.Global().Set(to_v8(key), to_v8(value))
108
+ end
109
+ return value
110
+ end
111
+
112
+ # Destroy this context and release any internal references it may
113
+ # contain to embedded Ruby objects.
114
+ #
115
+ # A disposed context may never again be used for anything, and all
116
+ # objects created with it will become unusable.
117
+ def dispose
118
+ return unless @native
119
+ @native.Dispose()
120
+ @native = nil
121
+ V8::C::V8::ContextDisposedNotification()
122
+ def self.enter
123
+ fail "cannot enter a context which has already been disposed"
124
+ end
125
+ end
126
+
127
+ # Returns this context's global object. This will be a `V8::Object`
128
+ # if no scope was provided or just an `Object` if a Ruby object
129
+ # is serving as the global scope.
130
+ #
131
+ # @return [Object] scope the context's global scope.
132
+ def scope
133
+ enter { to_ruby @native.Global() }
134
+ end
135
+
136
+ # Converts a v8 C++ object into its ruby counterpart. This is method
137
+ # is used to translate all values passed to Ruby from JavaScript, either
138
+ # as return values or as callback parameters.
139
+ #
140
+ # @param [V8::C::Object] v8_object the native c++ object to convert.
141
+ # @return [Object] to pass to Ruby
142
+ # @see V8::Conversion for how to customize and extend this mechanism
143
+ def to_ruby(v8_object)
144
+ @conversion.to_ruby(v8_object)
145
+ end
146
+
147
+ # Converts a Ruby object into a native v8 C++ object. This method is
148
+ # used to translate all values passed to JavaScript from Ruby, either
149
+ # as return value or as callback parameters.
150
+ #
151
+ # @param [Object] ruby_object the Ruby object to convert
152
+ # @return [V8::C::Object] to pass to V8
153
+ # @see V8::Conversion for customizing and extending this mechanism
154
+ def to_v8(ruby_object)
155
+ @conversion.to_v8(ruby_object)
156
+ end
157
+
158
+ # Marks a Ruby object and a v8 C++ Object as being the same. In other
159
+ # words whenever `ruby_object` is passed to v8, the result of the
160
+ # conversion should be `v8_object`. Conversely, whenever `v8_object`
161
+ # is passed to Ruby, the result of the conversion should be `ruby_object`.
162
+ # The Ruby Racer uses this mechanism to maintain referential integrity
163
+ # between Ruby and JavaScript peers
164
+ #
165
+ # @param [Object] ruby_object the Ruby half of the object identity
166
+ # @param [V8::C::Object] v8_object the V8 half of the object identity.
167
+ # @see V8::Conversion::Identity
168
+ def link(ruby_object, v8_object)
169
+ @conversion.equate ruby_object, v8_object
170
+ end
171
+
172
+ # Links `ruby_object` and `v8_object` inside the currently entered
173
+ # context. This is an error if no context has been entered.
174
+ #
175
+ # @param [Object] ruby_object the Ruby half of the object identity
176
+ # @param [V8::C::Object] v8_object the V8 half of the object identity.
177
+ def self.link(ruby_object, v8_object)
178
+ current.link ruby_object, v8_object
179
+ end
180
+
181
+ # Run some Ruby code in the context of this context.
182
+ #
183
+ # This will acquire the V8 interpreter lock (possibly blocking
184
+ # until it is available), and prepare V8 for JavaScript execution.
185
+ #
186
+ # Only one context may be running at a time per thread.
187
+ #
188
+ # @return [Object] the result of executing `block`
189
+ def enter(&block)
190
+ if !entered?
191
+ lock_scope_and_enter(&block)
192
+ else
193
+ yield
194
+ end
195
+ end
196
+
197
+ # Indicates if this context is the currently entered context
198
+ #
199
+ # @return true if this context is currently entered
200
+ def entered?
201
+ Context.current == self
202
+ end
203
+
204
+ # Get the currently entered context.
205
+ #
206
+ # @return [V8::Context] currently entered context, nil if none entered.
207
+ def self.current
208
+ Thread.current[:v8_context]
209
+ end
210
+
211
+ # Compile and execute the contents of the file with path `filename`
212
+ # as JavaScript code.
213
+ #
214
+ # @param [String] filename path to the file to execute.
215
+ # @return [Object] the result of the evaluation.
216
+ def load(filename)
217
+ File.open(filename) do |file|
218
+ self.eval file, filename
219
+ end
220
+ end
221
+
222
+ private
223
+
224
+ def self.current=(context)
225
+ Thread.current[:v8_context] = context
226
+ end
227
+
228
+ def lock_scope_and_enter
229
+ current = Context.current
230
+ Context.current = self
231
+ V8::C::Locker() do
232
+ V8::C::HandleScope() do
233
+ begin
234
+ @native.Enter()
235
+ yield if block_given?
236
+ ensure
237
+ @native.Exit()
238
+ end
239
+ end
240
+ end
241
+ ensure
242
+ Context.current = current
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,36 @@
1
+
2
+ class V8::Conversion
3
+ include Fundamental
4
+ include Identity
5
+
6
+ def to_ruby(v8_object)
7
+ super v8_object
8
+ end
9
+
10
+ def to_v8(ruby_object)
11
+ super ruby_object
12
+ end
13
+ end
14
+
15
+ for type in [TrueClass, FalseClass, NilClass, Float] do
16
+ type.class_eval do
17
+ include V8::Conversion::Primitive
18
+ end
19
+ end
20
+
21
+ for type in [Class, Object, Array, Hash, String, Symbol, Time, Proc, Method, Fixnum] do
22
+ type.class_eval do
23
+ include V8::Conversion.const_get(type.name)
24
+ end
25
+ end
26
+
27
+ class UnboundMethod
28
+ include V8::Conversion::Method
29
+ end
30
+
31
+ for type in [:Object, :String, :Date] do
32
+ V8::C::const_get(type).class_eval do
33
+ include V8::Conversion::const_get("Native#{type}")
34
+ end
35
+ end
36
+
@@ -0,0 +1,11 @@
1
+ class V8::Conversion
2
+ module Array
3
+ def to_v8
4
+ array = V8::Array.new(length)
5
+ each_with_index do |item, i|
6
+ array[i] = item
7
+ end
8
+ return array.to_v8
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,119 @@
1
+ class V8::Conversion
2
+ module Class
3
+ include V8::Conversion::Code
4
+
5
+ def to_template
6
+ weakcell(:constructor) do
7
+ template = V8::C::FunctionTemplate::New(V8::Conversion::Constructor.new(self))
8
+ prototype = template.InstanceTemplate()
9
+ prototype.SetNamedPropertyHandler(V8::Conversion::Get, V8::Conversion::Set)
10
+ prototype.SetIndexedPropertyHandler(V8::Conversion::IGet, V8::Conversion::ISet)
11
+ if self != ::Object && superclass != ::Object && superclass != ::Class
12
+ template.Inherit(superclass.to_template)
13
+ end
14
+ template
15
+ end
16
+ end
17
+ end
18
+
19
+ class Constructor
20
+ include V8::Error::Protect
21
+
22
+ def initialize(cls)
23
+ @class = cls
24
+ end
25
+
26
+ def call(arguments)
27
+ arguments.extend Args
28
+ protect do
29
+ if arguments.linkage_call?
30
+ arguments.link
31
+ else
32
+ arguments.construct @class
33
+ end
34
+ end
35
+ return arguments.This()
36
+ end
37
+
38
+ module Args
39
+ def linkage_call?
40
+ self.Length() == 1 && self[0].IsExternal()
41
+ end
42
+
43
+ def link
44
+ external = self[0]
45
+ This().SetHiddenValue("rr::implementation", external)
46
+ context.link external.Value(), This()
47
+ end
48
+
49
+ def construct(cls)
50
+ context.link cls.new(*to_args), This()
51
+ end
52
+
53
+ def context
54
+ V8::Context.current
55
+ end
56
+
57
+ def to_args
58
+ args = ::Array.new(Length())
59
+ 0.upto(args.length - 1) do |i|
60
+ args[i] = self[i]
61
+ end
62
+ return args
63
+ end
64
+ end
65
+ end
66
+
67
+ module Accessor
68
+ include V8::Error::Protect
69
+ def intercept(info, key, &block)
70
+ context = V8::Context.current
71
+ access = context.access
72
+ object = context.to_ruby(info.This())
73
+ handles_property = true
74
+ dontintercept = proc do
75
+ handles_property = false
76
+ end
77
+ protect do
78
+ result = block.call(context, access, object, context.to_ruby(key), dontintercept)
79
+ handles_property ? context.to_v8(result) : V8::C::Value::Empty
80
+ end
81
+ end
82
+ end
83
+
84
+ class Get
85
+ extend Accessor
86
+ def self.call(property, info)
87
+ intercept(info, property) do |context, access, object, key, dontintercept|
88
+ access.get(object, key, &dontintercept)
89
+ end
90
+ end
91
+ end
92
+
93
+ class Set
94
+ extend Accessor
95
+ def self.call(property, value, info)
96
+ intercept(info, property) do |context, access, object, key, dontintercept|
97
+ access.set(object, key, context.to_ruby(value), &dontintercept)
98
+ end
99
+ end
100
+ end
101
+
102
+ class IGet
103
+ extend Accessor
104
+ def self.call(property, info)
105
+ intercept(info, property) do |context, access, object, key, dontintercept|
106
+ access.iget(object, key, &dontintercept)
107
+ end
108
+ end
109
+ end
110
+
111
+ class ISet
112
+ extend Accessor
113
+ def self.call(property, value, info)
114
+ intercept(info, property) do |context, access, object, key, dontintercept|
115
+ access.iset(object, key, context.to_ruby(value), &dontintercept)
116
+ end
117
+ end
118
+ end
119
+ end