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.
- data/.gitignore +23 -0
- data/.travis.yml +10 -0
- data/Changelog.md +242 -0
- data/Gemfile +16 -0
- data/README.md +185 -0
- data/Rakefile +42 -0
- data/benchmarks.rb +218 -0
- data/ext/v8/accessor.cc +181 -0
- data/ext/v8/array.cc +26 -0
- data/ext/v8/backref.cc +45 -0
- data/ext/v8/build.rb +52 -0
- data/ext/v8/constants.cc +34 -0
- data/ext/v8/constraints.cc +52 -0
- data/ext/v8/context.cc +130 -0
- data/ext/v8/date.cc +18 -0
- data/ext/v8/exception.cc +38 -0
- data/ext/v8/extconf.rb +25 -0
- data/ext/v8/external.cc +43 -0
- data/ext/v8/function.cc +58 -0
- data/ext/v8/gc.cc +43 -0
- data/ext/v8/handles.cc +34 -0
- data/ext/v8/heap.cc +31 -0
- data/ext/v8/init.cc +39 -0
- data/ext/v8/init.so +0 -0
- data/ext/v8/invocation.cc +86 -0
- data/ext/v8/locker.cc +77 -0
- data/ext/v8/message.cc +51 -0
- data/ext/v8/object.cc +334 -0
- data/ext/v8/primitive.cc +8 -0
- data/ext/v8/rr.cc +83 -0
- data/ext/v8/rr.h +932 -0
- data/ext/v8/script.cc +80 -0
- data/ext/v8/signature.cc +18 -0
- data/ext/v8/stack.cc +76 -0
- data/ext/v8/string.cc +47 -0
- data/ext/v8/template.cc +175 -0
- data/ext/v8/trycatch.cc +87 -0
- data/ext/v8/v8.cc +87 -0
- data/ext/v8/value.cc +239 -0
- data/lib/v8.rb +30 -0
- data/lib/v8/access.rb +5 -0
- data/lib/v8/access/indices.rb +40 -0
- data/lib/v8/access/invocation.rb +47 -0
- data/lib/v8/access/names.rb +65 -0
- data/lib/v8/array.rb +26 -0
- data/lib/v8/context.rb +245 -0
- data/lib/v8/conversion.rb +36 -0
- data/lib/v8/conversion/array.rb +11 -0
- data/lib/v8/conversion/class.rb +119 -0
- data/lib/v8/conversion/code.rb +38 -0
- data/lib/v8/conversion/fixnum.rb +11 -0
- data/lib/v8/conversion/fundamental.rb +11 -0
- data/lib/v8/conversion/hash.rb +11 -0
- data/lib/v8/conversion/indentity.rb +31 -0
- data/lib/v8/conversion/method.rb +26 -0
- data/lib/v8/conversion/object.rb +28 -0
- data/lib/v8/conversion/primitive.rb +7 -0
- data/lib/v8/conversion/proc.rb +5 -0
- data/lib/v8/conversion/reference.rb +16 -0
- data/lib/v8/conversion/string.rb +12 -0
- data/lib/v8/conversion/symbol.rb +7 -0
- data/lib/v8/conversion/time.rb +13 -0
- data/lib/v8/error.rb +166 -0
- data/lib/v8/function.rb +28 -0
- data/lib/v8/object.rb +79 -0
- data/lib/v8/stack.rb +85 -0
- data/lib/v8/version.rb +3 -0
- data/lib/v8/weak.rb +70 -0
- data/spec/c/array_spec.rb +17 -0
- data/spec/c/constants_spec.rb +20 -0
- data/spec/c/exception_spec.rb +26 -0
- data/spec/c/external_spec.rb +9 -0
- data/spec/c/function_spec.rb +46 -0
- data/spec/c/handles_spec.rb +35 -0
- data/spec/c/locker_spec.rb +38 -0
- data/spec/c/object_spec.rb +46 -0
- data/spec/c/script_spec.rb +28 -0
- data/spec/c/string_spec.rb +16 -0
- data/spec/c/template_spec.rb +30 -0
- data/spec/c/trycatch_spec.rb +51 -0
- data/spec/mem/blunt_spec.rb +42 -0
- data/spec/redjs_spec.rb +10 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/threading_spec.rb +52 -0
- data/spec/v8/context_spec.rb +19 -0
- data/spec/v8/conversion_spec.rb +52 -0
- data/spec/v8/error_spec.rb +165 -0
- data/spec/v8/function_spec.rb +9 -0
- data/spec/v8/object_spec.rb +15 -0
- data/thefrontside.png +0 -0
- data/therubyracer.gemspec +20 -0
- metadata +164 -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,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,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
|
data/lib/v8/error.rb
ADDED
@@ -0,0 +1,166 @@
|
|
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
|
+
value = exception.to_ruby
|
143
|
+
cause = nil
|
144
|
+
javascript_backtrace = V8::StackTrace.new(trycatch.Message().GetStackTrace())
|
145
|
+
message = if !exception.kind_of?(V8::C::Value)
|
146
|
+
exception.to_s
|
147
|
+
elsif exception.IsNativeError()
|
148
|
+
if cause = exception.GetHiddenValue("rr::Cause")
|
149
|
+
cause = cause.Value()
|
150
|
+
end
|
151
|
+
if value['constructor'] == V8::Context.current['SyntaxError']
|
152
|
+
info = trycatch.Message()
|
153
|
+
resource_name = info.GetScriptResourceName().to_ruby
|
154
|
+
"#{value['message']} at #{resource_name}:#{info.GetLineNumber()}:#{info.GetStartColumn() + 1}"
|
155
|
+
else
|
156
|
+
exception.Get("message").to_ruby
|
157
|
+
end
|
158
|
+
elsif exception.IsObject()
|
159
|
+
value['message'] || value.to_s
|
160
|
+
else
|
161
|
+
value.to_s
|
162
|
+
end
|
163
|
+
V8::Error.new(message, value, javascript_backtrace, cause)
|
164
|
+
end
|
165
|
+
const_set :JSError, Error
|
166
|
+
end
|
data/lib/v8/function.rb
ADDED
@@ -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
|
data/lib/v8/object.rb
ADDED
@@ -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
|