sq_mini_racer 0.2.4.0.2 → 0.2.5.0.1.beta1
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.
- checksums.yaml +4 -4
- data/CHANGELOG +15 -0
- data/README.md +25 -0
- data/Rakefile +41 -0
- data/ext/mini_racer_extension/extconf.rb +50 -75
- data/ext/mini_racer_extension/mini_racer_extension.cc +270 -94
- data/lib/sqreen/mini_racer.rb +22 -0
- data/lib/sqreen/mini_racer/version.rb +1 -1
- data/mini_racer.gemspec +2 -1
- metadata +23 -12
- data/.dockerignore +0 -12
- data/Dockerfile +0 -22
- data/azure-pipelines.yml +0 -69
- data/azure-template.yml +0 -92
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4deece72e6d02478b4381a59ab9b1988a2fbff6a30e811596183240699fd018
|
4
|
+
data.tar.gz: ac83f077c9b56423cd8b8e716d8102bec73050c8a4ae0e525fda931f43ec6762
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cad6011c1066ccc51e1c3bfe3064c50e7dbdc6dd04127ce24f855a97f9ba8fd492a5de3b1af54b810b4a112d74f03bcd746c8d95af822a5f9d59e8cd9cdce8a2
|
7
|
+
data.tar.gz: f985a398202455acfadd914606306d5469928bfbf69394fd39b5a79b097f81a6994bf4875bb7765d01b4fd2797b00378a5e3d23de4a05b4d3588216e3ac59cc9
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
- 14-05-2019
|
2
|
+
|
3
|
+
- 0.2.6
|
4
|
+
|
5
|
+
- FEATURE: add support for write_heap_snapshot which helps you analyze memory
|
6
|
+
|
7
|
+
- 25-04-2019
|
8
|
+
|
9
|
+
- 0.2.5
|
10
|
+
|
11
|
+
- FIX: Compatiblity fixes for V8 7 and above @ignisf
|
12
|
+
- FIX: Memory leak in gc_callback @messense
|
13
|
+
- IMPROVEMENT: Added example of sourcemap support @ianks
|
14
|
+
- URGENT: you will need this release for latest version of libv8 to work
|
15
|
+
|
1
16
|
- 02-11-2018
|
2
17
|
|
3
18
|
- 0.2.4
|
data/README.md
CHANGED
@@ -101,6 +101,27 @@ context.eval('bar()', filename: 'a/bar.js')
|
|
101
101
|
|
102
102
|
```
|
103
103
|
|
104
|
+
### Fork safety
|
105
|
+
|
106
|
+
Some Ruby web servers employ forking (for example unicorn or puma in clustered mode). V8 is not fork safe.
|
107
|
+
Sadly Ruby does not have support for fork notifications per [#5446](https://bugs.ruby-lang.org/issues/5446).
|
108
|
+
|
109
|
+
If you want to ensure your application does not leak memory after fork either:
|
110
|
+
|
111
|
+
1. Ensure no MiniRacer::Context objects are created in the master process
|
112
|
+
|
113
|
+
Or
|
114
|
+
|
115
|
+
2. Dispose manually of all MiniRacer::Context objects prior to forking
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
# before fork
|
119
|
+
|
120
|
+
require 'objspace'
|
121
|
+
ObjectSpace.each_object(MiniRacer::Context){|c| c.dispose}
|
122
|
+
|
123
|
+
# fork here
|
124
|
+
```
|
104
125
|
|
105
126
|
### Threadsafe
|
106
127
|
|
@@ -350,6 +371,10 @@ Note how the global interpreter lock release leads to 2 threads doing the same w
|
|
350
371
|
|
351
372
|
As a rule MiniRacer strives to always support and depend on the latest stable version of libv8.
|
352
373
|
|
374
|
+
## Source Maps
|
375
|
+
|
376
|
+
MiniRacer can fully support source maps but must be configured correctly to do so. [Check out this example](./examples/source-map-support/) for a working implementation.
|
377
|
+
|
353
378
|
## Installation
|
354
379
|
|
355
380
|
Add this line to your application's Gemfile:
|
data/Rakefile
CHANGED
@@ -19,6 +19,22 @@ Rake::ExtensionTask.new('prv_ext_loader', gem)
|
|
19
19
|
|
20
20
|
# via http://blog.flavorjon.es/2009/06/easily-valgrind-gdb-your-ruby-c.html
|
21
21
|
namespace :test do
|
22
|
+
desc "run test suite with Address Sanitizer"
|
23
|
+
task :asan do
|
24
|
+
ENV["CONFIGURE_ARGS"] = [ENV["CONFIGURE_ARGS"], '--enable-asan'].compact.join(' ')
|
25
|
+
Rake::Task['compile'].invoke
|
26
|
+
|
27
|
+
asan_path = `ldconfig -N -p |grep libasan | grep -v 32 | sed 's/.* => \\(.*\\)$/\\1/'`.chomp.split("\n")[-1]
|
28
|
+
|
29
|
+
|
30
|
+
cmdline = "env LD_PRELOAD=\"#{asan_path}\" ruby test/test_leak.rb"
|
31
|
+
puts cmdline
|
32
|
+
system cmdline
|
33
|
+
|
34
|
+
cmdline = "env LD_PRELOAD=\"#{asan_path}\" rake test"
|
35
|
+
puts cmdline
|
36
|
+
system cmdline
|
37
|
+
end
|
22
38
|
# partial-loads-ok and undef-value-errors necessary to ignore
|
23
39
|
# spurious (and eminently ignorable) warnings from the ruby
|
24
40
|
# interpreter
|
@@ -55,3 +71,28 @@ namespace :test do
|
|
55
71
|
end
|
56
72
|
end
|
57
73
|
end
|
74
|
+
|
75
|
+
desc 'run clang-tidy linter on mini_racer_extension.cc'
|
76
|
+
task :lint do
|
77
|
+
require 'mkmf'
|
78
|
+
require 'libv8'
|
79
|
+
|
80
|
+
Libv8.configure_makefile
|
81
|
+
|
82
|
+
conf = RbConfig::CONFIG.merge('hdrdir' => $hdrdir.quote, 'srcdir' => $srcdir.quote,
|
83
|
+
'arch_hdrdir' => $arch_hdrdir.quote,
|
84
|
+
'top_srcdir' => $top_srcdir.quote)
|
85
|
+
if $universal and (arch_flag = conf['ARCH_FLAG']) and !arch_flag.empty?
|
86
|
+
conf['ARCH_FLAG'] = arch_flag.gsub(/(?:\G|\s)-arch\s+\S+/, '')
|
87
|
+
end
|
88
|
+
|
89
|
+
checks = %W(bugprone-*
|
90
|
+
cert-*
|
91
|
+
cppcoreguidelines-*
|
92
|
+
clang-analyzer-*
|
93
|
+
performance-*
|
94
|
+
portability-*
|
95
|
+
readability-*).join(',')
|
96
|
+
|
97
|
+
sh RbConfig::expand("clang-tidy -checks='#{checks}' ext/mini_racer_extension/mini_racer_extension.cc -- #$INCFLAGS #$CPPFLAGS", conf)
|
98
|
+
end
|
@@ -26,58 +26,46 @@ def cppflags_add_cpu_extension!
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def libv8_gem_name
|
29
|
-
|
30
|
-
|
29
|
+
return "libv8-solaris" if IS_SOLARIS
|
30
|
+
return "libv8-alpine" if IS_LINUX_MUSL
|
31
31
|
|
32
|
-
'libv8
|
32
|
+
'libv8'
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
36
|
-
'
|
35
|
+
def libv8_version
|
36
|
+
'7.3.492.27.1'
|
37
37
|
end
|
38
38
|
|
39
|
-
def libv8_basename
|
40
|
-
"#{libv8_gem_name}-#{
|
39
|
+
def libv8_basename
|
40
|
+
"#{libv8_gem_name}-#{libv8_version}-#{ruby_platform}"
|
41
41
|
end
|
42
42
|
|
43
|
-
def libv8_gemspec
|
44
|
-
"#{libv8_basename
|
43
|
+
def libv8_gemspec
|
44
|
+
"#{libv8_basename}.gemspec"
|
45
45
|
end
|
46
46
|
|
47
|
-
def libv8_local_path
|
48
|
-
|
47
|
+
def libv8_local_path
|
48
|
+
puts "looking for #{libv8_gemspec} in installed gems"
|
49
|
+
candidates = Gem.path.map { |p| File.join(p, 'specifications', libv8_gemspec) }
|
50
|
+
found = candidates.select { |f| File.exist?(f) }.first
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
paths = path.map { |p| Dir.glob(File.join(p, 'specifications', name_glob + '.gemspec')) }.flatten
|
53
|
-
|
54
|
-
if paths.empty?
|
55
|
-
puts "#{name_glob} not found in #{path.inspect}"
|
56
|
-
return
|
57
|
-
end
|
58
|
-
|
59
|
-
specs = paths.map { |p| [p, eval(File.read(p))] }
|
60
|
-
.select { |_, spec| Gem::Requirement.new(libv8_requirement).satisfied_by?(spec.version) }
|
61
|
-
found_path, found_spec = specs.sort_by { |_, spec| spec.version }.last
|
62
|
-
|
63
|
-
unless found_path && found_spec
|
64
|
-
puts "not found in specs: no '#{libv8_requirement}' in #{paths.inspect}"
|
52
|
+
unless found
|
53
|
+
puts "#{libv8_gemspec} not found in installed gems"
|
65
54
|
return
|
66
55
|
end
|
67
56
|
|
68
|
-
puts "found in specs: #{
|
57
|
+
puts "found in installed specs: #{found}"
|
69
58
|
|
70
|
-
|
71
|
-
dir = File.expand_path(File.join(found_path, '..', '..', 'gems', gemdir))
|
59
|
+
dir = File.expand_path(File.join(found, '..', '..', 'gems', libv8_basename))
|
72
60
|
|
73
61
|
unless Dir.exist?(dir)
|
74
|
-
puts "not found in gems: #{dir}"
|
62
|
+
puts "not found in installed gems: #{dir}"
|
75
63
|
return
|
76
64
|
end
|
77
65
|
|
78
|
-
puts "found in gems: #{dir}"
|
66
|
+
puts "found in installed gems: #{dir}"
|
79
67
|
|
80
|
-
|
68
|
+
dir
|
81
69
|
end
|
82
70
|
|
83
71
|
def vendor_path
|
@@ -85,14 +73,25 @@ def vendor_path
|
|
85
73
|
end
|
86
74
|
|
87
75
|
def libv8_vendor_path
|
88
|
-
|
76
|
+
puts "looking for #{libv8_basename} in #{vendor_path}"
|
77
|
+
path = Dir.glob("#{vendor_path}/#{libv8_basename}").first
|
78
|
+
|
79
|
+
unless path
|
80
|
+
puts "#{libv8_basename} not found in #{vendor_path}"
|
81
|
+
return
|
82
|
+
end
|
83
|
+
|
84
|
+
puts "looking for #{libv8_basename}/lib/libv8.rb in #{vendor_path}"
|
85
|
+
unless Dir.glob(File.join(vendor_path, libv8_basename, 'lib', 'libv8.rb')).first
|
86
|
+
puts "#{libv8_basename}/lib/libv8.rb not found in #{vendor_path}"
|
87
|
+
return
|
88
|
+
end
|
89
|
+
|
90
|
+
path
|
89
91
|
end
|
90
92
|
|
91
93
|
def parse_platform(str)
|
92
|
-
Gem::Platform.new(str).tap
|
93
|
-
p.instance_eval { @version = 'musl' } if str =~ /-musl/ && p.version.nil?
|
94
|
-
p.instance_eval { @cpu = 'x86_64' } if str =~ /universal.*darwin/
|
95
|
-
end
|
94
|
+
Gem::Platform.new(str).tap { |p| p.instance_eval { @os = 'linux-musl' } if str =~ /musl/ }
|
96
95
|
end
|
97
96
|
|
98
97
|
def ruby_platform
|
@@ -114,23 +113,21 @@ def libv8_remote_search
|
|
114
113
|
json = JSON.parse(body)
|
115
114
|
|
116
115
|
versions = json.select do |v|
|
117
|
-
Gem::
|
116
|
+
Gem::Version.new(v['number']) == Gem::Version.new(libv8_version)
|
118
117
|
end
|
119
118
|
abort(<<-ERROR) if versions.empty?
|
120
|
-
ERROR: could not find #{
|
119
|
+
ERROR: could not find #{libv8_version}
|
121
120
|
ERROR
|
122
121
|
|
123
122
|
platform_versions = versions.select do |v|
|
124
|
-
parse_platform(v['platform']) == ruby_platform
|
123
|
+
parse_platform(v['platform']) == ruby_platform
|
125
124
|
end
|
126
125
|
abort(<<-ERROR) if platform_versions.empty?
|
127
|
-
ERROR: found
|
128
|
-
try "gem install #{libv8_gem_name}
|
126
|
+
ERROR: found #{libv8_gem_name}-#{libv8_version}, but no binary for #{ruby_platform}
|
127
|
+
try "gem install #{libv8_gem_name} -v '#{libv8_version}'" to attempt to build libv8 from source
|
129
128
|
ERROR
|
130
129
|
|
131
|
-
|
132
|
-
|
133
|
-
platform_versions.sort_by { |v| Gem::Version.new(v['number']) }.last
|
130
|
+
platform_versions.first
|
134
131
|
end
|
135
132
|
|
136
133
|
def libv8_download_uri(name, version, platform)
|
@@ -142,47 +139,27 @@ def libv8_downloaded_gem(name, version, platform)
|
|
142
139
|
end
|
143
140
|
|
144
141
|
def libv8_download(name, version, platform)
|
145
|
-
FileUtils.mkdir_p(
|
142
|
+
FileUtils.mkdir_p(vendor_path)
|
146
143
|
body = http_get(libv8_download_uri(name, version, platform))
|
147
|
-
File.open(File.join(vendor_path,
|
148
|
-
end
|
149
|
-
|
150
|
-
def libv8_install!
|
151
|
-
cmd = "gem install #{libv8_gem_name} --version '#{libv8_requirement}' --install-dir '#{vendor_path}'"
|
152
|
-
puts "installing #{libv8_gem_name} using `#{cmd}`"
|
153
|
-
rc = system(cmd)
|
154
|
-
|
155
|
-
abort(<<-ERROR) unless rc
|
156
|
-
ERROR: could not install #{libv8_gem_name}:#{libv8_requirement}
|
157
|
-
try "gem install #{libv8_gem_name} -v '#{libv8_requirement}'" to attempt to build libv8 from source
|
158
|
-
ERROR
|
159
|
-
|
160
|
-
libv8_local_path([vendor_path])
|
144
|
+
File.open(File.join(vendor_path, libv8_downloaded_gem(name, version, platform)), 'wb') { |f| f.write(body) }
|
161
145
|
end
|
162
146
|
|
163
147
|
def libv8_vendor!
|
164
|
-
return libv8_install! if Gem::VERSION < '2.0'
|
165
|
-
|
166
148
|
version = libv8_remote_search
|
167
149
|
|
168
150
|
puts "downloading #{libv8_downloaded_gem(libv8_gem_name, version['number'], version['platform'])} to #{vendor_path}"
|
169
151
|
libv8_download(libv8_gem_name, version['number'], version['platform'])
|
170
152
|
|
171
|
-
package = Gem::Package.new(File.join(vendor_path,
|
172
|
-
package.extract_files(File.join(vendor_path,
|
173
|
-
FileUtils.mkdir_p(File.join(vendor_path, 'specifications'))
|
174
|
-
File.open(File.join(vendor_path, 'specifications', File.basename(libv8_downloaded_gem(libv8_gem_name, version['number'], version['platform']), '.gem') + '.gemspec'), 'wb') { |f| f.write(package.spec.to_ruby) }
|
153
|
+
package = Gem::Package.new(File.join(vendor_path, libv8_downloaded_gem(libv8_gem_name, version['number'], version['platform'])))
|
154
|
+
package.extract_files(File.join(vendor_path, File.basename(libv8_downloaded_gem(libv8_gem_name, version['number'], version['platform']), '.gem')))
|
175
155
|
|
176
156
|
libv8_vendor_path
|
177
157
|
end
|
178
158
|
|
179
159
|
def ensure_libv8_load_path
|
180
|
-
puts "platform
|
160
|
+
puts "detected platform #{RUBY_PLATFORM} => #{ruby_platform}"
|
181
161
|
|
182
|
-
libv8_path
|
183
|
-
if !ENV['ONLY_INSTALLED_LIBV8_GEM'] && !libv8_path
|
184
|
-
libv8_path, spec = libv8_vendor_path || libv8_vendor!
|
185
|
-
end
|
162
|
+
libv8_path = libv8_local_path || libv8_vendor_path || libv8_vendor!
|
186
163
|
|
187
164
|
abort(<<-ERROR) unless libv8_path
|
188
165
|
ERROR: could not find #{libv8_gem_name}
|
@@ -194,7 +171,7 @@ end
|
|
194
171
|
|
195
172
|
ensure_libv8_load_path
|
196
173
|
|
197
|
-
require 'libv8
|
174
|
+
require 'libv8'
|
198
175
|
|
199
176
|
IS_DARWIN = RUBY_PLATFORM =~ /darwin/
|
200
177
|
|
@@ -213,8 +190,6 @@ cppflags_add_cpu_extension!
|
|
213
190
|
$CPPFLAGS += " -Wno-reserved-user-defined-literal" if IS_DARWIN
|
214
191
|
|
215
192
|
$LDFLAGS.insert(0, " -stdlib=libc++ ") if IS_DARWIN
|
216
|
-
$LDFLAGS += " -Wl,--no-undefined " unless IS_DARWIN
|
217
|
-
$LDFLAGS += " -Wl,-undefined,error " if IS_DARWIN
|
218
193
|
|
219
194
|
if ENV['CXX']
|
220
195
|
puts "SETTING CXX"
|
@@ -253,7 +228,7 @@ if enable_config('debug') || enable_config('asan')
|
|
253
228
|
CONFIG['debugflags'] << ' -ggdb3 -O0'
|
254
229
|
end
|
255
230
|
|
256
|
-
Libv8
|
231
|
+
Libv8.configure_makefile
|
257
232
|
|
258
233
|
if enable_config('asan')
|
259
234
|
$CPPFLAGS.insert(0, " -fsanitize=address ")
|
@@ -23,7 +23,9 @@
|
|
23
23
|
#if RUBY_API_VERSION_MAJOR > 1
|
24
24
|
#include <ruby/thread.h>
|
25
25
|
#endif
|
26
|
+
#include <ruby/io.h>
|
26
27
|
#include <v8.h>
|
28
|
+
#include <v8-profiler.h>
|
27
29
|
#include <libplatform/libplatform.h>
|
28
30
|
#include <ruby/encoding.h>
|
29
31
|
#include <pthread.h>
|
@@ -174,7 +176,7 @@ static VALUE rb_mJSON;
|
|
174
176
|
static VALUE rb_cFailedV8Conversion;
|
175
177
|
static VALUE rb_cDateTime = Qnil;
|
176
178
|
|
177
|
-
static Platform
|
179
|
+
static std::unique_ptr<Platform> current_platform = NULL;
|
178
180
|
static std::mutex platform_lock;
|
179
181
|
|
180
182
|
static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) {
|
@@ -211,8 +213,8 @@ static void init_v8() {
|
|
211
213
|
|
212
214
|
if (current_platform == NULL) {
|
213
215
|
V8::InitializeICU();
|
214
|
-
current_platform = platform::
|
215
|
-
V8::InitializePlatform(current_platform);
|
216
|
+
current_platform = platform::NewDefaultPlatform();
|
217
|
+
V8::InitializePlatform(current_platform.get());
|
216
218
|
V8::Initialize();
|
217
219
|
}
|
218
220
|
|
@@ -254,16 +256,16 @@ static void prepare_result(MaybeLocal<Value> v8res,
|
|
254
256
|
Local<Value> local_value = v8res.ToLocalChecked();
|
255
257
|
if ((local_value->IsObject() || local_value->IsArray()) &&
|
256
258
|
!local_value->IsDate() && !local_value->IsFunction()) {
|
257
|
-
Local<Object> JSON = context->Global()->Get(
|
258
|
-
|
259
|
+
Local<Object> JSON = context->Global()->Get(String::NewFromUtf8(isolate, "JSON"))
|
260
|
+
->ToObject(context).ToLocalChecked();
|
259
261
|
|
260
262
|
Local<Function> stringify = JSON->Get(v8::String::NewFromUtf8(isolate, "stringify"))
|
261
263
|
.As<Function>();
|
262
264
|
|
263
|
-
Local<Object> object = local_value->ToObject();
|
265
|
+
Local<Object> object = local_value->ToObject(context).ToLocalChecked();
|
264
266
|
const unsigned argc = 1;
|
265
267
|
Local<Value> argv[argc] = { object };
|
266
|
-
MaybeLocal<Value> json = stringify->Call(JSON, argc, argv);
|
268
|
+
MaybeLocal<Value> json = stringify->Call(context, JSON, argc, argv);
|
267
269
|
|
268
270
|
if (json.IsEmpty()) {
|
269
271
|
evalRes.executed = false;
|
@@ -287,11 +289,21 @@ static void prepare_result(MaybeLocal<Value> v8res,
|
|
287
289
|
evalRes.message = new Persistent<Value>();
|
288
290
|
Local<Message> message = trycatch.Message();
|
289
291
|
char buf[1000];
|
290
|
-
int len;
|
292
|
+
int len, line, column;
|
293
|
+
|
294
|
+
if (!message->GetLineNumber(context).To(&line)) {
|
295
|
+
line = 0;
|
296
|
+
}
|
297
|
+
|
298
|
+
if (!message->GetStartColumn(context).To(&column)) {
|
299
|
+
column = 0;
|
300
|
+
}
|
301
|
+
|
291
302
|
len = snprintf(buf, sizeof(buf), "%s at %s:%i:%i", *String::Utf8Value(isolate, message->Get()),
|
292
|
-
*String::Utf8Value(isolate, message->GetScriptResourceName()->ToString()),
|
293
|
-
|
294
|
-
|
303
|
+
*String::Utf8Value(isolate, message->GetScriptResourceName()->ToString(context).ToLocalChecked()),
|
304
|
+
line,
|
305
|
+
column);
|
306
|
+
|
295
307
|
if ((size_t) len >= sizeof(buf)) {
|
296
308
|
len = sizeof(buf) - 1;
|
297
309
|
buf[len] = '\0';
|
@@ -307,7 +319,8 @@ static void prepare_result(MaybeLocal<Value> v8res,
|
|
307
319
|
}
|
308
320
|
if (!trycatch.StackTrace(context).IsEmpty()) {
|
309
321
|
evalRes.backtrace = new Persistent<Value>();
|
310
|
-
evalRes.backtrace->Reset(isolate,
|
322
|
+
evalRes.backtrace->Reset(isolate,
|
323
|
+
trycatch.StackTrace(context).ToLocalChecked()->ToString(context).ToLocalChecked());
|
311
324
|
}
|
312
325
|
}
|
313
326
|
}
|
@@ -391,11 +404,11 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
|
|
391
404
|
}
|
392
405
|
|
393
406
|
if (value->IsInt32()) {
|
394
|
-
return INT2FIX(value->Int32Value());
|
407
|
+
return INT2FIX(value->Int32Value(context).ToChecked());
|
395
408
|
}
|
396
409
|
|
397
410
|
if (value->IsNumber()) {
|
398
|
-
return rb_float_new(value->NumberValue());
|
411
|
+
return rb_float_new(value->NumberValue(context).ToChecked());
|
399
412
|
}
|
400
413
|
|
401
414
|
if (value->IsTrue()) {
|
@@ -436,7 +449,7 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
|
|
436
449
|
VALUE rb_hash = rb_hash_new();
|
437
450
|
TryCatch trycatch(isolate);
|
438
451
|
|
439
|
-
Local<Object> object = value->ToObject();
|
452
|
+
Local<Object> object = value->ToObject(context).ToLocalChecked();
|
440
453
|
auto maybe_props = object->GetOwnPropertyNames(context);
|
441
454
|
if (!maybe_props.IsEmpty()) {
|
442
455
|
Local<Array> props = maybe_props.ToLocalChecked();
|
@@ -459,8 +472,8 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
|
|
459
472
|
return rb_hash;
|
460
473
|
}
|
461
474
|
|
462
|
-
Local<String> rstr = value->ToString();
|
463
|
-
return rb_enc_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(), rb_enc_find("utf-8"));
|
475
|
+
Local<String> rstr = value->ToString(context).ToLocalChecked();
|
476
|
+
return rb_enc_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate), rb_enc_find("utf-8"));
|
464
477
|
}
|
465
478
|
|
466
479
|
static VALUE convert_v8_to_ruby(Isolate* isolate,
|
@@ -557,7 +570,7 @@ treat_as_latin1:
|
|
557
570
|
return v8str.ToLocalChecked();
|
558
571
|
}
|
559
572
|
|
560
|
-
static Local<Value> convert_ruby_to_v8(Isolate* isolate, VALUE value)
|
573
|
+
static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context, VALUE value)
|
561
574
|
{
|
562
575
|
EscapableHandleScope scope(isolate);
|
563
576
|
|
@@ -571,87 +584,86 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, VALUE value)
|
|
571
584
|
VALUE klass;
|
572
585
|
|
573
586
|
switch (TYPE(value)) {
|
574
|
-
|
587
|
+
case T_FIXNUM:
|
575
588
|
{
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
589
|
+
fixnum = NUM2LONG(value);
|
590
|
+
if (fixnum > INT_MAX)
|
591
|
+
{
|
592
|
+
return scope.Escape(Number::New(isolate, (double)fixnum));
|
593
|
+
}
|
594
|
+
return scope.Escape(Integer::New(isolate, (int)fixnum));
|
582
595
|
}
|
583
|
-
|
584
|
-
|
585
|
-
|
596
|
+
case T_FLOAT:
|
597
|
+
return scope.Escape(Number::New(isolate, NUM2DBL(value)));
|
598
|
+
case T_STRING:
|
586
599
|
return scope.Escape(convert_ruby_str_to_v8(scope, isolate, value));
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
600
|
+
case T_NIL:
|
601
|
+
return scope.Escape(Null(isolate));
|
602
|
+
case T_TRUE:
|
603
|
+
return scope.Escape(True(isolate));
|
604
|
+
case T_FALSE:
|
605
|
+
return scope.Escape(False(isolate));
|
606
|
+
case T_ARRAY:
|
594
607
|
{
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
608
|
+
length = RARRAY_LEN(value);
|
609
|
+
array = Array::New(isolate, (int)length);
|
610
|
+
for(i=0; i<length; i++) {
|
611
|
+
array->Set(i, convert_ruby_to_v8(isolate, context, rb_ary_entry(value, i)));
|
612
|
+
}
|
613
|
+
return scope.Escape(array);
|
601
614
|
}
|
602
|
-
|
615
|
+
case T_HASH:
|
603
616
|
{
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
617
|
+
object = Object::New(isolate);
|
618
|
+
hash_as_array = rb_funcall(value, rb_intern("to_a"), 0);
|
619
|
+
length = RARRAY_LEN(hash_as_array);
|
620
|
+
for(i=0; i<length; i++) {
|
621
|
+
pair = rb_ary_entry(hash_as_array, i);
|
622
|
+
object->Set(convert_ruby_to_v8(isolate, context, rb_ary_entry(pair, 0)),
|
623
|
+
convert_ruby_to_v8(isolate, context, rb_ary_entry(pair, 1)));
|
624
|
+
}
|
625
|
+
return scope.Escape(object);
|
613
626
|
}
|
614
|
-
|
627
|
+
case T_SYMBOL:
|
615
628
|
{
|
616
|
-
|
629
|
+
value = rb_funcall(value, rb_intern("to_s"), 0);
|
617
630
|
return scope.Escape(convert_ruby_str_to_v8(scope, isolate, value));
|
618
631
|
}
|
619
|
-
|
632
|
+
case T_DATA:
|
633
|
+
{
|
634
|
+
klass = rb_funcall(value, rb_intern("class"), 0);
|
635
|
+
if (klass == rb_cTime || klass == rb_cDateTime)
|
620
636
|
{
|
621
|
-
|
622
|
-
if (klass == rb_cTime || klass == rb_cDateTime)
|
637
|
+
if (klass == rb_cDateTime)
|
623
638
|
{
|
624
|
-
|
625
|
-
{
|
626
|
-
value = rb_funcall(value, rb_intern("to_time"), 0);
|
627
|
-
}
|
628
|
-
value = rb_funcall(value, rb_intern("to_f"), 0);
|
629
|
-
return scope.Escape(Date::New(isolate, NUM2DBL(value) * 1000));
|
639
|
+
value = rb_funcall(value, rb_intern("to_time"), 0);
|
630
640
|
}
|
641
|
+
value = rb_funcall(value, rb_intern("to_f"), 0);
|
642
|
+
return scope.Escape(Date::New(context, NUM2DBL(value) * 1000).ToLocalChecked());
|
643
|
+
}
|
631
644
|
// break intentionally missing
|
632
645
|
}
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
646
|
+
case T_OBJECT:
|
647
|
+
case T_CLASS:
|
648
|
+
case T_ICLASS:
|
649
|
+
case T_MODULE:
|
650
|
+
case T_REGEXP:
|
651
|
+
case T_MATCH:
|
652
|
+
case T_STRUCT:
|
653
|
+
case T_BIGNUM:
|
654
|
+
case T_FILE:
|
655
|
+
case T_UNDEF:
|
656
|
+
case T_NODE:
|
657
|
+
default:
|
645
658
|
{
|
646
659
|
if (rb_respond_to(value, rb_intern("to_s"))) {
|
647
660
|
// TODO: if this throws we're screwed
|
648
661
|
value = rb_funcall(value, rb_intern("to_s"), 0);
|
649
662
|
return scope.Escape(convert_ruby_str_to_v8(scope, isolate, value));
|
650
663
|
}
|
651
|
-
|
652
|
-
|
664
|
+
return scope.Escape(String::NewFromUtf8(isolate, "Undefined Conversion"));
|
665
|
+
}
|
653
666
|
}
|
654
|
-
|
655
667
|
}
|
656
668
|
|
657
669
|
static void unblock_eval(void *ptr) {
|
@@ -659,6 +671,91 @@ static void unblock_eval(void *ptr) {
|
|
659
671
|
eval->context_info->isolate_info->interrupted = true;
|
660
672
|
}
|
661
673
|
|
674
|
+
/*
|
675
|
+
* The implementations of the run_extra_code(), create_snapshot_data_blob() and
|
676
|
+
* warm_up_snapshot_data_blob() functions have been derived from V8's test suite.
|
677
|
+
*/
|
678
|
+
bool run_extra_code(Isolate *isolate, Local<v8::Context> context,
|
679
|
+
const char *utf8_source, const char *name) {
|
680
|
+
Context::Scope context_scope(context);
|
681
|
+
TryCatch try_catch(isolate);
|
682
|
+
Local<String> source_string;
|
683
|
+
if (!String::NewFromUtf8(isolate, utf8_source,
|
684
|
+
NewStringType::kNormal)
|
685
|
+
.ToLocal(&source_string)) {
|
686
|
+
return false;
|
687
|
+
}
|
688
|
+
Local<v8::String> resource_name =
|
689
|
+
String::NewFromUtf8(isolate, name, NewStringType::kNormal)
|
690
|
+
.ToLocalChecked();
|
691
|
+
ScriptOrigin origin(resource_name);
|
692
|
+
ScriptCompiler::Source source(source_string, origin);
|
693
|
+
Local<Script> script;
|
694
|
+
if (!ScriptCompiler::Compile(context, &source).ToLocal(&script))
|
695
|
+
return false;
|
696
|
+
if (script->Run(context).IsEmpty())
|
697
|
+
return false;
|
698
|
+
// CHECK(!try_catch.HasCaught());
|
699
|
+
return true;
|
700
|
+
}
|
701
|
+
|
702
|
+
StartupData
|
703
|
+
create_snapshot_data_blob(const char *embedded_source = nullptr) {
|
704
|
+
// Create a new isolate and a new context from scratch, optionally run
|
705
|
+
// a script to embed, and serialize to create a snapshot blob.
|
706
|
+
StartupData result = {nullptr, 0};
|
707
|
+
{
|
708
|
+
SnapshotCreator snapshot_creator;
|
709
|
+
Isolate *isolate = snapshot_creator.GetIsolate();
|
710
|
+
{
|
711
|
+
HandleScope scope(isolate);
|
712
|
+
Local<Context> context = Context::New(isolate);
|
713
|
+
if (embedded_source != nullptr &&
|
714
|
+
!run_extra_code(isolate, context, embedded_source,
|
715
|
+
"<embedded>")) {
|
716
|
+
return result;
|
717
|
+
}
|
718
|
+
snapshot_creator.SetDefaultContext(context);
|
719
|
+
}
|
720
|
+
result = snapshot_creator.CreateBlob(
|
721
|
+
SnapshotCreator::FunctionCodeHandling::kClear);
|
722
|
+
}
|
723
|
+
return result;
|
724
|
+
}
|
725
|
+
|
726
|
+
StartupData warm_up_snapshot_data_blob(StartupData cold_snapshot_blob,
|
727
|
+
const char *warmup_source) {
|
728
|
+
// Use following steps to create a warmed up snapshot blob from a cold one:
|
729
|
+
// - Create a new isolate from the cold snapshot.
|
730
|
+
// - Create a new context to run the warmup script. This will trigger
|
731
|
+
// compilation of executed functions.
|
732
|
+
// - Create a new context. This context will be unpolluted.
|
733
|
+
// - Serialize the isolate and the second context into a new snapshot blob.
|
734
|
+
StartupData result = {nullptr, 0};
|
735
|
+
|
736
|
+
if (cold_snapshot_blob.raw_size > 0 && cold_snapshot_blob.data != nullptr &&
|
737
|
+
warmup_source != NULL) {
|
738
|
+
SnapshotCreator snapshot_creator(nullptr, &cold_snapshot_blob);
|
739
|
+
Isolate *isolate = snapshot_creator.GetIsolate();
|
740
|
+
{
|
741
|
+
HandleScope scope(isolate);
|
742
|
+
Local<Context> context = Context::New(isolate);
|
743
|
+
if (!run_extra_code(isolate, context, warmup_source, "<warm-up>")) {
|
744
|
+
return result;
|
745
|
+
}
|
746
|
+
}
|
747
|
+
{
|
748
|
+
HandleScope handle_scope(isolate);
|
749
|
+
isolate->ContextDisposedNotification(false);
|
750
|
+
Local<Context> context = Context::New(isolate);
|
751
|
+
snapshot_creator.SetDefaultContext(context);
|
752
|
+
}
|
753
|
+
result = snapshot_creator.CreateBlob(
|
754
|
+
SnapshotCreator::FunctionCodeHandling::kKeep);
|
755
|
+
}
|
756
|
+
return result;
|
757
|
+
}
|
758
|
+
|
662
759
|
static VALUE rb_snapshot_size(VALUE self, VALUE str) {
|
663
760
|
SnapshotInfo* snapshot_info;
|
664
761
|
Data_Get_Struct(self, SnapshotInfo, snapshot_info);
|
@@ -677,7 +774,7 @@ static VALUE rb_snapshot_load(VALUE self, VALUE str) {
|
|
677
774
|
|
678
775
|
init_v8();
|
679
776
|
|
680
|
-
StartupData startup_data =
|
777
|
+
StartupData startup_data = create_snapshot_data_blob(RSTRING_PTR(str));
|
681
778
|
|
682
779
|
if (startup_data.data == NULL && startup_data.raw_size == 0) {
|
683
780
|
rb_raise(rb_eSnapshotError, "Could not create snapshot, most likely the source is incorrect");
|
@@ -708,7 +805,7 @@ static VALUE rb_snapshot_warmup_unsafe(VALUE self, VALUE str) {
|
|
708
805
|
init_v8();
|
709
806
|
|
710
807
|
StartupData cold_startup_data = {snapshot_info->data, snapshot_info->raw_size};
|
711
|
-
StartupData warm_startup_data =
|
808
|
+
StartupData warm_startup_data = warm_up_snapshot_data_blob(cold_startup_data, RSTRING_PTR(str));
|
712
809
|
|
713
810
|
if (warm_startup_data.data == NULL && warm_startup_data.raw_size == 0) {
|
714
811
|
rb_raise(rb_eSnapshotError, "Could not warm up snapshot, most likely the source is incorrect");
|
@@ -887,8 +984,8 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
|
|
887
984
|
Local<Value> tmp = Local<Value>::New(isolate, *result.value);
|
888
985
|
|
889
986
|
if (result.json) {
|
890
|
-
Local<String> rstr = tmp->ToString();
|
891
|
-
VALUE json_string = rb_enc_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(), rb_enc_find("utf-8"));
|
987
|
+
Local<String> rstr = tmp->ToString(p_ctx->Get(isolate)).ToLocalChecked();
|
988
|
+
VALUE json_string = rb_enc_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate), rb_enc_find("utf-8"));
|
892
989
|
ret = rb_funcall(rb_mJSON, rb_intern("parse"), 1, json_string);
|
893
990
|
} else {
|
894
991
|
ret = convert_v8_to_ruby(isolate, *p_ctx, tmp);
|
@@ -1009,6 +1106,8 @@ gvl_ruby_callback(void* data) {
|
|
1009
1106
|
VALUE result;
|
1010
1107
|
VALUE self;
|
1011
1108
|
VALUE parent;
|
1109
|
+
ContextInfo* context_info;
|
1110
|
+
|
1012
1111
|
{
|
1013
1112
|
HandleScope scope(args->GetIsolate());
|
1014
1113
|
Local<External> external = Local<External>::Cast(args->Data());
|
@@ -1021,7 +1120,6 @@ gvl_ruby_callback(void* data) {
|
|
1021
1120
|
return NULL;
|
1022
1121
|
}
|
1023
1122
|
|
1024
|
-
ContextInfo* context_info;
|
1025
1123
|
Data_Get_Struct(parent, ContextInfo, context_info);
|
1026
1124
|
|
1027
1125
|
if (length > 0) {
|
@@ -1031,7 +1129,7 @@ gvl_ruby_callback(void* data) {
|
|
1031
1129
|
for (int i = 0; i < length; i++) {
|
1032
1130
|
Local<Value> value = ((*args)[i]).As<Value>();
|
1033
1131
|
VALUE tmp = convert_v8_to_ruby(args->GetIsolate(),
|
1034
|
-
|
1132
|
+
*context_info->context, value);
|
1035
1133
|
rb_ary_push(ruby_args, tmp);
|
1036
1134
|
}
|
1037
1135
|
}
|
@@ -1062,7 +1160,7 @@ gvl_ruby_callback(void* data) {
|
|
1062
1160
|
}
|
1063
1161
|
else {
|
1064
1162
|
HandleScope scope(args->GetIsolate());
|
1065
|
-
Handle<Value> v8_result = convert_ruby_to_v8(args->GetIsolate(), result);
|
1163
|
+
Handle<Value> v8_result = convert_ruby_to_v8(args->GetIsolate(), context_info->context->Get(args->GetIsolate()), result);
|
1066
1164
|
args->GetReturnValue().Set(v8_result);
|
1067
1165
|
}
|
1068
1166
|
|
@@ -1119,8 +1217,10 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
1119
1217
|
Local<Context> context = context_info->context->Get(isolate);
|
1120
1218
|
Context::Scope context_scope(context);
|
1121
1219
|
|
1122
|
-
Local<String> v8_str =
|
1123
|
-
|
1220
|
+
Local<String> v8_str =
|
1221
|
+
String::NewFromUtf8(isolate, RSTRING_PTR(name),
|
1222
|
+
NewStringType::kNormal, (int)RSTRING_LEN(name))
|
1223
|
+
.ToLocalChecked();
|
1124
1224
|
|
1125
1225
|
// copy self so we can access from v8 external
|
1126
1226
|
VALUE* self_copy;
|
@@ -1130,23 +1230,34 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
1130
1230
|
Local<Value> external = External::New(isolate, self_copy);
|
1131
1231
|
|
1132
1232
|
if (parent_object == Qnil) {
|
1133
|
-
context->Global()->Set(
|
1134
|
-
|
1233
|
+
context->Global()->Set(
|
1234
|
+
v8_str, FunctionTemplate::New(isolate, ruby_callback, external)
|
1235
|
+
->GetFunction(context)
|
1236
|
+
.ToLocalChecked());
|
1135
1237
|
|
1136
|
-
|
1137
|
-
|
1238
|
+
} else {
|
1239
|
+
Local<String> eval =
|
1240
|
+
String::NewFromUtf8(isolate, RSTRING_PTR(parent_object_eval),
|
1241
|
+
NewStringType::kNormal,
|
1242
|
+
(int)RSTRING_LEN(parent_object_eval))
|
1243
|
+
.ToLocalChecked();
|
1138
1244
|
|
1139
1245
|
MaybeLocal<Script> parsed_script = Script::Compile(context, eval);
|
1140
1246
|
if (parsed_script.IsEmpty()) {
|
1141
1247
|
parse_error = true;
|
1142
1248
|
} else {
|
1143
|
-
MaybeLocal<Value> maybe_value =
|
1249
|
+
MaybeLocal<Value> maybe_value =
|
1250
|
+
parsed_script.ToLocalChecked()->Run(context);
|
1144
1251
|
attach_error = true;
|
1145
1252
|
|
1146
1253
|
if (!maybe_value.IsEmpty()) {
|
1147
1254
|
Local<Value> value = maybe_value.ToLocalChecked();
|
1148
|
-
if (value->IsObject()){
|
1149
|
-
|
1255
|
+
if (value->IsObject()) {
|
1256
|
+
value.As<Object>()->Set(
|
1257
|
+
v8_str, FunctionTemplate::New(
|
1258
|
+
isolate, ruby_callback, external)
|
1259
|
+
->GetFunction(context)
|
1260
|
+
.ToLocalChecked());
|
1150
1261
|
attach_error = false;
|
1151
1262
|
}
|
1152
1263
|
}
|
@@ -1350,6 +1461,69 @@ rb_heap_stats(VALUE self) {
|
|
1350
1461
|
return rval;
|
1351
1462
|
}
|
1352
1463
|
|
1464
|
+
// https://github.com/bnoordhuis/node-heapdump/blob/master/src/heapdump.cc
|
1465
|
+
class FileOutputStream : public OutputStream {
|
1466
|
+
public:
|
1467
|
+
FileOutputStream(FILE* stream) : stream_(stream) {}
|
1468
|
+
|
1469
|
+
virtual int GetChunkSize() {
|
1470
|
+
return 65536;
|
1471
|
+
}
|
1472
|
+
|
1473
|
+
virtual void EndOfStream() {}
|
1474
|
+
|
1475
|
+
virtual WriteResult WriteAsciiChunk(char* data, int size) {
|
1476
|
+
const size_t len = static_cast<size_t>(size);
|
1477
|
+
size_t off = 0;
|
1478
|
+
|
1479
|
+
while (off < len && !feof(stream_) && !ferror(stream_))
|
1480
|
+
off += fwrite(data + off, 1, len - off, stream_);
|
1481
|
+
|
1482
|
+
return off == len ? kContinue : kAbort;
|
1483
|
+
}
|
1484
|
+
|
1485
|
+
private:
|
1486
|
+
FILE* stream_;
|
1487
|
+
};
|
1488
|
+
|
1489
|
+
|
1490
|
+
static VALUE
|
1491
|
+
rb_heap_snapshot(VALUE self, VALUE file) {
|
1492
|
+
|
1493
|
+
rb_io_t *fptr;
|
1494
|
+
|
1495
|
+
fptr = RFILE(file)->fptr;
|
1496
|
+
|
1497
|
+
if (!fptr) return Qfalse;
|
1498
|
+
|
1499
|
+
FILE* fp;
|
1500
|
+
fp = fdopen(fptr->fd, "w");
|
1501
|
+
if (fp == NULL) return Qfalse;
|
1502
|
+
|
1503
|
+
|
1504
|
+
ContextInfo* context_info;
|
1505
|
+
Data_Get_Struct(self, ContextInfo, context_info);
|
1506
|
+
Isolate* isolate;
|
1507
|
+
isolate = context_info->isolate_info ? context_info->isolate_info->isolate : NULL;
|
1508
|
+
|
1509
|
+
if (!isolate) return Qfalse;
|
1510
|
+
|
1511
|
+
Locker lock(isolate);
|
1512
|
+
Isolate::Scope isolate_scope(isolate);
|
1513
|
+
HandleScope handle_scope(isolate);
|
1514
|
+
|
1515
|
+
HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
|
1516
|
+
|
1517
|
+
const HeapSnapshot* const snap = heap_profiler->TakeHeapSnapshot();
|
1518
|
+
|
1519
|
+
FileOutputStream stream(fp);
|
1520
|
+
snap->Serialize(&stream, HeapSnapshot::kJSON);
|
1521
|
+
|
1522
|
+
const_cast<HeapSnapshot*>(snap)->Delete();
|
1523
|
+
|
1524
|
+
return Qtrue;
|
1525
|
+
}
|
1526
|
+
|
1353
1527
|
static VALUE
|
1354
1528
|
rb_context_stop(VALUE self) {
|
1355
1529
|
|
@@ -1494,7 +1668,7 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
|
|
1494
1668
|
return Qnil;
|
1495
1669
|
}
|
1496
1670
|
for(int i=0; i < fun_argc; i++) {
|
1497
|
-
call.argv[i] = convert_ruby_to_v8(isolate, call_argv[i]);
|
1671
|
+
call.argv[i] = convert_ruby_to_v8(isolate, context, call_argv[i]);
|
1498
1672
|
}
|
1499
1673
|
}
|
1500
1674
|
#if RUBY_API_VERSION_MAJOR > 1
|
@@ -1558,6 +1732,8 @@ extern "C" {
|
|
1558
1732
|
rb_define_method(rb_cContext, "dispose_unsafe", (VALUE(*)(...))&rb_context_dispose, 0);
|
1559
1733
|
rb_define_method(rb_cContext, "low_memory_notification", (VALUE(*)(...))&rb_context_low_memory_notification, 0);
|
1560
1734
|
rb_define_method(rb_cContext, "heap_stats", (VALUE(*)(...))&rb_heap_stats, 0);
|
1735
|
+
rb_define_method(rb_cContext, "write_heap_snapshot_unsafe", (VALUE(*)(...))&rb_heap_snapshot, 1);
|
1736
|
+
|
1561
1737
|
rb_define_private_method(rb_cContext, "create_isolate_value",(VALUE(*)(...))&rb_context_create_isolate_value, 0);
|
1562
1738
|
rb_define_private_method(rb_cContext, "eval_unsafe",(VALUE(*)(...))&rb_context_eval_unsafe, 2);
|
1563
1739
|
rb_define_private_method(rb_cContext, "call_unsafe", (VALUE(*)(...))&rb_context_call_unsafe, -1);
|
data/lib/sqreen/mini_racer.rb
CHANGED
@@ -178,6 +178,28 @@ module MiniRacer
|
|
178
178
|
eval(File.read(filename))
|
179
179
|
end
|
180
180
|
|
181
|
+
def write_heap_snapshot(file_or_io)
|
182
|
+
f = nil
|
183
|
+
implicit = false
|
184
|
+
|
185
|
+
|
186
|
+
if String === file_or_io
|
187
|
+
f = File.open(file_or_io, "w")
|
188
|
+
implicit = true
|
189
|
+
else
|
190
|
+
f = file_or_io
|
191
|
+
end
|
192
|
+
|
193
|
+
if !(File === f)
|
194
|
+
raise ArgumentError("file_or_io")
|
195
|
+
end
|
196
|
+
|
197
|
+
write_heap_snapshot_unsafe(f)
|
198
|
+
|
199
|
+
ensure
|
200
|
+
f.close if implicit
|
201
|
+
end
|
202
|
+
|
181
203
|
def eval(str, options=nil)
|
182
204
|
raise(ContextDisposedError, 'attempted to call eval on a disposed context!') if @disposed
|
183
205
|
|
data/mini_racer.gemspec
CHANGED
@@ -15,12 +15,13 @@ Gem::Specification.new do |spec|
|
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
17
|
|
18
|
-
REJECTS = %r{\A((benchmark|test|spec|features)/|bench\.rb|.+\.sh|Jenkinsfile)}
|
18
|
+
REJECTS = %r{\A((benchmark|test|spec|features|examples)/|bench\.rb|.+\.sh|Jenkinsfile)}
|
19
19
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(REJECTS) }
|
20
20
|
spec.bindir = "exe"
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
24
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
25
26
|
spec.add_development_dependency "minitest", "~> 5.0"
|
26
27
|
spec.add_development_dependency "rake-compiler"
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sq_mini_racer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5.0.1.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Saffron
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.12'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.12'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rake
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -61,18 +75,14 @@ extensions:
|
|
61
75
|
- ext/prv_ext_loader/extconf.rb
|
62
76
|
extra_rdoc_files: []
|
63
77
|
files:
|
64
|
-
- ".dockerignore"
|
65
78
|
- ".gitignore"
|
66
79
|
- ".travis.yml"
|
67
80
|
- CHANGELOG
|
68
81
|
- CODE_OF_CONDUCT.md
|
69
|
-
- Dockerfile
|
70
82
|
- Gemfile
|
71
83
|
- LICENSE.txt
|
72
84
|
- README.md
|
73
85
|
- Rakefile
|
74
|
-
- azure-pipelines.yml
|
75
|
-
- azure-template.yml
|
76
86
|
- bin/console
|
77
87
|
- bin/setup
|
78
88
|
- ext/mini_racer_extension/compat.hpp
|
@@ -88,7 +98,7 @@ homepage: https://github.com/sqreen/mini_racer
|
|
88
98
|
licenses:
|
89
99
|
- MIT
|
90
100
|
metadata: {}
|
91
|
-
post_install_message:
|
101
|
+
post_install_message:
|
92
102
|
rdoc_options: []
|
93
103
|
require_paths:
|
94
104
|
- lib
|
@@ -100,12 +110,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
110
|
version: 1.9.3
|
101
111
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
112
|
requirements:
|
103
|
-
- - "
|
113
|
+
- - ">"
|
104
114
|
- !ruby/object:Gem::Version
|
105
|
-
version:
|
115
|
+
version: 1.3.1
|
106
116
|
requirements: []
|
107
|
-
|
108
|
-
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 2.7.7
|
119
|
+
signing_key:
|
109
120
|
specification_version: 4
|
110
121
|
summary: Minimal embedded v8 for Ruby
|
111
122
|
test_files: []
|
data/.dockerignore
DELETED
data/Dockerfile
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
ARG RUBY_VERSION=2.7
|
2
|
-
FROM ruby:${RUBY_VERSION}
|
3
|
-
|
4
|
-
RUN test ! -f /etc/alpine-release || apk add --no-cache build-base git
|
5
|
-
|
6
|
-
# without this `COPY .git`, we get the following error:
|
7
|
-
# fatal: not a git repository (or any of the parent directories): .git
|
8
|
-
# but with it we need the full gem just to compile the extension because
|
9
|
-
# of gemspec's `git --ls-files`
|
10
|
-
# COPY .git /code/.git
|
11
|
-
|
12
|
-
COPY Gemfile mini_racer.gemspec /code/
|
13
|
-
COPY lib/sqreen/mini_racer/version.rb /code/lib/sqreen/mini_racer/version.rb
|
14
|
-
WORKDIR /code
|
15
|
-
RUN bundle install
|
16
|
-
|
17
|
-
COPY Rakefile /code/
|
18
|
-
COPY ext /code/ext/
|
19
|
-
RUN bundle exec rake compile
|
20
|
-
|
21
|
-
COPY . /code/
|
22
|
-
CMD bundle exec irb -rmini_racer
|
data/azure-pipelines.yml
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
jobs:
|
2
|
-
- template: azure-template.yml
|
3
|
-
parameters:
|
4
|
-
name: linux_2_0
|
5
|
-
displayName: Linux Ruby 2.0
|
6
|
-
rubyVersion: '2.0'
|
7
|
-
publishCoverage: true
|
8
|
-
|
9
|
-
- template: azure-template.yml
|
10
|
-
parameters:
|
11
|
-
name: linux_2_1
|
12
|
-
displayName: Linux Ruby 2.1
|
13
|
-
rubyVersion: '2.1'
|
14
|
-
|
15
|
-
- template: azure-template.yml
|
16
|
-
parameters:
|
17
|
-
name: linux_2_2
|
18
|
-
displayName: Linux Ruby 2.2
|
19
|
-
rubyVersion: '2.2'
|
20
|
-
|
21
|
-
- template: azure-template.yml
|
22
|
-
parameters:
|
23
|
-
name: linux_2_3
|
24
|
-
displayName: Linux Ruby 2.3
|
25
|
-
rubyVersion: '2.3'
|
26
|
-
|
27
|
-
- template: azure-template.yml
|
28
|
-
parameters:
|
29
|
-
name: linux_2_4
|
30
|
-
displayName: Linux Ruby 2.4
|
31
|
-
rubyVersion: '2.4'
|
32
|
-
|
33
|
-
- template: azure-template.yml
|
34
|
-
parameters:
|
35
|
-
name: linux_2_5
|
36
|
-
displayName: Linux Ruby 2.5
|
37
|
-
rubyVersion: '2.5'
|
38
|
-
|
39
|
-
- template: azure-template.yml
|
40
|
-
parameters:
|
41
|
-
name: linux_2_6
|
42
|
-
displayName: Linux Ruby 2.6
|
43
|
-
rubyVersion: '2.6'
|
44
|
-
|
45
|
-
- template: azure-template.yml
|
46
|
-
parameters:
|
47
|
-
name: linux_2_7
|
48
|
-
displayName: Linux Ruby 2.7
|
49
|
-
rubyVersion: '2.7'
|
50
|
-
|
51
|
-
- template: azure-template.yml
|
52
|
-
parameters:
|
53
|
-
name: linux_2_7_mini_racer
|
54
|
-
displayName: Linux Ruby 2.7 (with mini_racer)
|
55
|
-
rubyVersion: '2.7'
|
56
|
-
with_mini_racer: true
|
57
|
-
|
58
|
-
- template: azure-template.yml
|
59
|
-
parameters:
|
60
|
-
name: linux_2_7_therubyracer
|
61
|
-
displayName: Linux Ruby 2.7 (with therubyracer)
|
62
|
-
rubyVersion: '2.7'
|
63
|
-
with_therubyracer: true
|
64
|
-
|
65
|
-
- template: azure-template.yml
|
66
|
-
parameters:
|
67
|
-
name: macos_10_15
|
68
|
-
displayName: MacOS 10.15
|
69
|
-
imageName: 'macos-10.15'
|
data/azure-template.yml
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
parameters:
|
2
|
-
name: ~
|
3
|
-
displayName: ~
|
4
|
-
rubyVersion: bundled
|
5
|
-
imageName: ubuntu-18.04
|
6
|
-
publishCoverage: false
|
7
|
-
with_mini_racer: false
|
8
|
-
with_therubyracer: false
|
9
|
-
|
10
|
-
jobs:
|
11
|
-
- job: ${{ parameters.name }}
|
12
|
-
displayName: ${{ parameters.displayName }}
|
13
|
-
pool:
|
14
|
-
vmImage: ${{ parameters.imageName }}
|
15
|
-
|
16
|
-
variables:
|
17
|
-
TESTOPTS: -v
|
18
|
-
${{ if eq(parameters.publishCoverage, true) }}:
|
19
|
-
CPPFLAGS: --coverage
|
20
|
-
LDFLAGS: --coverage
|
21
|
-
${{ if eq(parameters.rubyVersion, 'bundled') }}:
|
22
|
-
gem: gem
|
23
|
-
bundle: bundle
|
24
|
-
${{ if ne(parameters.rubyVersion, 'bundled') }}:
|
25
|
-
gem: /opt/ruby/${{ parameters.rubyVersion }}/bin/gem
|
26
|
-
bundle: /opt/ruby/${{ parameters.rubyVersion }}/bin/bundle
|
27
|
-
GEM_HOME: /opt/ruby/${{ parameters.rubyVersion }}/lib/ruby/gems/${{ parameters.rubyVersion }}.0
|
28
|
-
|
29
|
-
steps:
|
30
|
-
- checkout: self
|
31
|
-
displayName: Checkout
|
32
|
-
clean: true
|
33
|
-
submodules: recursive
|
34
|
-
|
35
|
-
- ${{ if ne(parameters.rubyVersion, 'bundled') }}:
|
36
|
-
- script: |
|
37
|
-
sudo apt-get install -y gnupg
|
38
|
-
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 5D98E7264E3F3D89463B314B12229434A9F003C9
|
39
|
-
echo deb [arch=amd64] http://sqreen-download-private.s3.amazonaws.com/deb bionic main | sudo tee -a /etc/apt/sources.list
|
40
|
-
sudo apt-get update
|
41
|
-
sudo apt-get install -y sq-ruby${{ parameters.rubyVersion }} ruby-
|
42
|
-
displayName: Install Ruby
|
43
|
-
|
44
|
-
- ${{ if eq(parameters.rubyVersion, 'bundled') }}:
|
45
|
-
- script: sudo $(gem) install bundler --version '< 2.0' --no-document
|
46
|
-
displayName: Install bundler
|
47
|
-
|
48
|
-
- ${{ if eq(parameters.imageName, 'ubuntu-18.04') }}:
|
49
|
-
- script: |
|
50
|
-
sudo apt-get install -y build-essential git curl valgrind g++ make
|
51
|
-
displayName: Install Linux packages
|
52
|
-
|
53
|
-
- script: $(bundle) install --path vendor/bundle
|
54
|
-
displayName: Install gem dependencies
|
55
|
-
env:
|
56
|
-
${{ if eq(parameters.with_mini_racer, true) }}:
|
57
|
-
LOAD_MINI_RACER: 1
|
58
|
-
${{ if eq(parameters.with_therubyracer, true) }}:
|
59
|
-
LOAD_THERUBYRACER: 1
|
60
|
-
|
61
|
-
- script: PATH=`dirname $(bundle)`:$PATH CPPFLAGS=$(CPPFLAGS) LDFLAGS=$(LDFLAGS) $(bundle) exec rake compile
|
62
|
-
displayName: Compile extension
|
63
|
-
|
64
|
-
- script: |
|
65
|
-
find . -name '*.log' -exec cat '{}' \;
|
66
|
-
displayName: Print logs
|
67
|
-
condition: failed()
|
68
|
-
|
69
|
-
- script: $(bundle) exec rake test
|
70
|
-
displayName: Run tests
|
71
|
-
env:
|
72
|
-
${{ if eq(parameters.with_mini_racer, true) }}:
|
73
|
-
LOAD_MINI_RACER: 1
|
74
|
-
${{ if eq(parameters.with_therubyracer, true) }}:
|
75
|
-
LOAD_THERUBYRACER: 1
|
76
|
-
|
77
|
-
- ${{ if and(eq(parameters.imageName, 'ubuntu-18.04'), eq(parameters.with_mini_racer, false), eq(parameters.with_therubyracer, false)) }}:
|
78
|
-
- script: $(bundle) exec rake test:valgrind
|
79
|
-
displayName: Run tests w/ valgrind
|
80
|
-
|
81
|
-
- script: |
|
82
|
-
PATH=$PATH:$(dirname $(which $(gem)))
|
83
|
-
$(bundle) exec rake build
|
84
|
-
sudo PATH=$PATH $(gem) install pkg/*.gem
|
85
|
-
displayName: Check that the gem is installable
|
86
|
-
|
87
|
-
- ${{ if eq(parameters.publishCoverage, true) }}:
|
88
|
-
- bash: >
|
89
|
-
test -z "$CODECOV_TOKEN" || bash <(curl -s https://codecov.io/bash)
|
90
|
-
displayName: "Publish coverage (Codecov)"
|
91
|
-
env:
|
92
|
-
CODECOV_TOKEN: $(CODECOV_TOKEN)
|