therubyracer-tmpfork 0.12.2

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 (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.travis.yml +14 -0
  4. data/Changelog.md +263 -0
  5. data/Gemfile +15 -0
  6. data/README.md +224 -0
  7. data/Rakefile +42 -0
  8. data/benchmarks.rb +218 -0
  9. data/ext/v8/accessor.cc +181 -0
  10. data/ext/v8/array.cc +26 -0
  11. data/ext/v8/backref.cc +45 -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 +34 -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 +35 -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 +335 -0
  28. data/ext/v8/primitive.cc +8 -0
  29. data/ext/v8/rr.cc +83 -0
  30. data/ext/v8/rr.h +934 -0
  31. data/ext/v8/script.cc +115 -0
  32. data/ext/v8/signature.cc +18 -0
  33. data/ext/v8/stack.cc +76 -0
  34. data/ext/v8/string.cc +47 -0
  35. data/ext/v8/template.cc +175 -0
  36. data/ext/v8/trycatch.cc +87 -0
  37. data/ext/v8/v8.cc +87 -0
  38. data/ext/v8/value.cc +239 -0
  39. data/lib/therubyracer.rb +1 -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 +258 -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 +169 -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 +82 -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 +64 -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 +167 -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-tmpfork.gemspec +22 -0
  92. metadata +186 -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
@@ -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
@@ -0,0 +1,258 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'stringio'
3
+ module V8
4
+ # All JavaScript must be executed in a context. This context consists of a global scope containing the
5
+ # standard JavaScript objects¨and functions like Object, String, Array, as well as any objects or
6
+ # functions from Ruby which have been embedded into it from the containing enviroment. E.g.
7
+ #
8
+ # V8::Context.new do |cxt|
9
+ # cxt['num'] = 5
10
+ # cxt.eval('num + 5') #=> 10
11
+ # end
12
+ #
13
+ # The same object may appear in any number of contexts, but only one context may be executing JavaScript code
14
+ # in any given thread. If a new context is opened in a thread in which a context is already opened, the second
15
+ # context will "mask" the old context e.g.
16
+ #
17
+ # six = 6
18
+ # Context.new do |cxt|
19
+ # cxt['num'] = 5
20
+ # cxt.eval('num') # => 5
21
+ # Context.new do |cxt|
22
+ # cxt['num'] = 10
23
+ # cxt.eval('num') # => 10
24
+ # cxt.eval('++num') # => 11
25
+ # end
26
+ # cxt.eval('num') # => 5
27
+ # end
28
+ class Context
29
+ include V8::Error::Try
30
+
31
+ # @!attribute [r] conversion
32
+ # @return [V8::Conversion] conversion behavior for this context
33
+ attr_reader :conversion
34
+
35
+ # @!attrribute [r] access
36
+ # @return [V8::Access] Ruby access behavior for this context
37
+ attr_reader :access
38
+
39
+ # @!attribute [r] native
40
+ # @return [V8::C::Context] the underlying C++ object
41
+ attr_reader :native
42
+
43
+ # @!attribute [r] timeout
44
+ # @return [Number] maximum execution time in milliseconds for scripts executed in this context
45
+ attr_reader :timeout
46
+
47
+ # Creates a new context.
48
+ #
49
+ # If passed the `:with` option, that object will be used as
50
+ # the global scope of the newly creating context. e.g.
51
+ #
52
+ # scope = Object.new
53
+ # def scope.hello; "Hi"; end
54
+ # V8::Context.new(:with => scope) do |cxt|
55
+ # cxt['hello'] #=> 'Hi'
56
+ # end
57
+ #
58
+ # If passed the `:timeout` option, every eval will timeout once
59
+ # N milliseconds elapse
60
+ #
61
+ # @param [Hash<Symbol, Object>] options initial context configuration
62
+ # * :with scope serves as the global scope of the new context
63
+ # @yield [V8::Context] the newly created context
64
+ def initialize(options = {})
65
+ @conversion = Conversion.new
66
+ @access = Access.new
67
+ @timeout = options[:timeout]
68
+ if global = options[:with]
69
+ Context.new.enter do
70
+ global_template = global.class.to_template.InstanceTemplate()
71
+ @native = V8::C::Context::New(nil, global_template)
72
+ end
73
+ enter {link global, @native.Global()}
74
+ else
75
+ V8::C::Locker() do
76
+ @native = V8::C::Context::New()
77
+ end
78
+ end
79
+ yield self if block_given?
80
+ end
81
+
82
+ # Compile and execute a string of JavaScript source.
83
+ #
84
+ # If `source` is an IO object it will be read fully before being evaluated
85
+ #
86
+ # @param [String,IO] source the source code to compile and execute
87
+ # @param [String] filename the name to use for this code when generating stack traces
88
+ # @param [Integer] line the line number to start with
89
+ # @return [Object] the result of the evaluation
90
+ def eval(source, filename = '<eval>', line = 1)
91
+ if IO === source || StringIO === source
92
+ source = source.read
93
+ end
94
+ enter do
95
+ script = try { V8::C::Script::New(source.to_s, filename.to_s) }
96
+ if @timeout
97
+ to_ruby try {script.RunWithTimeout(@timeout)}
98
+ else
99
+ to_ruby try {script.Run()}
100
+ end
101
+ end
102
+ end
103
+
104
+ # Read a value from the global scope of this context
105
+ #
106
+ # @param [Object] key the name of the value to read
107
+ # @return [Object] value the value at `key`
108
+ def [](key)
109
+ enter do
110
+ to_ruby(@native.Global().Get(to_v8(key)))
111
+ end
112
+ end
113
+
114
+ # Binds `value` to the name `key` in the global scope of this context.
115
+ #
116
+ # @param [Object] key the name to bind to
117
+ # @param [Object] value the value to bind
118
+ def []=(key, value)
119
+ enter do
120
+ @native.Global().Set(to_v8(key), to_v8(value))
121
+ end
122
+ return value
123
+ end
124
+
125
+ # Destroy this context and release any internal references it may
126
+ # contain to embedded Ruby objects.
127
+ #
128
+ # A disposed context may never again be used for anything, and all
129
+ # objects created with it will become unusable.
130
+ def dispose
131
+ return unless @native
132
+ @native.Dispose()
133
+ @native = nil
134
+ V8::C::V8::ContextDisposedNotification()
135
+ def self.enter
136
+ fail "cannot enter a context which has already been disposed"
137
+ end
138
+ end
139
+
140
+ # Returns this context's global object. This will be a `V8::Object`
141
+ # if no scope was provided or just an `Object` if a Ruby object
142
+ # is serving as the global scope.
143
+ #
144
+ # @return [Object] scope the context's global scope.
145
+ def scope
146
+ enter { to_ruby @native.Global() }
147
+ end
148
+
149
+ # Converts a v8 C++ object into its ruby counterpart. This is method
150
+ # is used to translate all values passed to Ruby from JavaScript, either
151
+ # as return values or as callback parameters.
152
+ #
153
+ # @param [V8::C::Object] v8_object the native c++ object to convert.
154
+ # @return [Object] to pass to Ruby
155
+ # @see V8::Conversion for how to customize and extend this mechanism
156
+ def to_ruby(v8_object)
157
+ @conversion.to_ruby(v8_object)
158
+ end
159
+
160
+ # Converts a Ruby object into a native v8 C++ object. This method is
161
+ # used to translate all values passed to JavaScript from Ruby, either
162
+ # as return value or as callback parameters.
163
+ #
164
+ # @param [Object] ruby_object the Ruby object to convert
165
+ # @return [V8::C::Object] to pass to V8
166
+ # @see V8::Conversion for customizing and extending this mechanism
167
+ def to_v8(ruby_object)
168
+ @conversion.to_v8(ruby_object)
169
+ end
170
+
171
+ # Marks a Ruby object and a v8 C++ Object as being the same. In other
172
+ # words whenever `ruby_object` is passed to v8, the result of the
173
+ # conversion should be `v8_object`. Conversely, whenever `v8_object`
174
+ # is passed to Ruby, the result of the conversion should be `ruby_object`.
175
+ # The Ruby Racer uses this mechanism to maintain referential integrity
176
+ # between Ruby and JavaScript peers
177
+ #
178
+ # @param [Object] ruby_object the Ruby half of the object identity
179
+ # @param [V8::C::Object] v8_object the V8 half of the object identity.
180
+ # @see V8::Conversion::Identity
181
+ def link(ruby_object, v8_object)
182
+ @conversion.equate ruby_object, v8_object
183
+ end
184
+
185
+ # Links `ruby_object` and `v8_object` inside the currently entered
186
+ # context. This is an error if no context has been entered.
187
+ #
188
+ # @param [Object] ruby_object the Ruby half of the object identity
189
+ # @param [V8::C::Object] v8_object the V8 half of the object identity.
190
+ def self.link(ruby_object, v8_object)
191
+ current.link ruby_object, v8_object
192
+ end
193
+
194
+ # Run some Ruby code in the context of this context.
195
+ #
196
+ # This will acquire the V8 interpreter lock (possibly blocking
197
+ # until it is available), and prepare V8 for JavaScript execution.
198
+ #
199
+ # Only one context may be running at a time per thread.
200
+ #
201
+ # @return [Object] the result of executing `block`
202
+ def enter(&block)
203
+ if !entered?
204
+ lock_scope_and_enter(&block)
205
+ else
206
+ yield
207
+ end
208
+ end
209
+
210
+ # Indicates if this context is the currently entered context
211
+ #
212
+ # @return true if this context is currently entered
213
+ def entered?
214
+ Context.current == self
215
+ end
216
+
217
+ # Get the currently entered context.
218
+ #
219
+ # @return [V8::Context] currently entered context, nil if none entered.
220
+ def self.current
221
+ Thread.current[:v8_context]
222
+ end
223
+
224
+ # Compile and execute the contents of the file with path `filename`
225
+ # as JavaScript code.
226
+ #
227
+ # @param [String] filename path to the file to execute.
228
+ # @return [Object] the result of the evaluation.
229
+ def load(filename)
230
+ File.open(filename) do |file|
231
+ self.eval file, filename
232
+ end
233
+ end
234
+
235
+ private
236
+
237
+ def self.current=(context)
238
+ Thread.current[:v8_context] = context
239
+ end
240
+
241
+ def lock_scope_and_enter
242
+ current = Context.current
243
+ Context.current = self
244
+ V8::C::Locker() do
245
+ V8::C::HandleScope() do
246
+ begin
247
+ @native.Enter()
248
+ yield if block_given?
249
+ ensure
250
+ @native.Exit()
251
+ end
252
+ end
253
+ end
254
+ ensure
255
+ Context.current = current
256
+ end
257
+ end
258
+ 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