ruby_box 0.0.0.1 → 1.0.0
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/lib/ruby_box/bridging.rb +1 -1
- data/lib/ruby_box/version.rb +1 -1
- metadata +11 -34
- data/vendor/gems/mini_racer/ext/mini_racer_extension/extconf.rb +0 -54
- data/vendor/gems/mini_racer/ext/mini_racer_extension/mini_racer_extension.cc +0 -910
- data/vendor/gems/mini_racer/lib/mini_racer.rb +0 -261
- data/vendor/gems/mini_racer/lib/mini_racer/version.rb +0 -3
- data/vendor/gems/mini_racer/lib/mini_racer_extension.bundle +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad18cf425468583ca9d68b028decf40c0cab4c8d
|
4
|
+
data.tar.gz: a396ac061daca869cc7614703ab9446a2fd2ab6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 276d89862d95255ef094c8f906c154be97ff20e1d31d7139ea3f183f5a79eca6bec87a05ca06daa5321996c5a9ae5493347b5106cc13870373520088987fa02d
|
7
|
+
data.tar.gz: e8959d5af99de60849293ec31e7ecfee684006f22a6856f849f06f89b4cd0a90ca52fb5bc9e975372e01f22ce2bc317ed4b74f5b96fd54136510f3c0a23057cc
|
data/lib/ruby_box/bridging.rb
CHANGED
@@ -42,7 +42,7 @@ module RubyBox
|
|
42
42
|
handle = "Opal.RubyBox.CurrentBoxProxy.__exposed_method_#{method_name}"
|
43
43
|
|
44
44
|
wrapper = ->(serialized_args) do
|
45
|
-
args = JSON.parse(serialized_args)
|
45
|
+
args = JSON.parse(serialized_args, quirks_mode: true)
|
46
46
|
value = send(method_name, *args)
|
47
47
|
value.to_json
|
48
48
|
end
|
data/lib/ruby_box/version.rb
CHANGED
metadata
CHANGED
@@ -1,43 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_box
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alec Larsen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: mini_racer
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake-compiler
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
26
|
+
version: '0.1'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: opal
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,16 +56,16 @@ dependencies:
|
|
70
56
|
name: bundler
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
72
58
|
requirements:
|
73
|
-
- - "
|
59
|
+
- - ">="
|
74
60
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
61
|
+
version: '0'
|
76
62
|
type: :development
|
77
63
|
prerelease: false
|
78
64
|
version_requirements: !ruby/object:Gem::Requirement
|
79
65
|
requirements:
|
80
|
-
- - "
|
66
|
+
- - ">="
|
81
67
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
68
|
+
version: '0'
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
name: rake
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -154,8 +140,7 @@ description:
|
|
154
140
|
email:
|
155
141
|
- aleclarsen42@gmail.com
|
156
142
|
executables: []
|
157
|
-
extensions:
|
158
|
-
- vendor/gems/mini_racer/ext/mini_racer_extension/extconf.rb
|
143
|
+
extensions: []
|
159
144
|
extra_rdoc_files: []
|
160
145
|
files:
|
161
146
|
- lib/ruby_box.rb
|
@@ -171,11 +156,6 @@ files:
|
|
171
156
|
- lib/ruby_box/thread_safety.rb
|
172
157
|
- lib/ruby_box/timeout_error.rb
|
173
158
|
- lib/ruby_box/version.rb
|
174
|
-
- vendor/gems/mini_racer/ext/mini_racer_extension/extconf.rb
|
175
|
-
- vendor/gems/mini_racer/ext/mini_racer_extension/mini_racer_extension.cc
|
176
|
-
- vendor/gems/mini_racer/lib/mini_racer.rb
|
177
|
-
- vendor/gems/mini_racer/lib/mini_racer/version.rb
|
178
|
-
- vendor/gems/mini_racer/lib/mini_racer_extension.bundle
|
179
159
|
homepage: https://github.com/anarchocurious/ruby_box
|
180
160
|
licenses:
|
181
161
|
- MIT
|
@@ -184,8 +164,6 @@ post_install_message:
|
|
184
164
|
rdoc_options: []
|
185
165
|
require_paths:
|
186
166
|
- lib
|
187
|
-
- vendor/gems/mini_racer/lib
|
188
|
-
- vendor/gems/mini_racer/ext
|
189
167
|
required_ruby_version: !ruby/object:Gem::Requirement
|
190
168
|
requirements:
|
191
169
|
- - ">="
|
@@ -198,9 +176,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
198
176
|
version: '0'
|
199
177
|
requirements: []
|
200
178
|
rubyforge_project:
|
201
|
-
rubygems_version: 2.
|
179
|
+
rubygems_version: 2.5.1
|
202
180
|
signing_key:
|
203
181
|
specification_version: 4
|
204
182
|
summary: RubyBox allows the execution of untrusted Ruby code safely in a sandbox.
|
205
183
|
test_files: []
|
206
|
-
has_rdoc:
|
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'mkmf'
|
2
|
-
require 'libv8'
|
3
|
-
|
4
|
-
have_library('pthread')
|
5
|
-
have_library('objc') if RUBY_PLATFORM =~ /darwin/
|
6
|
-
$CPPFLAGS += " -Wall" unless $CPPFLAGS.split.include? "-Wall"
|
7
|
-
$CPPFLAGS += " -g" unless $CPPFLAGS.split.include? "-g"
|
8
|
-
$CPPFLAGS += " -rdynamic" unless $CPPFLAGS.split.include? "-rdynamic"
|
9
|
-
$CPPFLAGS += " -fPIC" unless $CPPFLAGS.split.include? "-rdynamic" or RUBY_PLATFORM =~ /darwin/
|
10
|
-
$CPPFLAGS += " -std=c++0x"
|
11
|
-
$CPPFLAGS += " -fpermissive"
|
12
|
-
|
13
|
-
$LDFLAGS.insert 0, " -stdlib=libstdc++ " if RUBY_PLATFORM =~ /darwin/
|
14
|
-
|
15
|
-
if ENV['CXX']
|
16
|
-
puts "SETTING CXX"
|
17
|
-
CONFIG['CXX'] = ENV['CXX']
|
18
|
-
end
|
19
|
-
|
20
|
-
CXX11_TEST = <<EOS
|
21
|
-
#if __cplusplus <= 199711L
|
22
|
-
# error A compiler that supports at least C++11 is required in order to compile this project.
|
23
|
-
#endif
|
24
|
-
EOS
|
25
|
-
|
26
|
-
`echo "#{CXX11_TEST}" | #{CONFIG['CXX']} -std=c++0x -x c++ -E -`
|
27
|
-
unless $?.success?
|
28
|
-
warn <<EOS
|
29
|
-
|
30
|
-
|
31
|
-
WARNING: C++11 support is required for compiling mini_racer. Please make sure
|
32
|
-
you are using a compiler that supports at least C++11. Examples of such
|
33
|
-
compilers are GCC 4.7+ and Clang 3.2+.
|
34
|
-
|
35
|
-
If you are using Travis, consider either migrating your bulid to Ubuntu Trusty or
|
36
|
-
installing GCC 4.8. See mini_racer's README.md for more information.
|
37
|
-
|
38
|
-
|
39
|
-
EOS
|
40
|
-
end
|
41
|
-
|
42
|
-
CONFIG['LDSHARED'] = '$(CXX) -shared' unless RUBY_PLATFORM =~ /darwin/
|
43
|
-
if CONFIG['warnflags']
|
44
|
-
CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '')
|
45
|
-
CONFIG['warnflags'].gsub!('-Wimplicit-function-declaration', '')
|
46
|
-
end
|
47
|
-
|
48
|
-
if enable_config('debug')
|
49
|
-
CONFIG['debugflags'] << ' -ggdb3 -O0'
|
50
|
-
end
|
51
|
-
|
52
|
-
Libv8.configure_makefile
|
53
|
-
|
54
|
-
create_makefile 'mini_racer_extension'
|
@@ -1,910 +0,0 @@
|
|
1
|
-
#include <stdio.h>
|
2
|
-
#include <ruby.h>
|
3
|
-
#include <ruby/thread.h>
|
4
|
-
#include <v8.h>
|
5
|
-
#include <libplatform/libplatform.h>
|
6
|
-
#include <ruby/encoding.h>
|
7
|
-
#include <pthread.h>
|
8
|
-
#include <unistd.h>
|
9
|
-
#include <mutex>
|
10
|
-
|
11
|
-
using namespace v8;
|
12
|
-
|
13
|
-
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
|
14
|
-
public:
|
15
|
-
virtual void* Allocate(size_t length) {
|
16
|
-
void* data = AllocateUninitialized(length);
|
17
|
-
return data == NULL ? data : memset(data, 0, length);
|
18
|
-
}
|
19
|
-
virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
|
20
|
-
virtual void Free(void* data, size_t) { free(data); }
|
21
|
-
};
|
22
|
-
|
23
|
-
typedef struct {
|
24
|
-
const char* data;
|
25
|
-
int raw_size;
|
26
|
-
} SnapshotInfo;
|
27
|
-
|
28
|
-
typedef struct {
|
29
|
-
Isolate* isolate;
|
30
|
-
ArrayBufferAllocator* allocator;
|
31
|
-
StartupData* startup_data;
|
32
|
-
bool interrupted;
|
33
|
-
|
34
|
-
// how many references to this isolate exist
|
35
|
-
// we can't rely on Ruby's GC for this, because when destroying
|
36
|
-
// objects, Ruby will destroy ruby objects first, then call the
|
37
|
-
// extenstion's deallocators. In this case, that means it would
|
38
|
-
// call `deallocate_isolate` _before_ `deallocate`, causing a segfault
|
39
|
-
int refs_count;
|
40
|
-
} IsolateInfo;
|
41
|
-
|
42
|
-
typedef struct {
|
43
|
-
IsolateInfo* isolate_info;
|
44
|
-
Persistent<Context>* context;
|
45
|
-
} ContextInfo;
|
46
|
-
|
47
|
-
typedef struct {
|
48
|
-
bool parsed;
|
49
|
-
bool executed;
|
50
|
-
bool terminated;
|
51
|
-
Persistent<Value>* value;
|
52
|
-
Persistent<Value>* message;
|
53
|
-
Persistent<Value>* backtrace;
|
54
|
-
} EvalResult;
|
55
|
-
|
56
|
-
typedef struct {
|
57
|
-
ContextInfo* context_info;
|
58
|
-
Local<String>* eval;
|
59
|
-
useconds_t timeout;
|
60
|
-
EvalResult* result;
|
61
|
-
} EvalParams;
|
62
|
-
|
63
|
-
static VALUE rb_eScriptTerminatedError;
|
64
|
-
static VALUE rb_eParseError;
|
65
|
-
static VALUE rb_eScriptRuntimeError;
|
66
|
-
static VALUE rb_cJavaScriptFunction;
|
67
|
-
static VALUE rb_eSnapshotError;
|
68
|
-
static VALUE rb_ePlatformAlreadyInitializedError;
|
69
|
-
|
70
|
-
static VALUE rb_cFailedV8Conversion;
|
71
|
-
static VALUE rb_cDateTime = Qnil;
|
72
|
-
|
73
|
-
static Platform* current_platform = NULL;
|
74
|
-
static std::mutex platform_lock;
|
75
|
-
|
76
|
-
static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) {
|
77
|
-
bool platform_already_initialized = false;
|
78
|
-
|
79
|
-
platform_lock.lock();
|
80
|
-
|
81
|
-
if (current_platform == NULL) {
|
82
|
-
V8::SetFlagsFromString(RSTRING_PTR(flag_as_str), (int)RSTRING_LEN(flag_as_str));
|
83
|
-
} else {
|
84
|
-
platform_already_initialized = true;
|
85
|
-
}
|
86
|
-
|
87
|
-
platform_lock.unlock();
|
88
|
-
|
89
|
-
// important to raise outside of the lock
|
90
|
-
if (platform_already_initialized) {
|
91
|
-
rb_raise(rb_ePlatformAlreadyInitializedError, "The V8 platform is already initialized");
|
92
|
-
}
|
93
|
-
|
94
|
-
return Qnil;
|
95
|
-
}
|
96
|
-
|
97
|
-
static void init_v8() {
|
98
|
-
// no need to wait for the lock if already initialized
|
99
|
-
if (current_platform != NULL) return;
|
100
|
-
|
101
|
-
platform_lock.lock();
|
102
|
-
|
103
|
-
if (current_platform == NULL) {
|
104
|
-
V8::InitializeICU();
|
105
|
-
current_platform = platform::CreateDefaultPlatform();
|
106
|
-
V8::InitializePlatform(current_platform);
|
107
|
-
V8::Initialize();
|
108
|
-
}
|
109
|
-
|
110
|
-
platform_lock.unlock();
|
111
|
-
}
|
112
|
-
|
113
|
-
void*
|
114
|
-
nogvl_context_eval(void* arg) {
|
115
|
-
|
116
|
-
EvalParams* eval_params = (EvalParams*)arg;
|
117
|
-
EvalResult* result = eval_params->result;
|
118
|
-
Isolate* isolate = eval_params->context_info->isolate_info->isolate;
|
119
|
-
Isolate::Scope isolate_scope(isolate);
|
120
|
-
HandleScope handle_scope(isolate);
|
121
|
-
|
122
|
-
TryCatch trycatch(isolate);
|
123
|
-
|
124
|
-
Local<Context> context = eval_params->context_info->context->Get(isolate);
|
125
|
-
Context::Scope context_scope(context);
|
126
|
-
|
127
|
-
// in gvl flag
|
128
|
-
isolate->SetData(0, (void*)false);
|
129
|
-
// terminate ASAP
|
130
|
-
isolate->SetData(1, (void*)false);
|
131
|
-
|
132
|
-
MaybeLocal<Script> parsed_script = Script::Compile(context, *eval_params->eval);
|
133
|
-
result->parsed = !parsed_script.IsEmpty();
|
134
|
-
result->executed = false;
|
135
|
-
result->terminated = false;
|
136
|
-
result->value = NULL;
|
137
|
-
|
138
|
-
if (!result->parsed) {
|
139
|
-
result->message = new Persistent<Value>();
|
140
|
-
result->message->Reset(isolate, trycatch.Exception());
|
141
|
-
} else {
|
142
|
-
|
143
|
-
MaybeLocal<Value> maybe_value = parsed_script.ToLocalChecked()->Run(context);
|
144
|
-
|
145
|
-
result->executed = !maybe_value.IsEmpty();
|
146
|
-
|
147
|
-
if (result->executed) {
|
148
|
-
Persistent<Value>* persistent = new Persistent<Value>();
|
149
|
-
persistent->Reset(isolate, maybe_value.ToLocalChecked());
|
150
|
-
result->value = persistent;
|
151
|
-
}
|
152
|
-
}
|
153
|
-
|
154
|
-
if (!result->executed || !result->parsed) {
|
155
|
-
if (trycatch.HasCaught()) {
|
156
|
-
if (!trycatch.Exception()->IsNull()) {
|
157
|
-
result->message = new Persistent<Value>();
|
158
|
-
Local<Message> message = trycatch.Message();
|
159
|
-
char buf[1000];
|
160
|
-
int len;
|
161
|
-
len = snprintf(buf, sizeof(buf), "%s at %s:%i:%i", *String::Utf8Value(message->Get()),
|
162
|
-
*String::Utf8Value(message->GetScriptResourceName()->ToString()),
|
163
|
-
message->GetLineNumber(),
|
164
|
-
message->GetStartColumn());
|
165
|
-
|
166
|
-
Local<String> v8_message = String::NewFromUtf8(isolate, buf, NewStringType::kNormal, (int)len).ToLocalChecked();
|
167
|
-
result->message->Reset(isolate, v8_message);
|
168
|
-
} else if(trycatch.HasTerminated()) {
|
169
|
-
|
170
|
-
|
171
|
-
result->terminated = true;
|
172
|
-
result->message = new Persistent<Value>();
|
173
|
-
Local<String> tmp = String::NewFromUtf8(isolate, "JavaScript was terminated (either by timeout or explicitly)");
|
174
|
-
result->message->Reset(isolate, tmp);
|
175
|
-
}
|
176
|
-
if (!trycatch.StackTrace().IsEmpty()) {
|
177
|
-
result->backtrace = new Persistent<Value>();
|
178
|
-
result->backtrace->Reset(isolate, trycatch.StackTrace()->ToString());
|
179
|
-
}
|
180
|
-
}
|
181
|
-
}
|
182
|
-
|
183
|
-
isolate->SetData(0, (void*)true);
|
184
|
-
|
185
|
-
|
186
|
-
return NULL;
|
187
|
-
}
|
188
|
-
|
189
|
-
static VALUE convert_v8_to_ruby(Isolate* isolate, Handle<Value> &value) {
|
190
|
-
|
191
|
-
HandleScope scope(isolate);
|
192
|
-
|
193
|
-
if (value->IsNull() || value->IsUndefined()){
|
194
|
-
return Qnil;
|
195
|
-
}
|
196
|
-
|
197
|
-
if (value->IsInt32()) {
|
198
|
-
return INT2FIX(value->Int32Value());
|
199
|
-
}
|
200
|
-
|
201
|
-
if (value->IsNumber()) {
|
202
|
-
return rb_float_new(value->NumberValue());
|
203
|
-
}
|
204
|
-
|
205
|
-
if (value->IsTrue()) {
|
206
|
-
return Qtrue;
|
207
|
-
}
|
208
|
-
|
209
|
-
if (value->IsFalse()) {
|
210
|
-
return Qfalse;
|
211
|
-
}
|
212
|
-
|
213
|
-
if (value->IsArray()) {
|
214
|
-
VALUE rb_array = rb_ary_new();
|
215
|
-
Local<Array> arr = Local<Array>::Cast(value);
|
216
|
-
for(uint32_t i=0; i < arr->Length(); i++) {
|
217
|
-
Local<Value> element = arr->Get(i);
|
218
|
-
VALUE rb_elem = convert_v8_to_ruby(isolate, element);
|
219
|
-
if (rb_funcall(rb_elem, rb_intern("class"), 0) == rb_cFailedV8Conversion) {
|
220
|
-
return rb_elem;
|
221
|
-
}
|
222
|
-
rb_ary_push(rb_array, rb_elem);
|
223
|
-
}
|
224
|
-
return rb_array;
|
225
|
-
}
|
226
|
-
|
227
|
-
if (value->IsFunction()){
|
228
|
-
return rb_funcall(rb_cJavaScriptFunction, rb_intern("new"), 0);
|
229
|
-
}
|
230
|
-
|
231
|
-
if (value->IsDate()){
|
232
|
-
double ts = Local<Date>::Cast(value)->ValueOf();
|
233
|
-
double secs = ts/1000;
|
234
|
-
long nanos = round((secs - floor(secs)) * 1000000);
|
235
|
-
|
236
|
-
return rb_time_new(secs, nanos);
|
237
|
-
}
|
238
|
-
|
239
|
-
if (value->IsObject()) {
|
240
|
-
|
241
|
-
TryCatch trycatch(isolate);
|
242
|
-
|
243
|
-
VALUE rb_hash = rb_hash_new();
|
244
|
-
Local<Context> context = Context::New(isolate);
|
245
|
-
Local<Object> object = value->ToObject();
|
246
|
-
MaybeLocal<Array> maybe_props = object->GetOwnPropertyNames(context);
|
247
|
-
if (!maybe_props.IsEmpty()) {
|
248
|
-
Local<Array> props = maybe_props.ToLocalChecked();
|
249
|
-
for(uint32_t i=0; i < props->Length(); i++) {
|
250
|
-
Local<Value> key = props->Get(i);
|
251
|
-
VALUE rb_key = convert_v8_to_ruby(isolate, key);
|
252
|
-
Local<Value> value = object->Get(key);
|
253
|
-
// this may have failed due to Get raising
|
254
|
-
|
255
|
-
if (trycatch.HasCaught()) {
|
256
|
-
// TODO isolate code that translates execption to ruby
|
257
|
-
// exception so we can properly return it
|
258
|
-
return rb_funcall(rb_cFailedV8Conversion, rb_intern("new"), 1, rb_str_new2(""));
|
259
|
-
}
|
260
|
-
|
261
|
-
VALUE rb_value = convert_v8_to_ruby(isolate, value);
|
262
|
-
rb_hash_aset(rb_hash, rb_key, rb_value);
|
263
|
-
}
|
264
|
-
}
|
265
|
-
return rb_hash;
|
266
|
-
}
|
267
|
-
|
268
|
-
Local<String> rstr = value->ToString();
|
269
|
-
return rb_enc_str_new(*String::Utf8Value(rstr), rstr->Utf8Length(), rb_enc_find("utf-8"));
|
270
|
-
}
|
271
|
-
|
272
|
-
static Handle<Value> convert_ruby_to_v8(Isolate* isolate, VALUE value) {
|
273
|
-
EscapableHandleScope scope(isolate);
|
274
|
-
|
275
|
-
Local<Array> array;
|
276
|
-
Local<Object> object;
|
277
|
-
VALUE hash_as_array;
|
278
|
-
VALUE pair;
|
279
|
-
int i;
|
280
|
-
long length;
|
281
|
-
long fixnum;
|
282
|
-
VALUE klass;
|
283
|
-
|
284
|
-
switch (TYPE(value)) {
|
285
|
-
case T_FIXNUM:
|
286
|
-
fixnum = NUM2LONG(value);
|
287
|
-
if (fixnum > INT_MAX)
|
288
|
-
{
|
289
|
-
return scope.Escape(Number::New(isolate, (double)fixnum));
|
290
|
-
}
|
291
|
-
return scope.Escape(Integer::New(isolate, (int)fixnum));
|
292
|
-
case T_FLOAT:
|
293
|
-
return scope.Escape(Number::New(isolate, NUM2DBL(value)));
|
294
|
-
case T_STRING:
|
295
|
-
return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, (int)RSTRING_LEN(value)).ToLocalChecked());
|
296
|
-
case T_NIL:
|
297
|
-
return scope.Escape(Null(isolate));
|
298
|
-
case T_TRUE:
|
299
|
-
return scope.Escape(True(isolate));
|
300
|
-
case T_FALSE:
|
301
|
-
return scope.Escape(False(isolate));
|
302
|
-
case T_ARRAY:
|
303
|
-
length = RARRAY_LEN(value);
|
304
|
-
array = Array::New(isolate, (int)length);
|
305
|
-
for(i=0; i<length; i++) {
|
306
|
-
array->Set(i, convert_ruby_to_v8(isolate, rb_ary_entry(value, i)));
|
307
|
-
}
|
308
|
-
return scope.Escape(array);
|
309
|
-
case T_HASH:
|
310
|
-
object = Object::New(isolate);
|
311
|
-
hash_as_array = rb_funcall(value, rb_intern("to_a"), 0);
|
312
|
-
length = RARRAY_LEN(hash_as_array);
|
313
|
-
for(i=0; i<length; i++) {
|
314
|
-
pair = rb_ary_entry(hash_as_array, i);
|
315
|
-
object->Set(convert_ruby_to_v8(isolate, rb_ary_entry(pair, 0)),
|
316
|
-
convert_ruby_to_v8(isolate, rb_ary_entry(pair, 1)));
|
317
|
-
}
|
318
|
-
return scope.Escape(object);
|
319
|
-
case T_SYMBOL:
|
320
|
-
value = rb_funcall(value, rb_intern("to_s"), 0);
|
321
|
-
return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, (int)RSTRING_LEN(value)).ToLocalChecked());
|
322
|
-
case T_DATA:
|
323
|
-
klass = rb_funcall(value, rb_intern("class"), 0);
|
324
|
-
if (klass == rb_cTime || klass == rb_cDateTime)
|
325
|
-
{
|
326
|
-
if (klass == rb_cDateTime)
|
327
|
-
{
|
328
|
-
value = rb_funcall(value, rb_intern("to_time"), 0);
|
329
|
-
}
|
330
|
-
value = rb_funcall(value, rb_intern("to_f"), 0);
|
331
|
-
return scope.Escape(Date::New(isolate, NUM2DBL(value) * 1000));
|
332
|
-
}
|
333
|
-
case T_OBJECT:
|
334
|
-
case T_CLASS:
|
335
|
-
case T_ICLASS:
|
336
|
-
case T_MODULE:
|
337
|
-
case T_REGEXP:
|
338
|
-
case T_MATCH:
|
339
|
-
case T_STRUCT:
|
340
|
-
case T_BIGNUM:
|
341
|
-
case T_FILE:
|
342
|
-
case T_UNDEF:
|
343
|
-
case T_NODE:
|
344
|
-
default:
|
345
|
-
return scope.Escape(String::NewFromUtf8(isolate, "Undefined Conversion"));
|
346
|
-
}
|
347
|
-
|
348
|
-
}
|
349
|
-
|
350
|
-
static void unblock_eval(void *ptr) {
|
351
|
-
EvalParams* eval = (EvalParams*)ptr;
|
352
|
-
eval->context_info->isolate_info->interrupted = true;
|
353
|
-
}
|
354
|
-
|
355
|
-
static VALUE rb_snapshot_size(VALUE self, VALUE str) {
|
356
|
-
SnapshotInfo* snapshot_info;
|
357
|
-
Data_Get_Struct(self, SnapshotInfo, snapshot_info);
|
358
|
-
|
359
|
-
return INT2NUM(snapshot_info->raw_size);
|
360
|
-
}
|
361
|
-
|
362
|
-
static VALUE rb_snapshot_load(VALUE self, VALUE str) {
|
363
|
-
SnapshotInfo* snapshot_info;
|
364
|
-
Data_Get_Struct(self, SnapshotInfo, snapshot_info);
|
365
|
-
|
366
|
-
init_v8();
|
367
|
-
|
368
|
-
StartupData startup_data = V8::CreateSnapshotDataBlob(RSTRING_PTR(str));
|
369
|
-
|
370
|
-
if (startup_data.data == NULL && startup_data.raw_size == 0) {
|
371
|
-
rb_raise(rb_eSnapshotError, "Could not create snapshot, most likely the source is incorrect");
|
372
|
-
}
|
373
|
-
|
374
|
-
snapshot_info->data = startup_data.data;
|
375
|
-
snapshot_info->raw_size = startup_data.raw_size;
|
376
|
-
|
377
|
-
return Qnil;
|
378
|
-
}
|
379
|
-
|
380
|
-
static VALUE rb_snapshot_warmup(VALUE self, VALUE str) {
|
381
|
-
SnapshotInfo* snapshot_info;
|
382
|
-
Data_Get_Struct(self, SnapshotInfo, snapshot_info);
|
383
|
-
|
384
|
-
init_v8();
|
385
|
-
|
386
|
-
StartupData cold_startup_data = {snapshot_info->data, snapshot_info->raw_size};
|
387
|
-
StartupData warm_startup_data = V8::WarmUpSnapshotDataBlob(cold_startup_data, RSTRING_PTR(str));
|
388
|
-
|
389
|
-
if (warm_startup_data.data == NULL && warm_startup_data.raw_size == 0) {
|
390
|
-
rb_raise(rb_eSnapshotError, "Could not warm up snapshot, most likely the source is incorrect");
|
391
|
-
} else {
|
392
|
-
delete[] snapshot_info->data;
|
393
|
-
|
394
|
-
snapshot_info->data = warm_startup_data.data;
|
395
|
-
snapshot_info->raw_size = warm_startup_data.raw_size;
|
396
|
-
}
|
397
|
-
|
398
|
-
return self;
|
399
|
-
}
|
400
|
-
|
401
|
-
static VALUE rb_isolate_init_with_snapshot(VALUE self, VALUE snapshot) {
|
402
|
-
IsolateInfo* isolate_info;
|
403
|
-
Data_Get_Struct(self, IsolateInfo, isolate_info);
|
404
|
-
|
405
|
-
init_v8();
|
406
|
-
|
407
|
-
isolate_info->allocator = new ArrayBufferAllocator();
|
408
|
-
isolate_info->interrupted = false;
|
409
|
-
isolate_info->refs_count = 1;
|
410
|
-
|
411
|
-
Isolate::CreateParams create_params;
|
412
|
-
create_params.array_buffer_allocator = isolate_info->allocator;
|
413
|
-
|
414
|
-
StartupData* startup_data = NULL;
|
415
|
-
if (!NIL_P(snapshot)) {
|
416
|
-
SnapshotInfo* snapshot_info;
|
417
|
-
Data_Get_Struct(snapshot, SnapshotInfo, snapshot_info);
|
418
|
-
|
419
|
-
int raw_size = snapshot_info->raw_size;
|
420
|
-
char* data = new char[raw_size];
|
421
|
-
memcpy(data, snapshot_info->data, sizeof(char) * raw_size);
|
422
|
-
|
423
|
-
startup_data = new StartupData;
|
424
|
-
startup_data->data = data;
|
425
|
-
startup_data->raw_size = raw_size;
|
426
|
-
|
427
|
-
create_params.snapshot_blob = startup_data;
|
428
|
-
}
|
429
|
-
|
430
|
-
isolate_info->startup_data = startup_data;
|
431
|
-
isolate_info->isolate = Isolate::New(create_params);
|
432
|
-
|
433
|
-
return Qnil;
|
434
|
-
}
|
435
|
-
|
436
|
-
static VALUE rb_isolate_idle_notification(VALUE self, VALUE idle_time_in_ms) {
|
437
|
-
IsolateInfo* isolate_info;
|
438
|
-
Data_Get_Struct(self, IsolateInfo, isolate_info);
|
439
|
-
|
440
|
-
return isolate_info->isolate->IdleNotification(NUM2INT(idle_time_in_ms)) ? Qtrue : Qfalse;
|
441
|
-
}
|
442
|
-
|
443
|
-
static VALUE rb_context_init_with_isolate(VALUE self, VALUE isolate) {
|
444
|
-
ContextInfo* context_info;
|
445
|
-
Data_Get_Struct(self, ContextInfo, context_info);
|
446
|
-
|
447
|
-
init_v8();
|
448
|
-
|
449
|
-
IsolateInfo* isolate_info;
|
450
|
-
Data_Get_Struct(isolate, IsolateInfo, isolate_info);
|
451
|
-
|
452
|
-
context_info->isolate_info = isolate_info;
|
453
|
-
isolate_info->refs_count++;
|
454
|
-
|
455
|
-
{
|
456
|
-
Locker lock(isolate_info->isolate);
|
457
|
-
Isolate::Scope isolate_scope(isolate_info->isolate);
|
458
|
-
HandleScope handle_scope(isolate_info->isolate);
|
459
|
-
|
460
|
-
Local<Context> context = Context::New(isolate_info->isolate);
|
461
|
-
|
462
|
-
context_info->context = new Persistent<Context>();
|
463
|
-
context_info->context->Reset(isolate_info->isolate, context);
|
464
|
-
}
|
465
|
-
|
466
|
-
if (Qnil == rb_cDateTime && rb_funcall(rb_cObject, rb_intern("const_defined?"), 1, rb_str_new2("DateTime")) == Qtrue)
|
467
|
-
{
|
468
|
-
rb_cDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));
|
469
|
-
}
|
470
|
-
|
471
|
-
return Qnil;
|
472
|
-
}
|
473
|
-
|
474
|
-
static VALUE rb_context_eval_unsafe(VALUE self, VALUE str) {
|
475
|
-
|
476
|
-
EvalParams eval_params;
|
477
|
-
EvalResult eval_result;
|
478
|
-
ContextInfo* context_info;
|
479
|
-
VALUE result;
|
480
|
-
|
481
|
-
VALUE message = Qnil;
|
482
|
-
VALUE backtrace = Qnil;
|
483
|
-
|
484
|
-
Data_Get_Struct(self, ContextInfo, context_info);
|
485
|
-
Isolate* isolate = context_info->isolate_info->isolate;
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
{
|
490
|
-
Locker lock(isolate);
|
491
|
-
Isolate::Scope isolate_scope(isolate);
|
492
|
-
HandleScope handle_scope(isolate);
|
493
|
-
|
494
|
-
Local<String> eval = String::NewFromUtf8(isolate, RSTRING_PTR(str),
|
495
|
-
NewStringType::kNormal, (int)RSTRING_LEN(str)).ToLocalChecked();
|
496
|
-
|
497
|
-
eval_params.context_info = context_info;
|
498
|
-
eval_params.eval = &eval;
|
499
|
-
eval_params.result = &eval_result;
|
500
|
-
eval_params.timeout = 0;
|
501
|
-
VALUE timeout = rb_iv_get(self, "@timeout");
|
502
|
-
if (timeout != Qnil) {
|
503
|
-
eval_params.timeout = (useconds_t)NUM2LONG(timeout);
|
504
|
-
}
|
505
|
-
|
506
|
-
eval_result.message = NULL;
|
507
|
-
eval_result.backtrace = NULL;
|
508
|
-
|
509
|
-
rb_thread_call_without_gvl(nogvl_context_eval, &eval_params, unblock_eval, &eval_params);
|
510
|
-
|
511
|
-
if (eval_result.message != NULL) {
|
512
|
-
Local<Value> tmp = Local<Value>::New(isolate, *eval_result.message);
|
513
|
-
message = convert_v8_to_ruby(isolate, tmp);
|
514
|
-
eval_result.message->Reset();
|
515
|
-
delete eval_result.message;
|
516
|
-
}
|
517
|
-
|
518
|
-
if (eval_result.backtrace != NULL) {
|
519
|
-
Local<Value> tmp = Local<Value>::New(isolate, *eval_result.backtrace);
|
520
|
-
backtrace = convert_v8_to_ruby(isolate, tmp);
|
521
|
-
eval_result.backtrace->Reset();
|
522
|
-
delete eval_result.backtrace;
|
523
|
-
}
|
524
|
-
}
|
525
|
-
|
526
|
-
// NOTE: this is very important, we can not do an rb_raise from within
|
527
|
-
// a v8 scope, if we do the scope is never cleaned up properly and we leak
|
528
|
-
if (!eval_result.parsed) {
|
529
|
-
if(TYPE(message) == T_STRING) {
|
530
|
-
rb_raise(rb_eParseError, "%s", RSTRING_PTR(message));
|
531
|
-
} else {
|
532
|
-
rb_raise(rb_eParseError, "Unknown JavaScript Error during parse");
|
533
|
-
}
|
534
|
-
}
|
535
|
-
|
536
|
-
if (!eval_result.executed) {
|
537
|
-
VALUE ruby_exception = rb_iv_get(self, "@current_exception");
|
538
|
-
if (ruby_exception == Qnil) {
|
539
|
-
ruby_exception = eval_result.terminated ? rb_eScriptTerminatedError : rb_eScriptRuntimeError;
|
540
|
-
// exception report about what happened
|
541
|
-
if(TYPE(backtrace) == T_STRING) {
|
542
|
-
rb_raise(ruby_exception, "%s", RSTRING_PTR(backtrace));
|
543
|
-
} else if(TYPE(message) == T_STRING) {
|
544
|
-
rb_raise(ruby_exception, "%s", RSTRING_PTR(message));
|
545
|
-
} else {
|
546
|
-
rb_raise(ruby_exception, "Unknown JavaScript Error during execution");
|
547
|
-
}
|
548
|
-
} else {
|
549
|
-
VALUE rb_str = rb_funcall(ruby_exception, rb_intern("to_s"), 0);
|
550
|
-
rb_raise(CLASS_OF(ruby_exception), "%s", RSTRING_PTR(rb_str));
|
551
|
-
}
|
552
|
-
}
|
553
|
-
|
554
|
-
// New scope for return value, must release GVL which
|
555
|
-
{
|
556
|
-
Locker lock(isolate);
|
557
|
-
Isolate::Scope isolate_scope(isolate);
|
558
|
-
HandleScope handle_scope(isolate);
|
559
|
-
|
560
|
-
Local<Value> tmp = Local<Value>::New(isolate, *eval_result.value);
|
561
|
-
result = convert_v8_to_ruby(isolate, tmp);
|
562
|
-
|
563
|
-
eval_result.value->Reset();
|
564
|
-
delete eval_result.value;
|
565
|
-
}
|
566
|
-
|
567
|
-
if (rb_funcall(result, rb_intern("class"), 0) == rb_cFailedV8Conversion) {
|
568
|
-
// TODO try to recover stack trace from the conversion error
|
569
|
-
rb_raise(rb_eScriptRuntimeError, "Error converting JS object to Ruby object");
|
570
|
-
}
|
571
|
-
|
572
|
-
|
573
|
-
return result;
|
574
|
-
}
|
575
|
-
|
576
|
-
typedef struct {
|
577
|
-
VALUE callback;
|
578
|
-
int length;
|
579
|
-
VALUE* args;
|
580
|
-
bool failed;
|
581
|
-
} protected_callback_data;
|
582
|
-
|
583
|
-
static
|
584
|
-
VALUE protected_callback(VALUE rdata) {
|
585
|
-
protected_callback_data* data = (protected_callback_data*)rdata;
|
586
|
-
VALUE result;
|
587
|
-
|
588
|
-
if (data->length > 0) {
|
589
|
-
result = rb_funcall2(data->callback, rb_intern("call"), data->length, data->args);
|
590
|
-
} else {
|
591
|
-
result = rb_funcall(data->callback, rb_intern("call"), 0);
|
592
|
-
}
|
593
|
-
return result;
|
594
|
-
}
|
595
|
-
|
596
|
-
static
|
597
|
-
VALUE rescue_callback(VALUE rdata, VALUE exception) {
|
598
|
-
protected_callback_data* data = (protected_callback_data*)rdata;
|
599
|
-
data->failed = true;
|
600
|
-
return exception;
|
601
|
-
}
|
602
|
-
|
603
|
-
void*
|
604
|
-
gvl_ruby_callback(void* data) {
|
605
|
-
|
606
|
-
FunctionCallbackInfo<Value>* args = (FunctionCallbackInfo<Value>*)data;
|
607
|
-
VALUE* ruby_args = NULL;
|
608
|
-
int length = args->Length();
|
609
|
-
VALUE callback;
|
610
|
-
VALUE result;
|
611
|
-
VALUE self;
|
612
|
-
|
613
|
-
{
|
614
|
-
HandleScope scope(args->GetIsolate());
|
615
|
-
Handle<External> external = Handle<External>::Cast(args->Data());
|
616
|
-
|
617
|
-
VALUE* self_pointer = (VALUE*)(external->Value());
|
618
|
-
self = *self_pointer;
|
619
|
-
callback = rb_iv_get(self, "@callback");
|
620
|
-
|
621
|
-
if (length > 0) {
|
622
|
-
ruby_args = ALLOC_N(VALUE, length);
|
623
|
-
}
|
624
|
-
|
625
|
-
|
626
|
-
for (int i = 0; i < length; i++) {
|
627
|
-
Local<Value> value = ((*args)[i]).As<Value>();
|
628
|
-
ruby_args[i] = convert_v8_to_ruby(args->GetIsolate(), value);
|
629
|
-
}
|
630
|
-
}
|
631
|
-
|
632
|
-
// may raise exception stay clear of handle scope
|
633
|
-
protected_callback_data callback_data;
|
634
|
-
callback_data.length = length;
|
635
|
-
callback_data.callback = callback;
|
636
|
-
callback_data.args = ruby_args;
|
637
|
-
callback_data.failed = false;
|
638
|
-
|
639
|
-
if ((bool)args->GetIsolate()->GetData(1) == true) {
|
640
|
-
args->GetIsolate()->ThrowException(String::NewFromUtf8(args->GetIsolate(), "Terminated execution during tansition from Ruby to JS"));
|
641
|
-
V8::TerminateExecution(args->GetIsolate());
|
642
|
-
return NULL;
|
643
|
-
}
|
644
|
-
|
645
|
-
result = rb_rescue2((VALUE(*)(...))&protected_callback, (VALUE)(&callback_data),
|
646
|
-
(VALUE(*)(...))&rescue_callback, (VALUE)(&callback_data), rb_eException, (VALUE)0);
|
647
|
-
|
648
|
-
if(callback_data.failed) {
|
649
|
-
VALUE parent = rb_iv_get(self, "@parent");
|
650
|
-
rb_iv_set(parent, "@current_exception", result);
|
651
|
-
args->GetIsolate()->ThrowException(String::NewFromUtf8(args->GetIsolate(), "Ruby exception"));
|
652
|
-
}
|
653
|
-
else {
|
654
|
-
HandleScope scope(args->GetIsolate());
|
655
|
-
Handle<Value> v8_result = convert_ruby_to_v8(args->GetIsolate(), result);
|
656
|
-
args->GetReturnValue().Set(v8_result);
|
657
|
-
}
|
658
|
-
|
659
|
-
if (length > 0) {
|
660
|
-
xfree(ruby_args);
|
661
|
-
}
|
662
|
-
|
663
|
-
if ((bool)args->GetIsolate()->GetData(1) == true) {
|
664
|
-
Isolate* isolate = args->GetIsolate();
|
665
|
-
V8::TerminateExecution(isolate);
|
666
|
-
}
|
667
|
-
|
668
|
-
return NULL;
|
669
|
-
}
|
670
|
-
|
671
|
-
static void ruby_callback(const FunctionCallbackInfo<Value>& args) {
|
672
|
-
|
673
|
-
bool has_gvl = (bool)args.GetIsolate()->GetData(0);
|
674
|
-
|
675
|
-
if(has_gvl) {
|
676
|
-
gvl_ruby_callback((void*)&args);
|
677
|
-
} else {
|
678
|
-
rb_thread_call_with_gvl(gvl_ruby_callback, (void*)(&args));
|
679
|
-
}
|
680
|
-
}
|
681
|
-
|
682
|
-
|
683
|
-
static VALUE rb_external_function_notify_v8(VALUE self) {
|
684
|
-
|
685
|
-
ContextInfo* context_info;
|
686
|
-
|
687
|
-
VALUE parent = rb_iv_get(self, "@parent");
|
688
|
-
VALUE name = rb_iv_get(self, "@name");
|
689
|
-
VALUE parent_object = rb_iv_get(self, "@parent_object");
|
690
|
-
VALUE parent_object_eval = rb_iv_get(self, "@parent_object_eval");
|
691
|
-
|
692
|
-
bool parse_error = false;
|
693
|
-
bool attach_error = false;
|
694
|
-
|
695
|
-
Data_Get_Struct(parent, ContextInfo, context_info);
|
696
|
-
Isolate* isolate = context_info->isolate_info->isolate;
|
697
|
-
|
698
|
-
{
|
699
|
-
Locker lock(isolate);
|
700
|
-
Isolate::Scope isolate_scope(isolate);
|
701
|
-
HandleScope handle_scope(isolate);
|
702
|
-
|
703
|
-
Local<Context> context = context_info->context->Get(isolate);
|
704
|
-
Context::Scope context_scope(context);
|
705
|
-
|
706
|
-
Local<String> v8_str = String::NewFromUtf8(isolate, RSTRING_PTR(name),
|
707
|
-
NewStringType::kNormal, (int)RSTRING_LEN(name)).ToLocalChecked();
|
708
|
-
|
709
|
-
// copy self so we can access from v8 external
|
710
|
-
VALUE* self_copy;
|
711
|
-
Data_Get_Struct(self, VALUE, self_copy);
|
712
|
-
*self_copy = self;
|
713
|
-
|
714
|
-
Local<Value> external = External::New(isolate, self_copy);
|
715
|
-
|
716
|
-
if (parent_object == Qnil) {
|
717
|
-
context->Global()->Set(v8_str, FunctionTemplate::New(isolate, ruby_callback, external)->GetFunction());
|
718
|
-
} else {
|
719
|
-
|
720
|
-
Local<String> eval = String::NewFromUtf8(isolate, RSTRING_PTR(parent_object_eval),
|
721
|
-
NewStringType::kNormal, (int)RSTRING_LEN(parent_object_eval)).ToLocalChecked();
|
722
|
-
|
723
|
-
MaybeLocal<Script> parsed_script = Script::Compile(context, eval);
|
724
|
-
if (parsed_script.IsEmpty()) {
|
725
|
-
parse_error = true;
|
726
|
-
} else {
|
727
|
-
MaybeLocal<Value> maybe_value = parsed_script.ToLocalChecked()->Run(context);
|
728
|
-
attach_error = true;
|
729
|
-
|
730
|
-
if (!maybe_value.IsEmpty()) {
|
731
|
-
Local<Value> value = maybe_value.ToLocalChecked();
|
732
|
-
if (value->IsObject()){
|
733
|
-
value.As<Object>()->Set(v8_str, FunctionTemplate::New(isolate, ruby_callback, external)->GetFunction());
|
734
|
-
attach_error = false;
|
735
|
-
}
|
736
|
-
}
|
737
|
-
}
|
738
|
-
}
|
739
|
-
}
|
740
|
-
|
741
|
-
// always raise out of V8 context
|
742
|
-
if (parse_error) {
|
743
|
-
rb_raise(rb_eParseError, "Invalid object %s", RSTRING_PTR(parent_object));
|
744
|
-
}
|
745
|
-
|
746
|
-
if (attach_error) {
|
747
|
-
rb_raise(rb_eParseError, "Was expecting %s to be an object", RSTRING_PTR(parent_object));
|
748
|
-
}
|
749
|
-
|
750
|
-
return Qnil;
|
751
|
-
}
|
752
|
-
|
753
|
-
void maybe_free_isolate_info(IsolateInfo* isolate_info) {
|
754
|
-
// an isolate can only be freed if no Isolate or Context (ruby) object
|
755
|
-
// still need it
|
756
|
-
if (isolate_info == NULL || isolate_info->refs_count > 0) {
|
757
|
-
return;
|
758
|
-
}
|
759
|
-
|
760
|
-
if (isolate_info->isolate) {
|
761
|
-
Locker lock(isolate_info->isolate);
|
762
|
-
}
|
763
|
-
|
764
|
-
if (isolate_info->isolate) {
|
765
|
-
if (isolate_info->interrupted) {
|
766
|
-
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.");
|
767
|
-
} else {
|
768
|
-
|
769
|
-
isolate_info->isolate->Dispose();
|
770
|
-
}
|
771
|
-
isolate_info->isolate = NULL;
|
772
|
-
}
|
773
|
-
|
774
|
-
if (isolate_info->startup_data) {
|
775
|
-
delete[] isolate_info->startup_data->data;
|
776
|
-
delete isolate_info->startup_data;
|
777
|
-
}
|
778
|
-
|
779
|
-
delete isolate_info->allocator;
|
780
|
-
xfree(isolate_info);
|
781
|
-
}
|
782
|
-
|
783
|
-
void deallocate_isolate(void* data) {
|
784
|
-
IsolateInfo* isolate_info = (IsolateInfo*) data;
|
785
|
-
|
786
|
-
isolate_info->refs_count--;
|
787
|
-
|
788
|
-
maybe_free_isolate_info(isolate_info);
|
789
|
-
}
|
790
|
-
|
791
|
-
void deallocate(void* data) {
|
792
|
-
ContextInfo* context_info = (ContextInfo*)data;
|
793
|
-
IsolateInfo* isolate_info = context_info->isolate_info;
|
794
|
-
|
795
|
-
if (context_info->context && isolate_info && isolate_info->isolate) {
|
796
|
-
Locker lock(isolate_info->isolate);
|
797
|
-
v8::Isolate::Scope isolate_scope(isolate_info->isolate);
|
798
|
-
context_info->context->Reset();
|
799
|
-
delete context_info->context;
|
800
|
-
}
|
801
|
-
|
802
|
-
if (isolate_info) {
|
803
|
-
isolate_info->refs_count--;
|
804
|
-
maybe_free_isolate_info(isolate_info);
|
805
|
-
}
|
806
|
-
}
|
807
|
-
|
808
|
-
void deallocate_external_function(void * data) {
|
809
|
-
xfree(data);
|
810
|
-
}
|
811
|
-
|
812
|
-
void deallocate_snapshot(void * data) {
|
813
|
-
SnapshotInfo* snapshot_info = (SnapshotInfo*)data;
|
814
|
-
|
815
|
-
delete[] snapshot_info->data;
|
816
|
-
|
817
|
-
xfree(snapshot_info);
|
818
|
-
}
|
819
|
-
|
820
|
-
VALUE allocate_external_function(VALUE klass) {
|
821
|
-
VALUE* self = ALLOC(VALUE);
|
822
|
-
return Data_Wrap_Struct(klass, NULL, deallocate_external_function, (void*)self);
|
823
|
-
}
|
824
|
-
|
825
|
-
VALUE allocate(VALUE klass) {
|
826
|
-
ContextInfo* context_info = ALLOC(ContextInfo);
|
827
|
-
context_info->isolate_info = NULL;
|
828
|
-
context_info->context = NULL;
|
829
|
-
|
830
|
-
return Data_Wrap_Struct(klass, NULL, deallocate, (void*)context_info);
|
831
|
-
}
|
832
|
-
|
833
|
-
VALUE allocate_snapshot(VALUE klass) {
|
834
|
-
SnapshotInfo* snapshot_info = ALLOC(SnapshotInfo);
|
835
|
-
snapshot_info->data = NULL;
|
836
|
-
snapshot_info->raw_size = 0;
|
837
|
-
|
838
|
-
return Data_Wrap_Struct(klass, NULL, deallocate_snapshot, (void*)snapshot_info);
|
839
|
-
}
|
840
|
-
|
841
|
-
VALUE allocate_isolate(VALUE klass) {
|
842
|
-
IsolateInfo* isolate_info = ALLOC(IsolateInfo);
|
843
|
-
|
844
|
-
isolate_info->isolate = NULL;
|
845
|
-
isolate_info->allocator = NULL;
|
846
|
-
isolate_info->startup_data = NULL;
|
847
|
-
isolate_info->interrupted = false;
|
848
|
-
isolate_info->refs_count = 0;
|
849
|
-
|
850
|
-
return Data_Wrap_Struct(klass, NULL, deallocate_isolate, (void*)isolate_info);
|
851
|
-
}
|
852
|
-
|
853
|
-
static VALUE
|
854
|
-
rb_context_stop(VALUE self) {
|
855
|
-
|
856
|
-
ContextInfo* context_info;
|
857
|
-
Data_Get_Struct(self, ContextInfo, context_info);
|
858
|
-
|
859
|
-
Isolate* isolate = context_info->isolate_info->isolate;
|
860
|
-
|
861
|
-
// flag for termination
|
862
|
-
isolate->SetData(1, (void*)true);
|
863
|
-
|
864
|
-
V8::TerminateExecution(isolate);
|
865
|
-
rb_funcall(self, rb_intern("stop_attached"), 0);
|
866
|
-
|
867
|
-
return Qnil;
|
868
|
-
}
|
869
|
-
|
870
|
-
extern "C" {
|
871
|
-
|
872
|
-
void Init_mini_racer_extension ( void )
|
873
|
-
{
|
874
|
-
VALUE rb_mMiniRacer = rb_define_module("MiniRacer");
|
875
|
-
VALUE rb_cContext = rb_define_class_under(rb_mMiniRacer, "Context", rb_cObject);
|
876
|
-
VALUE rb_cSnapshot = rb_define_class_under(rb_mMiniRacer, "Snapshot", rb_cObject);
|
877
|
-
VALUE rb_cIsolate = rb_define_class_under(rb_mMiniRacer, "Isolate", rb_cObject);
|
878
|
-
VALUE rb_cPlatform = rb_define_class_under(rb_mMiniRacer, "Platform", rb_cObject);
|
879
|
-
|
880
|
-
VALUE rb_eEvalError = rb_define_class_under(rb_mMiniRacer, "EvalError", rb_eStandardError);
|
881
|
-
rb_eScriptTerminatedError = rb_define_class_under(rb_mMiniRacer, "ScriptTerminatedError", rb_eEvalError);
|
882
|
-
rb_eParseError = rb_define_class_under(rb_mMiniRacer, "ParseError", rb_eEvalError);
|
883
|
-
rb_eScriptRuntimeError = rb_define_class_under(rb_mMiniRacer, "RuntimeError", rb_eEvalError);
|
884
|
-
rb_cJavaScriptFunction = rb_define_class_under(rb_mMiniRacer, "JavaScriptFunction", rb_cObject);
|
885
|
-
rb_eSnapshotError = rb_define_class_under(rb_mMiniRacer, "SnapshotError", rb_eStandardError);
|
886
|
-
rb_ePlatformAlreadyInitializedError = rb_define_class_under(rb_mMiniRacer, "PlatformAlreadyInitialized", rb_eStandardError);
|
887
|
-
rb_cFailedV8Conversion = rb_define_class_under(rb_mMiniRacer, "FailedV8Conversion", rb_cObject);
|
888
|
-
|
889
|
-
VALUE rb_cExternalFunction = rb_define_class_under(rb_cContext, "ExternalFunction", rb_cObject);
|
890
|
-
rb_define_method(rb_cContext, "stop", (VALUE(*)(...))&rb_context_stop, 0);
|
891
|
-
rb_define_alloc_func(rb_cContext, allocate);
|
892
|
-
rb_define_alloc_func(rb_cSnapshot, allocate_snapshot);
|
893
|
-
rb_define_alloc_func(rb_cIsolate, allocate_isolate);
|
894
|
-
|
895
|
-
rb_define_private_method(rb_cContext, "eval_unsafe",(VALUE(*)(...))&rb_context_eval_unsafe, 1);
|
896
|
-
rb_define_private_method(rb_cContext, "init_with_isolate",(VALUE(*)(...))&rb_context_init_with_isolate, 1);
|
897
|
-
rb_define_private_method(rb_cExternalFunction, "notify_v8", (VALUE(*)(...))&rb_external_function_notify_v8, 0);
|
898
|
-
rb_define_alloc_func(rb_cExternalFunction, allocate_external_function);
|
899
|
-
|
900
|
-
rb_define_method(rb_cSnapshot, "size", (VALUE(*)(...))&rb_snapshot_size, 0);
|
901
|
-
rb_define_method(rb_cSnapshot, "warmup!", (VALUE(*)(...))&rb_snapshot_warmup, 1);
|
902
|
-
rb_define_private_method(rb_cSnapshot, "load", (VALUE(*)(...))&rb_snapshot_load, 1);
|
903
|
-
|
904
|
-
rb_define_method(rb_cIsolate, "idle_notification", (VALUE(*)(...))&rb_isolate_idle_notification, 1);
|
905
|
-
rb_define_private_method(rb_cIsolate, "init_with_snapshot",(VALUE(*)(...))&rb_isolate_init_with_snapshot, 1);
|
906
|
-
|
907
|
-
rb_define_singleton_method(rb_cPlatform, "set_flag_as_str!", (VALUE(*)(...))&rb_platform_set_flag_as_str, 1);
|
908
|
-
}
|
909
|
-
|
910
|
-
}
|
@@ -1,261 +0,0 @@
|
|
1
|
-
require "mini_racer/version"
|
2
|
-
require "mini_racer_extension"
|
3
|
-
require "thread"
|
4
|
-
|
5
|
-
module MiniRacer
|
6
|
-
|
7
|
-
class EvalError < StandardError; end
|
8
|
-
class ScriptTerminatedError < EvalError; end
|
9
|
-
class ParseError < EvalError; end
|
10
|
-
class SnapshotError < StandardError; end
|
11
|
-
class PlatformAlreadyInitialized < StandardError; end
|
12
|
-
|
13
|
-
class FailedV8Conversion
|
14
|
-
attr_reader :info
|
15
|
-
def initialize(info)
|
16
|
-
@info = info
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class RuntimeError < EvalError
|
21
|
-
def initialize(message)
|
22
|
-
message, js_backtrace = message.split("\n", 2)
|
23
|
-
if js_backtrace && !js_backtrace.empty?
|
24
|
-
@js_backtrace = js_backtrace.split("\n")
|
25
|
-
@js_backtrace.map!{|f| "JavaScript #{f.strip}"}
|
26
|
-
else
|
27
|
-
@js_backtrace = nil
|
28
|
-
end
|
29
|
-
super(message)
|
30
|
-
end
|
31
|
-
|
32
|
-
def backtrace
|
33
|
-
val = super
|
34
|
-
return unless val
|
35
|
-
if @js_backtrace
|
36
|
-
@js_backtrace + val
|
37
|
-
else
|
38
|
-
val
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
# helper class returned when we have a JavaScript function
|
44
|
-
class JavaScriptFunction
|
45
|
-
def to_s
|
46
|
-
"JavaScript Function"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
class Isolate
|
51
|
-
def initialize(snapshot = nil)
|
52
|
-
unless snapshot.nil? || snapshot.is_a?(Snapshot)
|
53
|
-
raise ArgumentError, "snapshot must be a Snapshot object, passed a #{snapshot.inspect}"
|
54
|
-
end
|
55
|
-
|
56
|
-
@lock = Mutex.new
|
57
|
-
|
58
|
-
# defined in the C class
|
59
|
-
init_with_snapshot(snapshot)
|
60
|
-
end
|
61
|
-
|
62
|
-
def with_lock
|
63
|
-
@lock.synchronize { yield }
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
class Platform
|
68
|
-
class << self
|
69
|
-
def set_flags!(*args, **kwargs)
|
70
|
-
flags_to_strings([args, kwargs]).each do |flag|
|
71
|
-
# defined in the C class
|
72
|
-
set_flag_as_str!(flag)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
private
|
77
|
-
|
78
|
-
def flags_to_strings(flags)
|
79
|
-
flags.flatten.map { |flag| flag_to_string(flag) }.flatten
|
80
|
-
end
|
81
|
-
|
82
|
-
# normalize flags to strings, and adds leading dashes if needed
|
83
|
-
def flag_to_string(flag)
|
84
|
-
if flag.is_a?(Hash)
|
85
|
-
flag.map do |key, value|
|
86
|
-
"#{flag_to_string(key)} #{value}"
|
87
|
-
end
|
88
|
-
else
|
89
|
-
str = flag.to_s
|
90
|
-
str = "--#{str}" unless str.start_with?('--')
|
91
|
-
str
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
# eval is defined in the C class
|
98
|
-
class Context
|
99
|
-
|
100
|
-
class ExternalFunction
|
101
|
-
def initialize(name, callback, parent)
|
102
|
-
unless String === name
|
103
|
-
raise ArgumentError, "parent_object must be a String"
|
104
|
-
end
|
105
|
-
parent_object, _ , @name = name.rpartition(".")
|
106
|
-
@callback = callback
|
107
|
-
@parent = parent
|
108
|
-
@parent_object_eval = nil
|
109
|
-
@parent_object = nil
|
110
|
-
|
111
|
-
unless parent_object.empty?
|
112
|
-
@parent_object = parent_object
|
113
|
-
|
114
|
-
@parent_object_eval = ""
|
115
|
-
prev = ""
|
116
|
-
first = true
|
117
|
-
parent_object.split(".").each do |obj|
|
118
|
-
prev << obj
|
119
|
-
if first
|
120
|
-
@parent_object_eval << "if (typeof #{prev} === 'undefined') { #{prev} = {} };\n"
|
121
|
-
else
|
122
|
-
@parent_object_eval << "#{prev} = #{prev} || {};\n"
|
123
|
-
end
|
124
|
-
prev << "."
|
125
|
-
first = false
|
126
|
-
end
|
127
|
-
@parent_object_eval << "#{parent_object};"
|
128
|
-
end
|
129
|
-
notify_v8
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
attr_reader :isolate
|
134
|
-
|
135
|
-
def initialize(options = nil)
|
136
|
-
options ||= {}
|
137
|
-
|
138
|
-
check_init_options!(options)
|
139
|
-
|
140
|
-
@functions = {}
|
141
|
-
@timeout = nil
|
142
|
-
@current_exception = nil
|
143
|
-
@timeout = options[:timeout]
|
144
|
-
@isolate = options[:isolate] || Isolate.new(options[:snapshot])
|
145
|
-
|
146
|
-
@callback_mutex = Mutex.new
|
147
|
-
@callback_running = false
|
148
|
-
@thread_raise_called = false
|
149
|
-
@eval_thread = nil
|
150
|
-
|
151
|
-
isolate.with_lock do
|
152
|
-
# defined in the C class
|
153
|
-
init_with_isolate(@isolate)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def load(filename)
|
158
|
-
# TODO do this native cause no need to allocate VALUE here
|
159
|
-
eval(File.read(filename))
|
160
|
-
end
|
161
|
-
|
162
|
-
def eval(str)
|
163
|
-
@eval_thread = Thread.current
|
164
|
-
isolate.with_lock do
|
165
|
-
@current_exception = nil
|
166
|
-
timeout do
|
167
|
-
eval_unsafe(str)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
ensure
|
171
|
-
@eval_thread = nil
|
172
|
-
end
|
173
|
-
|
174
|
-
|
175
|
-
def attach(name, callback)
|
176
|
-
|
177
|
-
wrapped = lambda do |*args|
|
178
|
-
begin
|
179
|
-
@callback_mutex.synchronize{
|
180
|
-
@callback_running = true
|
181
|
-
}
|
182
|
-
|
183
|
-
callback.call(*args)
|
184
|
-
ensure
|
185
|
-
@callback_mutex.synchronize {
|
186
|
-
@callback_running = false
|
187
|
-
|
188
|
-
# this is some odd code, but it is required
|
189
|
-
# if we raised on this thread we better wait for it
|
190
|
-
# otherwise we may end up raising in an unsafe spot
|
191
|
-
if @thread_raise_called
|
192
|
-
sleep 0.1
|
193
|
-
end
|
194
|
-
@thread_raise_called = false
|
195
|
-
}
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
isolate.with_lock do
|
200
|
-
external = ExternalFunction.new(name, wrapped, self)
|
201
|
-
@functions["#{name}"] = external
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
private
|
206
|
-
|
207
|
-
def stop_attached
|
208
|
-
@callback_mutex.synchronize{
|
209
|
-
if @callback_running
|
210
|
-
@eval_thread.raise ScriptTerminatedError, "Terminated during callback"
|
211
|
-
@thread_raise_called = true
|
212
|
-
end
|
213
|
-
}
|
214
|
-
end
|
215
|
-
|
216
|
-
def timeout(&blk)
|
217
|
-
return blk.call unless @timeout
|
218
|
-
|
219
|
-
_,wp = IO.pipe
|
220
|
-
|
221
|
-
Thread.new do
|
222
|
-
begin
|
223
|
-
result = IO.select([wp],[],[],(@timeout/1000.0))
|
224
|
-
if !result
|
225
|
-
stop
|
226
|
-
end
|
227
|
-
rescue
|
228
|
-
STDERR.puts "FAILED TO TERMINATE DUE TO TIMEOUT"
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
rval = blk.call
|
233
|
-
wp.write("done")
|
234
|
-
|
235
|
-
rval
|
236
|
-
end
|
237
|
-
|
238
|
-
def check_init_options!(options)
|
239
|
-
assert_option_is_nil_or_a('isolate', options[:isolate], Isolate)
|
240
|
-
assert_option_is_nil_or_a('snapshot', options[:snapshot], Snapshot)
|
241
|
-
|
242
|
-
if options[:isolate] && options[:snapshot]
|
243
|
-
raise ArgumentError, 'can only pass one of isolate and snapshot options'
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
def assert_option_is_nil_or_a(option_name, object, klass)
|
248
|
-
unless object.nil? || object.is_a?(klass)
|
249
|
-
raise ArgumentError, "#{option_name} must be a #{klass} object, passed a #{object.inspect}"
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
# `size` and `warmup!` public methods are defined in the C class
|
255
|
-
class Snapshot
|
256
|
-
def initialize(str = '')
|
257
|
-
# defined in the C class
|
258
|
-
load(str)
|
259
|
-
end
|
260
|
-
end
|
261
|
-
end
|
Binary file
|