sq_mini_racer 0.2.5.0.1.beta3 → 0.3.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/.dockerignore +12 -0
- data/.gitignore +9 -0
- data/CHANGELOG +73 -0
- data/Dockerfile +22 -0
- data/README.md +17 -2
- data/Rakefile +44 -62
- data/azure-pipelines.yml +69 -0
- data/azure-template.yml +101 -0
- data/ext/mini_racer_extension/extconf.rb +30 -16
- data/ext/mini_racer_extension/mini_racer_extension.cc +239 -97
- data/ext/mini_racer_loader/extconf.rb +8 -0
- data/ext/{prv_ext_loader/prv_ext_loader.c → mini_racer_loader/mini_racer_loader.c} +24 -5
- data/lib/sqreen/mini_racer.rb +90 -24
- data/lib/sqreen/mini_racer/version.rb +3 -3
- data/mini_racer.gemspec +14 -6
- data/valgrind.supp +74 -0
- metadata +61 -20
- data/.travis.yml +0 -73
- data/ext/prv_ext_loader/extconf.rb +0 -5
| @@ -26,37 +26,43 @@ def cppflags_add_cpu_extension! | |
| 26 26 | 
             
            end
         | 
| 27 27 |  | 
| 28 28 | 
             
            def libv8_gem_name
         | 
| 29 | 
            -
               | 
| 30 | 
            -
              return "libv8-alpine" if IS_LINUX_MUSL
         | 
| 31 | 
            -
             | 
| 32 | 
            -
              'libv8'
         | 
| 29 | 
            +
              'libv8-node'
         | 
| 33 30 | 
             
            end
         | 
| 34 31 |  | 
| 35 32 | 
             
            def libv8_version
         | 
| 36 | 
            -
              ' | 
| 33 | 
            +
              '14.14.0.0.beta2'
         | 
| 37 34 | 
             
            end
         | 
| 38 35 |  | 
| 39 36 | 
             
            def libv8_basename
         | 
| 40 37 | 
             
              "#{libv8_gem_name}-#{libv8_version}-#{ruby_platform}"
         | 
| 41 38 | 
             
            end
         | 
| 42 39 |  | 
| 40 | 
            +
            def libv8_gemspec_no_libc
         | 
| 41 | 
            +
              platform_no_libc = ruby_platform.to_s.split('-')[0..1].join('-')
         | 
| 42 | 
            +
              "#{libv8_gem_name}-#{libv8_version}-#{platform_no_libc}.gemspec"
         | 
| 43 | 
            +
            end
         | 
| 44 | 
            +
             | 
| 43 45 | 
             
            def libv8_gemspec
         | 
| 44 46 | 
             
              "#{libv8_basename}.gemspec"
         | 
| 45 47 | 
             
            end
         | 
| 46 48 |  | 
| 47 49 | 
             
            def libv8_local_path(path=Gem.path)
         | 
| 48 | 
            -
               | 
| 49 | 
            -
               | 
| 50 | 
            +
              gemspecs = [libv8_gemspec, libv8_gemspec_no_libc].uniq
         | 
| 51 | 
            +
              puts "looking for #{gemspecs.join(', ')} in installed gems"
         | 
| 52 | 
            +
              candidates = path.product(gemspecs)
         | 
| 53 | 
            +
                .map { |(p, gemspec)| File.join(p, 'specifications', gemspec) }
         | 
| 54 | 
            +
              p candidates
         | 
| 50 55 | 
             
              found = candidates.select { |f| File.exist?(f) }.first
         | 
| 51 56 |  | 
| 52 57 | 
             
              unless found
         | 
| 53 | 
            -
                puts "#{ | 
| 58 | 
            +
                puts "#{gemspecs.join(', ')} not found in installed gems"
         | 
| 54 59 | 
             
                return
         | 
| 55 60 | 
             
              end
         | 
| 56 61 |  | 
| 57 62 | 
             
              puts "found in installed specs: #{found}"
         | 
| 58 63 |  | 
| 59 | 
            -
               | 
| 64 | 
            +
              gemdir = File.basename(found, '.gemspec')
         | 
| 65 | 
            +
              dir = File.expand_path(File.join(found, '..', '..', 'gems', gemdir))
         | 
| 60 66 |  | 
| 61 67 | 
             
              unless Dir.exist?(dir)
         | 
| 62 68 | 
             
                puts "not found in installed gems: #{dir}"
         | 
| @@ -81,8 +87,8 @@ def libv8_vendor_path | |
| 81 87 | 
             
                return
         | 
| 82 88 | 
             
              end
         | 
| 83 89 |  | 
| 84 | 
            -
              puts "looking for #{libv8_basename}/lib/libv8.rb in #{vendor_path}"
         | 
| 85 | 
            -
              unless Dir.glob(File.join(vendor_path, libv8_basename, 'lib', 'libv8.rb')).first
         | 
| 90 | 
            +
              puts "looking for #{libv8_basename}/lib/libv8-node.rb in #{vendor_path}"
         | 
| 91 | 
            +
              unless Dir.glob(File.join(vendor_path, libv8_basename, 'lib', 'libv8-node.rb')).first
         | 
| 86 92 | 
             
                puts "#{libv8_basename}/lib/libv8.rb not found in #{vendor_path}"
         | 
| 87 93 | 
             
                return
         | 
| 88 94 | 
             
              end
         | 
| @@ -92,7 +98,6 @@ end | |
| 92 98 |  | 
| 93 99 | 
             
            def parse_platform(str)
         | 
| 94 100 | 
             
              Gem::Platform.new(str).tap do |p|
         | 
| 95 | 
            -
                p.instance_eval { @os = 'linux-musl' } if str =~ /musl/
         | 
| 96 101 | 
             
                p.instance_eval { @cpu = 'x86_64' } if str =~ /universal.*darwin/
         | 
| 97 102 | 
             
              end
         | 
| 98 103 | 
             
            end
         | 
| @@ -119,7 +124,7 @@ def libv8_remote_search | |
| 119 124 | 
             
                Gem::Version.new(v['number']) == Gem::Version.new(libv8_version)
         | 
| 120 125 | 
             
              end
         | 
| 121 126 | 
             
              abort(<<-ERROR) if versions.empty?
         | 
| 122 | 
            -
              ERROR: could not find #{libv8_version}
         | 
| 127 | 
            +
              ERROR: could not find #{libv8_gem_name} (version #{libv8_version}) in rubygems.org
         | 
| 123 128 | 
             
              ERROR
         | 
| 124 129 |  | 
| 125 130 | 
             
              platform_versions = versions.select do |v|
         | 
| @@ -177,7 +182,10 @@ end | |
| 177 182 | 
             
            def ensure_libv8_load_path
         | 
| 178 183 | 
             
              puts "detected platform #{RUBY_PLATFORM} => #{ruby_platform}"
         | 
| 179 184 |  | 
| 180 | 
            -
              libv8_path = libv8_local_path | 
| 185 | 
            +
              libv8_path = libv8_local_path
         | 
| 186 | 
            +
              unless ENV['ONLY_INSTALLED_LIBV8_GEM']
         | 
| 187 | 
            +
                libv8_path ||= libv8_vendor_path || libv8_vendor!
         | 
| 188 | 
            +
              end
         | 
| 181 189 |  | 
| 182 190 | 
             
              abort(<<-ERROR) unless libv8_path
         | 
| 183 191 | 
             
              ERROR: could not find #{libv8_gem_name}
         | 
| @@ -189,7 +197,7 @@ end | |
| 189 197 |  | 
| 190 198 | 
             
            ensure_libv8_load_path
         | 
| 191 199 |  | 
| 192 | 
            -
            require 'libv8'
         | 
| 200 | 
            +
            require 'libv8-node'
         | 
| 193 201 |  | 
| 194 202 | 
             
            IS_DARWIN = RUBY_PLATFORM =~ /darwin/
         | 
| 195 203 |  | 
| @@ -202,17 +210,23 @@ $CPPFLAGS += " -rdynamic" unless $CPPFLAGS.split.include? "-rdynamic" | |
| 202 210 | 
             
            $CPPFLAGS += " -fPIC" unless $CPPFLAGS.split.include? "-rdynamic" or IS_DARWIN
         | 
| 203 211 | 
             
            $CPPFLAGS += " -std=c++0x"
         | 
| 204 212 | 
             
            $CPPFLAGS += " -fpermissive"
         | 
| 213 | 
            +
            $CPPFLAGS += " -DV8_COMPRESS_POINTERS"
         | 
| 214 | 
            +
            $CPPFLAGS += " -fvisibility=hidden "
         | 
| 205 215 | 
             
            cppflags_add_frame_pointer!
         | 
| 206 216 | 
             
            cppflags_add_cpu_extension!
         | 
| 207 217 |  | 
| 208 218 | 
             
            $CPPFLAGS += " -Wno-reserved-user-defined-literal" if IS_DARWIN
         | 
| 209 219 |  | 
| 210 220 | 
             
            $LDFLAGS.insert(0, " -stdlib=libc++ ") if IS_DARWIN
         | 
| 221 | 
            +
            $LDFLAGS += " -Wl,--no-undefined " unless IS_DARWIN
         | 
| 211 222 |  | 
| 212 223 | 
             
            if ENV['CXX']
         | 
| 213 224 | 
             
              puts "SETTING CXX"
         | 
| 214 225 | 
             
              CONFIG['CXX'] = ENV['CXX']
         | 
| 215 226 | 
             
            end
         | 
| 227 | 
            +
            # 1.9 has no $CXXFLAGS
         | 
| 228 | 
            +
            $CPPFLAGS += " #{ENV['CPPFLAGS']}" if ENV['CPPFLAGS']
         | 
| 229 | 
            +
            $LDFLAGS  += " #{ENV['LDFLAGS']}" if ENV['LDFLAGS']
         | 
| 216 230 |  | 
| 217 231 | 
             
            CXX11_TEST = <<EOS
         | 
| 218 232 | 
             
            #if __cplusplus <= 199711L
         | 
| @@ -246,7 +260,7 @@ if enable_config('debug') || enable_config('asan') | |
| 246 260 | 
             
              CONFIG['debugflags'] << ' -ggdb3 -O0'
         | 
| 247 261 | 
             
            end
         | 
| 248 262 |  | 
| 249 | 
            -
            Libv8.configure_makefile
         | 
| 263 | 
            +
            Libv8::Node.configure_makefile
         | 
| 250 264 |  | 
| 251 265 | 
             
            if enable_config('asan')
         | 
| 252 266 | 
             
              $CPPFLAGS.insert(0, " -fsanitize=address ")
         | 
| @@ -36,6 +36,8 @@ | |
| 36 36 | 
             
            #include "compat.hpp"
         | 
| 37 37 | 
             
            #include "simdutf8check.h"
         | 
| 38 38 |  | 
| 39 | 
            +
            #include <time.h>
         | 
| 40 | 
            +
             | 
| 39 41 | 
             
            using namespace v8;
         | 
| 40 42 |  | 
| 41 43 | 
             
            typedef struct {
         | 
| @@ -49,6 +51,7 @@ public: | |
| 49 51 | 
             
                ArrayBuffer::Allocator* allocator;
         | 
| 50 52 | 
             
                StartupData* startup_data;
         | 
| 51 53 | 
             
                bool interrupted;
         | 
| 54 | 
            +
                bool added_gc_cb;
         | 
| 52 55 | 
             
                pid_t pid;
         | 
| 53 56 | 
             
                VALUE mutex;
         | 
| 54 57 |  | 
| @@ -66,15 +69,12 @@ public: | |
| 66 69 |  | 
| 67 70 |  | 
| 68 71 | 
             
                IsolateInfo() : isolate(nullptr), allocator(nullptr), startup_data(nullptr),
         | 
| 69 | 
            -
                    interrupted(false), pid(getpid()), refs_count(0) {
         | 
| 72 | 
            +
                    interrupted(false), added_gc_cb(false), pid(getpid()), refs_count(0) {
         | 
| 70 73 | 
             
                    VALUE cMutex = rb_const_get(rb_cThread, rb_intern("Mutex"));
         | 
| 71 74 | 
             
                    mutex = rb_class_new_instance(0, nullptr, cMutex);
         | 
| 72 75 | 
             
                }
         | 
| 73 76 |  | 
| 74 | 
            -
                ~IsolateInfo() | 
| 75 | 
            -
                    void free_isolate(IsolateInfo*);
         | 
| 76 | 
            -
                    free_isolate(this);
         | 
| 77 | 
            -
                }
         | 
| 77 | 
            +
                ~IsolateInfo();
         | 
| 78 78 |  | 
| 79 79 | 
             
                void init(SnapshotInfo* snapshot_info = nullptr);
         | 
| 80 80 |  | 
| @@ -151,6 +151,7 @@ typedef struct { | |
| 151 151 | 
             
                Local<Function> fun;
         | 
| 152 152 | 
             
                Local<Value> *argv;
         | 
| 153 153 | 
             
                EvalResult result;
         | 
| 154 | 
            +
                size_t max_memory;
         | 
| 154 155 | 
             
            } FunctionCall;
         | 
| 155 156 |  | 
| 156 157 | 
             
            enum IsolateFlags {
         | 
| @@ -179,6 +180,11 @@ static VALUE rb_cDateTime = Qnil; | |
| 179 180 | 
             
            static std::unique_ptr<Platform> current_platform = NULL;
         | 
| 180 181 | 
             
            static std::mutex platform_lock;
         | 
| 181 182 |  | 
| 183 | 
            +
            static pthread_attr_t *thread_attr_p;
         | 
| 184 | 
            +
            static pthread_rwlock_t exit_lock = PTHREAD_RWLOCK_INITIALIZER;
         | 
| 185 | 
            +
            static bool ruby_exiting = false; // guarded by exit_lock
         | 
| 186 | 
            +
            static bool single_threaded = false;
         | 
| 187 | 
            +
             | 
| 182 188 | 
             
            static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) {
         | 
| 183 189 | 
             
                bool platform_already_initialized = false;
         | 
| 184 190 |  | 
| @@ -190,6 +196,9 @@ static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) { | |
| 190 196 | 
             
                platform_lock.lock();
         | 
| 191 197 |  | 
| 192 198 | 
             
                if (current_platform == NULL) {
         | 
| 199 | 
            +
            	if (!strcmp(RSTRING_PTR(flag_as_str), "--single_threaded")) {
         | 
| 200 | 
            +
            	   single_threaded = true;
         | 
| 201 | 
            +
            	}
         | 
| 193 202 | 
             
                    V8::SetFlagsFromString(RSTRING_PTR(flag_as_str), (int)RSTRING_LEN(flag_as_str));
         | 
| 194 203 | 
             
                } else {
         | 
| 195 204 | 
             
                    platform_already_initialized = true;
         | 
| @@ -256,11 +265,13 @@ static void prepare_result(MaybeLocal<Value> v8res, | |
| 256 265 | 
             
                    Local<Value> local_value = v8res.ToLocalChecked();
         | 
| 257 266 | 
             
                    if ((local_value->IsObject() || local_value->IsArray()) &&
         | 
| 258 267 | 
             
                            !local_value->IsDate() && !local_value->IsFunction()) {
         | 
| 259 | 
            -
                        Local<Object> JSON = context->Global()->Get( | 
| 260 | 
            -
             | 
| 268 | 
            +
                        Local<Object> JSON = context->Global()->Get(
         | 
| 269 | 
            +
                                    context, String::NewFromUtf8Literal(isolate, "JSON"))
         | 
| 270 | 
            +
                                .ToLocalChecked().As<Object>();
         | 
| 261 271 |  | 
| 262 | 
            -
                        Local<Function> stringify = JSON->Get( | 
| 263 | 
            -
             | 
| 272 | 
            +
                        Local<Function> stringify = JSON->Get(
         | 
| 273 | 
            +
                                    context, v8::String::NewFromUtf8Literal(isolate, "stringify"))
         | 
| 274 | 
            +
                                .ToLocalChecked().As<Function>();
         | 
| 264 275 |  | 
| 265 276 | 
             
                        Local<Object> object = local_value->ToObject(context).ToLocalChecked();
         | 
| 266 277 | 
             
                        const unsigned argc = 1;
         | 
| @@ -314,7 +325,7 @@ static void prepare_result(MaybeLocal<Value> v8res, | |
| 314 325 | 
             
                        } else if(trycatch.HasTerminated()) {
         | 
| 315 326 | 
             
                            evalRes.terminated = true;
         | 
| 316 327 | 
             
                            evalRes.message = new Persistent<Value>();
         | 
| 317 | 
            -
                            Local<String> tmp = String:: | 
| 328 | 
            +
                            Local<String> tmp = String::NewFromUtf8Literal(isolate, "JavaScript was terminated (either by timeout or explicitly)");
         | 
| 318 329 | 
             
                            evalRes.message->Reset(isolate, tmp);
         | 
| 319 330 | 
             
                        }
         | 
| 320 331 | 
             
                        if (!trycatch.StackTrace(context).IsEmpty()) {
         | 
| @@ -335,7 +346,8 @@ nogvl_context_eval(void* arg) { | |
| 335 346 |  | 
| 336 347 | 
             
                EvalParams* eval_params = (EvalParams*)arg;
         | 
| 337 348 | 
             
                EvalResult* result = eval_params->result;
         | 
| 338 | 
            -
                 | 
| 349 | 
            +
                IsolateInfo* isolate_info = eval_params->context_info->isolate_info;
         | 
| 350 | 
            +
                Isolate* isolate = isolate_info->isolate;
         | 
| 339 351 |  | 
| 340 352 | 
             
                Isolate::Scope isolate_scope(isolate);
         | 
| 341 353 | 
             
                HandleScope handle_scope(isolate);
         | 
| @@ -379,7 +391,10 @@ nogvl_context_eval(void* arg) { | |
| 379 391 | 
             
                    // parsing successful
         | 
| 380 392 | 
             
                    if (eval_params->max_memory > 0) {
         | 
| 381 393 | 
             
                        isolate->SetData(MEM_SOFTLIMIT_VALUE, &eval_params->max_memory);
         | 
| 394 | 
            +
                        if (!isolate_info->added_gc_cb) {
         | 
| 382 395 | 
             
                        isolate->AddGCEpilogueCallback(gc_callback);
         | 
| 396 | 
            +
                            isolate_info->added_gc_cb = true;
         | 
| 397 | 
            +
                        }
         | 
| 383 398 | 
             
                    }
         | 
| 384 399 |  | 
| 385 400 | 
             
                    maybe_value = parsed_script.ToLocalChecked()->Run(context);
         | 
| @@ -392,6 +407,12 @@ nogvl_context_eval(void* arg) { | |
| 392 407 | 
             
                return 0;
         | 
| 393 408 | 
             
            }
         | 
| 394 409 |  | 
| 410 | 
            +
            static VALUE new_empty_failed_conv_obj() {
         | 
| 411 | 
            +
                // TODO isolate code that translates execption to ruby
         | 
| 412 | 
            +
                // exception so we can properly return it
         | 
| 413 | 
            +
                return rb_funcall(rb_cFailedV8Conversion, rb_intern("new"), 1, rb_str_new2(""));
         | 
| 414 | 
            +
            }
         | 
| 415 | 
            +
             | 
| 395 416 | 
             
            // assumes isolate locking is in place
         | 
| 396 417 | 
             
            static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
         | 
| 397 418 | 
             
                                            Local<Value> value) {
         | 
| @@ -423,8 +444,11 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context, | |
| 423 444 | 
             
                  VALUE rb_array = rb_ary_new();
         | 
| 424 445 | 
             
                  Local<Array> arr = Local<Array>::Cast(value);
         | 
| 425 446 | 
             
                  for(uint32_t i=0; i < arr->Length(); i++) {
         | 
| 426 | 
            -
                       | 
| 427 | 
            -
                       | 
| 447 | 
            +
                      MaybeLocal<Value> element = arr->Get(context, i);
         | 
| 448 | 
            +
                      if (element.IsEmpty()) {
         | 
| 449 | 
            +
                          continue;
         | 
| 450 | 
            +
                      }
         | 
| 451 | 
            +
                      VALUE rb_elem = convert_v8_to_ruby(isolate, context, element.ToLocalChecked());
         | 
| 428 452 | 
             
                      if (rb_funcall(rb_elem, rb_intern("class"), 0) == rb_cFailedV8Conversion) {
         | 
| 429 453 | 
             
                        return rb_elem;
         | 
| 430 454 | 
             
                      }
         | 
| @@ -454,26 +478,47 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context, | |
| 454 478 | 
             
                    if (!maybe_props.IsEmpty()) {
         | 
| 455 479 | 
             
                        Local<Array> props = maybe_props.ToLocalChecked();
         | 
| 456 480 | 
             
                        for(uint32_t i=0; i < props->Length(); i++) {
         | 
| 457 | 
            -
                          | 
| 458 | 
            -
                          | 
| 459 | 
            -
             | 
| 460 | 
            -
                          | 
| 481 | 
            +
                         MaybeLocal<Value> key = props->Get(context, i);
         | 
| 482 | 
            +
                         if (key.IsEmpty()) {
         | 
| 483 | 
            +
                            return rb_funcall(rb_cFailedV8Conversion, rb_intern("new"), 1, rb_str_new2(""));
         | 
| 484 | 
            +
                         }
         | 
| 485 | 
            +
                         VALUE rb_key = convert_v8_to_ruby(isolate, context, key.ToLocalChecked());
         | 
| 461 486 |  | 
| 462 | 
            -
                          | 
| 463 | 
            -
                         //  | 
| 464 | 
            -
                          | 
| 465 | 
            -
             | 
| 487 | 
            +
                         MaybeLocal<Value> prop_value = object->Get(context, key.ToLocalChecked());
         | 
| 488 | 
            +
                         // this may have failed due to Get raising
         | 
| 489 | 
            +
                         if (prop_value.IsEmpty() || trycatch.HasCaught()) {
         | 
| 490 | 
            +
                             return new_empty_failed_conv_obj();
         | 
| 466 491 | 
             
                         }
         | 
| 467 492 |  | 
| 468 | 
            -
                         VALUE rb_value = convert_v8_to_ruby( | 
| 493 | 
            +
                         VALUE rb_value = convert_v8_to_ruby(
         | 
| 494 | 
            +
                                     isolate, context, prop_value.ToLocalChecked());
         | 
| 469 495 | 
             
                         rb_hash_aset(rb_hash, rb_key, rb_value);
         | 
| 470 496 | 
             
                        }
         | 
| 471 497 | 
             
                    }
         | 
| 472 498 | 
             
                    return rb_hash;
         | 
| 473 499 | 
             
                }
         | 
| 474 500 |  | 
| 475 | 
            -
                 | 
| 476 | 
            -
             | 
| 501 | 
            +
                if (value->IsSymbol()) {
         | 
| 502 | 
            +
            	v8::String::Utf8Value symbol_name(isolate,
         | 
| 503 | 
            +
            	    Local<Symbol>::Cast(value)->Name());
         | 
| 504 | 
            +
             | 
| 505 | 
            +
            	VALUE str_symbol = rb_enc_str_new(
         | 
| 506 | 
            +
            	    *symbol_name,
         | 
| 507 | 
            +
            	    symbol_name.length(),
         | 
| 508 | 
            +
            	    rb_enc_find("utf-8")
         | 
| 509 | 
            +
            	);
         | 
| 510 | 
            +
             | 
| 511 | 
            +
            	return ID2SYM(rb_intern_str(str_symbol));
         | 
| 512 | 
            +
                }
         | 
| 513 | 
            +
             | 
| 514 | 
            +
                MaybeLocal<String> rstr_maybe = value->ToString(context);
         | 
| 515 | 
            +
             | 
| 516 | 
            +
                if (rstr_maybe.IsEmpty()) {
         | 
| 517 | 
            +
            	return Qnil;
         | 
| 518 | 
            +
                } else {
         | 
| 519 | 
            +
            	Local<String> rstr = rstr_maybe.ToLocalChecked();
         | 
| 520 | 
            +
            	return rb_enc_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate), rb_enc_find("utf-8"));
         | 
| 521 | 
            +
                }
         | 
| 477 522 | 
             
            }
         | 
| 478 523 |  | 
| 479 524 | 
             
            static VALUE convert_v8_to_ruby(Isolate* isolate,
         | 
| @@ -608,7 +653,7 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context, | |
| 608 653 | 
             
            	length = RARRAY_LEN(value);
         | 
| 609 654 | 
             
            	array = Array::New(isolate, (int)length);
         | 
| 610 655 | 
             
            	for(i=0; i<length; i++) {
         | 
| 611 | 
            -
             | 
| 656 | 
            +
                        array->Set(context, i, convert_ruby_to_v8(isolate, context, rb_ary_entry(value, i)));
         | 
| 612 657 | 
             
            	}
         | 
| 613 658 | 
             
            	return scope.Escape(array);
         | 
| 614 659 | 
             
                    }
         | 
| @@ -619,7 +664,7 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context, | |
| 619 664 | 
             
            	length = RARRAY_LEN(hash_as_array);
         | 
| 620 665 | 
             
            	for(i=0; i<length; i++) {
         | 
| 621 666 | 
             
            	    pair = rb_ary_entry(hash_as_array, i);
         | 
| 622 | 
            -
             | 
| 667 | 
            +
                        object->Set(context, convert_ruby_to_v8(isolate, context, rb_ary_entry(pair, 0)),
         | 
| 623 668 | 
             
                              convert_ruby_to_v8(isolate, context, rb_ary_entry(pair, 1)));
         | 
| 624 669 | 
             
            	}
         | 
| 625 670 | 
             
            	return scope.Escape(object);
         | 
| @@ -661,8 +706,9 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context, | |
| 661 706 | 
             
                            value = rb_funcall(value, rb_intern("to_s"), 0);
         | 
| 662 707 | 
             
                            return scope.Escape(convert_ruby_str_to_v8(scope, isolate, value));
         | 
| 663 708 | 
             
                        }
         | 
| 664 | 
            -
             | 
| 665 | 
            -
             | 
| 709 | 
            +
                        return scope.Escape(
         | 
| 710 | 
            +
                            String::NewFromUtf8Literal(isolate, "Undefined Conversion"));
         | 
| 711 | 
            +
                    }
         | 
| 666 712 | 
             
                }
         | 
| 667 713 | 
             
            }
         | 
| 668 714 |  | 
| @@ -675,53 +721,43 @@ static void unblock_eval(void *ptr) { | |
| 675 721 | 
             
             * The implementations of the run_extra_code(), create_snapshot_data_blob() and
         | 
| 676 722 | 
             
             * warm_up_snapshot_data_blob() functions have been derived from V8's test suite.
         | 
| 677 723 | 
             
             */
         | 
| 678 | 
            -
            bool run_extra_code(Isolate *isolate, Local<v8::Context> context,
         | 
| 724 | 
            +
            static bool run_extra_code(Isolate *isolate, Local<v8::Context> context,
         | 
| 679 725 | 
             
                                const char *utf8_source, const char *name) {
         | 
| 680 726 | 
             
                Context::Scope context_scope(context);
         | 
| 681 727 | 
             
                TryCatch try_catch(isolate);
         | 
| 682 728 | 
             
                Local<String> source_string;
         | 
| 683 | 
            -
                if (!String::NewFromUtf8(isolate, utf8_source | 
| 684 | 
            -
                                         NewStringType::kNormal)
         | 
| 685 | 
            -
                         .ToLocal(&source_string)) {
         | 
| 729 | 
            +
                if (!String::NewFromUtf8(isolate, utf8_source).ToLocal(&source_string)) {
         | 
| 686 730 | 
             
                    return false;
         | 
| 687 731 | 
             
                }
         | 
| 688 | 
            -
                Local< | 
| 689 | 
            -
             | 
| 690 | 
            -
                        .ToLocalChecked();
         | 
| 732 | 
            +
                Local<String> resource_name =
         | 
| 733 | 
            +
                        String::NewFromUtf8(isolate, name).ToLocalChecked();
         | 
| 691 734 | 
             
                ScriptOrigin origin(resource_name);
         | 
| 692 735 | 
             
                ScriptCompiler::Source source(source_string, origin);
         | 
| 693 736 | 
             
                Local<Script> script;
         | 
| 694 737 | 
             
                if (!ScriptCompiler::Compile(context, &source).ToLocal(&script))
         | 
| 695 738 | 
             
                    return false;
         | 
| 696 | 
            -
                if (script->Run(context).IsEmpty())
         | 
| 697 | 
            -
                    return false;
         | 
| 698 | 
            -
                // CHECK(!try_catch.HasCaught());
         | 
| 739 | 
            +
                if (script->Run(context).IsEmpty()) return false;
         | 
| 699 740 | 
             
                return true;
         | 
| 700 741 | 
             
            }
         | 
| 701 742 |  | 
| 702 | 
            -
            StartupData
         | 
| 743 | 
            +
            static StartupData
         | 
| 703 744 | 
             
            create_snapshot_data_blob(const char *embedded_source = nullptr) {
         | 
| 704 | 
            -
                 | 
| 705 | 
            -
             | 
| 706 | 
            -
                 | 
| 745 | 
            +
                Isolate *isolate = Isolate::Allocate();
         | 
| 746 | 
            +
             | 
| 747 | 
            +
                // Optionally run a script to embed, and serialize to create a snapshot blob.
         | 
| 748 | 
            +
                SnapshotCreator snapshot_creator(isolate);
         | 
| 707 749 | 
             
                {
         | 
| 708 | 
            -
                    SnapshotCreator snapshot_creator;
         | 
| 709 | 
            -
                    Isolate *isolate = snapshot_creator.GetIsolate();
         | 
| 710 | 
            -
                    {
         | 
| 711 750 | 
             
                        HandleScope scope(isolate);
         | 
| 712 | 
            -
             | 
| 751 | 
            +
                    Local<v8::Context> context = v8::Context::New(isolate);
         | 
| 713 752 | 
             
                        if (embedded_source != nullptr &&
         | 
| 714 | 
            -
                            !run_extra_code(isolate, context, embedded_source,
         | 
| 715 | 
            -
             | 
| 716 | 
            -
                            return result;
         | 
| 753 | 
            +
                            !run_extra_code(isolate, context, embedded_source, "<embedded>")) {
         | 
| 754 | 
            +
                       return {};
         | 
| 717 755 | 
             
                        }
         | 
| 718 756 | 
             
                        snapshot_creator.SetDefaultContext(context);
         | 
| 719 757 | 
             
                    }
         | 
| 720 | 
            -
             | 
| 758 | 
            +
                return snapshot_creator.CreateBlob(
         | 
| 721 759 | 
             
                        SnapshotCreator::FunctionCodeHandling::kClear);
         | 
| 722 760 | 
             
                }
         | 
| 723 | 
            -
                return result;
         | 
| 724 | 
            -
            }
         | 
| 725 761 |  | 
| 726 762 | 
             
            StartupData warm_up_snapshot_data_blob(StartupData cold_snapshot_blob,
         | 
| 727 763 | 
             
                                                   const char *warmup_source) {
         | 
| @@ -868,6 +904,29 @@ static VALUE rb_isolate_idle_notification(VALUE self, VALUE idle_time_in_ms) { | |
| 868 904 | 
             
                return isolate_info->isolate->IdleNotificationDeadline(now + duration) ? Qtrue : Qfalse;
         | 
| 869 905 | 
             
            }
         | 
| 870 906 |  | 
| 907 | 
            +
            static VALUE rb_isolate_low_memory_notification(VALUE self) {
         | 
| 908 | 
            +
                IsolateInfo* isolate_info;
         | 
| 909 | 
            +
                Data_Get_Struct(self, IsolateInfo, isolate_info);
         | 
| 910 | 
            +
             | 
| 911 | 
            +
                if (current_platform == NULL) return Qfalse;
         | 
| 912 | 
            +
             | 
| 913 | 
            +
                isolate_info->isolate->LowMemoryNotification();
         | 
| 914 | 
            +
                return Qnil;
         | 
| 915 | 
            +
            }
         | 
| 916 | 
            +
             | 
| 917 | 
            +
            static VALUE rb_isolate_pump_message_loop(VALUE self) {
         | 
| 918 | 
            +
                IsolateInfo* isolate_info;
         | 
| 919 | 
            +
                Data_Get_Struct(self, IsolateInfo, isolate_info);
         | 
| 920 | 
            +
             | 
| 921 | 
            +
                if (current_platform == NULL) return Qfalse;
         | 
| 922 | 
            +
             | 
| 923 | 
            +
                if (platform::PumpMessageLoop(current_platform.get(), isolate_info->isolate)){
         | 
| 924 | 
            +
            	return Qtrue;
         | 
| 925 | 
            +
                } else {
         | 
| 926 | 
            +
            	return Qfalse;
         | 
| 927 | 
            +
                }
         | 
| 928 | 
            +
            }
         | 
| 929 | 
            +
             | 
| 871 930 | 
             
            static VALUE rb_context_init_unsafe(VALUE self, VALUE isolate, VALUE snap) {
         | 
| 872 931 | 
             
                ContextInfo* context_info;
         | 
| 873 932 | 
             
                Data_Get_Struct(self, ContextInfo, context_info);
         | 
| @@ -1142,7 +1201,9 @@ gvl_ruby_callback(void* data) { | |
| 1142 1201 | 
             
                callback_data.failed = false;
         | 
| 1143 1202 |  | 
| 1144 1203 | 
             
                if ((bool)args->GetIsolate()->GetData(DO_TERMINATE) == true) {
         | 
| 1145 | 
            -
                    args->GetIsolate()->ThrowException( | 
| 1204 | 
            +
                    args->GetIsolate()->ThrowException(
         | 
| 1205 | 
            +
                                String::NewFromUtf8Literal(args->GetIsolate(),
         | 
| 1206 | 
            +
                                                           "Terminated execution during transition from Ruby to JS"));
         | 
| 1146 1207 | 
             
                    args->GetIsolate()->TerminateExecution();
         | 
| 1147 1208 | 
             
                    if (length > 0) {
         | 
| 1148 1209 | 
             
                        rb_ary_clear(ruby_args);
         | 
| @@ -1156,7 +1217,7 @@ gvl_ruby_callback(void* data) { | |
| 1156 1217 |  | 
| 1157 1218 | 
             
                if(callback_data.failed) {
         | 
| 1158 1219 | 
             
                    rb_iv_set(parent, "@current_exception", result);
         | 
| 1159 | 
            -
                    args->GetIsolate()->ThrowException(String:: | 
| 1220 | 
            +
                    args->GetIsolate()->ThrowException(String::NewFromUtf8Literal(args->GetIsolate(), "Ruby exception"));
         | 
| 1160 1221 | 
             
                }
         | 
| 1161 1222 | 
             
                else {
         | 
| 1162 1223 | 
             
                    HandleScope scope(args->GetIsolate());
         | 
| @@ -1231,7 +1292,9 @@ static VALUE rb_external_function_notify_v8(VALUE self) { | |
| 1231 1292 |  | 
| 1232 1293 | 
             
                    if (parent_object == Qnil) {
         | 
| 1233 1294 | 
             
                        context->Global()->Set(
         | 
| 1234 | 
            -
             | 
| 1295 | 
            +
                                    context,
         | 
| 1296 | 
            +
                                    v8_str,
         | 
| 1297 | 
            +
                                    FunctionTemplate::New(isolate, ruby_callback, external)
         | 
| 1235 1298 | 
             
                                        ->GetFunction(context)
         | 
| 1236 1299 | 
             
                                        .ToLocalChecked());
         | 
| 1237 1300 |  | 
| @@ -1244,7 +1307,7 @@ static VALUE rb_external_function_notify_v8(VALUE self) { | |
| 1244 1307 |  | 
| 1245 1308 | 
             
                        MaybeLocal<Script> parsed_script = Script::Compile(context, eval);
         | 
| 1246 1309 | 
             
                        if (parsed_script.IsEmpty()) {
         | 
| 1247 | 
            -
             | 
| 1310 | 
            +
                            parse_error = true;
         | 
| 1248 1311 | 
             
                        } else {
         | 
| 1249 1312 | 
             
                            MaybeLocal<Value> maybe_value =
         | 
| 1250 1313 | 
             
                                parsed_script.ToLocalChecked()->Run(context);
         | 
| @@ -1254,11 +1317,12 @@ static VALUE rb_external_function_notify_v8(VALUE self) { | |
| 1254 1317 | 
             
                                Local<Value> value = maybe_value.ToLocalChecked();
         | 
| 1255 1318 | 
             
                                if (value->IsObject()) {
         | 
| 1256 1319 | 
             
                                    value.As<Object>()->Set(
         | 
| 1257 | 
            -
             | 
| 1258 | 
            -
             | 
| 1320 | 
            +
                                                context,
         | 
| 1321 | 
            +
                                                v8_str,
         | 
| 1322 | 
            +
                                                FunctionTemplate::New(isolate, ruby_callback, external)
         | 
| 1259 1323 | 
             
                                                    ->GetFunction(context)
         | 
| 1260 1324 | 
             
                                                    .ToLocalChecked());
         | 
| 1261 | 
            -
             | 
| 1325 | 
            +
                                    attach_error = false;
         | 
| 1262 1326 | 
             
                                }
         | 
| 1263 1327 | 
             
                            }
         | 
| 1264 1328 | 
             
                        }
         | 
| @@ -1288,35 +1352,39 @@ static VALUE rb_context_isolate_mutex(VALUE self) { | |
| 1288 1352 | 
             
                return context_info->isolate_info->mutex;
         | 
| 1289 1353 | 
             
            }
         | 
| 1290 1354 |  | 
| 1291 | 
            -
             | 
| 1292 | 
            -
             | 
| 1293 | 
            -
             | 
| 1294 | 
            -
             | 
| 1295 | 
            -
             | 
| 1296 | 
            -
             | 
| 1297 | 
            -
                if (isolate_info->isolate) {
         | 
| 1298 | 
            -
                    if (isolate_info->interrupted) {
         | 
| 1299 | 
            -
                        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.\n");
         | 
| 1355 | 
            +
            IsolateInfo::~IsolateInfo() {
         | 
| 1356 | 
            +
                if (isolate) {
         | 
| 1357 | 
            +
                    if (this->interrupted) {
         | 
| 1358 | 
            +
                        fprintf(stderr, "WARNING: V8 isolate was interrupted by Ruby, "
         | 
| 1359 | 
            +
                                        "it can not be disposed and memory will not be "
         | 
| 1360 | 
            +
                                        "reclaimed till the Ruby process exits.\n");
         | 
| 1300 1361 | 
             
                    } else {
         | 
| 1301 | 
            -
                        
         | 
| 1302 | 
            -
             | 
| 1303 | 
            -
             | 
| 1362 | 
            +
                        if (this->pid != getpid() && !single_threaded) {
         | 
| 1363 | 
            +
                            fprintf(stderr, "WARNING: V8 isolate was forked, "
         | 
| 1364 | 
            +
                                            "it can not be disposed and "
         | 
| 1365 | 
            +
                                            "memory will not be reclaimed "
         | 
| 1366 | 
            +
                                            "till the Ruby process exits.\n"
         | 
| 1367 | 
            +
            				"It is VERY likely your process will hang.\n"
         | 
| 1368 | 
            +
            				"If you wish to use v8 in forked environment "
         | 
| 1369 | 
            +
            				"please ensure the platform is initialized with:\n"
         | 
| 1370 | 
            +
            				"MiniRacer::Platform.set_flags! :single_threaded\n"
         | 
| 1371 | 
            +
            				);
         | 
| 1304 1372 | 
             
                        } else {
         | 
| 1305 | 
            -
                             | 
| 1373 | 
            +
                            isolate->Dispose();
         | 
| 1306 1374 | 
             
                        }
         | 
| 1307 1375 | 
             
                    }
         | 
| 1308 | 
            -
                     | 
| 1376 | 
            +
                    isolate = nullptr;
         | 
| 1309 1377 | 
             
                }
         | 
| 1310 1378 |  | 
| 1311 | 
            -
                if ( | 
| 1312 | 
            -
                    delete[]  | 
| 1313 | 
            -
                    delete  | 
| 1379 | 
            +
                if (startup_data) {
         | 
| 1380 | 
            +
                    delete[] startup_data->data;
         | 
| 1381 | 
            +
                    delete startup_data;
         | 
| 1314 1382 | 
             
                }
         | 
| 1315 1383 |  | 
| 1316 | 
            -
                delete  | 
| 1384 | 
            +
                delete allocator;
         | 
| 1317 1385 | 
             
            }
         | 
| 1318 1386 |  | 
| 1319 | 
            -
            static void  | 
| 1387 | 
            +
            static void free_context_raw(void *arg) {
         | 
| 1320 1388 | 
             
                ContextInfo* context_info = (ContextInfo*)arg;
         | 
| 1321 1389 | 
             
                IsolateInfo* isolate_info = context_info->isolate_info;
         | 
| 1322 1390 | 
             
                Persistent<Context>* context = context_info->context;
         | 
| @@ -1333,6 +1401,20 @@ static void *free_context_raw(void* arg) { | |
| 1333 1401 | 
             
                }
         | 
| 1334 1402 |  | 
| 1335 1403 | 
             
                xfree(context_info);
         | 
| 1404 | 
            +
            }
         | 
| 1405 | 
            +
             | 
| 1406 | 
            +
            static void *free_context_thr(void* arg) {
         | 
| 1407 | 
            +
                if (pthread_rwlock_tryrdlock(&exit_lock) != 0) {
         | 
| 1408 | 
            +
                    return NULL;
         | 
| 1409 | 
            +
                }
         | 
| 1410 | 
            +
                if (ruby_exiting) {
         | 
| 1411 | 
            +
                return NULL;
         | 
| 1412 | 
            +
            }
         | 
| 1413 | 
            +
             | 
| 1414 | 
            +
                free_context_raw(arg);
         | 
| 1415 | 
            +
             | 
| 1416 | 
            +
                pthread_rwlock_unlock(&exit_lock);
         | 
| 1417 | 
            +
             | 
| 1336 1418 | 
             
                return NULL;
         | 
| 1337 1419 | 
             
            }
         | 
| 1338 1420 |  | 
| @@ -1347,22 +1429,17 @@ static void free_context(ContextInfo* context_info) { | |
| 1347 1429 |  | 
| 1348 1430 | 
             
                if (isolate_info && isolate_info->refs() > 1) {
         | 
| 1349 1431 | 
             
                pthread_t free_context_thread;
         | 
| 1350 | 
            -
             | 
| 1432 | 
            +
                    if (pthread_create(&free_context_thread, thread_attr_p,
         | 
| 1433 | 
            +
                                       free_context_thr, (void*)context_info_copy)) {
         | 
| 1351 1434 | 
             
                    fprintf(stderr, "WARNING failed to release memory in MiniRacer, thread to release could not be created, process will leak memory\n");
         | 
| 1352 1435 | 
             
                }
         | 
| 1353 | 
            -
             | 
| 1354 1436 | 
             
                } else {
         | 
| 1355 1437 | 
             
                    free_context_raw(context_info_copy);
         | 
| 1356 1438 | 
             
                }
         | 
| 1357 1439 |  | 
| 1358 | 
            -
                if (context_info->context && isolate_info && isolate_info->isolate) {
         | 
| 1359 1440 | 
             
                    context_info->context = NULL;
         | 
| 1360 | 
            -
                }
         | 
| 1361 | 
            -
             | 
| 1362 | 
            -
                if (isolate_info) {
         | 
| 1363 1441 | 
             
                    context_info->isolate_info = NULL;
         | 
| 1364 1442 | 
             
                }
         | 
| 1365 | 
            -
            }
         | 
| 1366 1443 |  | 
| 1367 1444 | 
             
            static void deallocate_isolate(void* data) {
         | 
| 1368 1445 |  | 
| @@ -1376,7 +1453,7 @@ static void mark_isolate(void* data) { | |
| 1376 1453 | 
             
                isolate_info->mark();
         | 
| 1377 1454 | 
             
            }
         | 
| 1378 1455 |  | 
| 1379 | 
            -
            void deallocate(void* data) {
         | 
| 1456 | 
            +
            static void deallocate(void* data) {
         | 
| 1380 1457 | 
             
                ContextInfo* context_info = (ContextInfo*)data;
         | 
| 1381 1458 |  | 
| 1382 1459 | 
             
                free_context(context_info);
         | 
| @@ -1391,22 +1468,22 @@ static void mark_context(void* data) { | |
| 1391 1468 | 
             
                }
         | 
| 1392 1469 | 
             
            }
         | 
| 1393 1470 |  | 
| 1394 | 
            -
            void deallocate_external_function(void * data) {
         | 
| 1471 | 
            +
            static void deallocate_external_function(void * data) {
         | 
| 1395 1472 | 
             
                xfree(data);
         | 
| 1396 1473 | 
             
            }
         | 
| 1397 1474 |  | 
| 1398 | 
            -
            void deallocate_snapshot(void * data) {
         | 
| 1475 | 
            +
            static void deallocate_snapshot(void * data) {
         | 
| 1399 1476 | 
             
                SnapshotInfo* snapshot_info = (SnapshotInfo*)data;
         | 
| 1400 1477 | 
             
                delete[] snapshot_info->data;
         | 
| 1401 1478 | 
             
                xfree(snapshot_info);
         | 
| 1402 1479 | 
             
            }
         | 
| 1403 1480 |  | 
| 1404 | 
            -
            VALUE allocate_external_function(VALUE klass) {
         | 
| 1481 | 
            +
            static VALUE allocate_external_function(VALUE klass) {
         | 
| 1405 1482 | 
             
                VALUE* self = ALLOC(VALUE);
         | 
| 1406 1483 | 
             
                return Data_Wrap_Struct(klass, NULL, deallocate_external_function, (void*)self);
         | 
| 1407 1484 | 
             
            }
         | 
| 1408 1485 |  | 
| 1409 | 
            -
            VALUE allocate(VALUE klass) {
         | 
| 1486 | 
            +
            static VALUE allocate(VALUE klass) {
         | 
| 1410 1487 | 
             
                ContextInfo* context_info = ALLOC(ContextInfo);
         | 
| 1411 1488 | 
             
                context_info->isolate_info = NULL;
         | 
| 1412 1489 | 
             
                context_info->context = NULL;
         | 
| @@ -1414,7 +1491,7 @@ VALUE allocate(VALUE klass) { | |
| 1414 1491 | 
             
                return Data_Wrap_Struct(klass, mark_context, deallocate, (void*)context_info);
         | 
| 1415 1492 | 
             
            }
         | 
| 1416 1493 |  | 
| 1417 | 
            -
            VALUE allocate_snapshot(VALUE klass) {
         | 
| 1494 | 
            +
            static VALUE allocate_snapshot(VALUE klass) {
         | 
| 1418 1495 | 
             
                SnapshotInfo* snapshot_info = ALLOC(SnapshotInfo);
         | 
| 1419 1496 | 
             
                snapshot_info->data = NULL;
         | 
| 1420 1497 | 
             
                snapshot_info->raw_size = 0;
         | 
| @@ -1422,7 +1499,7 @@ VALUE allocate_snapshot(VALUE klass) { | |
| 1422 1499 | 
             
                return Data_Wrap_Struct(klass, NULL, deallocate_snapshot, (void*)snapshot_info);
         | 
| 1423 1500 | 
             
            }
         | 
| 1424 1501 |  | 
| 1425 | 
            -
            VALUE allocate_isolate(VALUE klass) {
         | 
| 1502 | 
            +
            static VALUE allocate_isolate(VALUE klass) {
         | 
| 1426 1503 | 
             
                IsolateInfo* isolate_info = new IsolateInfo();
         | 
| 1427 1504 |  | 
| 1428 1505 | 
             
                return Data_Wrap_Struct(klass, mark_isolate, deallocate_isolate, (void*)isolate_info);
         | 
| @@ -1519,6 +1596,8 @@ rb_heap_snapshot(VALUE self, VALUE file) { | |
| 1519 1596 | 
             
                FileOutputStream stream(fp);
         | 
| 1520 1597 | 
             
                snap->Serialize(&stream, HeapSnapshot::kJSON);
         | 
| 1521 1598 |  | 
| 1599 | 
            +
                fflush(fp);
         | 
| 1600 | 
            +
             | 
| 1522 1601 | 
             
                const_cast<HeapSnapshot*>(snap)->Delete();
         | 
| 1523 1602 |  | 
| 1524 1603 | 
             
                return Qtrue;
         | 
| @@ -1576,13 +1655,23 @@ nogvl_context_call(void *args) { | |
| 1576 1655 | 
             
                if (!call) {
         | 
| 1577 1656 | 
             
                    return 0;
         | 
| 1578 1657 | 
             
                }
         | 
| 1579 | 
            -
                 | 
| 1658 | 
            +
                IsolateInfo *isolate_info = call->context_info->isolate_info;
         | 
| 1659 | 
            +
                Isolate* isolate = isolate_info->isolate;
         | 
| 1580 1660 |  | 
| 1581 1661 | 
             
                // in gvl flag
         | 
| 1582 1662 | 
             
                isolate->SetData(IN_GVL, (void*)false);
         | 
| 1583 1663 | 
             
                // terminate ASAP
         | 
| 1584 1664 | 
             
                isolate->SetData(DO_TERMINATE, (void*)false);
         | 
| 1585 1665 |  | 
| 1666 | 
            +
                if (call->max_memory > 0) {
         | 
| 1667 | 
            +
                    isolate->SetData(MEM_SOFTLIMIT_VALUE, &call->max_memory);
         | 
| 1668 | 
            +
                    isolate->SetData(MEM_SOFTLIMIT_REACHED, (void*)false);
         | 
| 1669 | 
            +
                    if (!isolate_info->added_gc_cb) {
         | 
| 1670 | 
            +
                    isolate->AddGCEpilogueCallback(gc_callback);
         | 
| 1671 | 
            +
                        isolate_info->added_gc_cb = true;
         | 
| 1672 | 
            +
                }
         | 
| 1673 | 
            +
                }
         | 
| 1674 | 
            +
             | 
| 1586 1675 | 
             
                Isolate::Scope isolate_scope(isolate);
         | 
| 1587 1676 | 
             
                EscapableHandleScope handle_scope(isolate);
         | 
| 1588 1677 | 
             
                TryCatch trycatch(isolate);
         | 
| @@ -1640,6 +1729,13 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) { | |
| 1640 1729 | 
             
                    call_argv = argv + 1;
         | 
| 1641 1730 | 
             
                }
         | 
| 1642 1731 |  | 
| 1732 | 
            +
                call.max_memory = 0;
         | 
| 1733 | 
            +
                VALUE mem_softlimit = rb_iv_get(self, "@max_memory");
         | 
| 1734 | 
            +
                if (mem_softlimit != Qnil) {
         | 
| 1735 | 
            +
                    unsigned long sl_int = NUM2ULONG(mem_softlimit);
         | 
| 1736 | 
            +
                    call.max_memory = (size_t)sl_int;
         | 
| 1737 | 
            +
                }
         | 
| 1738 | 
            +
             | 
| 1643 1739 | 
             
                bool missingFunction = false;
         | 
| 1644 1740 | 
             
                {
         | 
| 1645 1741 | 
             
                    Locker lock(isolate);
         | 
| @@ -1651,8 +1747,11 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) { | |
| 1651 1747 |  | 
| 1652 1748 | 
             
                    // examples of such usage can be found in
         | 
| 1653 1749 | 
             
                    // https://github.com/v8/v8/blob/36b32aa28db5e993312f4588d60aad5c8330c8a5/test/cctest/test-api.cc#L15711
         | 
| 1654 | 
            -
                     | 
| 1655 | 
            -
                    MaybeLocal<v8::Value> val | 
| 1750 | 
            +
                    MaybeLocal<String> fname = String::NewFromUtf8(isolate, call.function_name);
         | 
| 1751 | 
            +
                    MaybeLocal<v8::Value> val;
         | 
| 1752 | 
            +
                    if (!fname.IsEmpty()) {
         | 
| 1753 | 
            +
                        val = context->Global()->Get(context, fname.ToLocalChecked());
         | 
| 1754 | 
            +
                    }
         | 
| 1656 1755 |  | 
| 1657 1756 | 
             
                    if (val.IsEmpty() || !val.ToLocalChecked()->IsFunction()) {
         | 
| 1658 1757 | 
             
                        missingFunction = true;
         | 
| @@ -1701,12 +1800,44 @@ static VALUE rb_context_create_isolate_value(VALUE self) { | |
| 1701 1800 | 
             
                return Data_Wrap_Struct(rb_cIsolate, NULL, &deallocate_isolate, isolate_info);
         | 
| 1702 1801 | 
             
            }
         | 
| 1703 1802 |  | 
| 1803 | 
            +
            static void set_ruby_exiting(VALUE value) {
         | 
| 1804 | 
            +
                (void)value;
         | 
| 1805 | 
            +
             | 
| 1806 | 
            +
                int res = pthread_rwlock_wrlock(&exit_lock);
         | 
| 1807 | 
            +
             | 
| 1808 | 
            +
                ruby_exiting  = true;
         | 
| 1809 | 
            +
                if (res == 0) {
         | 
| 1810 | 
            +
                    pthread_rwlock_unlock(&exit_lock);
         | 
| 1811 | 
            +
                }
         | 
| 1812 | 
            +
            }
         | 
| 1813 | 
            +
             | 
| 1814 | 
            +
            static VALUE rb_monotime(VALUE self) {
         | 
| 1815 | 
            +
                struct timespec ts;
         | 
| 1816 | 
            +
                if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
         | 
| 1817 | 
            +
                    return INT2FIX(-1);
         | 
| 1818 | 
            +
                }
         | 
| 1819 | 
            +
             | 
| 1820 | 
            +
                return DBL2NUM(
         | 
| 1821 | 
            +
                    (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0);
         | 
| 1822 | 
            +
            }
         | 
| 1823 | 
            +
             | 
| 1704 1824 | 
             
            extern "C" {
         | 
| 1705 1825 |  | 
| 1706 | 
            -
                void Init_sq_mini_racer_extension ( void )
         | 
| 1826 | 
            +
                __attribute__((visibility("default"))) void Init_sq_mini_racer_extension ( void )
         | 
| 1707 1827 | 
             
                {
         | 
| 1708 | 
            -
             | 
| 1828 | 
            +
            		ID sqreen_id = rb_intern("Sqreen");
         | 
| 1829 | 
            +
            		VALUE rb_mSqreen;
         | 
| 1830 | 
            +
            		if (rb_const_defined(rb_cObject, sqreen_id)) {
         | 
| 1831 | 
            +
            			rb_mSqreen = rb_const_get(rb_cObject, sqreen_id);
         | 
| 1832 | 
            +
            			if (TYPE(rb_mSqreen) != T_MODULE) {
         | 
| 1833 | 
            +
            				rb_raise(rb_eTypeError, "Sqreen is not a module");
         | 
| 1834 | 
            +
            				return;
         | 
| 1835 | 
            +
            			}
         | 
| 1836 | 
            +
            		} else {
         | 
| 1837 | 
            +
            			rb_mSqreen = rb_define_module("Sqreen");
         | 
| 1838 | 
            +
            		}
         | 
| 1709 1839 | 
             
                    VALUE rb_mMiniRacer = rb_define_module_under(rb_mSqreen, "MiniRacer");
         | 
| 1840 | 
            +
                    rb_define_module_function(rb_mMiniRacer, "monotime", (VALUE(*)(...))&rb_monotime, 0);
         | 
| 1710 1841 | 
             
                    rb_cContext = rb_define_class_under(rb_mMiniRacer, "Context", rb_cObject);
         | 
| 1711 1842 | 
             
                    rb_cSnapshot = rb_define_class_under(rb_mMiniRacer, "Snapshot", rb_cObject);
         | 
| 1712 1843 | 
             
                    rb_cIsolate = rb_define_class_under(rb_mMiniRacer, "Isolate", rb_cObject);
         | 
| @@ -1753,8 +1884,19 @@ extern "C" { | |
| 1753 1884 | 
             
                    rb_define_private_method(rb_cSnapshot, "load", (VALUE(*)(...))&rb_snapshot_load, 1);
         | 
| 1754 1885 |  | 
| 1755 1886 | 
             
                    rb_define_method(rb_cIsolate, "idle_notification", (VALUE(*)(...))&rb_isolate_idle_notification, 1);
         | 
| 1887 | 
            +
                    rb_define_method(rb_cIsolate, "low_memory_notification", (VALUE(*)(...))&rb_isolate_low_memory_notification, 0);
         | 
| 1888 | 
            +
                    rb_define_method(rb_cIsolate, "pump_message_loop", (VALUE(*)(...))&rb_isolate_pump_message_loop, 0);
         | 
| 1756 1889 | 
             
                    rb_define_private_method(rb_cIsolate, "init_with_snapshot",(VALUE(*)(...))&rb_isolate_init_with_snapshot, 1);
         | 
| 1757 1890 |  | 
| 1758 1891 | 
             
                    rb_define_singleton_method(rb_cPlatform, "set_flag_as_str!", (VALUE(*)(...))&rb_platform_set_flag_as_str, 1);
         | 
| 1892 | 
            +
             | 
| 1893 | 
            +
                    rb_set_end_proc(set_ruby_exiting, Qnil);
         | 
| 1894 | 
            +
             | 
| 1895 | 
            +
                    static pthread_attr_t attr;
         | 
| 1896 | 
            +
                    if (pthread_attr_init(&attr) == 0) {
         | 
| 1897 | 
            +
                        if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0) {
         | 
| 1898 | 
            +
                            thread_attr_p = &attr;
         | 
| 1899 | 
            +
                        }
         | 
| 1900 | 
            +
                    }
         | 
| 1759 1901 | 
             
                }
         | 
| 1760 1902 | 
             
            }
         |