mini_racer 0.1.12 → 0.1.13
Sign up to get free protection for your applications and to get access to all the features.
- 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
|