therubyracer-discourse 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.travis.yml +11 -0
  4. data/Changelog.md +247 -0
  5. data/Gemfile +9 -0
  6. data/README.md +176 -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/v8.rb +30 -0
  40. data/lib/v8/access.rb +5 -0
  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 +26 -0
  45. data/lib/v8/context.rb +256 -0
  46. data/lib/v8/conversion.rb +36 -0
  47. data/lib/v8/conversion/array.rb +11 -0
  48. data/lib/v8/conversion/class.rb +119 -0
  49. data/lib/v8/conversion/code.rb +38 -0
  50. data/lib/v8/conversion/fixnum.rb +11 -0
  51. data/lib/v8/conversion/fundamental.rb +11 -0
  52. data/lib/v8/conversion/hash.rb +11 -0
  53. data/lib/v8/conversion/indentity.rb +31 -0
  54. data/lib/v8/conversion/method.rb +26 -0
  55. data/lib/v8/conversion/object.rb +28 -0
  56. data/lib/v8/conversion/primitive.rb +7 -0
  57. data/lib/v8/conversion/proc.rb +5 -0
  58. data/lib/v8/conversion/reference.rb +16 -0
  59. data/lib/v8/conversion/string.rb +12 -0
  60. data/lib/v8/conversion/symbol.rb +7 -0
  61. data/lib/v8/conversion/time.rb +13 -0
  62. data/lib/v8/error.rb +169 -0
  63. data/lib/v8/function.rb +28 -0
  64. data/lib/v8/object.rb +79 -0
  65. data/lib/v8/stack.rb +85 -0
  66. data/lib/v8/version.rb +3 -0
  67. data/lib/v8/weak.rb +73 -0
  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 +45 -0
  83. data/spec/threading_spec.rb +64 -0
  84. data/spec/v8/context_spec.rb +19 -0
  85. data/spec/v8/conversion_spec.rb +52 -0
  86. data/spec/v8/error_spec.rb +165 -0
  87. data/spec/v8/function_spec.rb +9 -0
  88. data/spec/v8/object_spec.rb +15 -0
  89. data/thefrontside.png +0 -0
  90. data/therubyracer.gemspec +21 -0
  91. metadata +163 -0
@@ -0,0 +1,38 @@
1
+ class V8::Conversion
2
+ module Code
3
+ include V8::Weak::Cell
4
+
5
+ def to_v8
6
+ fn = to_template.GetFunction()
7
+ V8::Context.link self, fn
8
+ return fn
9
+ end
10
+
11
+ def to_template
12
+ weakcell(:template) {V8::C::FunctionTemplate::New(InvocationHandler.new(self))}
13
+ end
14
+
15
+ class InvocationHandler
16
+ include V8::Error::Protect
17
+
18
+ def initialize(code)
19
+ @code = code
20
+ end
21
+
22
+ def call(arguments)
23
+ protect do
24
+ context = V8::Context.current
25
+ access = context.access
26
+ args = ::Array.new(arguments.Length())
27
+ 0.upto(args.length - 1) do |i|
28
+ if i < args.length
29
+ args[i] = context.to_ruby arguments[i]
30
+ end
31
+ end
32
+ this = context.to_ruby arguments.This()
33
+ context.to_v8 access.methodcall(@code, this, args)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,11 @@
1
+ class V8::Conversion
2
+ module Fixnum
3
+ def to_ruby
4
+ self
5
+ end
6
+
7
+ def to_v8
8
+ self.to_f.to_v8
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class V8::Conversion
2
+ module Fundamental
3
+ def to_ruby(v8_object)
4
+ v8_object.to_ruby
5
+ end
6
+
7
+ def to_v8(ruby_object)
8
+ ruby_object.to_v8
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class V8::Conversion
2
+ module Hash
3
+ def to_v8
4
+ object = V8::Object.new
5
+ each do |key, value|
6
+ object[key] = value
7
+ end
8
+ return object.to_v8
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ require 'ref'
2
+
3
+ class V8::Conversion
4
+ module Identity
5
+ def to_ruby(v8_object)
6
+ if v8_object.class <= V8::C::Object
7
+ v8_idmap[v8_object.GetIdentityHash()] || super(v8_object)
8
+ else
9
+ super(v8_object)
10
+ end
11
+ end
12
+
13
+ def to_v8(ruby_object)
14
+ return super(ruby_object) if ruby_object.is_a?(String) || ruby_object.is_a?(Primitive)
15
+ rb_idmap[ruby_object.object_id] || super(ruby_object)
16
+ end
17
+
18
+ def equate(ruby_object, v8_object)
19
+ v8_idmap[v8_object.GetIdentityHash()] = ruby_object
20
+ rb_idmap[ruby_object.object_id] = v8_object
21
+ end
22
+
23
+ def v8_idmap
24
+ @v8_idmap ||= V8::Weak::WeakValueMap.new
25
+ end
26
+
27
+ def rb_idmap
28
+ @ruby_idmap ||= V8::Weak::WeakValueMap.new
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ class V8::Conversion
2
+ module Method
3
+ include V8::Conversion::Code
4
+
5
+ def to_v8
6
+ template = @@method_cache[self] ||= to_template
7
+ template.GetFunction()
8
+ end
9
+
10
+ class MethodCache
11
+ def initialize
12
+ @map = V8::Weak::WeakValueMap.new
13
+ end
14
+
15
+ def [](method)
16
+ @map[method.to_s]
17
+ end
18
+
19
+ def []=(method, template)
20
+ @map[method.to_s] = template
21
+ end
22
+ end
23
+
24
+ @@method_cache = MethodCache.new
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ class V8::Conversion
2
+ module Object
3
+ def to_v8
4
+ Reference.construct! self
5
+ end
6
+
7
+ def to_ruby
8
+ self
9
+ end
10
+ end
11
+
12
+ module NativeObject
13
+ def to_ruby
14
+ wrap = if IsArray()
15
+ ::V8::Array
16
+ elsif IsFunction()
17
+ ::V8::Function
18
+ else
19
+ ::V8::Object
20
+ end
21
+ wrap.new(self)
22
+ end
23
+
24
+ def to_v8
25
+ self
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ class V8::Conversion
2
+ module Primitive
3
+ def to_v8
4
+ return self
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class V8::Conversion
2
+ module Proc
3
+ include V8::Conversion::Code
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ class V8::Conversion
2
+ module Reference
3
+
4
+ def self.construct!(object)
5
+ context = V8::Context.current
6
+ constructor = context.to_v8(object.class)
7
+ reference = constructor.NewInstance([V8::C::External::New(object)])
8
+ return reference
9
+ end
10
+
11
+ def to_v8
12
+ Reference.construct! self
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ class V8::Conversion
2
+ module String
3
+ def to_v8
4
+ V8::C::String::New(self)
5
+ end
6
+ end
7
+ module NativeString
8
+ def to_ruby
9
+ self.Utf8Value()
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ class V8::Conversion
2
+ module Symbol
3
+ def to_v8
4
+ V8::C::String::NewSymbol(to_s)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ class V8::Conversion
2
+ module Time
3
+ def to_v8
4
+ V8::C::Date::New(to_f * 1000)
5
+ end
6
+ end
7
+
8
+ module NativeDate
9
+ def to_ruby
10
+ ::Time.at(self.NumberValue() / 1000)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,169 @@
1
+ module V8
2
+ # capture 99 stack frames on exception with normal details.
3
+ # You can adjust these values for performance or turn of stack capture entirely
4
+ V8::C::V8::SetCaptureStackTraceForUncaughtExceptions(true, 99, V8::C::StackTrace::kOverview)
5
+ class Error < StandardError
6
+ include Enumerable
7
+
8
+ # @!attribute [r] value
9
+ # @return [Object] the JavaScript value passed to the `throw` statement
10
+ attr_reader :value
11
+
12
+ # @!attribute [r] cause
13
+ # @return [Exception] the underlying error (if any) that triggered this error to be raised
14
+ attr_reader :cause
15
+
16
+ # @!attribute [r] javascript_backtrace
17
+ # @return [V8::StackTrace] the complete JavaScript stack at the point this error was thrown
18
+ attr_reader :javascript_backtrace
19
+
20
+ # keep an alias to the StandardError#backtrace method so that we can capture
21
+ # just ruby backtrace frames
22
+ alias_method :standard_error_backtrace, :backtrace
23
+
24
+ def initialize(message, value, javascript_backtrace, cause = nil)
25
+ super(message)
26
+ @value = value
27
+ @cause = cause
28
+ @javascript_backtrace = javascript_backtrace
29
+ end
30
+
31
+ def causes
32
+ [].tap do |causes|
33
+ current = self
34
+ until current.nil? do
35
+ causes.push current
36
+ current = current.respond_to?(:cause) ? current.cause : nil
37
+ end
38
+ end
39
+ end
40
+
41
+ def backtrace(*modifiers)
42
+ return unless super()
43
+ trace_framework = modifiers.include?(:framework)
44
+ trace_ruby = modifiers.length == 0 || modifiers.include?(:ruby)
45
+ trace_javascript = modifiers.length == 0 || modifiers.include?(:javascript)
46
+ bilingual_backtrace(trace_ruby, trace_javascript).tap do |trace|
47
+ trace.reject! {|frame| frame =~ %r{(lib/v8/.*\.rb|ext/v8/.*\.cc)}} unless modifiers.include?(:framework)
48
+ end
49
+ end
50
+
51
+ def root_cause
52
+ causes.last
53
+ end
54
+
55
+ def in_javascript?
56
+ causes.last.is_a? self.class
57
+ end
58
+
59
+ def in_ruby?
60
+ !in_javascript?
61
+ end
62
+
63
+ def bilingual_backtrace(trace_ruby = true, trace_javascript = true)
64
+ backtrace = causes.reduce(:backtrace => [], :ruby => -1, :javascript => -1) { |accumulator, cause|
65
+ accumulator.tap do
66
+ if trace_ruby
67
+ backtrace_selector = cause.respond_to?(:standard_error_backtrace) ? :standard_error_backtrace : :backtrace
68
+ ruby_frames = cause.send(backtrace_selector)[0..accumulator[:ruby]]
69
+ accumulator[:backtrace].unshift *ruby_frames
70
+ accumulator[:ruby] -= ruby_frames.length
71
+ end
72
+ if trace_javascript && cause.respond_to?(:javascript_backtrace)
73
+ javascript_frames = cause.javascript_backtrace.to_a[0..accumulator[:javascript]].map(&:to_s)
74
+ accumulator[:backtrace].unshift *javascript_frames
75
+ accumulator[:javascript] -= javascript_frames.length
76
+ end
77
+ end
78
+ }[:backtrace]
79
+ end
80
+
81
+ module Try
82
+ def try
83
+ V8::C::TryCatch() do |trycatch|
84
+ result = yield
85
+ if trycatch.HasCaught()
86
+ raise V8::Error(trycatch)
87
+ else
88
+ result
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ module Protect
95
+ def protect
96
+ yield
97
+ rescue Exception => e
98
+ error = V8::C::Exception::Error(e.message)
99
+ error.SetHiddenValue("rr::Cause", V8::C::External::New(e))
100
+ V8::C::ThrowException(error)
101
+ end
102
+ end
103
+
104
+ end
105
+
106
+ # Convert the result of a triggered JavaScript try/catch block into
107
+ # a V8::Error
108
+ #
109
+ # This is a bit of a yak-shave because JavaScript let's you throw all
110
+ # kinds of things. We do our best to make sure that the message property
111
+ # of the resulting V8::Error is as helpful as possible, and that it
112
+ # contains as much source location information as we can put onto it.
113
+ #
114
+ # For example:
115
+ #
116
+ # throw 4
117
+ # throw 'four'
118
+ # throw {number: 4}
119
+ #
120
+ # are all valid cases, none of which actually reference an exception object
121
+ # with a stack trace and a message. only with something like:
122
+ #
123
+ # throw new Error('fail!')
124
+ #
125
+ # do you get the a proper stacktrace and a message property. However a lot of
126
+ # times JavaScript library authors are lazy and do this:
127
+ #
128
+ # throw {message: 'foo', otherMetadata: 'bar'}
129
+ #
130
+ # It's common enough so we do the courtesy of having the resulting V8::Error
131
+ # have as its message in ruby land the 'message' property of the value object
132
+ #
133
+ # To further complicate things, SyntaxErrors do not have a JavaScript stack
134
+ # (even if they occur during js execution). This can make debugging a nightmare
135
+ # so we copy in the source location of the syntax error into the message of
136
+ # the resulting V8::Error
137
+ #
138
+ # @param [V8::C::TryCatch] native trycatch object that has been triggered
139
+ # @return [V8::Error] the error generated by this try/catch
140
+ def self.Error(trycatch)
141
+ exception = trycatch.Exception()
142
+
143
+ value = exception.to_ruby
144
+ cause = nil
145
+ message = trycatch.Message()
146
+ javascript_backtrace = V8::StackTrace.new(message.GetStackTrace()) if message
147
+
148
+ message = if !exception.kind_of?(V8::C::Value)
149
+ exception.to_s==""?"Script Timed Out":exception.to_s
150
+ elsif exception.IsNativeError()
151
+ if cause = exception.GetHiddenValue("rr::Cause")
152
+ cause = cause.Value()
153
+ end
154
+ if value['constructor'] == V8::Context.current['SyntaxError']
155
+ info = trycatch.Message()
156
+ resource_name = info.GetScriptResourceName().to_ruby
157
+ "#{value['message']} at #{resource_name}:#{info.GetLineNumber()}:#{info.GetStartColumn() + 1}"
158
+ else
159
+ exception.Get("message").to_ruby
160
+ end
161
+ elsif exception.IsObject()
162
+ value['message'] || value.to_s
163
+ else
164
+ value.to_s
165
+ end
166
+ V8::Error.new(message, value, javascript_backtrace, cause)
167
+ end
168
+ const_set :JSError, Error
169
+ end
@@ -0,0 +1,28 @@
1
+ class V8::Function < V8::Object
2
+ include V8::Error::Try
3
+
4
+ def initialize(native = nil)
5
+ super do
6
+ native || V8::C::FunctionTemplate::New().GetFunction()
7
+ end
8
+ end
9
+
10
+ def methodcall(this, *args)
11
+ @context.enter do
12
+ this ||= @context.native.Global()
13
+ @context.to_ruby try {native.Call(@context.to_v8(this), args.map {|a| @context.to_v8 a})}
14
+ end
15
+ end
16
+
17
+ def call(*args)
18
+ @context.enter do
19
+ methodcall @context.native.Global(), *args
20
+ end
21
+ end
22
+
23
+ def new(*args)
24
+ @context.enter do
25
+ @context.to_ruby try {native.NewInstance(args.map {|a| @context.to_v8 a})}
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,79 @@
1
+ class V8::Object
2
+ include Enumerable
3
+ attr_reader :native
4
+ alias_method :to_v8, :native
5
+
6
+ def initialize(native = nil)
7
+ @context = V8::Context.current or fail "tried to initialize a #{self.class} without being in an entered V8::Context"
8
+ @native = block_given? ? yield : native || V8::C::Object::New()
9
+ @context.link self, @native
10
+ end
11
+
12
+ def [](key)
13
+ @context.enter do
14
+ @context.to_ruby @native.Get(@context.to_v8(key))
15
+ end
16
+ end
17
+
18
+ def []=(key, value)
19
+ @context.enter do
20
+ @native.Set(@context.to_v8(key), @context.to_v8(value))
21
+ end
22
+ return value
23
+ end
24
+
25
+ def keys
26
+ @context.enter do
27
+ names = @native.GetPropertyNames()
28
+ 0.upto( names.Length() - 1).to_enum.map {|i| @context.to_ruby names.Get(i)}
29
+ end
30
+ end
31
+
32
+ def values
33
+ @context.enter do
34
+ names = @native.GetPropertyNames()
35
+ 0.upto( names.Length() - 1).to_enum.map {|i| @context.to_ruby @native.Get(names.Get(i))}
36
+ end
37
+ end
38
+
39
+ def each
40
+ @context.enter do
41
+ names = @native.GetPropertyNames()
42
+ 0.upto(names.Length() - 1) do |i|
43
+ name = names.Get(i)
44
+ yield @context.to_ruby(name), @context.to_ruby(@native.Get(name))
45
+ end
46
+ end
47
+ end
48
+
49
+ def to_s
50
+ @context.enter do
51
+ @context.to_ruby @native.ToString()
52
+ end
53
+ end
54
+
55
+ def respond_to?(method)
56
+ super or self[method] != nil
57
+ end
58
+
59
+ def method_missing(name, *args, &block)
60
+ if name.to_s =~ /(.*)=$/
61
+ if args.length > 1
62
+ self[$1] = args
63
+ return args
64
+ else
65
+ self[$1] = args.first
66
+ return args
67
+ end
68
+ end
69
+ return super(name, *args, &block) unless self.respond_to?(name)
70
+ property = self[name]
71
+ if property.kind_of?(V8::Function)
72
+ property.methodcall(self, *args)
73
+ elsif args.empty?
74
+ property
75
+ else
76
+ raise ArgumentError, "wrong number of arguments (#{args.length} for 0)" unless args.empty?
77
+ end
78
+ end
79
+ end