mini_racer 0.6.0 → 0.6.3

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
  SHA256:
3
- metadata.gz: 179c0a63082cf1ec6bc7f8ead94fbcba3c41255ee91b1639482570d1ec3f7646
4
- data.tar.gz: cdef6f06a6ab72060aa43b21518c6f0103bf80c034bee09b7cf1d6f215620c31
3
+ metadata.gz: 4290b52d3d19c196567892c0d3eda0b47f07047afe059e63d4ac976258cb52a0
4
+ data.tar.gz: 55e41b4e8ab93cdfe45446ff08a5b3c42323356e36b79d91f2e564c43a7715fe
5
5
  SHA512:
6
- metadata.gz: 0efd1873f139141ac489ed24ebcad3e289092ea67ea7823d0b94fe07a3acfcd602ed64c287b39b556d370db5c17b094d38a9c5ff06f31f546dddda7694d01c81
7
- data.tar.gz: 1ccc24b53320211be2b3cd887ac1193ee0654e0b54c0d2b3da636a382ce00c95d4af3ba5acd23a931436d08e0707dc0b4d348b6bbd0863cb56df9fb2fbd2678e
6
+ metadata.gz: c0e0cca11803ffa6ba38998810ccb82413257145947a637f3800252f4a0d47bd47fde425786c09f1eedf6c28b1bb584d34914b111effffef908ff182e79c5329
7
+ data.tar.gz: 05dbfe34c140fedf6fbd33f5eee62f6cc6880579d238039f2e351a0279fa9267575b46ae7890f9c7d19ebd43bf1020e9bb57d445ad4e6ac8f89440ac3e2744d3
@@ -1,48 +1,92 @@
1
- name: Test
1
+ name: Tests
2
+
2
3
  on:
3
- - push
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - master
4
8
 
5
9
  jobs:
10
+ test-truffleruby:
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ os:
15
+ - "macos-11"
16
+ - "macos-12"
17
+ - "ubuntu-20.04"
18
+ ruby:
19
+ - "truffleruby+graalvm-head"
20
+
21
+ name: ${{ matrix.os }} - ${{ matrix.ruby }}
22
+ runs-on: ${{ matrix.os }}
23
+
24
+ env:
25
+ TRUFFLERUBYOPT: "--jvm --polyglot"
26
+
27
+ steps:
28
+ - uses: actions/checkout@v3
29
+ - uses: ruby/setup-ruby@v1
30
+ with:
31
+ ruby-version: ${{ matrix.ruby }}
32
+ bundler-cache: true
33
+ - name: Install GraalVM JS component
34
+ run: gu install js
35
+ - name: Compile
36
+ run: bundle exec rake compile
37
+ - name: Test
38
+ run: bundle exec rake test
39
+
6
40
  test-darwin:
7
41
  strategy:
8
42
  fail-fast: false
9
43
  matrix:
10
44
  os:
11
- - '10.15'
12
- - '11.0'
13
- platform:
14
- - x86_64
15
- # arm64
16
- name: Test (darwin)
17
- runs-on: macos-${{ matrix.os }}
45
+ - "macos-11"
46
+ - "macos-12"
47
+ ruby:
48
+ - "ruby-2.6"
49
+ - "ruby-2.7"
50
+ - "ruby-3.0"
51
+ - "ruby-3.1"
52
+
53
+ name: ${{ matrix.os }} - ${{ matrix.ruby }}
54
+ runs-on: ${{ matrix.os }}
55
+
18
56
  steps:
19
- - name: Checkout
20
- uses: actions/checkout@v2
21
- - name: Bundle
22
- run: bundle install
57
+ - uses: actions/checkout@v3
58
+ - uses: ruby/setup-ruby@v1
59
+ with:
60
+ ruby-version: ${{ matrix.ruby }}
61
+ bundler-cache: true
23
62
  - name: Compile
24
63
  run: bundle exec rake compile
25
64
  - name: Test
26
65
  run: bundle exec rake test
66
+
27
67
  test-linux:
28
68
  strategy:
29
69
  fail-fast: false
30
70
  matrix:
31
71
  ruby:
32
- - '2.6'
33
- - '2.7'
34
- - '3.0'
72
+ - "2.6"
73
+ - "2.7"
74
+ - "3.0"
75
+ - "3.1"
35
76
  platform:
36
- - amd64
37
- - arm64
38
- # arm
39
- # ppc64le
40
- # s390x
77
+ - "amd64"
78
+ - "arm64"
41
79
  libc:
42
- - gnu
43
- - musl
44
- name: Test (linux)
80
+ - "gnu"
81
+ - "musl"
82
+ exclude:
83
+ # there's no libv8-node (v16) for aarch64-linux-musl at the moment
84
+ - platform: "arm64"
85
+ libc: "musl"
86
+
87
+ name: linux-${{ matrix.platform }} - ruby-${{ matrix.ruby }} - ${{ matrix.libc }}
45
88
  runs-on: ubuntu-20.04
89
+
46
90
  steps:
47
91
  - name: Enable ${{ matrix.platform }} platform
48
92
  id: qemu
@@ -67,9 +111,11 @@ jobs:
67
111
  echo "::set-output name=id::$(cat container_id)"
68
112
  - name: Install Alpine system dependencies
69
113
  if: ${{ matrix.libc == 'musl' }}
70
- run: docker exec -w "${PWD}" ${{ steps.container.outputs.id }} apk add --no-cache build-base linux-headers bash python2 python3 git curl tar clang binutils-gold
114
+ run: docker exec -w "${PWD}" ${{ steps.container.outputs.id }} apk add --no-cache build-base bash git
71
115
  - name: Checkout
72
- uses: actions/checkout@v2
116
+ uses: actions/checkout@v3
117
+ - name: Update Rubygems
118
+ run: docker exec -w "${PWD}" ${{ steps.container.outputs.id }} gem update --system
73
119
  - name: Bundle
74
120
  run: docker exec -w "${PWD}" ${{ steps.container.outputs.id }} bundle install
75
121
  - name: Compile
data/CHANGELOG CHANGED
@@ -1,5 +1,30 @@
1
+ - 16-08-2022
2
+
3
+ - 0.6.3
4
+
5
+ - Truffle ruby support! Thanks to Brandon Fish and the truffle team
6
+ - Hide libv8 symbols on ELF targets
7
+ - Slightly shrunk binary size
8
+ - Simplified timeout implementation
9
+ - Some stability fixes
10
+
11
+ - 17-01-2022
12
+
13
+ - 0.6.2
14
+
15
+ - Fix support for compilation on 2.6, llvm compiles
16
+ - Stability patches to handle rare memory leaks
17
+ - Corrected re-raising of exceptions to support strings
18
+ - During early termination of context under certain conditions MiniRacer could crash
19
+
20
+
1
21
  - 31-12-2021
2
22
 
23
+ - 0.6.1
24
+
25
+ - Added support for single threaded platform: `MiniRacer::Platform.set_flags! :single_threaded`
26
+ must be called prior to booting ANY MiniRacer::Context
27
+
3
28
  - 0.6.0
4
29
 
5
30
  - Ruby 3.1 support
@@ -13,7 +38,6 @@
13
38
  - Fixes issues on aarch (Apple M1)
14
39
  - Update to use libv8-node 16.x (#210) [Loic Nageleisen]
15
40
  - FEATURE: Configurable max marshal stack depth (#202) [seanmakesgames]
16
- - FEATURE: Configurable max marshal stack depth (#202) [seanmakesgames]
17
41
  - Ruby 2.3 and 2.4 are EOL, we no longer support them
18
42
 
19
43
  - 0.4.0
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MiniRacer
2
2
 
3
- [![Build Status](https://travis-ci.org/rubyjs/mini_racer.svg?branch=master)](https://travis-ci.org/rubyjs/mini_racer)
3
+ [![Test](https://github.com/rubyjs/mini_racer/actions/workflows/ci.yml/badge.svg)](https://github.com/rubyjs/mini_racer/actions/workflows/ci.yml)
4
4
 
5
5
  Minimal, modern embedded V8 for Ruby.
6
6
 
@@ -12,7 +12,7 @@ MiniRacer has an adapter for [execjs](https://github.com/rails/execjs) so it can
12
12
 
13
13
  ### A note about Ruby version Support
14
14
 
15
- MiniRacer only supports non-EOL versions of Ruby. See [Ruby](https://www.ruby-lang.org/en/downloads) to see the list of non-EOL Rubies.
15
+ MiniRacer only supports non-EOL versions of Ruby. See [Ruby Maintenance Branches](https://www.ruby-lang.org/en/downloads/branches/) for the list of non-EOL Rubies.
16
16
 
17
17
  If you require support for older versions of Ruby install an older version of the gem.
18
18
 
@@ -112,16 +112,21 @@ context.eval('bar()', filename: 'a/bar.js')
112
112
 
113
113
  ### Fork safety
114
114
 
115
- Some Ruby web servers employ forking (for example unicorn or puma in clustered mode). V8 is not fork safe.
116
- Sadly Ruby does not have support for fork notifications per [#5446](https://bugs.ruby-lang.org/issues/5446).
115
+ Some Ruby web servers employ forking (for example unicorn or puma in clustered mode). V8 is not fork safe by default and sadly Ruby does not have support for fork notifications per [#5446](https://bugs.ruby-lang.org/issues/5446).
116
+
117
+ Since 0.6.1 mini_racer does support V8 single threaded platform mode which should remove most forking related issues. To enable run this before using `MiniRacer::Context`:
118
+
119
+ ```ruby
120
+ MiniRacer::Platform.set_flags!(:single_threaded)
121
+ ```
117
122
 
118
123
  If you want to ensure your application does not leak memory after fork either:
119
124
 
120
- 1. Ensure no MiniRacer::Context objects are created in the master process
125
+ 1. Ensure no `MiniRacer::Context` objects are created in the master process
121
126
 
122
127
  Or
123
128
 
124
- 2. Dispose manually of all MiniRacer::Context objects prior to forking
129
+ 2. Dispose manually of all `MiniRacer::Context` objects prior to forking
125
130
 
126
131
  ```ruby
127
132
  # before fork
@@ -419,18 +424,15 @@ Or install it yourself as:
419
424
  **Note** using v8.h and compiling MiniRacer requires a C++11 standard compiler, more specifically clang 3.5 (or later) or GCC 6.3 (or later).
420
425
 
421
426
 
422
- ## Travis-ci
427
+ ### Troubleshooting
423
428
 
424
- To install `mini-racer` you will need a version of GCC that supports C++11 (GCC 6.3) this is included by default in ubuntu trusty based images.
429
+ If you have a problem installing mini_racer, please consider the following steps:
425
430
 
426
- Travis today ships by default with a precise based image. Precise Pangolin (12.04 LTS) was first released in August 2012. Even though you can install GCC 6.3 on precise the simpler approach is to opt for the trusty based image.
427
-
428
- Add this to your .travis.yml file:
429
-
430
- ```
431
- - sudo: required
432
- - dist: trusty
433
- ```
431
+ * make sure you try the latest released version of mini_racer
432
+ * make sure you have Rubygems >= 3.2.13 and bundler >= 2.2.13 installed via `gem update --system`
433
+ * if you are using bundler, make sure to have `PLATFORMS` set correctly in `Gemfile.lock` via `bundle lock --add-platform`
434
+ * make sure to recompile/reinstall `mini_racer` and `libv8-node` after system upgrades (for example via `gem uninstall --all mini_racer libv8-node`)
435
+ * make sure you are on the latest patch/teeny version of a supported Ruby branch
434
436
 
435
437
  ## Similar Projects
436
438
 
data/Rakefile CHANGED
@@ -1,6 +1,5 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rake/testtask"
3
- require "rake/extensiontask"
4
3
 
5
4
  Rake::TestTask.new(:test) do |t|
6
5
  t.libs << "test"
@@ -11,8 +10,21 @@ end
11
10
  task :default => [:compile, :test]
12
11
 
13
12
  gem = Gem::Specification.load( File.dirname(__FILE__) + '/mini_racer.gemspec' )
14
- Rake::ExtensionTask.new( 'mini_racer_loader', gem )
15
- Rake::ExtensionTask.new( 'mini_racer_extension', gem )
13
+
14
+ if RUBY_ENGINE == "truffleruby"
15
+ task :compile do
16
+ # noop
17
+ end
18
+
19
+ task :clean do
20
+ # noop
21
+ end
22
+ else
23
+ require 'rake/extensiontask'
24
+ Rake::ExtensionTask.new( 'mini_racer_loader', gem )
25
+ Rake::ExtensionTask.new( 'mini_racer_extension', gem )
26
+ end
27
+
16
28
 
17
29
 
18
30
  # via http://blog.flavorjon.es/2009/06/easily-valgrind-gdb-your-ruby-c.html
@@ -1,4 +1,10 @@
1
1
  require 'mkmf'
2
+
3
+ if RUBY_ENGINE == "truffleruby"
4
+ File.write("Makefile", dummy_makefile($srcdir).join(""))
5
+ return
6
+ end
7
+
2
8
  require_relative '../../lib/mini_racer/version'
3
9
  gem 'libv8-node', MiniRacer::LIBV8_NODE_VERSION
4
10
  require 'libv8-node'
@@ -70,9 +76,17 @@ end
70
76
 
71
77
  Libv8::Node.configure_makefile
72
78
 
79
+ # --exclude-libs is only for i386 PE and ELF targeted ports
80
+ append_ldflags("-Wl,--exclude-libs=ALL ")
81
+
73
82
  if enable_config('asan')
74
83
  $CXXFLAGS.insert(0, " -fsanitize=address ")
75
84
  $LDFLAGS.insert(0, " -fsanitize=address ")
76
85
  end
77
86
 
87
+ # there doesn't seem to be a CPP macro for this in Ruby 2.6:
88
+ if RUBY_ENGINE == 'ruby'
89
+ $CPPFLAGS += ' -DENGINE_IS_CRUBY '
90
+ end
91
+
78
92
  create_makefile 'mini_racer_extension'
@@ -2,6 +2,7 @@
2
2
  #include <ruby.h>
3
3
  #include <ruby/thread.h>
4
4
  #include <ruby/io.h>
5
+ #include <ruby/version.h>
5
6
  #include <v8.h>
6
7
  #include <v8-profiler.h>
7
8
  #include <libplatform/libplatform.h>
@@ -13,6 +14,14 @@
13
14
  #include <math.h>
14
15
  #include <errno.h>
15
16
 
17
+ /* workaround C Ruby <= 2.x problems w/ clang in C++ mode */
18
+ #if defined(ENGINE_IS_CRUBY) && \
19
+ RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR <= 6
20
+ # define MR_METHOD_FUNC(fn) RUBY_METHOD_FUNC(fn)
21
+ #else
22
+ # define MR_METHOD_FUNC(fn) fn
23
+ #endif
24
+
16
25
  using namespace v8;
17
26
 
18
27
  typedef struct {
@@ -296,8 +305,7 @@ static std::unique_ptr<Platform> current_platform = NULL;
296
305
  static std::mutex platform_lock;
297
306
 
298
307
  static pthread_attr_t *thread_attr_p;
299
- static pthread_rwlock_t exit_lock = PTHREAD_RWLOCK_INITIALIZER;
300
- static bool ruby_exiting = false; // guarded by exit_lock
308
+ static std::atomic_int ruby_exiting(0);
301
309
  static bool single_threaded = false;
302
310
 
303
311
  static void mark_context(void *);
@@ -326,10 +334,7 @@ static const rb_data_type_t isolate_type = {
326
334
  static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) {
327
335
  bool platform_already_initialized = false;
328
336
 
329
- if(TYPE(flag_as_str) != T_STRING) {
330
- rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE" (should be a string)",
331
- rb_obj_class(flag_as_str));
332
- }
337
+ Check_Type(flag_as_str, T_STRING);
333
338
 
334
339
  platform_lock.lock();
335
340
 
@@ -337,7 +342,7 @@ static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) {
337
342
  if (!strcmp(RSTRING_PTR(flag_as_str), "--single_threaded")) {
338
343
  single_threaded = true;
339
344
  }
340
- V8::SetFlagsFromString(RSTRING_PTR(flag_as_str), (int)RSTRING_LEN(flag_as_str));
345
+ V8::SetFlagsFromString(RSTRING_PTR(flag_as_str), RSTRING_LENINT(flag_as_str));
341
346
  } else {
342
347
  platform_already_initialized = true;
343
348
  }
@@ -360,7 +365,11 @@ static void init_v8() {
360
365
 
361
366
  if (current_platform == NULL) {
362
367
  V8::InitializeICU();
363
- current_platform = platform::NewDefaultPlatform();
368
+ if (single_threaded) {
369
+ current_platform = platform::NewSingleThreadedDefaultPlatform();
370
+ } else {
371
+ current_platform = platform::NewDefaultPlatform();
372
+ }
364
373
  V8::InitializePlatform(current_platform.get());
365
374
  V8::Initialize();
366
375
  }
@@ -405,28 +414,32 @@ static void prepare_result(MaybeLocal<Value> v8res,
405
414
  Local<Value> local_value = v8res.ToLocalChecked();
406
415
  if ((local_value->IsObject() || local_value->IsArray()) &&
407
416
  !local_value->IsDate() && !local_value->IsFunction()) {
408
- Local<Object> JSON = context->Global()->Get(
409
- context, String::NewFromUtf8Literal(isolate, "JSON"))
410
- .ToLocalChecked().As<Object>();
411
-
412
- Local<Function> stringify = JSON->Get(
413
- context, v8::String::NewFromUtf8Literal(isolate, "stringify"))
414
- .ToLocalChecked().As<Function>();
417
+ MaybeLocal<v8::Value> ml = context->Global()->Get(
418
+ context, String::NewFromUtf8Literal(isolate, "JSON"));
415
419
 
416
- Local<Object> object = local_value->ToObject(context).ToLocalChecked();
417
- const unsigned argc = 1;
418
- Local<Value> argv[argc] = { object };
419
- MaybeLocal<Value> json = stringify->Call(context, JSON, argc, argv);
420
-
421
- if (json.IsEmpty()) {
420
+ if (ml.IsEmpty()) { // exception
422
421
  evalRes.executed = false;
423
422
  } else {
424
- evalRes.json = true;
425
- Persistent<Value>* persistent = new Persistent<Value>();
426
- persistent->Reset(isolate, json.ToLocalChecked());
427
- evalRes.value = persistent;
423
+ Local<Object> JSON = ml.ToLocalChecked().As<Object>();
424
+
425
+ Local<Function> stringify = JSON->Get(
426
+ context, v8::String::NewFromUtf8Literal(isolate, "stringify"))
427
+ .ToLocalChecked().As<Function>();
428
+
429
+ Local<Object> object = local_value->ToObject(context).ToLocalChecked();
430
+ const unsigned argc = 1;
431
+ Local<Value> argv[argc] = { object };
432
+ MaybeLocal<Value> json = stringify->Call(context, JSON, argc, argv);
433
+
434
+ if (json.IsEmpty()) {
435
+ evalRes.executed = false;
436
+ } else {
437
+ evalRes.json = true;
438
+ Persistent<Value>* persistent = new Persistent<Value>();
439
+ persistent->Reset(isolate, json.ToLocalChecked());
440
+ evalRes.value = persistent;
441
+ }
428
442
  }
429
-
430
443
  } else {
431
444
  Persistent<Value>* persistent = new Persistent<Value>();
432
445
  persistent->Reset(isolate, local_value);
@@ -647,11 +660,7 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
647
660
  v8::String::Utf8Value symbol_name(isolate,
648
661
  Local<Symbol>::Cast(value)->Name());
649
662
 
650
- VALUE str_symbol = rb_enc_str_new(
651
- *symbol_name,
652
- symbol_name.length(),
653
- rb_enc_find("utf-8")
654
- );
663
+ VALUE str_symbol = rb_utf8_str_new(*symbol_name, symbol_name.length());
655
664
 
656
665
  return rb_str_intern(str_symbol);
657
666
  }
@@ -662,7 +671,7 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
662
671
  return Qnil;
663
672
  } else {
664
673
  Local<String> rstr = rstr_maybe.ToLocalChecked();
665
- return rb_enc_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate), rb_enc_find("utf-8"));
674
+ return rb_utf8_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate));
666
675
  }
667
676
  }
668
677
 
@@ -707,7 +716,7 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context,
707
716
  case T_FLOAT:
708
717
  return scope.Escape(Number::New(isolate, NUM2DBL(value)));
709
718
  case T_STRING:
710
- return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, (int)RSTRING_LEN(value)).ToLocalChecked());
719
+ return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, RSTRING_LENINT(value)).ToLocalChecked());
711
720
  case T_NIL:
712
721
  return scope.Escape(Null(isolate));
713
722
  case T_TRUE:
@@ -735,7 +744,7 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context,
735
744
  return scope.Escape(object);
736
745
  case T_SYMBOL:
737
746
  value = rb_funcall(value, rb_intern("to_s"), 0);
738
- return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, (int)RSTRING_LEN(value)).ToLocalChecked());
747
+ return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, RSTRING_LENINT(value)).ToLocalChecked());
739
748
  case T_DATA:
740
749
  klass = rb_funcall(value, rb_intern("class"), 0);
741
750
  if (klass == rb_cTime || klass == rb_cDateTime)
@@ -844,7 +853,7 @@ StartupData warm_up_snapshot_data_blob(StartupData cold_snapshot_blob,
844
853
  return result;
845
854
  }
846
855
 
847
- static VALUE rb_snapshot_size(VALUE self, VALUE str) {
856
+ static VALUE rb_snapshot_size(VALUE self) {
848
857
  SnapshotInfo* snapshot_info;
849
858
  TypedData_Get_Struct(self, SnapshotInfo, &snapshot_type, snapshot_info);
850
859
 
@@ -855,10 +864,7 @@ static VALUE rb_snapshot_load(VALUE self, VALUE str) {
855
864
  SnapshotInfo* snapshot_info;
856
865
  TypedData_Get_Struct(self, SnapshotInfo, &snapshot_type, snapshot_info);
857
866
 
858
- if(TYPE(str) != T_STRING) {
859
- rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE " (should be a string)",
860
- rb_obj_class(str));
861
- }
867
+ Check_Type(str, T_STRING);
862
868
 
863
869
  init_v8();
864
870
 
@@ -874,7 +880,7 @@ static VALUE rb_snapshot_load(VALUE self, VALUE str) {
874
880
  return Qnil;
875
881
  }
876
882
 
877
- static VALUE rb_snapshot_dump(VALUE self, VALUE str) {
883
+ static VALUE rb_snapshot_dump(VALUE self) {
878
884
  SnapshotInfo* snapshot_info;
879
885
  TypedData_Get_Struct(self, SnapshotInfo, &snapshot_type, snapshot_info);
880
886
 
@@ -885,10 +891,7 @@ static VALUE rb_snapshot_warmup_unsafe(VALUE self, VALUE str) {
885
891
  SnapshotInfo* snapshot_info;
886
892
  TypedData_Get_Struct(self, SnapshotInfo, &snapshot_type, snapshot_info);
887
893
 
888
- if(TYPE(str) != T_STRING) {
889
- rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE " (should be a string)",
890
- rb_obj_class(str));
891
- }
894
+ Check_Type(str, T_STRING);
892
895
 
893
896
  init_v8();
894
897
 
@@ -1053,7 +1056,7 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
1053
1056
  // a v8 scope, if we do the scope is never cleaned up properly and we leak
1054
1057
  if (!result.parsed) {
1055
1058
  if(TYPE(message) == T_STRING) {
1056
- rb_raise(rb_eParseError, "%s", RSTRING_PTR(message));
1059
+ rb_raise(rb_eParseError, "%" PRIsVALUE, message);
1057
1060
  } else {
1058
1061
  rb_raise(rb_eParseError, "Unknown JavaScript Error during parse");
1059
1062
  }
@@ -1067,8 +1070,7 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
1067
1070
  // If we were terminated or have the memory softlimit flag set
1068
1071
  if (marshal_stack_maxdepth_reached) {
1069
1072
  ruby_exception = rb_eScriptRuntimeError;
1070
- std::string msg = std::string("Marshal object depth too deep. Script terminated.");
1071
- message = rb_enc_str_new(msg.c_str(), msg.length(), rb_enc_find("utf-8"));
1073
+ message = rb_utf8_str_new_literal("Marshal object depth too deep. Script terminated.");
1072
1074
  } else if (result.terminated || mem_softlimit_reached) {
1073
1075
  ruby_exception = mem_softlimit_reached ? rb_eV8OutOfMemoryError : rb_eScriptTerminatedError;
1074
1076
  } else {
@@ -1077,15 +1079,17 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
1077
1079
 
1078
1080
  // exception report about what happened
1079
1081
  if (TYPE(backtrace) == T_STRING) {
1080
- rb_raise(ruby_exception, "%s", RSTRING_PTR(backtrace));
1082
+ rb_raise(ruby_exception, "%" PRIsVALUE, backtrace);
1081
1083
  } else if(TYPE(message) == T_STRING) {
1082
- rb_raise(ruby_exception, "%s", RSTRING_PTR(message));
1084
+ rb_raise(ruby_exception, "%" PRIsVALUE, message);
1083
1085
  } else {
1084
1086
  rb_raise(ruby_exception, "Unknown JavaScript Error during execution");
1085
1087
  }
1088
+ } else if (rb_obj_is_kind_of(ruby_exception, rb_eException)) {
1089
+ rb_exc_raise(ruby_exception);
1086
1090
  } else {
1087
1091
  VALUE rb_str = rb_funcall(ruby_exception, rb_intern("to_s"), 0);
1088
- rb_raise(CLASS_OF(ruby_exception), "%s", RSTRING_PTR(rb_str));
1092
+ rb_raise(CLASS_OF(ruby_exception), "%" PRIsVALUE, rb_str);
1089
1093
  }
1090
1094
  }
1091
1095
 
@@ -1101,7 +1105,7 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
1101
1105
 
1102
1106
  if (result.json) {
1103
1107
  Local<String> rstr = tmp->ToString(p_ctx->Get(isolate)).ToLocalChecked();
1104
- VALUE json_string = rb_enc_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate), rb_enc_find("utf-8"));
1108
+ VALUE json_string = rb_utf8_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate));
1105
1109
  ret = rb_funcall(rb_mJSON, rb_intern("parse"), 1, json_string);
1106
1110
  } else {
1107
1111
  StackCounter::Reset(isolate);
@@ -1130,13 +1134,10 @@ static VALUE rb_context_eval_unsafe(VALUE self, VALUE str, VALUE filename) {
1130
1134
  TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
1131
1135
  Isolate* isolate = context_info->isolate_info->isolate;
1132
1136
 
1133
- if(TYPE(str) != T_STRING) {
1134
- rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE " (should be a string)",
1135
- rb_obj_class(str));
1136
- }
1137
- if(filename != Qnil && TYPE(filename) != T_STRING) {
1138
- rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE " (should be nil or a string)",
1139
- rb_obj_class(filename));
1137
+ Check_Type(str, T_STRING);
1138
+
1139
+ if (!NIL_P(filename)) {
1140
+ Check_Type(filename, T_STRING);
1140
1141
  }
1141
1142
 
1142
1143
  {
@@ -1145,13 +1146,13 @@ static VALUE rb_context_eval_unsafe(VALUE self, VALUE str, VALUE filename) {
1145
1146
  HandleScope handle_scope(isolate);
1146
1147
 
1147
1148
  Local<String> eval = String::NewFromUtf8(isolate, RSTRING_PTR(str),
1148
- NewStringType::kNormal, (int)RSTRING_LEN(str)).ToLocalChecked();
1149
+ NewStringType::kNormal, RSTRING_LENINT(str)).ToLocalChecked();
1149
1150
 
1150
1151
  Local<String> local_filename;
1151
1152
 
1152
1153
  if (filename != Qnil) {
1153
1154
  local_filename = String::NewFromUtf8(isolate, RSTRING_PTR(filename),
1154
- NewStringType::kNormal, (int)RSTRING_LEN(filename)).ToLocalChecked();
1155
+ NewStringType::kNormal, RSTRING_LENINT(filename)).ToLocalChecked();
1155
1156
  eval_params.filename = &local_filename;
1156
1157
  } else {
1157
1158
  eval_params.filename = NULL;
@@ -1275,8 +1276,8 @@ gvl_ruby_callback(void* data) {
1275
1276
  VALUE callback_data_value = (VALUE)&callback_data;
1276
1277
 
1277
1278
  // TODO: use rb_vrescue2 in Ruby 2.7 and above
1278
- result = rb_rescue2(protected_callback, callback_data_value,
1279
- rescue_callback, callback_data_value, rb_eException, (VALUE)0);
1279
+ result = rb_rescue2(MR_METHOD_FUNC(protected_callback), callback_data_value,
1280
+ MR_METHOD_FUNC(rescue_callback), callback_data_value, rb_eException, (VALUE)0);
1280
1281
 
1281
1282
  if(callback_data.failed) {
1282
1283
  rb_iv_set(parent, "@current_exception", result);
@@ -1337,7 +1338,7 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
1337
1338
 
1338
1339
  Local<String> v8_str =
1339
1340
  String::NewFromUtf8(isolate, RSTRING_PTR(name),
1340
- NewStringType::kNormal, (int)RSTRING_LEN(name))
1341
+ NewStringType::kNormal, RSTRING_LENINT(name))
1341
1342
  .ToLocalChecked();
1342
1343
 
1343
1344
  // Note that self (rb_cExternalFunction) is a pure Ruby T_OBJECT,
@@ -1357,7 +1358,7 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
1357
1358
  Local<String> eval =
1358
1359
  String::NewFromUtf8(isolate, RSTRING_PTR(parent_object_eval),
1359
1360
  NewStringType::kNormal,
1360
- (int)RSTRING_LEN(parent_object_eval))
1361
+ RSTRING_LENINT(parent_object_eval))
1361
1362
  .ToLocalChecked();
1362
1363
 
1363
1364
  MaybeLocal<Script> parsed_script = Script::Compile(context, eval);
@@ -1455,42 +1456,33 @@ static void free_context_raw(void *arg) {
1455
1456
  if (isolate_info) {
1456
1457
  isolate_info->release();
1457
1458
  }
1458
-
1459
- xfree(context_info);
1460
1459
  }
1461
1460
 
1462
1461
  static void *free_context_thr(void* arg) {
1463
- if (pthread_rwlock_tryrdlock(&exit_lock) != 0) {
1464
- return NULL;
1465
- }
1466
- if (ruby_exiting) {
1467
- return NULL;
1462
+ if (ruby_exiting.load() == 0) {
1463
+ free_context_raw(arg);
1464
+ xfree(arg);
1468
1465
  }
1469
-
1470
- free_context_raw(arg);
1471
-
1472
- pthread_rwlock_unlock(&exit_lock);
1473
-
1474
1466
  return NULL;
1475
1467
  }
1476
1468
 
1477
1469
  // destroys everything except freeing the ContextInfo struct (see deallocate())
1478
1470
  static void free_context(ContextInfo* context_info) {
1479
-
1480
1471
  IsolateInfo* isolate_info = context_info->isolate_info;
1481
1472
 
1482
- ContextInfo* context_info_copy = ALLOC(ContextInfo);
1483
- context_info_copy->isolate_info = context_info->isolate_info;
1484
- context_info_copy->context = context_info->context;
1485
-
1486
1473
  if (isolate_info && isolate_info->refs() > 1) {
1487
1474
  pthread_t free_context_thread;
1475
+ ContextInfo* context_info_copy = ALLOC(ContextInfo);
1476
+
1477
+ context_info_copy->isolate_info = context_info->isolate_info;
1478
+ context_info_copy->context = context_info->context;
1488
1479
  if (pthread_create(&free_context_thread, thread_attr_p,
1489
1480
  free_context_thr, (void*)context_info_copy)) {
1490
1481
  fprintf(stderr, "WARNING failed to release memory in MiniRacer, thread to release could not be created, process will leak memory\n");
1482
+ xfree(context_info_copy);
1491
1483
  }
1492
1484
  } else {
1493
- free_context_raw(context_info_copy);
1485
+ free_context_raw(context_info);
1494
1486
  }
1495
1487
 
1496
1488
  context_info->context = NULL;
@@ -1763,9 +1755,7 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
1763
1755
  }
1764
1756
 
1765
1757
  VALUE function_name = argv[0];
1766
- if (TYPE(function_name) != T_STRING) {
1767
- rb_raise(rb_eTypeError, "first argument should be a String");
1768
- }
1758
+ Check_Type(function_name, T_STRING);
1769
1759
 
1770
1760
  char *fname = RSTRING_PTR(function_name);
1771
1761
  if (!fname) {
@@ -1816,23 +1806,15 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
1816
1806
  if (val.IsEmpty() || !val.ToLocalChecked()->IsFunction()) {
1817
1807
  missingFunction = true;
1818
1808
  } else {
1819
-
1820
1809
  Local<v8::Function> fun = Local<v8::Function>::Cast(val.ToLocalChecked());
1810
+ VALUE tmp;
1821
1811
  call.fun = fun;
1822
- int fun_argc = call.argc;
1823
-
1824
- if (fun_argc > 0) {
1825
- call.argv = (v8::Local<Value> *) malloc(sizeof(void *) * fun_argc);
1826
- if (!call.argv) {
1827
- return Qnil;
1828
- }
1829
- for(int i=0; i < fun_argc; i++) {
1830
- call.argv[i] = convert_ruby_to_v8(isolate, context, call_argv[i]);
1831
- }
1812
+ call.argv = (v8::Local<Value> *)RB_ALLOCV_N(void *, tmp, call.argc);
1813
+ for(int i=0; i < call.argc; i++) {
1814
+ call.argv[i] = convert_ruby_to_v8(isolate, context, call_argv[i]);
1832
1815
  }
1833
1816
  rb_thread_call_without_gvl(nogvl_context_call, &call, unblock_function, &call);
1834
- free(call.argv);
1835
-
1817
+ RB_ALLOCV_END(tmp);
1836
1818
  }
1837
1819
  }
1838
1820
 
@@ -1859,12 +1841,7 @@ static VALUE rb_context_create_isolate_value(VALUE self) {
1859
1841
  static void set_ruby_exiting(VALUE value) {
1860
1842
  (void)value;
1861
1843
 
1862
- int res = pthread_rwlock_wrlock(&exit_lock);
1863
-
1864
- ruby_exiting = true;
1865
- if (res == 0) {
1866
- pthread_rwlock_unlock(&exit_lock);
1867
- }
1844
+ ruby_exiting.store(1);
1868
1845
  }
1869
1846
 
1870
1847
  extern "C" {
@@ -1930,9 +1907,5 @@ extern "C" {
1930
1907
  thread_attr_p = &attr;
1931
1908
  }
1932
1909
  }
1933
- auto on_fork_for_child = []() {
1934
- exit_lock = PTHREAD_RWLOCK_INITIALIZER;
1935
- };
1936
- pthread_atfork(nullptr, nullptr, on_fork_for_child);
1937
1910
  }
1938
1911
  }
@@ -1,5 +1,10 @@
1
1
  require 'mkmf'
2
2
 
3
+ if RUBY_ENGINE == "truffleruby"
4
+ File.write("Makefile", dummy_makefile($srcdir).join(""))
5
+ return
6
+ end
7
+
3
8
  extension_name = 'mini_racer_loader'
4
9
  dir_config extension_name
5
10
 
@@ -0,0 +1,353 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MiniRacer
4
+
5
+ class Context
6
+
7
+ class ExternalFunction
8
+ private
9
+
10
+ def notify_v8
11
+ name = @name.encode(::Encoding::UTF_8)
12
+ wrapped = lambda do |*args|
13
+ converted = @parent.send(:convert_js_to_ruby, args)
14
+ begin
15
+ result = @callback.call(*converted)
16
+ rescue Polyglot::ForeignException => e
17
+ e = RuntimeError.new(e.message)
18
+ e.set_backtrace(e.backtrace)
19
+ @parent.instance_variable_set(:@current_exception, e)
20
+ raise e
21
+ rescue => e
22
+ @parent.instance_variable_set(:@current_exception, e)
23
+ raise e
24
+ end
25
+ @parent.send(:convert_ruby_to_js, result)
26
+ end
27
+
28
+ if @parent_object.nil?
29
+ # set global name to proc
30
+ result = @parent.eval_in_context('this')
31
+ result[name] = wrapped
32
+ else
33
+ parent_object_eval = @parent_object_eval.encode(::Encoding::UTF_8)
34
+ begin
35
+ result = @parent.eval_in_context(parent_object_eval)
36
+ rescue Polyglot::ForeignException, StandardError => e
37
+ raise ParseError, "Was expecting #{@parent_object} to be an object", e.backtrace
38
+ end
39
+ result[name] = wrapped
40
+ # set evaluated object results name to proc
41
+ end
42
+ end
43
+ end
44
+
45
+ def heap_stats
46
+ {
47
+ total_physical_size: 0,
48
+ total_heap_size_executable: 0,
49
+ total_heap_size: 0,
50
+ used_heap_size: 0,
51
+ heap_size_limit: 0,
52
+ }
53
+ end
54
+
55
+ def stop
56
+ if @entered
57
+ @context.stop
58
+ @stopped = true
59
+ stop_attached
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ @context_initialized = false
66
+ @use_strict = false
67
+
68
+ def init_unsafe(isolate, snapshot)
69
+ unless defined?(Polyglot::InnerContext)
70
+ raise "TruffleRuby #{RUBY_ENGINE_VERSION} does not have support for inner contexts, use a more recent version"
71
+ end
72
+
73
+ unless Polyglot.languages.include? "js"
74
+ warn "You also need to install the 'js' component with 'gu install js' on GraalVM 22.2+", uplevel: 0 if $VERBOSE
75
+ end
76
+
77
+ @context = Polyglot::InnerContext.new(on_cancelled: -> {
78
+ raise ScriptTerminatedError, 'JavaScript was terminated (either by timeout or explicitly)'
79
+ })
80
+ Context.instance_variable_set(:@context_initialized, true)
81
+ @js_object = @context.eval('js', 'Object')
82
+ @isolate_mutex = Mutex.new
83
+ @stopped = false
84
+ @entered = false
85
+ @has_entered = false
86
+ @current_exception = nil
87
+ if isolate && snapshot
88
+ isolate.instance_variable_set(:@snapshot, snapshot)
89
+ end
90
+ if snapshot
91
+ @snapshot = snapshot
92
+ elsif isolate
93
+ @snapshot = isolate.instance_variable_get(:@snapshot)
94
+ else
95
+ @snapshot = nil
96
+ end
97
+ @is_object_or_array_func, @is_time_func, @js_date_to_time_func, @is_symbol_func, @js_symbol_to_symbol_func, @js_new_date_func, @js_new_array_func = eval_in_context <<-CODE
98
+ [
99
+ (x) => { return (x instanceof Object || x instanceof Array) && !(x instanceof Date) && !(x instanceof Function) },
100
+ (x) => { return x instanceof Date },
101
+ (x) => { return x.getTime(x) },
102
+ (x) => { return typeof x === 'symbol' },
103
+ (x) => { var r = x.description; return r === undefined ? 'undefined' : r },
104
+ (x) => { return new Date(x) },
105
+ (x) => { return new Array(x) },
106
+ ]
107
+ CODE
108
+ end
109
+
110
+ def dispose_unsafe
111
+ @context.close
112
+ end
113
+
114
+ def eval_unsafe(str, filename)
115
+ @entered = true
116
+ if !@has_entered && @snapshot
117
+ snapshot_src = encode(@snapshot.instance_variable_get(:@source))
118
+ begin
119
+ eval_in_context(snapshot_src, filename)
120
+ rescue Polyglot::ForeignException => e
121
+ raise RuntimeError, e.message, e.backtrace
122
+ end
123
+ end
124
+ @has_entered = true
125
+ raise RuntimeError, "TruffleRuby does not support eval after stop" if @stopped
126
+ raise TypeError, "wrong type argument #{str.class} (should be a string)" unless str.is_a?(String)
127
+ raise TypeError, "wrong type argument #{filename.class} (should be a string)" unless filename.nil? || filename.is_a?(String)
128
+
129
+ str = encode(str)
130
+ begin
131
+ translate do
132
+ eval_in_context(str, filename)
133
+ end
134
+ rescue Polyglot::ForeignException => e
135
+ raise RuntimeError, e.message, e.backtrace
136
+ rescue ::RuntimeError => e
137
+ if @current_exception
138
+ e = @current_exception
139
+ @current_exception = nil
140
+ raise e
141
+ else
142
+ raise e, e.message
143
+ end
144
+ end
145
+ ensure
146
+ @entered = false
147
+ end
148
+
149
+ def call_unsafe(function_name, *arguments)
150
+ @entered = true
151
+ if !@has_entered && @snapshot
152
+ src = encode(@snapshot.instance_variable_get(:source))
153
+ begin
154
+ eval_in_context(src)
155
+ rescue Polyglot::ForeignException => e
156
+ raise RuntimeError, e.message, e.backtrace
157
+ end
158
+ end
159
+ @has_entered = true
160
+ raise RuntimeError, "TruffleRuby does not support call after stop" if @stopped
161
+ begin
162
+ translate do
163
+ function = eval_in_context(function_name)
164
+ function.call(*convert_ruby_to_js(arguments))
165
+ end
166
+ rescue Polyglot::ForeignException => e
167
+ raise RuntimeError, e.message, e.backtrace
168
+ end
169
+ ensure
170
+ @entered = false
171
+ end
172
+
173
+ def create_isolate_value
174
+ # Returning a dummy object since TruffleRuby does not have a 1-1 concept with isolate.
175
+ # However, code and ASTs are shared between contexts.
176
+ Isolate.new
177
+ end
178
+
179
+ def isolate_mutex
180
+ @isolate_mutex
181
+ end
182
+
183
+ def translate
184
+ convert_js_to_ruby yield
185
+ rescue Object => e
186
+ message = e.message
187
+ if @current_exception
188
+ raise @current_exception
189
+ elsif e.message && e.message.start_with?('SyntaxError:')
190
+ error_class = MiniRacer::ParseError
191
+ elsif e.is_a?(MiniRacer::ScriptTerminatedError)
192
+ error_class = MiniRacer::ScriptTerminatedError
193
+ else
194
+ error_class = MiniRacer::RuntimeError
195
+ end
196
+
197
+ if error_class == MiniRacer::RuntimeError
198
+ bls = e.backtrace_locations&.select { |bl| bl&.source_location&.language == 'js' }
199
+ if bls && !bls.empty?
200
+ if '(eval)' != bls[0].path
201
+ message = "#{e.message}\n at #{bls[0]}\n" + bls[1..].map(&:to_s).join("\n")
202
+ else
203
+ message = "#{e.message}\n" + bls.map(&:to_s).join("\n")
204
+ end
205
+ end
206
+ raise error_class, message
207
+ else
208
+ raise error_class, message, e.backtrace
209
+ end
210
+ end
211
+
212
+ def convert_js_to_ruby(value)
213
+ case value
214
+ when true, false, Integer, Float
215
+ value
216
+ else
217
+ if value.nil?
218
+ nil
219
+ elsif value.respond_to?(:call)
220
+ MiniRacer::JavaScriptFunction.new
221
+ elsif value.respond_to?(:to_str)
222
+ value.to_str.dup
223
+ elsif value.respond_to?(:to_ary)
224
+ value.to_ary.map do |e|
225
+ if e.respond_to?(:call)
226
+ nil
227
+ else
228
+ convert_js_to_ruby(e)
229
+ end
230
+ end
231
+ elsif time?(value)
232
+ js_date_to_time(value)
233
+ elsif symbol?(value)
234
+ js_symbol_to_symbol(value)
235
+ else
236
+ object = value
237
+ h = {}
238
+ object.instance_variables.each do |member|
239
+ v = object[member]
240
+ unless v.respond_to?(:call)
241
+ h[member.to_s] = convert_js_to_ruby(v)
242
+ end
243
+ end
244
+ h
245
+ end
246
+ end
247
+ end
248
+
249
+ def object_or_array?(val)
250
+ @is_object_or_array_func.call(val)
251
+ end
252
+
253
+ def time?(value)
254
+ @is_time_func.call(value)
255
+ end
256
+
257
+ def js_date_to_time(value)
258
+ millis = @js_date_to_time_func.call(value)
259
+ Time.at(Rational(millis, 1000))
260
+ end
261
+
262
+ def symbol?(value)
263
+ @is_symbol_func.call(value)
264
+ end
265
+
266
+ def js_symbol_to_symbol(value)
267
+ @js_symbol_to_symbol_func.call(value).to_s.to_sym
268
+ end
269
+
270
+ def js_new_date(value)
271
+ @js_new_date_func.call(value)
272
+ end
273
+
274
+ def js_new_array(size)
275
+ @js_new_array_func.call(size)
276
+ end
277
+
278
+ def convert_ruby_to_js(value)
279
+ case value
280
+ when nil, true, false, Integer, Float
281
+ value
282
+ when Array
283
+ ary = js_new_array(value.size)
284
+ value.each_with_index do |v, i|
285
+ ary[i] = convert_ruby_to_js(v)
286
+ end
287
+ ary
288
+ when Hash
289
+ h = @js_object.new
290
+ value.each_pair do |k, v|
291
+ h[convert_ruby_to_js(k.to_s)] = convert_ruby_to_js(v)
292
+ end
293
+ h
294
+ when String, Symbol
295
+ Truffle::Interop.as_truffle_string value
296
+ when Time
297
+ js_new_date(value.to_f * 1000)
298
+ when DateTime
299
+ js_new_date(value.to_time.to_f * 1000)
300
+ else
301
+ "Undefined Conversion"
302
+ end
303
+ end
304
+
305
+ def encode(string)
306
+ raise ArgumentError unless string
307
+ string.encode(::Encoding::UTF_8)
308
+ end
309
+
310
+ class_eval <<-'RUBY', "(mini_racer)", 1
311
+ def eval_in_context(code, file = nil); code = ('"use strict";' + code) if Context.instance_variable_get(:@use_strict); @context.eval('js', code, file || '(mini_racer)'); end
312
+ RUBY
313
+
314
+ end
315
+
316
+ class Isolate
317
+ def init_with_snapshot(snapshot)
318
+ # TruffleRuby does not have a 1-1 concept with isolate.
319
+ # However, isolate can hold a snapshot, and code and ASTs are shared between contexts.
320
+ @snapshot = snapshot
321
+ end
322
+
323
+ def low_memory_notification
324
+ GC.start
325
+ end
326
+
327
+ def idle_notification(idle_time)
328
+ true
329
+ end
330
+ end
331
+
332
+ class Platform
333
+ def self.set_flag_as_str!(flag)
334
+ raise TypeError, "wrong type argument #{flag.class} (should be a string)" unless flag.is_a?(String)
335
+ raise MiniRacer::PlatformAlreadyInitialized, "The platform is already initialized." if Context.instance_variable_get(:@context_initialized)
336
+ Context.instance_variable_set(:@use_strict, true) if "--use_strict" == flag
337
+ end
338
+ end
339
+
340
+ class Snapshot
341
+ def load(str)
342
+ raise TypeError, "wrong type argument #{str.class} (should be a string)" unless str.is_a?(String)
343
+ # Intentionally noop since TruffleRuby mocks the snapshot API
344
+ end
345
+
346
+ def warmup_unsafe!(src)
347
+ raise TypeError, "wrong type argument #{src.class} (should be a string)" unless src.is_a?(String)
348
+ # Intentionally noop since TruffleRuby mocks the snapshot API
349
+ # by replaying snapshot source before the first eval/call
350
+ self
351
+ end
352
+ end
353
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MiniRacer
4
- VERSION = "0.6.0"
4
+ VERSION = "0.6.3"
5
5
  LIBV8_NODE_VERSION = "~> 16.10.0.0"
6
6
  end
data/lib/mini_racer.rb CHANGED
@@ -1,17 +1,22 @@
1
1
  require "mini_racer/version"
2
- require "mini_racer_loader"
3
2
  require "pathname"
4
3
 
5
- ext_filename = "mini_racer_extension.#{RbConfig::CONFIG['DLEXT']}"
6
- ext_path = Gem.loaded_specs['mini_racer'].require_paths
7
- .map { |p| (p = Pathname.new(p)).absolute? ? p : Pathname.new(__dir__).parent + p }
8
- ext_found = ext_path.map { |p| p + ext_filename }.find { |p| p.file? }
9
-
10
- raise LoadError, "Could not find #{ext_filename} in #{ext_path.map(&:to_s)}" unless ext_found
11
- MiniRacer::Loader.load(ext_found.to_s)
4
+ if RUBY_ENGINE == "truffleruby"
5
+ require "mini_racer/truffleruby"
6
+ else
7
+ require "mini_racer_loader"
8
+ ext_filename = "mini_racer_extension.#{RbConfig::CONFIG['DLEXT']}"
9
+ ext_path = Gem.loaded_specs['mini_racer'].require_paths
10
+ .map { |p| (p = Pathname.new(p)).absolute? ? p : Pathname.new(__dir__).parent + p }
11
+ ext_found = ext_path.map { |p| p + ext_filename }.find { |p| p.file? }
12
+
13
+ raise LoadError, "Could not find #{ext_filename} in #{ext_path.map(&:to_s)}" unless ext_found
14
+ MiniRacer::Loader.load(ext_found.to_s)
15
+ end
12
16
 
13
17
  require "thread"
14
18
  require "json"
19
+ require "io/wait"
15
20
 
16
21
  module MiniRacer
17
22
 
@@ -202,7 +207,7 @@ module MiniRacer
202
207
  end
203
208
 
204
209
  if !(File === f)
205
- raise ArgumentError("file_or_io")
210
+ raise ArgumentError, "file_or_io"
206
211
  end
207
212
 
208
213
  write_heap_snapshot_unsafe(f)
@@ -349,7 +354,7 @@ module MiniRacer
349
354
 
350
355
  t = Thread.new do
351
356
  begin
352
- result = IO.select([rp],[],[],(@timeout/1000.0))
357
+ result = rp.wait_readable(@timeout/1000.0)
353
358
  if !result
354
359
  mutex.synchronize do
355
360
  stop unless done
@@ -366,7 +371,7 @@ module MiniRacer
366
371
  done = true
367
372
  end
368
373
 
369
- wp.write("done")
374
+ wp.close
370
375
 
371
376
  # ensure we do not leak a thread in state
372
377
  t.join
@@ -375,12 +380,9 @@ module MiniRacer
375
380
  rval
376
381
  ensure
377
382
  # exceptions need to be handled
378
- if t && wp
379
- wp.write("done")
380
- t.join
381
- end
382
- wp.close if wp
383
- rp.close if rp
383
+ wp&.close
384
+ t&.join
385
+ rp&.close
384
386
  end
385
387
 
386
388
  def check_init_options!(isolate:, snapshot:, max_memory:, marshal_stack_depth:, ensure_gc_after_idle:, timeout:)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_racer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-31 00:00:00.000000000 Z
11
+ date: 2022-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -106,7 +106,6 @@ files:
106
106
  - ".dockerignore"
107
107
  - ".github/workflows/ci.yml"
108
108
  - ".gitignore"
109
- - ".travis.yml"
110
109
  - CHANGELOG
111
110
  - CODE_OF_CONDUCT.md
112
111
  - Dockerfile
@@ -121,6 +120,7 @@ files:
121
120
  - ext/mini_racer_loader/extconf.rb
122
121
  - ext/mini_racer_loader/mini_racer_loader.c
123
122
  - lib/mini_racer.rb
123
+ - lib/mini_racer/truffleruby.rb
124
124
  - lib/mini_racer/version.rb
125
125
  - mini_racer.gemspec
126
126
  homepage: https://github.com/discourse/mini_racer
@@ -128,9 +128,9 @@ licenses:
128
128
  - MIT
129
129
  metadata:
130
130
  bug_tracker_uri: https://github.com/discourse/mini_racer/issues
131
- changelog_uri: https://github.com/discourse/mini_racer/blob/v0.6.0/CHANGELOG
132
- documentation_uri: https://www.rubydoc.info/gems/mini_racer/0.6.0
133
- source_code_uri: https://github.com/discourse/mini_racer/tree/v0.6.0
131
+ changelog_uri: https://github.com/discourse/mini_racer/blob/v0.6.3/CHANGELOG
132
+ documentation_uri: https://www.rubydoc.info/gems/mini_racer/0.6.3
133
+ source_code_uri: https://github.com/discourse/mini_racer/tree/v0.6.3
134
134
  post_install_message:
135
135
  rdoc_options: []
136
136
  require_paths:
@@ -147,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
147
147
  - !ruby/object:Gem::Version
148
148
  version: '0'
149
149
  requirements: []
150
- rubygems_version: 3.1.6
150
+ rubygems_version: 3.3.20
151
151
  signing_key:
152
152
  specification_version: 4
153
153
  summary: Minimal embedded v8 for Ruby
data/.travis.yml DELETED
@@ -1,23 +0,0 @@
1
- language: ruby
2
- os: linux
3
- rvm:
4
- - 2.6
5
- - 2.7
6
- - 3.0
7
- - ruby-head
8
- arch:
9
- - amd64
10
- - arm64
11
- jobs:
12
- include:
13
- - rvm: 2.6
14
- os: osx
15
- osx_image: xcode11.3
16
- - rvm: 2.6
17
- os: osx
18
- osx_image: xcode12.2
19
- - rvm: 2.7
20
- os: osx
21
- osx_image: xcode12.2
22
- dist: xenial
23
- cache: bundler