therubyracer-tmpfork 0.12.2

Sign up to get free protection for your applications and to get access to all the features.
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