mini_racer 0.1.12 → 0.1.13
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 +6 -0
- data/README.md +11 -0
- data/ext/mini_racer_extension/mini_racer_extension.cc +44 -18
- data/lib/mini_racer.rb +3 -0
- data/lib/mini_racer/version.rb +1 -1
- data/mini_racer.gemspec +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02fb924ef1736f4c3626fba401b25725bc70e99d
|
4
|
+
data.tar.gz: 15b87d9a11b8104204fc5def731360ae101c6eb7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d2c4dc1eade12fa0c6ba01b38d91366fa0edcab211fc2483014191cd00c685d16eb469f4f9dd5e93ac8263803f7570b40e19e525671be5d5f6fbd154ac8cdca
|
7
|
+
data.tar.gz: 10c2065a5eaa3a967a6109d7e67339e914125c047c9302ab4fedeeac9b058e827503f96936465cfe0465afe5757546ff14ba3ecc21714b6a2616af17b2b93623
|
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -68,6 +68,17 @@ context.eval 'while(true){}'
|
|
68
68
|
# => exception is raised
|
69
69
|
```
|
70
70
|
|
71
|
+
### Memory softlimit support
|
72
|
+
|
73
|
+
Contexts can specify a memory softlimit for scripts
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
# terminates script if heap usage exceeds 200mb after V8 garbage collection has run
|
77
|
+
context = MiniRacer::Context.new(max_memory: 200000000)
|
78
|
+
context.eval 'var a = new Array(10000); while(true) {a = a.concat(new Array(10000)); print("loop " + a.length);}'
|
79
|
+
# => V8OutOfMemoryError is raised
|
80
|
+
```
|
81
|
+
|
71
82
|
### Rich debugging with "filename" support
|
72
83
|
|
73
84
|
```ruby
|
@@ -11,20 +11,6 @@
|
|
11
11
|
|
12
12
|
using namespace v8;
|
13
13
|
|
14
|
-
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
|
15
|
-
public:
|
16
|
-
virtual void* Allocate(size_t length) {
|
17
|
-
void* data = AllocateUninitialized(length);
|
18
|
-
return data == NULL ? data : memset(data, 0, length);
|
19
|
-
}
|
20
|
-
virtual void* AllocateUninitialized(size_t length) {
|
21
|
-
return malloc(length);
|
22
|
-
}
|
23
|
-
virtual void Free(void* data, size_t) {
|
24
|
-
free(data);
|
25
|
-
}
|
26
|
-
};
|
27
|
-
|
28
14
|
typedef struct {
|
29
15
|
const char* data;
|
30
16
|
int raw_size;
|
@@ -32,7 +18,7 @@ typedef struct {
|
|
32
18
|
|
33
19
|
typedef struct {
|
34
20
|
Isolate* isolate;
|
35
|
-
|
21
|
+
ArrayBuffer::Allocator* allocator;
|
36
22
|
StartupData* startup_data;
|
37
23
|
bool interrupted;
|
38
24
|
bool disposed;
|
@@ -67,9 +53,11 @@ typedef struct {
|
|
67
53
|
Local<String>* filename;
|
68
54
|
useconds_t timeout;
|
69
55
|
EvalResult* result;
|
56
|
+
long max_memory;
|
70
57
|
} EvalParams;
|
71
58
|
|
72
59
|
static VALUE rb_eScriptTerminatedError;
|
60
|
+
static VALUE rb_eV8OutOfMemoryError;
|
73
61
|
static VALUE rb_eParseError;
|
74
62
|
static VALUE rb_eScriptRuntimeError;
|
75
63
|
static VALUE rb_cJavaScriptFunction;
|
@@ -120,6 +108,21 @@ static void init_v8() {
|
|
120
108
|
platform_lock.unlock();
|
121
109
|
}
|
122
110
|
|
111
|
+
static void gc_callback(Isolate *isolate, GCType type, GCCallbackFlags flags) {
|
112
|
+
if((bool)isolate->GetData(3)) return;
|
113
|
+
|
114
|
+
long softlimit = *(long*) isolate->GetData(2);
|
115
|
+
|
116
|
+
HeapStatistics* stats = new HeapStatistics();
|
117
|
+
isolate->GetHeapStatistics(stats);
|
118
|
+
long used = stats->used_heap_size();
|
119
|
+
|
120
|
+
if(used > softlimit) {
|
121
|
+
isolate->SetData(3, (void*)true);
|
122
|
+
V8::TerminateExecution(isolate);
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
123
126
|
void*
|
124
127
|
nogvl_context_eval(void* arg) {
|
125
128
|
|
@@ -138,6 +141,10 @@ nogvl_context_eval(void* arg) {
|
|
138
141
|
isolate->SetData(0, (void*)false);
|
139
142
|
// terminate ASAP
|
140
143
|
isolate->SetData(1, (void*)false);
|
144
|
+
// Memory softlimit
|
145
|
+
isolate->SetData(2, (void*)false);
|
146
|
+
// Memory softlimit hit flag
|
147
|
+
isolate->SetData(3, (void*)false);
|
141
148
|
|
142
149
|
MaybeLocal<Script> parsed_script;
|
143
150
|
|
@@ -162,6 +169,11 @@ nogvl_context_eval(void* arg) {
|
|
162
169
|
result->message->Reset(isolate, trycatch.Exception());
|
163
170
|
} else {
|
164
171
|
|
172
|
+
if(eval_params->max_memory > 0) {
|
173
|
+
isolate->SetData(2, &eval_params->max_memory);
|
174
|
+
isolate->AddGCEpilogueCallback(gc_callback);
|
175
|
+
}
|
176
|
+
|
165
177
|
MaybeLocal<Value> maybe_value = parsed_script.ToLocalChecked()->Run(context);
|
166
178
|
|
167
179
|
result->executed = !maybe_value.IsEmpty();
|
@@ -453,7 +465,7 @@ static VALUE rb_isolate_init_with_snapshot(VALUE self, VALUE snapshot) {
|
|
453
465
|
|
454
466
|
init_v8();
|
455
467
|
|
456
|
-
isolate_info->allocator =
|
468
|
+
isolate_info->allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
|
457
469
|
isolate_info->interrupted = false;
|
458
470
|
isolate_info->refs_count = 1;
|
459
471
|
|
@@ -555,11 +567,17 @@ static VALUE rb_context_eval_unsafe(VALUE self, VALUE str, VALUE filename) {
|
|
555
567
|
eval_params.eval = &eval;
|
556
568
|
eval_params.result = &eval_result;
|
557
569
|
eval_params.timeout = 0;
|
570
|
+
eval_params.max_memory = 0;
|
558
571
|
VALUE timeout = rb_iv_get(self, "@timeout");
|
559
572
|
if (timeout != Qnil) {
|
560
573
|
eval_params.timeout = (useconds_t)NUM2LONG(timeout);
|
561
574
|
}
|
562
575
|
|
576
|
+
VALUE mem_softlimit = rb_iv_get(self, "@max_memory");
|
577
|
+
if (mem_softlimit != Qnil) {
|
578
|
+
eval_params.max_memory = (long)NUM2LONG(mem_softlimit);
|
579
|
+
}
|
580
|
+
|
563
581
|
eval_result.message = NULL;
|
564
582
|
eval_result.backtrace = NULL;
|
565
583
|
|
@@ -593,7 +611,14 @@ static VALUE rb_context_eval_unsafe(VALUE self, VALUE str, VALUE filename) {
|
|
593
611
|
if (!eval_result.executed) {
|
594
612
|
VALUE ruby_exception = rb_iv_get(self, "@current_exception");
|
595
613
|
if (ruby_exception == Qnil) {
|
596
|
-
|
614
|
+
bool mem_softlimit_reached = (bool)isolate->GetData(3);
|
615
|
+
// If we were terminated or have the memory softlimit flag set
|
616
|
+
if(eval_result.terminated || mem_softlimit_reached) {
|
617
|
+
ruby_exception = mem_softlimit_reached ? rb_eV8OutOfMemoryError : rb_eScriptTerminatedError;
|
618
|
+
} else {
|
619
|
+
ruby_exception = rb_eScriptRuntimeError;
|
620
|
+
}
|
621
|
+
|
597
622
|
// exception report about what happened
|
598
623
|
if(TYPE(backtrace) == T_STRING) {
|
599
624
|
rb_raise(ruby_exception, "%s", RSTRING_PTR(backtrace));
|
@@ -701,7 +726,7 @@ gvl_ruby_callback(void* data) {
|
|
701
726
|
callback_data.failed = false;
|
702
727
|
|
703
728
|
if ((bool)args->GetIsolate()->GetData(1) == true) {
|
704
|
-
args->GetIsolate()->ThrowException(String::NewFromUtf8(args->GetIsolate(), "Terminated execution during
|
729
|
+
args->GetIsolate()->ThrowException(String::NewFromUtf8(args->GetIsolate(), "Terminated execution during transition from Ruby to JS"));
|
705
730
|
V8::TerminateExecution(args->GetIsolate());
|
706
731
|
return NULL;
|
707
732
|
}
|
@@ -1035,6 +1060,7 @@ extern "C" {
|
|
1035
1060
|
|
1036
1061
|
VALUE rb_eEvalError = rb_define_class_under(rb_mMiniRacer, "EvalError", rb_eError);
|
1037
1062
|
rb_eScriptTerminatedError = rb_define_class_under(rb_mMiniRacer, "ScriptTerminatedError", rb_eEvalError);
|
1063
|
+
rb_eV8OutOfMemoryError = rb_define_class_under(rb_mMiniRacer, "V8OutOfMemoryError", rb_eEvalError);
|
1038
1064
|
rb_eParseError = rb_define_class_under(rb_mMiniRacer, "ParseError", rb_eEvalError);
|
1039
1065
|
rb_eScriptRuntimeError = rb_define_class_under(rb_mMiniRacer, "RuntimeError", rb_eEvalError);
|
1040
1066
|
|
data/lib/mini_racer.rb
CHANGED
@@ -14,6 +14,7 @@ module MiniRacer
|
|
14
14
|
class EvalError < Error; end
|
15
15
|
class ParseError < EvalError; end
|
16
16
|
class ScriptTerminatedError < EvalError; end
|
17
|
+
class V8OutOfMemoryError < EvalError; end
|
17
18
|
|
18
19
|
class FailedV8Conversion
|
19
20
|
attr_reader :info
|
@@ -144,8 +145,10 @@ module MiniRacer
|
|
144
145
|
|
145
146
|
@functions = {}
|
146
147
|
@timeout = nil
|
148
|
+
@max_memory = nil
|
147
149
|
@current_exception = nil
|
148
150
|
@timeout = options[:timeout]
|
151
|
+
@max_memory = options[:max_memory]
|
149
152
|
@isolate = options[:isolate] || Isolate.new(options[:snapshot])
|
150
153
|
@disposed = false
|
151
154
|
|
data/lib/mini_racer/version.rb
CHANGED
data/mini_racer.gemspec
CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_development_dependency "minitest", "~> 5.0"
|
26
26
|
spec.add_development_dependency "rake-compiler"
|
27
27
|
|
28
|
-
spec.add_dependency 'libv8', '
|
28
|
+
spec.add_dependency 'libv8', ' = 6.0.286.44.0beta1'
|
29
29
|
spec.require_paths = ["lib", "ext"]
|
30
30
|
|
31
31
|
spec.extensions = ["ext/mini_racer_extension/extconf.rb"]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mini_racer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Saffron
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -70,16 +70,16 @@ dependencies:
|
|
70
70
|
name: libv8
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - '='
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: 6.0.286.44.0beta1
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - '='
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: 6.0.286.44.0beta1
|
83
83
|
description: Minimal embedded v8 engine for Ruby
|
84
84
|
email:
|
85
85
|
- sam.saffron@gmail.com
|