ruby_box 0.0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 24712c9c81020b44d9311a1cb883279c29d2cbd2
4
- data.tar.gz: a5bdfa62602acb7c577cd4c8f4248ac010fd6f1d
3
+ metadata.gz: ad18cf425468583ca9d68b028decf40c0cab4c8d
4
+ data.tar.gz: a396ac061daca869cc7614703ab9446a2fd2ab6e
5
5
  SHA512:
6
- metadata.gz: 2c08690552b840b62dc8566d827b2cc218fbb7e4c38803fc3eade15fae4b5d37f08d2eba6bdf421c0ca6f2a4ea57c80ec67091ffcfe2e4d61974817087b479d6
7
- data.tar.gz: 743bf09d576224b268caebdd9dc95dd2d54acf2df7fa35c247d746cc1d46cc7960a591ef56351b43af41946b1d2e11e12b7c2357b89fc77409301f8eed76d120
6
+ metadata.gz: 276d89862d95255ef094c8f906c154be97ff20e1d31d7139ea3f183f5a79eca6bec87a05ca06daa5321996c5a9ae5493347b5106cc13870373520088987fa02d
7
+ data.tar.gz: e8959d5af99de60849293ec31e7ecfee684006f22a6856f849f06f89b4cd0a90ca52fb5bc9e975372e01f22ce2bc317ed4b74f5b96fd54136510f3c0a23057cc
@@ -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
@@ -1,3 +1,3 @@
1
1
  module RubyBox
2
- VERSION = '0.0.0.1'
2
+ VERSION = '1.0.0'
3
3
  end
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: 0.0.0.1
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: 2016-09-26 00:00:00.000000000 Z
11
+ date: 2017-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: libv8
14
+ name: mini_racer
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '5.1'
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: '5.1'
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: '1.10'
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: '1.10'
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.4.6
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
@@ -1,3 +0,0 @@
1
- module MiniRacer
2
- VERSION = "0.1.4"
3
- end