sq_mini_racer 0.2.5.0.1.beta3 → 0.3.1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dockerignore +12 -0
- data/.gitignore +9 -0
- data/CHANGELOG +73 -0
- data/Dockerfile +22 -0
- data/README.md +17 -2
- data/Rakefile +44 -62
- data/azure-pipelines.yml +69 -0
- data/azure-template.yml +101 -0
- data/ext/mini_racer_extension/extconf.rb +61 -52
- data/ext/mini_racer_extension/mini_racer_extension.cc +265 -99
- data/ext/mini_racer_loader/extconf.rb +8 -0
- data/ext/{prv_ext_loader/prv_ext_loader.c → mini_racer_loader/mini_racer_loader.c} +24 -5
- data/lib/sqreen/mini_racer.rb +90 -24
- data/lib/sqreen/mini_racer/version.rb +3 -3
- data/mini_racer.gemspec +14 -6
- data/valgrind.supp +74 -0
- metadata +64 -23
- data/.travis.yml +0 -73
- data/ext/prv_ext_loader/extconf.rb +0 -5
@@ -26,46 +26,55 @@ def cppflags_add_cpu_extension!
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def libv8_gem_name
|
29
|
-
|
30
|
-
return "libv8-alpine" if IS_LINUX_MUSL
|
31
|
-
|
32
|
-
'libv8'
|
29
|
+
'libv8-node'
|
33
30
|
end
|
34
31
|
|
35
|
-
def
|
36
|
-
'
|
32
|
+
def libv8_requirement
|
33
|
+
'~> 15.5.1.0.beta1'
|
37
34
|
end
|
38
35
|
|
39
|
-
def libv8_basename
|
40
|
-
"#{libv8_gem_name}-#{
|
36
|
+
def libv8_basename(version)
|
37
|
+
"#{libv8_gem_name}-#{version}-#{ruby_platform}"
|
41
38
|
end
|
42
39
|
|
43
|
-
def libv8_gemspec
|
44
|
-
"#{libv8_basename}.gemspec"
|
40
|
+
def libv8_gemspec(version)
|
41
|
+
"#{libv8_basename(version)}.gemspec"
|
45
42
|
end
|
46
43
|
|
47
44
|
def libv8_local_path(path=Gem.path)
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
name_glob = "#{libv8_gem_name}-*-#{ruby_platform}"
|
46
|
+
|
47
|
+
puts "looking for #{name_glob} in #{path.inspect}"
|
48
|
+
|
49
|
+
paths = path.map { |p| Dir.glob(File.join(p, 'specifications', name_glob + '.gemspec')) }.flatten
|
51
50
|
|
52
|
-
|
53
|
-
puts "#{
|
51
|
+
if paths.empty?
|
52
|
+
puts "#{name_glob} not found in #{path.inspect}"
|
54
53
|
return
|
55
54
|
end
|
56
55
|
|
57
|
-
|
56
|
+
specs = paths.map { |p| [p, eval(File.read(p))] }
|
57
|
+
.select { |_, spec| Gem::Requirement.new(libv8_requirement).satisfied_by?(spec.version) }
|
58
|
+
found_path, found_spec = specs.sort_by { |_, spec| spec.version }.last
|
58
59
|
|
59
|
-
|
60
|
+
unless found_path && found_spec
|
61
|
+
puts "not found in specs: no '#{libv8_requirement}' in #{paths.inspect}"
|
62
|
+
return
|
63
|
+
end
|
64
|
+
|
65
|
+
puts "found in specs: #{found_path}"
|
66
|
+
|
67
|
+
gemdir = File.basename(found_path, '.gemspec')
|
68
|
+
dir = File.expand_path(File.join(found_path, '..', '..', 'gems', gemdir))
|
60
69
|
|
61
70
|
unless Dir.exist?(dir)
|
62
|
-
puts "not found in
|
71
|
+
puts "not found in gems: #{dir}"
|
63
72
|
return
|
64
73
|
end
|
65
74
|
|
66
|
-
puts "found in
|
75
|
+
puts "found in gems: #{dir}"
|
67
76
|
|
68
|
-
dir
|
77
|
+
[dir, found_spec]
|
69
78
|
end
|
70
79
|
|
71
80
|
def vendor_path
|
@@ -73,26 +82,12 @@ def vendor_path
|
|
73
82
|
end
|
74
83
|
|
75
84
|
def libv8_vendor_path
|
76
|
-
|
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
|
85
|
+
libv8_local_path([vendor_path])
|
91
86
|
end
|
92
87
|
|
93
88
|
def parse_platform(str)
|
94
89
|
Gem::Platform.new(str).tap do |p|
|
95
|
-
p.instance_eval { @
|
90
|
+
p.instance_eval { @version = 'musl' } if str =~ /-musl/ && p.version.nil?
|
96
91
|
p.instance_eval { @cpu = 'x86_64' } if str =~ /universal.*darwin/
|
97
92
|
end
|
98
93
|
end
|
@@ -116,21 +111,23 @@ def libv8_remote_search
|
|
116
111
|
json = JSON.parse(body)
|
117
112
|
|
118
113
|
versions = json.select do |v|
|
119
|
-
Gem::Version.new(v['number'])
|
114
|
+
Gem::Requirement.new(libv8_requirement).satisfied_by?(Gem::Version.new(v['number']))
|
120
115
|
end
|
121
116
|
abort(<<-ERROR) if versions.empty?
|
122
|
-
ERROR: could not find #{
|
117
|
+
ERROR: could not find #{libv8_gem_name} (requirement #{libv8_requirement}) in rubygems.org
|
123
118
|
ERROR
|
124
119
|
|
125
120
|
platform_versions = versions.select do |v|
|
126
121
|
parse_platform(v['platform']) == ruby_platform unless v['platform'] =~ /universal.*darwin/
|
127
122
|
end
|
128
123
|
abort(<<-ERROR) if platform_versions.empty?
|
129
|
-
ERROR: found #{libv8_gem_name}
|
130
|
-
try "gem install #{libv8_gem_name}
|
124
|
+
ERROR: found gems matching #{libv8_gem_name}:'#{libv8_requirement}', but no binary for #{ruby_platform}
|
125
|
+
try "gem install #{libv8_gem_name}:'#{libv8_requirement}'" to attempt to build #{libv8_gem_name} from source
|
131
126
|
ERROR
|
132
127
|
|
133
|
-
platform_versions.
|
128
|
+
puts "found #{libv8_gem_name} for #{ruby_platform} on rubygems: #{platform_versions.map { |v| v['number'] }.join(', ')}"
|
129
|
+
|
130
|
+
platform_versions.sort_by { |v| Gem::Version.new(v['number']) }.last
|
134
131
|
end
|
135
132
|
|
136
133
|
def libv8_download_uri(name, version, platform)
|
@@ -142,19 +139,19 @@ def libv8_downloaded_gem(name, version, platform)
|
|
142
139
|
end
|
143
140
|
|
144
141
|
def libv8_download(name, version, platform)
|
145
|
-
FileUtils.mkdir_p(vendor_path)
|
142
|
+
FileUtils.mkdir_p(File.join(vendor_path, 'cache'))
|
146
143
|
body = http_get(libv8_download_uri(name, version, platform))
|
147
|
-
File.open(File.join(vendor_path, libv8_downloaded_gem(name, version, platform)), 'wb') { |f| f.write(body) }
|
144
|
+
File.open(File.join(vendor_path, 'cache', libv8_downloaded_gem(name, version, platform)), 'wb') { |f| f.write(body) }
|
148
145
|
end
|
149
146
|
|
150
147
|
def libv8_install!
|
151
|
-
cmd = "gem install #{libv8_gem_name} --version '#{
|
148
|
+
cmd = "gem install #{libv8_gem_name} --version '#{libv8_requirement}' --install-dir '#{vendor_path}'"
|
152
149
|
puts "installing #{libv8_gem_name} using `#{cmd}`"
|
153
150
|
rc = system(cmd)
|
154
151
|
|
155
152
|
abort(<<-ERROR) unless rc
|
156
|
-
ERROR: could not install #{libv8_gem_name}
|
157
|
-
try "gem install #{libv8_gem_name} -v '#{
|
153
|
+
ERROR: could not install #{libv8_gem_name}:#{libv8_requirement}
|
154
|
+
try "gem install #{libv8_gem_name} -v '#{libv8_requirement}'" to attempt to build libv8 from source
|
158
155
|
ERROR
|
159
156
|
|
160
157
|
libv8_local_path([vendor_path])
|
@@ -168,16 +165,21 @@ def libv8_vendor!
|
|
168
165
|
puts "downloading #{libv8_downloaded_gem(libv8_gem_name, version['number'], version['platform'])} to #{vendor_path}"
|
169
166
|
libv8_download(libv8_gem_name, version['number'], version['platform'])
|
170
167
|
|
171
|
-
package = Gem::Package.new(File.join(vendor_path, libv8_downloaded_gem(libv8_gem_name, version['number'], version['platform'])))
|
172
|
-
package.extract_files(File.join(vendor_path, File.basename(libv8_downloaded_gem(libv8_gem_name, version['number'], version['platform']), '.gem')))
|
168
|
+
package = Gem::Package.new(File.join(vendor_path, 'cache', libv8_downloaded_gem(libv8_gem_name, version['number'], version['platform'])))
|
169
|
+
package.extract_files(File.join(vendor_path, 'gems', File.basename(libv8_downloaded_gem(libv8_gem_name, version['number'], version['platform']), '.gem')))
|
170
|
+
FileUtils.mkdir_p(File.join(vendor_path, 'specifications'))
|
171
|
+
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) }
|
173
172
|
|
174
173
|
libv8_vendor_path
|
175
174
|
end
|
176
175
|
|
177
176
|
def ensure_libv8_load_path
|
178
|
-
puts "
|
177
|
+
puts "platform ruby:#{RUBY_PLATFORM} rubygems:#{Gem::Platform.new(RUBY_PLATFORM)} detected:#{ruby_platform}"
|
179
178
|
|
180
|
-
libv8_path = libv8_local_path
|
179
|
+
libv8_path, spec = libv8_local_path
|
180
|
+
if !ENV['ONLY_INSTALLED_LIBV8_GEM'] && !libv8_path
|
181
|
+
libv8_path, spec = libv8_vendor_path || libv8_vendor!
|
182
|
+
end
|
181
183
|
|
182
184
|
abort(<<-ERROR) unless libv8_path
|
183
185
|
ERROR: could not find #{libv8_gem_name}
|
@@ -189,7 +191,7 @@ end
|
|
189
191
|
|
190
192
|
ensure_libv8_load_path
|
191
193
|
|
192
|
-
require 'libv8'
|
194
|
+
require 'libv8-node'
|
193
195
|
|
194
196
|
IS_DARWIN = RUBY_PLATFORM =~ /darwin/
|
195
197
|
|
@@ -202,17 +204,24 @@ $CPPFLAGS += " -rdynamic" unless $CPPFLAGS.split.include? "-rdynamic"
|
|
202
204
|
$CPPFLAGS += " -fPIC" unless $CPPFLAGS.split.include? "-rdynamic" or IS_DARWIN
|
203
205
|
$CPPFLAGS += " -std=c++0x"
|
204
206
|
$CPPFLAGS += " -fpermissive"
|
207
|
+
$CPPFLAGS += " -DV8_COMPRESS_POINTERS"
|
208
|
+
$CPPFLAGS += " -fvisibility=hidden "
|
205
209
|
cppflags_add_frame_pointer!
|
206
210
|
cppflags_add_cpu_extension!
|
207
211
|
|
208
212
|
$CPPFLAGS += " -Wno-reserved-user-defined-literal" if IS_DARWIN
|
209
213
|
|
210
214
|
$LDFLAGS.insert(0, " -stdlib=libc++ ") if IS_DARWIN
|
215
|
+
$LDFLAGS += " -Wl,--no-undefined " unless IS_DARWIN
|
216
|
+
$LDFLAGS += " -Wl,-undefined,error " if IS_DARWIN
|
211
217
|
|
212
218
|
if ENV['CXX']
|
213
219
|
puts "SETTING CXX"
|
214
220
|
CONFIG['CXX'] = ENV['CXX']
|
215
221
|
end
|
222
|
+
# 1.9 has no $CXXFLAGS
|
223
|
+
$CPPFLAGS += " #{ENV['CPPFLAGS']}" if ENV['CPPFLAGS']
|
224
|
+
$LDFLAGS += " #{ENV['LDFLAGS']}" if ENV['LDFLAGS']
|
216
225
|
|
217
226
|
CXX11_TEST = <<EOS
|
218
227
|
#if __cplusplus <= 199711L
|
@@ -246,7 +255,7 @@ if enable_config('debug') || enable_config('asan')
|
|
246
255
|
CONFIG['debugflags'] << ' -ggdb3 -O0'
|
247
256
|
end
|
248
257
|
|
249
|
-
Libv8.configure_makefile
|
258
|
+
Libv8::Node.configure_makefile
|
250
259
|
|
251
260
|
if enable_config('asan')
|
252
261
|
$CPPFLAGS.insert(0, " -fsanitize=address ")
|
@@ -34,7 +34,11 @@
|
|
34
34
|
#include <atomic>
|
35
35
|
#include <math.h>
|
36
36
|
#include "compat.hpp"
|
37
|
+
#ifdef __x86_64__
|
37
38
|
#include "simdutf8check.h"
|
39
|
+
#endif
|
40
|
+
|
41
|
+
#include <time.h>
|
38
42
|
|
39
43
|
using namespace v8;
|
40
44
|
|
@@ -49,6 +53,7 @@ public:
|
|
49
53
|
ArrayBuffer::Allocator* allocator;
|
50
54
|
StartupData* startup_data;
|
51
55
|
bool interrupted;
|
56
|
+
bool added_gc_cb;
|
52
57
|
pid_t pid;
|
53
58
|
VALUE mutex;
|
54
59
|
|
@@ -66,15 +71,12 @@ public:
|
|
66
71
|
|
67
72
|
|
68
73
|
IsolateInfo() : isolate(nullptr), allocator(nullptr), startup_data(nullptr),
|
69
|
-
interrupted(false), pid(getpid()), refs_count(0) {
|
74
|
+
interrupted(false), added_gc_cb(false), pid(getpid()), refs_count(0) {
|
70
75
|
VALUE cMutex = rb_const_get(rb_cThread, rb_intern("Mutex"));
|
71
76
|
mutex = rb_class_new_instance(0, nullptr, cMutex);
|
72
77
|
}
|
73
78
|
|
74
|
-
~IsolateInfo()
|
75
|
-
void free_isolate(IsolateInfo*);
|
76
|
-
free_isolate(this);
|
77
|
-
}
|
79
|
+
~IsolateInfo();
|
78
80
|
|
79
81
|
void init(SnapshotInfo* snapshot_info = nullptr);
|
80
82
|
|
@@ -151,6 +153,7 @@ typedef struct {
|
|
151
153
|
Local<Function> fun;
|
152
154
|
Local<Value> *argv;
|
153
155
|
EvalResult result;
|
156
|
+
size_t max_memory;
|
154
157
|
} FunctionCall;
|
155
158
|
|
156
159
|
enum IsolateFlags {
|
@@ -179,6 +182,11 @@ static VALUE rb_cDateTime = Qnil;
|
|
179
182
|
static std::unique_ptr<Platform> current_platform = NULL;
|
180
183
|
static std::mutex platform_lock;
|
181
184
|
|
185
|
+
static pthread_attr_t *thread_attr_p;
|
186
|
+
static pthread_rwlock_t exit_lock = PTHREAD_RWLOCK_INITIALIZER;
|
187
|
+
static bool ruby_exiting = false; // guarded by exit_lock
|
188
|
+
static bool single_threaded = false;
|
189
|
+
|
182
190
|
static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) {
|
183
191
|
bool platform_already_initialized = false;
|
184
192
|
|
@@ -190,6 +198,9 @@ static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) {
|
|
190
198
|
platform_lock.lock();
|
191
199
|
|
192
200
|
if (current_platform == NULL) {
|
201
|
+
if (!strcmp(RSTRING_PTR(flag_as_str), "--single_threaded")) {
|
202
|
+
single_threaded = true;
|
203
|
+
}
|
193
204
|
V8::SetFlagsFromString(RSTRING_PTR(flag_as_str), (int)RSTRING_LEN(flag_as_str));
|
194
205
|
} else {
|
195
206
|
platform_already_initialized = true;
|
@@ -256,11 +267,13 @@ static void prepare_result(MaybeLocal<Value> v8res,
|
|
256
267
|
Local<Value> local_value = v8res.ToLocalChecked();
|
257
268
|
if ((local_value->IsObject() || local_value->IsArray()) &&
|
258
269
|
!local_value->IsDate() && !local_value->IsFunction()) {
|
259
|
-
Local<Object> JSON = context->Global()->Get(
|
260
|
-
|
270
|
+
Local<Object> JSON = context->Global()->Get(
|
271
|
+
context, String::NewFromUtf8Literal(isolate, "JSON"))
|
272
|
+
.ToLocalChecked().As<Object>();
|
261
273
|
|
262
|
-
Local<Function> stringify = JSON->Get(
|
263
|
-
|
274
|
+
Local<Function> stringify = JSON->Get(
|
275
|
+
context, v8::String::NewFromUtf8Literal(isolate, "stringify"))
|
276
|
+
.ToLocalChecked().As<Function>();
|
264
277
|
|
265
278
|
Local<Object> object = local_value->ToObject(context).ToLocalChecked();
|
266
279
|
const unsigned argc = 1;
|
@@ -314,7 +327,7 @@ static void prepare_result(MaybeLocal<Value> v8res,
|
|
314
327
|
} else if(trycatch.HasTerminated()) {
|
315
328
|
evalRes.terminated = true;
|
316
329
|
evalRes.message = new Persistent<Value>();
|
317
|
-
Local<String> tmp = String::
|
330
|
+
Local<String> tmp = String::NewFromUtf8Literal(isolate, "JavaScript was terminated (either by timeout or explicitly)");
|
318
331
|
evalRes.message->Reset(isolate, tmp);
|
319
332
|
}
|
320
333
|
if (!trycatch.StackTrace(context).IsEmpty()) {
|
@@ -335,7 +348,8 @@ nogvl_context_eval(void* arg) {
|
|
335
348
|
|
336
349
|
EvalParams* eval_params = (EvalParams*)arg;
|
337
350
|
EvalResult* result = eval_params->result;
|
338
|
-
|
351
|
+
IsolateInfo* isolate_info = eval_params->context_info->isolate_info;
|
352
|
+
Isolate* isolate = isolate_info->isolate;
|
339
353
|
|
340
354
|
Isolate::Scope isolate_scope(isolate);
|
341
355
|
HandleScope handle_scope(isolate);
|
@@ -379,7 +393,10 @@ nogvl_context_eval(void* arg) {
|
|
379
393
|
// parsing successful
|
380
394
|
if (eval_params->max_memory > 0) {
|
381
395
|
isolate->SetData(MEM_SOFTLIMIT_VALUE, &eval_params->max_memory);
|
396
|
+
if (!isolate_info->added_gc_cb) {
|
382
397
|
isolate->AddGCEpilogueCallback(gc_callback);
|
398
|
+
isolate_info->added_gc_cb = true;
|
399
|
+
}
|
383
400
|
}
|
384
401
|
|
385
402
|
maybe_value = parsed_script.ToLocalChecked()->Run(context);
|
@@ -392,6 +409,12 @@ nogvl_context_eval(void* arg) {
|
|
392
409
|
return 0;
|
393
410
|
}
|
394
411
|
|
412
|
+
static VALUE new_empty_failed_conv_obj() {
|
413
|
+
// TODO isolate code that translates execption to ruby
|
414
|
+
// exception so we can properly return it
|
415
|
+
return rb_funcall(rb_cFailedV8Conversion, rb_intern("new"), 1, rb_str_new2(""));
|
416
|
+
}
|
417
|
+
|
395
418
|
// assumes isolate locking is in place
|
396
419
|
static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
|
397
420
|
Local<Value> value) {
|
@@ -423,8 +446,11 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
|
|
423
446
|
VALUE rb_array = rb_ary_new();
|
424
447
|
Local<Array> arr = Local<Array>::Cast(value);
|
425
448
|
for(uint32_t i=0; i < arr->Length(); i++) {
|
426
|
-
|
427
|
-
|
449
|
+
MaybeLocal<Value> element = arr->Get(context, i);
|
450
|
+
if (element.IsEmpty()) {
|
451
|
+
continue;
|
452
|
+
}
|
453
|
+
VALUE rb_elem = convert_v8_to_ruby(isolate, context, element.ToLocalChecked());
|
428
454
|
if (rb_funcall(rb_elem, rb_intern("class"), 0) == rb_cFailedV8Conversion) {
|
429
455
|
return rb_elem;
|
430
456
|
}
|
@@ -454,26 +480,47 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
|
|
454
480
|
if (!maybe_props.IsEmpty()) {
|
455
481
|
Local<Array> props = maybe_props.ToLocalChecked();
|
456
482
|
for(uint32_t i=0; i < props->Length(); i++) {
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
483
|
+
MaybeLocal<Value> key = props->Get(context, i);
|
484
|
+
if (key.IsEmpty()) {
|
485
|
+
return rb_funcall(rb_cFailedV8Conversion, rb_intern("new"), 1, rb_str_new2(""));
|
486
|
+
}
|
487
|
+
VALUE rb_key = convert_v8_to_ruby(isolate, context, key.ToLocalChecked());
|
461
488
|
|
462
|
-
|
463
|
-
//
|
464
|
-
|
465
|
-
|
489
|
+
MaybeLocal<Value> prop_value = object->Get(context, key.ToLocalChecked());
|
490
|
+
// this may have failed due to Get raising
|
491
|
+
if (prop_value.IsEmpty() || trycatch.HasCaught()) {
|
492
|
+
return new_empty_failed_conv_obj();
|
466
493
|
}
|
467
494
|
|
468
|
-
VALUE rb_value = convert_v8_to_ruby(
|
495
|
+
VALUE rb_value = convert_v8_to_ruby(
|
496
|
+
isolate, context, prop_value.ToLocalChecked());
|
469
497
|
rb_hash_aset(rb_hash, rb_key, rb_value);
|
470
498
|
}
|
471
499
|
}
|
472
500
|
return rb_hash;
|
473
501
|
}
|
474
502
|
|
475
|
-
|
476
|
-
|
503
|
+
if (value->IsSymbol()) {
|
504
|
+
v8::String::Utf8Value symbol_name(isolate,
|
505
|
+
Local<Symbol>::Cast(value)->Name());
|
506
|
+
|
507
|
+
VALUE str_symbol = rb_enc_str_new(
|
508
|
+
*symbol_name,
|
509
|
+
symbol_name.length(),
|
510
|
+
rb_enc_find("utf-8")
|
511
|
+
);
|
512
|
+
|
513
|
+
return ID2SYM(rb_intern_str(str_symbol));
|
514
|
+
}
|
515
|
+
|
516
|
+
MaybeLocal<String> rstr_maybe = value->ToString(context);
|
517
|
+
|
518
|
+
if (rstr_maybe.IsEmpty()) {
|
519
|
+
return Qnil;
|
520
|
+
} else {
|
521
|
+
Local<String> rstr = rstr_maybe.ToLocalChecked();
|
522
|
+
return rb_enc_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate), rb_enc_find("utf-8"));
|
523
|
+
}
|
477
524
|
}
|
478
525
|
|
479
526
|
static VALUE convert_v8_to_ruby(Isolate* isolate,
|
@@ -519,11 +566,13 @@ static inline Local<Value> convert_ruby_str_to_v8(
|
|
519
566
|
static const rb_encoding *usascii_enc = rb_usascii_encoding();
|
520
567
|
static const rb_encoding *latin1_enc = rb_enc_find("ISO-8859-1");
|
521
568
|
assert(latin1_enc != nullptr);
|
569
|
+
#ifdef __x86_64__
|
522
570
|
#ifndef __AVX2__
|
523
571
|
# define validate_utf8 validate_utf8_fast
|
524
572
|
#else
|
525
573
|
static const (*validate_utf8)(const char *, size_t) =
|
526
574
|
best_utf8_validate_func();
|
575
|
+
#endif
|
527
576
|
#endif
|
528
577
|
|
529
578
|
rb_encoding *enc = rb_enc_get(value);
|
@@ -532,8 +581,12 @@ static inline Local<Value> convert_ruby_str_to_v8(
|
|
532
581
|
if (len < 0 || len > INT_MAX) {
|
533
582
|
return Null(isolate);
|
534
583
|
}
|
584
|
+
#ifdef __x86_64__
|
535
585
|
bool is_valid_utf8 = enc == utf8_enc &&
|
536
586
|
validate_utf8(str, static_cast<size_t>(len));
|
587
|
+
#else
|
588
|
+
bool is_valid_utf8 = false;
|
589
|
+
#endif
|
537
590
|
|
538
591
|
MaybeLocal<String> v8str;
|
539
592
|
int int_len = static_cast<int>(len);
|
@@ -596,7 +649,11 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context,
|
|
596
649
|
case T_FLOAT:
|
597
650
|
return scope.Escape(Number::New(isolate, NUM2DBL(value)));
|
598
651
|
case T_STRING:
|
599
|
-
|
652
|
+
//#ifndef __x86_64__
|
653
|
+
// return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, (int)RSTRING_LEN(value)).ToLocalChecked());
|
654
|
+
//#else
|
655
|
+
return scope.Escape(convert_ruby_str_to_v8(scope, isolate, value));
|
656
|
+
//#endif
|
600
657
|
case T_NIL:
|
601
658
|
return scope.Escape(Null(isolate));
|
602
659
|
case T_TRUE:
|
@@ -608,7 +665,7 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context,
|
|
608
665
|
length = RARRAY_LEN(value);
|
609
666
|
array = Array::New(isolate, (int)length);
|
610
667
|
for(i=0; i<length; i++) {
|
611
|
-
|
668
|
+
array->Set(context, i, convert_ruby_to_v8(isolate, context, rb_ary_entry(value, i)));
|
612
669
|
}
|
613
670
|
return scope.Escape(array);
|
614
671
|
}
|
@@ -619,7 +676,7 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context,
|
|
619
676
|
length = RARRAY_LEN(hash_as_array);
|
620
677
|
for(i=0; i<length; i++) {
|
621
678
|
pair = rb_ary_entry(hash_as_array, i);
|
622
|
-
|
679
|
+
object->Set(context, convert_ruby_to_v8(isolate, context, rb_ary_entry(pair, 0)),
|
623
680
|
convert_ruby_to_v8(isolate, context, rb_ary_entry(pair, 1)));
|
624
681
|
}
|
625
682
|
return scope.Escape(object);
|
@@ -627,7 +684,11 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context,
|
|
627
684
|
case T_SYMBOL:
|
628
685
|
{
|
629
686
|
value = rb_funcall(value, rb_intern("to_s"), 0);
|
630
|
-
|
687
|
+
//#ifndef __x86_64__
|
688
|
+
// return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, (int)RSTRING_LEN(value)).ToLocalChecked());
|
689
|
+
//#else
|
690
|
+
return scope.Escape(convert_ruby_str_to_v8(scope, isolate, value));
|
691
|
+
//#endif
|
631
692
|
}
|
632
693
|
case T_DATA:
|
633
694
|
{
|
@@ -659,10 +720,15 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context,
|
|
659
720
|
if (rb_respond_to(value, rb_intern("to_s"))) {
|
660
721
|
// TODO: if this throws we're screwed
|
661
722
|
value = rb_funcall(value, rb_intern("to_s"), 0);
|
723
|
+
//#ifndef __x86_64__
|
724
|
+
// return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, (int)RSTRING_LEN(value)).ToLocalChecked());
|
725
|
+
//#else
|
662
726
|
return scope.Escape(convert_ruby_str_to_v8(scope, isolate, value));
|
727
|
+
//#endif
|
663
728
|
}
|
664
|
-
|
665
|
-
|
729
|
+
return scope.Escape(
|
730
|
+
String::NewFromUtf8Literal(isolate, "Undefined Conversion"));
|
731
|
+
}
|
666
732
|
}
|
667
733
|
}
|
668
734
|
|
@@ -675,53 +741,43 @@ static void unblock_eval(void *ptr) {
|
|
675
741
|
* The implementations of the run_extra_code(), create_snapshot_data_blob() and
|
676
742
|
* warm_up_snapshot_data_blob() functions have been derived from V8's test suite.
|
677
743
|
*/
|
678
|
-
bool run_extra_code(Isolate *isolate, Local<v8::Context> context,
|
744
|
+
static bool run_extra_code(Isolate *isolate, Local<v8::Context> context,
|
679
745
|
const char *utf8_source, const char *name) {
|
680
746
|
Context::Scope context_scope(context);
|
681
747
|
TryCatch try_catch(isolate);
|
682
748
|
Local<String> source_string;
|
683
|
-
if (!String::NewFromUtf8(isolate, utf8_source
|
684
|
-
NewStringType::kNormal)
|
685
|
-
.ToLocal(&source_string)) {
|
749
|
+
if (!String::NewFromUtf8(isolate, utf8_source).ToLocal(&source_string)) {
|
686
750
|
return false;
|
687
751
|
}
|
688
|
-
Local<
|
689
|
-
|
690
|
-
.ToLocalChecked();
|
752
|
+
Local<String> resource_name =
|
753
|
+
String::NewFromUtf8(isolate, name).ToLocalChecked();
|
691
754
|
ScriptOrigin origin(resource_name);
|
692
755
|
ScriptCompiler::Source source(source_string, origin);
|
693
756
|
Local<Script> script;
|
694
757
|
if (!ScriptCompiler::Compile(context, &source).ToLocal(&script))
|
695
758
|
return false;
|
696
|
-
if (script->Run(context).IsEmpty())
|
697
|
-
return false;
|
698
|
-
// CHECK(!try_catch.HasCaught());
|
759
|
+
if (script->Run(context).IsEmpty()) return false;
|
699
760
|
return true;
|
700
761
|
}
|
701
762
|
|
702
|
-
StartupData
|
763
|
+
static StartupData
|
703
764
|
create_snapshot_data_blob(const char *embedded_source = nullptr) {
|
704
|
-
|
705
|
-
|
706
|
-
|
765
|
+
Isolate *isolate = Isolate::Allocate();
|
766
|
+
|
767
|
+
// Optionally run a script to embed, and serialize to create a snapshot blob.
|
768
|
+
SnapshotCreator snapshot_creator(isolate);
|
707
769
|
{
|
708
|
-
SnapshotCreator snapshot_creator;
|
709
|
-
Isolate *isolate = snapshot_creator.GetIsolate();
|
710
|
-
{
|
711
770
|
HandleScope scope(isolate);
|
712
|
-
|
771
|
+
Local<v8::Context> context = v8::Context::New(isolate);
|
713
772
|
if (embedded_source != nullptr &&
|
714
|
-
!run_extra_code(isolate, context, embedded_source,
|
715
|
-
|
716
|
-
return result;
|
773
|
+
!run_extra_code(isolate, context, embedded_source, "<embedded>")) {
|
774
|
+
return {};
|
717
775
|
}
|
718
776
|
snapshot_creator.SetDefaultContext(context);
|
719
777
|
}
|
720
|
-
|
778
|
+
return snapshot_creator.CreateBlob(
|
721
779
|
SnapshotCreator::FunctionCodeHandling::kClear);
|
722
780
|
}
|
723
|
-
return result;
|
724
|
-
}
|
725
781
|
|
726
782
|
StartupData warm_up_snapshot_data_blob(StartupData cold_snapshot_blob,
|
727
783
|
const char *warmup_source) {
|
@@ -868,6 +924,29 @@ static VALUE rb_isolate_idle_notification(VALUE self, VALUE idle_time_in_ms) {
|
|
868
924
|
return isolate_info->isolate->IdleNotificationDeadline(now + duration) ? Qtrue : Qfalse;
|
869
925
|
}
|
870
926
|
|
927
|
+
static VALUE rb_isolate_low_memory_notification(VALUE self) {
|
928
|
+
IsolateInfo* isolate_info;
|
929
|
+
Data_Get_Struct(self, IsolateInfo, isolate_info);
|
930
|
+
|
931
|
+
if (current_platform == NULL) return Qfalse;
|
932
|
+
|
933
|
+
isolate_info->isolate->LowMemoryNotification();
|
934
|
+
return Qnil;
|
935
|
+
}
|
936
|
+
|
937
|
+
static VALUE rb_isolate_pump_message_loop(VALUE self) {
|
938
|
+
IsolateInfo* isolate_info;
|
939
|
+
Data_Get_Struct(self, IsolateInfo, isolate_info);
|
940
|
+
|
941
|
+
if (current_platform == NULL) return Qfalse;
|
942
|
+
|
943
|
+
if (platform::PumpMessageLoop(current_platform.get(), isolate_info->isolate)){
|
944
|
+
return Qtrue;
|
945
|
+
} else {
|
946
|
+
return Qfalse;
|
947
|
+
}
|
948
|
+
}
|
949
|
+
|
871
950
|
static VALUE rb_context_init_unsafe(VALUE self, VALUE isolate, VALUE snap) {
|
872
951
|
ContextInfo* context_info;
|
873
952
|
Data_Get_Struct(self, ContextInfo, context_info);
|
@@ -1142,7 +1221,9 @@ gvl_ruby_callback(void* data) {
|
|
1142
1221
|
callback_data.failed = false;
|
1143
1222
|
|
1144
1223
|
if ((bool)args->GetIsolate()->GetData(DO_TERMINATE) == true) {
|
1145
|
-
args->GetIsolate()->ThrowException(
|
1224
|
+
args->GetIsolate()->ThrowException(
|
1225
|
+
String::NewFromUtf8Literal(args->GetIsolate(),
|
1226
|
+
"Terminated execution during transition from Ruby to JS"));
|
1146
1227
|
args->GetIsolate()->TerminateExecution();
|
1147
1228
|
if (length > 0) {
|
1148
1229
|
rb_ary_clear(ruby_args);
|
@@ -1156,7 +1237,7 @@ gvl_ruby_callback(void* data) {
|
|
1156
1237
|
|
1157
1238
|
if(callback_data.failed) {
|
1158
1239
|
rb_iv_set(parent, "@current_exception", result);
|
1159
|
-
args->GetIsolate()->ThrowException(String::
|
1240
|
+
args->GetIsolate()->ThrowException(String::NewFromUtf8Literal(args->GetIsolate(), "Ruby exception"));
|
1160
1241
|
}
|
1161
1242
|
else {
|
1162
1243
|
HandleScope scope(args->GetIsolate());
|
@@ -1231,7 +1312,9 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
1231
1312
|
|
1232
1313
|
if (parent_object == Qnil) {
|
1233
1314
|
context->Global()->Set(
|
1234
|
-
|
1315
|
+
context,
|
1316
|
+
v8_str,
|
1317
|
+
FunctionTemplate::New(isolate, ruby_callback, external)
|
1235
1318
|
->GetFunction(context)
|
1236
1319
|
.ToLocalChecked());
|
1237
1320
|
|
@@ -1244,7 +1327,7 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
1244
1327
|
|
1245
1328
|
MaybeLocal<Script> parsed_script = Script::Compile(context, eval);
|
1246
1329
|
if (parsed_script.IsEmpty()) {
|
1247
|
-
|
1330
|
+
parse_error = true;
|
1248
1331
|
} else {
|
1249
1332
|
MaybeLocal<Value> maybe_value =
|
1250
1333
|
parsed_script.ToLocalChecked()->Run(context);
|
@@ -1254,11 +1337,12 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
1254
1337
|
Local<Value> value = maybe_value.ToLocalChecked();
|
1255
1338
|
if (value->IsObject()) {
|
1256
1339
|
value.As<Object>()->Set(
|
1257
|
-
|
1258
|
-
|
1340
|
+
context,
|
1341
|
+
v8_str,
|
1342
|
+
FunctionTemplate::New(isolate, ruby_callback, external)
|
1259
1343
|
->GetFunction(context)
|
1260
1344
|
.ToLocalChecked());
|
1261
|
-
|
1345
|
+
attach_error = false;
|
1262
1346
|
}
|
1263
1347
|
}
|
1264
1348
|
}
|
@@ -1288,35 +1372,39 @@ static VALUE rb_context_isolate_mutex(VALUE self) {
|
|
1288
1372
|
return context_info->isolate_info->mutex;
|
1289
1373
|
}
|
1290
1374
|
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
if (isolate_info->isolate) {
|
1298
|
-
if (isolate_info->interrupted) {
|
1299
|
-
fprintf(stderr, "WARNING: V8 isolate was interrupted by Ruby, it can not be disposed and memory will not be reclaimed till the Ruby process exits.\n");
|
1375
|
+
IsolateInfo::~IsolateInfo() {
|
1376
|
+
if (isolate) {
|
1377
|
+
if (this->interrupted) {
|
1378
|
+
fprintf(stderr, "WARNING: V8 isolate was interrupted by Ruby, "
|
1379
|
+
"it can not be disposed and memory will not be "
|
1380
|
+
"reclaimed till the Ruby process exits.\n");
|
1300
1381
|
} else {
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1382
|
+
if (this->pid != getpid() && !single_threaded) {
|
1383
|
+
fprintf(stderr, "WARNING: V8 isolate was forked, "
|
1384
|
+
"it can not be disposed and "
|
1385
|
+
"memory will not be reclaimed "
|
1386
|
+
"till the Ruby process exits.\n"
|
1387
|
+
"It is VERY likely your process will hang.\n"
|
1388
|
+
"If you wish to use v8 in forked environment "
|
1389
|
+
"please ensure the platform is initialized with:\n"
|
1390
|
+
"MiniRacer::Platform.set_flags! :single_threaded\n"
|
1391
|
+
);
|
1304
1392
|
} else {
|
1305
|
-
|
1393
|
+
isolate->Dispose();
|
1306
1394
|
}
|
1307
1395
|
}
|
1308
|
-
|
1396
|
+
isolate = nullptr;
|
1309
1397
|
}
|
1310
1398
|
|
1311
|
-
if (
|
1312
|
-
delete[]
|
1313
|
-
delete
|
1399
|
+
if (startup_data) {
|
1400
|
+
delete[] startup_data->data;
|
1401
|
+
delete startup_data;
|
1314
1402
|
}
|
1315
1403
|
|
1316
|
-
delete
|
1404
|
+
delete allocator;
|
1317
1405
|
}
|
1318
1406
|
|
1319
|
-
static void
|
1407
|
+
static void free_context_raw(void *arg) {
|
1320
1408
|
ContextInfo* context_info = (ContextInfo*)arg;
|
1321
1409
|
IsolateInfo* isolate_info = context_info->isolate_info;
|
1322
1410
|
Persistent<Context>* context = context_info->context;
|
@@ -1333,6 +1421,20 @@ static void *free_context_raw(void* arg) {
|
|
1333
1421
|
}
|
1334
1422
|
|
1335
1423
|
xfree(context_info);
|
1424
|
+
}
|
1425
|
+
|
1426
|
+
static void *free_context_thr(void* arg) {
|
1427
|
+
if (pthread_rwlock_tryrdlock(&exit_lock) != 0) {
|
1428
|
+
return NULL;
|
1429
|
+
}
|
1430
|
+
if (ruby_exiting) {
|
1431
|
+
return NULL;
|
1432
|
+
}
|
1433
|
+
|
1434
|
+
free_context_raw(arg);
|
1435
|
+
|
1436
|
+
pthread_rwlock_unlock(&exit_lock);
|
1437
|
+
|
1336
1438
|
return NULL;
|
1337
1439
|
}
|
1338
1440
|
|
@@ -1347,22 +1449,17 @@ static void free_context(ContextInfo* context_info) {
|
|
1347
1449
|
|
1348
1450
|
if (isolate_info && isolate_info->refs() > 1) {
|
1349
1451
|
pthread_t free_context_thread;
|
1350
|
-
|
1452
|
+
if (pthread_create(&free_context_thread, thread_attr_p,
|
1453
|
+
free_context_thr, (void*)context_info_copy)) {
|
1351
1454
|
fprintf(stderr, "WARNING failed to release memory in MiniRacer, thread to release could not be created, process will leak memory\n");
|
1352
1455
|
}
|
1353
|
-
|
1354
1456
|
} else {
|
1355
1457
|
free_context_raw(context_info_copy);
|
1356
1458
|
}
|
1357
1459
|
|
1358
|
-
if (context_info->context && isolate_info && isolate_info->isolate) {
|
1359
1460
|
context_info->context = NULL;
|
1360
|
-
}
|
1361
|
-
|
1362
|
-
if (isolate_info) {
|
1363
1461
|
context_info->isolate_info = NULL;
|
1364
1462
|
}
|
1365
|
-
}
|
1366
1463
|
|
1367
1464
|
static void deallocate_isolate(void* data) {
|
1368
1465
|
|
@@ -1376,7 +1473,7 @@ static void mark_isolate(void* data) {
|
|
1376
1473
|
isolate_info->mark();
|
1377
1474
|
}
|
1378
1475
|
|
1379
|
-
void deallocate(void* data) {
|
1476
|
+
static void deallocate(void* data) {
|
1380
1477
|
ContextInfo* context_info = (ContextInfo*)data;
|
1381
1478
|
|
1382
1479
|
free_context(context_info);
|
@@ -1391,22 +1488,22 @@ static void mark_context(void* data) {
|
|
1391
1488
|
}
|
1392
1489
|
}
|
1393
1490
|
|
1394
|
-
void deallocate_external_function(void * data) {
|
1491
|
+
static void deallocate_external_function(void * data) {
|
1395
1492
|
xfree(data);
|
1396
1493
|
}
|
1397
1494
|
|
1398
|
-
void deallocate_snapshot(void * data) {
|
1495
|
+
static void deallocate_snapshot(void * data) {
|
1399
1496
|
SnapshotInfo* snapshot_info = (SnapshotInfo*)data;
|
1400
1497
|
delete[] snapshot_info->data;
|
1401
1498
|
xfree(snapshot_info);
|
1402
1499
|
}
|
1403
1500
|
|
1404
|
-
VALUE allocate_external_function(VALUE klass) {
|
1501
|
+
static VALUE allocate_external_function(VALUE klass) {
|
1405
1502
|
VALUE* self = ALLOC(VALUE);
|
1406
1503
|
return Data_Wrap_Struct(klass, NULL, deallocate_external_function, (void*)self);
|
1407
1504
|
}
|
1408
1505
|
|
1409
|
-
VALUE allocate(VALUE klass) {
|
1506
|
+
static VALUE allocate(VALUE klass) {
|
1410
1507
|
ContextInfo* context_info = ALLOC(ContextInfo);
|
1411
1508
|
context_info->isolate_info = NULL;
|
1412
1509
|
context_info->context = NULL;
|
@@ -1414,7 +1511,7 @@ VALUE allocate(VALUE klass) {
|
|
1414
1511
|
return Data_Wrap_Struct(klass, mark_context, deallocate, (void*)context_info);
|
1415
1512
|
}
|
1416
1513
|
|
1417
|
-
VALUE allocate_snapshot(VALUE klass) {
|
1514
|
+
static VALUE allocate_snapshot(VALUE klass) {
|
1418
1515
|
SnapshotInfo* snapshot_info = ALLOC(SnapshotInfo);
|
1419
1516
|
snapshot_info->data = NULL;
|
1420
1517
|
snapshot_info->raw_size = 0;
|
@@ -1422,7 +1519,7 @@ VALUE allocate_snapshot(VALUE klass) {
|
|
1422
1519
|
return Data_Wrap_Struct(klass, NULL, deallocate_snapshot, (void*)snapshot_info);
|
1423
1520
|
}
|
1424
1521
|
|
1425
|
-
VALUE allocate_isolate(VALUE klass) {
|
1522
|
+
static VALUE allocate_isolate(VALUE klass) {
|
1426
1523
|
IsolateInfo* isolate_info = new IsolateInfo();
|
1427
1524
|
|
1428
1525
|
return Data_Wrap_Struct(klass, mark_isolate, deallocate_isolate, (void*)isolate_info);
|
@@ -1519,6 +1616,8 @@ rb_heap_snapshot(VALUE self, VALUE file) {
|
|
1519
1616
|
FileOutputStream stream(fp);
|
1520
1617
|
snap->Serialize(&stream, HeapSnapshot::kJSON);
|
1521
1618
|
|
1619
|
+
fflush(fp);
|
1620
|
+
|
1522
1621
|
const_cast<HeapSnapshot*>(snap)->Delete();
|
1523
1622
|
|
1524
1623
|
return Qtrue;
|
@@ -1576,13 +1675,23 @@ nogvl_context_call(void *args) {
|
|
1576
1675
|
if (!call) {
|
1577
1676
|
return 0;
|
1578
1677
|
}
|
1579
|
-
|
1678
|
+
IsolateInfo *isolate_info = call->context_info->isolate_info;
|
1679
|
+
Isolate* isolate = isolate_info->isolate;
|
1580
1680
|
|
1581
1681
|
// in gvl flag
|
1582
1682
|
isolate->SetData(IN_GVL, (void*)false);
|
1583
1683
|
// terminate ASAP
|
1584
1684
|
isolate->SetData(DO_TERMINATE, (void*)false);
|
1585
1685
|
|
1686
|
+
if (call->max_memory > 0) {
|
1687
|
+
isolate->SetData(MEM_SOFTLIMIT_VALUE, &call->max_memory);
|
1688
|
+
isolate->SetData(MEM_SOFTLIMIT_REACHED, (void*)false);
|
1689
|
+
if (!isolate_info->added_gc_cb) {
|
1690
|
+
isolate->AddGCEpilogueCallback(gc_callback);
|
1691
|
+
isolate_info->added_gc_cb = true;
|
1692
|
+
}
|
1693
|
+
}
|
1694
|
+
|
1586
1695
|
Isolate::Scope isolate_scope(isolate);
|
1587
1696
|
EscapableHandleScope handle_scope(isolate);
|
1588
1697
|
TryCatch trycatch(isolate);
|
@@ -1640,6 +1749,13 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
|
|
1640
1749
|
call_argv = argv + 1;
|
1641
1750
|
}
|
1642
1751
|
|
1752
|
+
call.max_memory = 0;
|
1753
|
+
VALUE mem_softlimit = rb_iv_get(self, "@max_memory");
|
1754
|
+
if (mem_softlimit != Qnil) {
|
1755
|
+
unsigned long sl_int = NUM2ULONG(mem_softlimit);
|
1756
|
+
call.max_memory = (size_t)sl_int;
|
1757
|
+
}
|
1758
|
+
|
1643
1759
|
bool missingFunction = false;
|
1644
1760
|
{
|
1645
1761
|
Locker lock(isolate);
|
@@ -1651,8 +1767,11 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
|
|
1651
1767
|
|
1652
1768
|
// examples of such usage can be found in
|
1653
1769
|
// https://github.com/v8/v8/blob/36b32aa28db5e993312f4588d60aad5c8330c8a5/test/cctest/test-api.cc#L15711
|
1654
|
-
|
1655
|
-
MaybeLocal<v8::Value> val
|
1770
|
+
MaybeLocal<String> fname = String::NewFromUtf8(isolate, call.function_name);
|
1771
|
+
MaybeLocal<v8::Value> val;
|
1772
|
+
if (!fname.IsEmpty()) {
|
1773
|
+
val = context->Global()->Get(context, fname.ToLocalChecked());
|
1774
|
+
}
|
1656
1775
|
|
1657
1776
|
if (val.IsEmpty() || !val.ToLocalChecked()->IsFunction()) {
|
1658
1777
|
missingFunction = true;
|
@@ -1701,12 +1820,44 @@ static VALUE rb_context_create_isolate_value(VALUE self) {
|
|
1701
1820
|
return Data_Wrap_Struct(rb_cIsolate, NULL, &deallocate_isolate, isolate_info);
|
1702
1821
|
}
|
1703
1822
|
|
1823
|
+
static void set_ruby_exiting(VALUE value) {
|
1824
|
+
(void)value;
|
1825
|
+
|
1826
|
+
int res = pthread_rwlock_wrlock(&exit_lock);
|
1827
|
+
|
1828
|
+
ruby_exiting = true;
|
1829
|
+
if (res == 0) {
|
1830
|
+
pthread_rwlock_unlock(&exit_lock);
|
1831
|
+
}
|
1832
|
+
}
|
1833
|
+
|
1834
|
+
static VALUE rb_monotime(VALUE self) {
|
1835
|
+
struct timespec ts;
|
1836
|
+
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
|
1837
|
+
return INT2FIX(-1);
|
1838
|
+
}
|
1839
|
+
|
1840
|
+
return DBL2NUM(
|
1841
|
+
(double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0);
|
1842
|
+
}
|
1843
|
+
|
1704
1844
|
extern "C" {
|
1705
1845
|
|
1706
|
-
void Init_sq_mini_racer_extension ( void )
|
1846
|
+
__attribute__((visibility("default"))) void Init_sq_mini_racer_extension ( void )
|
1707
1847
|
{
|
1708
|
-
|
1848
|
+
ID sqreen_id = rb_intern("Sqreen");
|
1849
|
+
VALUE rb_mSqreen;
|
1850
|
+
if (rb_const_defined(rb_cObject, sqreen_id)) {
|
1851
|
+
rb_mSqreen = rb_const_get(rb_cObject, sqreen_id);
|
1852
|
+
if (TYPE(rb_mSqreen) != T_MODULE) {
|
1853
|
+
rb_raise(rb_eTypeError, "Sqreen is not a module");
|
1854
|
+
return;
|
1855
|
+
}
|
1856
|
+
} else {
|
1857
|
+
rb_mSqreen = rb_define_module("Sqreen");
|
1858
|
+
}
|
1709
1859
|
VALUE rb_mMiniRacer = rb_define_module_under(rb_mSqreen, "MiniRacer");
|
1860
|
+
rb_define_module_function(rb_mMiniRacer, "monotime", (VALUE(*)(...))&rb_monotime, 0);
|
1710
1861
|
rb_cContext = rb_define_class_under(rb_mMiniRacer, "Context", rb_cObject);
|
1711
1862
|
rb_cSnapshot = rb_define_class_under(rb_mMiniRacer, "Snapshot", rb_cObject);
|
1712
1863
|
rb_cIsolate = rb_define_class_under(rb_mMiniRacer, "Isolate", rb_cObject);
|
@@ -1753,8 +1904,23 @@ extern "C" {
|
|
1753
1904
|
rb_define_private_method(rb_cSnapshot, "load", (VALUE(*)(...))&rb_snapshot_load, 1);
|
1754
1905
|
|
1755
1906
|
rb_define_method(rb_cIsolate, "idle_notification", (VALUE(*)(...))&rb_isolate_idle_notification, 1);
|
1907
|
+
rb_define_method(rb_cIsolate, "low_memory_notification", (VALUE(*)(...))&rb_isolate_low_memory_notification, 0);
|
1908
|
+
rb_define_method(rb_cIsolate, "pump_message_loop", (VALUE(*)(...))&rb_isolate_pump_message_loop, 0);
|
1756
1909
|
rb_define_private_method(rb_cIsolate, "init_with_snapshot",(VALUE(*)(...))&rb_isolate_init_with_snapshot, 1);
|
1757
1910
|
|
1758
1911
|
rb_define_singleton_method(rb_cPlatform, "set_flag_as_str!", (VALUE(*)(...))&rb_platform_set_flag_as_str, 1);
|
1912
|
+
|
1913
|
+
rb_set_end_proc(set_ruby_exiting, Qnil);
|
1914
|
+
|
1915
|
+
static pthread_attr_t attr;
|
1916
|
+
if (pthread_attr_init(&attr) == 0) {
|
1917
|
+
if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0) {
|
1918
|
+
thread_attr_p = &attr;
|
1919
|
+
}
|
1920
|
+
}
|
1921
|
+
auto on_fork_for_child = []() {
|
1922
|
+
exit_lock = PTHREAD_RWLOCK_INITIALIZER;
|
1923
|
+
};
|
1924
|
+
pthread_atfork(nullptr, nullptr, on_fork_for_child);
|
1759
1925
|
}
|
1760
1926
|
}
|