GithubHelp home page GithubHelp logo

mini_racer's Introduction

MiniRacer

Test Gem

Minimal, modern embedded V8 for Ruby.

MiniRacer provides a minimal two way bridge between the V8 JavaScript engine and Ruby.

It was created as an alternative to the excellent therubyracer, which is no longer maintained. Unlike therubyracer, mini_racer only implements a minimal bridge. This reduces the surface area making upgrading v8 much simpler and exhaustive testing simpler.

MiniRacer has an adapter for execjs so it can be used directly with Rails projects to minify assets, run babel or compile CoffeeScript.

Supported Ruby Versions & Troubleshooting

MiniRacer only supports non-EOL versions of Ruby. See Ruby Maintenance Branches for the list of non-EOL Rubies. If you require support for older versions of Ruby install an older version of the gem.

MiniRacer does not support Ruby built on MinGW, "pure windows" no Cygwin, no WSL2 (see rubyjs/libv8-node#9).

If you have a problem installing MiniRacer, please consider the following steps:

  • make sure you try the latest released version of mini_racer
  • make sure you have Rubygems >= 3.2.13 and bundler >= 2.2.13 installed: gem update --system
  • if you are using bundler
  • make sure to recompile/reinstall mini_racer and libv8-node after OS upgrades (for example via gem uninstall --all mini_racer libv8-node)
  • make sure you are on the latest patch/teeny version of a supported Ruby branch

Features

Simple eval for JavaScript

You can simply eval one or many JavaScript snippets in a shared context

context = MiniRacer::Context.new
context.eval("var adder = (a,b)=>a+b;")
puts context.eval("adder(20,22)")
# => 42

Attach global Ruby functions to your JavaScript context

You can attach one or many ruby proc that can be accessed via JavaScript

context = MiniRacer::Context.new
context.attach("math.adder", proc{|a,b| a+b})
puts context.eval("math.adder(20,22)")
# => 42
context = MiniRacer::Context.new
context.attach("array_and_hash", proc{{a: 1, b: [1, {a: 1}]}})
puts context.eval("array_and_hash()")
# => {"a" => 1, "b" => [1, {"a" => 1}]}

GIL free JavaScript execution

The Ruby Global interpreter lock is released when scripts are executing:

context = MiniRacer::Context.new
Thread.new do
  sleep 1
  context.stop
end
context.eval("while(true){}")
# => exception is raised

This allows you to execute multiple scripts in parallel.

Timeout Support

Contexts can specify a default timeout for scripts

context = MiniRacer::Context.new(timeout: 1000)
context.eval("while(true){}")
# => exception is raised after 1 second (1000 ms)

Memory softlimit Support

Contexts can specify a memory softlimit for scripts

# terminates script if heap usage exceeds 200mb after V8 garbage collection has run
context = MiniRacer::Context.new(max_memory: 200_000_000)
context.eval("var a = new Array(10000); while(true) {a = a.concat(new Array(10000)) }")
# => V8OutOfMemoryError is raised

Object marshal max Stack Ddepth Support

Contexts can specify a stack depth limit for object marshalling. Max depth is unbounded by default.

# terminates script if stack depth exceeds max during marshal
context = MiniRacer::Context.new(marshal_stack_depth: 500)
context.attach("a", proc{|a| a})

context.eval("let arr = []; arr.push(arr); a(arr)")
# => RuntimeError is raised

Rich Debugging with File Name in Stack Trace Support

You can provide filename: to #eval which will be used in stack traces produced by V8:

context = MiniRacer::Context.new
context.eval("var foo = function() {bar();}", filename: "a/foo.js")
context.eval("bar()", filename: "a/bar.js")

# JavaScript at a/bar.js:1:1: ReferenceError: bar is not defined (MiniRacer::RuntimeError)
# …

Fork Safety

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.

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, for example in a Rails initializer:

MiniRacer::Platform.set_flags!(:single_threaded)

If you want to ensure your application does not leak memory after fork either:

  1. Ensure no MiniRacer::Context objects are created in the master process; or
  2. Dispose manually of all MiniRacer::Context objects prior to forking
# before fork

require "objspace"
ObjectSpace.each_object(MiniRacer::Context){|c| c.dispose}

# fork here

Threadsafe

Context usage is threadsafe

context = MiniRacer::Context.new
context.eval("counter=0; plus=()=>counter++;")

(1..10).map do
  Thread.new {
    context.eval("plus()")
  }
end.each(&:join)

puts context.eval("counter")
# => 10

Snapshots

Contexts can be created with pre-loaded snapshots:

snapshot = MiniRacer::Snapshot.new("function hello() { return 'world!'; }")

context = MiniRacer::Context.new(snapshot: snapshot)

context.eval("hello()")
# => "world!"

Snapshots can come in handy for example if you want your contexts to be pre-loaded for efficiency. It uses V8 snapshots under the hood; see this link for caveats using these, in particular:

There is an important limitation to snapshots: they can only capture V8’s heap. Any interaction from V8 with the outside is off-limits when creating the snapshot. Such interactions include:

  • defining and calling API callbacks (i.e. functions created via v8::FunctionTemplate)
  • creating typed arrays, since the backing store may be allocated outside of V8

And of course, values derived from sources such as Math.random or Date.now are fixed once the snapshot has been captured. They are no longer really random nor reflect the current time.

Also note that snapshots can be warmed up, using the warmup! method, which allows you to call functions which are otherwise lazily compiled to get them to compile right away; any side effect of your warm up code being then dismissed. More details on warming up here, and a small example:

snapshot = MiniRacer::Snapshot.new("var counter = 0; function hello() { counter++; return 'world! '; }")

snapshot.warmup!("hello()")

context = MiniRacer::Context.new(snapshot: snapshot)

context.eval("hello()")
# => "world! 1"
context.eval("counter")
# => 1

Shared isolates

By default, MiniRacer's contexts each have their own isolate (V8 runtime). For efficiency, it is possible to re-use an isolate across contexts:

isolate = MiniRacer::Isolate.new

context1 = MiniRacer::Context.new(isolate: isolate)
context2 = MiniRacer::Context.new(isolate: isolate)

context1.isolate == context2.isolate
# => true

The main benefit of this is avoiding creating/destroying isolates when not needed (for example if you use a lot of contexts).

The caveat with this is that a given isolate can only execute one context at a time, so don't share isolates across contexts that you want to run concurrently.

Also, note that if you want to use shared isolates together with snapshots, you need to first create an isolate with that snapshot, and then create contexts from that isolate:

snapshot = MiniRacer::Snapshot.new("function hello() { return 'world!'; }")

isolate = MiniRacer::Isolate.new(snapshot)

context = MiniRacer::Context.new(isolate: isolate)

context.eval("hello()")
# => "world!"

Re-using the same isolate over and over again means V8's garbage collector will have to run to clean it up every now and then; it's possible to trigger a blocking V8 GC run inside your isolate by running the idle_notification method on it, which takes a single argument: the amount of time (in milliseconds) that V8 should use at most for garbage collecting:

isolate = MiniRacer::Isolate.new

context = MiniRacer::Context.new(isolate: isolate)

# do stuff with that context...

# give up to 100ms for V8 garbage collection
isolate.idle_notification(100)

# force V8 to perform a full GC
isolate.low_memory_notification

This can come in handy to force V8 GC runs for example in between requests if you use MiniRacer on a web application.

Note that this method maps directly to v8::Isolate::IdleNotification, and that in particular its return value is the same (true if there is no further garbage to collect, false otherwise) and the same caveats apply, in particular that there is no guarantee that the [call will return] within the time limit.

Additionally you may automate this process on a context by defining it with MiniRacer::Content.new(ensure_gc_after_idle: 1000). Using this will ensure V8 will run a full GC using context.isolate.low_memory_notification 1 second after the last eval on the context. Low memory notification is both slower and more aggressive than an idle_notification and will ensure long living isolates use minimal amounts of memory.

V8 Runtime flags

It is possible to set V8 Runtime flags:

MiniRacer::Platform.set_flags! :noconcurrent_recompilation, max_inlining_levels: 10

This can come in handy if you want to use MiniRacer with Unicorn, which doesn't seem to always appreciate V8's liberal use of threading:

MiniRacer::Platform.set_flags! :noconcurrent_recompilation, :noconcurrent_sweeping

Or else to unlock experimental features in V8, for example tail recursion optimization:

MiniRacer::Platform.set_flags! :harmony

js = <<-JS
'use strict';
var f = function f(n){
  if (n <= 0) {
    return  'foo';
  }
  return f(n - 1);
}

f(1e6);
JS

context = MiniRacer::Context.new

context.eval js
# => "foo"

The same code without the harmony runtime flag results in a MiniRacer::RuntimeError: RangeError: Maximum call stack size exceeded exception. Please refer to http://node.green/ as a reference on other harmony features.

A list of all V8 runtime flags can be found using node --v8-options, or else by perusing the V8 source code for flags (make sure to use the right version of V8).

Note that runtime flags must be set before any other operation (e.g. creating a context, a snapshot or an isolate), otherwise an exception will be thrown.

Flags:

  • :expose_gc: Will expose gc() which you can run in JavaScript to issue a GC run.
  • :max_old_space_size: defaults to 1400 (megs) on 64 bit, you can restrict memory usage by limiting this.

NOTE TO READER our documentation could be awesome we could be properly documenting all the flags, they are hugely useful, if you feel like documenting a few more, PLEASE DO, PRs are welcome.

Controlling memory

When hosting v8 you may want to keep track of memory usage, use #heap_stats to get memory usage:

context = MiniRacer::Context.new
# use context
p context.heap_stats
# {:total_physical_size=>1280640,
#  :total_heap_size_executable=>4194304,
#  :total_heap_size=>3100672,
#  :used_heap_size=>1205376,
#  :heap_size_limit=>1501560832}

If you wish to dispose of a context before waiting on the GC use #dispose:

context = MiniRacer::Context.new
context.eval("let a='testing';")
context.dispose
context.eval("a = 2")
# MiniRacer::ContextDisposedError

# nothing works on the context from now on, it's a shell waiting to be disposed

A MiniRacer context can also be dumped in a heapsnapshot file using #write_heap_snapshot(file_or_io)

context = MiniRacer::Context.new
# use context
context.write_heap_snapshot("test.heapsnapshot")

This file can then be loaded in the "memory" tab of the Chrome DevTools.

Function call

This calls the function passed as first argument:

context = MiniRacer::Context.new
context.eval("function hello(name) { return `Hello, ${name}!` }")
context.call("hello", "George")
# "Hello, George!"

Performance is slightly better than running context.eval("hello('George')") since:

  • compilation of eval'd string is avoided
  • function arguments don't need to be converted to JSON

Performance

The bench folder contains benchmark.

Benchmark minification of Discourse application.js (both minified and non-minified)

MiniRacer outperforms node when minifying assets via execjs.

  • MiniRacer version 0.1.9
  • node version 6.10
  • therubyracer version 0.12.2
$ bundle exec ruby bench.rb mini_racer
Benching with mini_racer
mini_racer minify discourse_app.js 9292.72063ms
mini_racer minify discourse_app_minified.js 11799.850171ms
mini_racer minify discourse_app.js twice (2 threads) 10269.570797ms

sam@ubuntu exec_js_uglify % bundle exec ruby bench.rb node
Benching with node
node minify discourse_app.js 13302.715484ms
node minify discourse_app_minified.js 18100.761243ms
node minify discourse_app.js twice (2 threads) 14383.600207000001ms

sam@ubuntu exec_js_uglify % bundle exec ruby bench.rb therubyracer
Benching with therubyracer
therubyracer minify discourse_app.js 171683.01867700001ms
therubyracer minify discourse_app_minified.js 143138.88492ms
therubyracer minify discourse_app.js twice (2 threads) NEVER FINISH

Killed: 9

The huge performance disparity (MiniRacer is 10x faster) is due to MiniRacer running latest version of V8. In July 2016 there is a queued upgrade to therubyracer which should bring some of the perf inline.

Note how the global interpreter lock release leads to 2 threads doing the same work taking the same wall time as 1 thread.

As a rule MiniRacer strives to always support and depend on the latest stable version of libv8.

Source Maps

MiniRacer can fully support source maps but must be configured correctly to do so. Check out this example for a working implementation.

Installation

Add this line to your application's Gemfile:

gem "mini_racer"

And then execute:

$ bundle

Or install it yourself as:

```terminal
$ gem install mini_racer

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).

Similar Projects

therubyracer

  • https://github.com/cowboyd/therubyracer
  • Most comprehensive bridge available
  • Provides the ability to "eval" JavaScript
  • Provides the ability to invoke Ruby code from JavaScript
  • Hold references to JavaScript objects and methods in your Ruby code
  • Hold references to Ruby objects and methods in JavaScript code
  • Uses libv8, so installation is fast
  • Supports timeouts for JavaScript execution
  • Does not release global interpreter lock, so performance is constrained to a single thread
  • Currently (May 2016) only supports v8 version 3.16.14 (Released approx November 2013), plans to upgrade by July 2016
  • Supports execjs

v8eval

  • https://github.com/sony/v8eval
  • Provides the ability to "eval" JavaScript using the latest V8 engine
  • Does not depend on the libv8 gem, installation can take 10-20 mins as V8 needs to be downloaded and compiled.
  • Does not release global interpreter lock when executing JavaScript
  • Does not allow you to invoke Ruby code from JavaScript
  • Multi runtime support due to SWIG based bindings
  • Supports a JavaScript debugger
  • Does not support timeouts for JavaScript execution
  • No support for execjs (can not be used with Rails uglifier and coffeescript gems)

therubyrhino

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/rubyjs/mini_racer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

mini_racer's People

Contributors

andrew avatar bryanp avatar bryant1410 avatar calasyr avatar cataphract avatar dependabot[bot] avatar dtheodor avatar eregon avatar fayti1703 avatar hackmud-dtr avatar ianks avatar ignisf avatar lloeki avatar messense avatar n00bish avatar nightpool avatar ojab avatar olleolleolle avatar p8 avatar samsaffron avatar seanmakesgames avatar taiki-san avatar tisba avatar ttanimichi avatar umanoda avatar vieditcom avatar warhammerkid avatar wk8 avatar yujideveloper avatar zogstrip avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mini_racer's Issues

uninitialized memory issues?

This is less of a 'fix something in mini_racer' and more of a 'am I doing this right?' issue.

There are two issues which are causing me problems:

The issues happen inconsistently at least once a day, occurring more often with higher user concurrency.

Context:

  • ruby on rails 4 server
  • mongodb backend
  • delayed_job worker
  • mini_racer js engine

-> client sends request to server 'some_js_scriptname'
-> unicorn handles request on a worker process
-> worker process validates request then schedules job with run info

-> delayed_job worker daemon process picks up job (only one worker; 1 job at a time)
-> in delayed_job worker:
-> js source code is pulled from mongo
-> context1 is lazy-init (stays for entire life of worker process) to validate source code
-> context2 is created to run source code
-> context2 attaches procs for the source code to access db operations (above issue procs)
-> context2 evals
-> context2 stop
-> context2 result stored in mongo
-> worker picks up next job

-> client sends request to server: get_script_results
-> unicorn handles req
-> gets results for user from mongo

multiple users, multiple clients, multiple script calls, multiple result queries, one worker (atm) runs contexts synchronously.

I'd love to get a better understanding of where I might need to synchronize operations, or where things could be falling apart. Any help is appreciated.

Can't install mini_race gem on Windows

I'm following this thread, that shows you how to install Disocurse using Vagrant. Everything goes well until I do "Bundle Install", most gems install fine but there seems to be a problem with this one. I get the following error message:

"An error occurred while installing mini_racer (0.1.3), and Bundler cannot continue.
Make sure that gem install mini_racer -v '0.1.3' succeeds before bundling."

Which doesn't say much, so I tried to install it as it says and I get this:

Building native extensions. This could take a while...
ERROR: Error installing mini_racer:
ERROR: Failed to build gem native extension.

/usr/bin/ruby2.2 -r ./siteconf20160528-1821-euyqum.rb extconf.rb

checking for main() in -lpthread... yes
creating Makefile

make "DESTDIR=" clean

make "DESTDIR="
compiling mini_racer_extension.cc
In file included from mini_racer_extension.cc:4:0:
/var/lib/gems/2.2.0/gems/libv8-5.0.71.48.3-x86-linux/vendor/v8/include/v8.h:341:1: error: expected unqualified-id before ‘using’
/var/lib/gems/2.2.0/gems/libv8-5.0.71.48.3-x86-linux/vendor/v8/include/v8.h:477:1: error: expected unqualified-id before ‘using’
/var/lib/gems/2.2.0/gems/libv8-5.0.71.48.3-x86-linux/vendor/v8/include/v8.h:871:1: error: expected unqualified-id before ‘using’
mini_racer_extension.cc:136:51: error: ‘Handle’ has not been declared
mini_racer_extension.cc:136:57: error: expected ‘,’ or ‘...’ before ‘<’ token
mini_racer_extension.cc: In function ‘VALUE convert_v8_to_ruby(v8::Isolate_, int)’:
mini_racer_extension.cc:140:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:144:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:148:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:152:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:156:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:160:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:165:55: error: cannot convert ‘v8::Localv8::Value’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate_, int)’
mini_racer_extension.cc:171:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:175:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:184:53: error: cannot convert ‘v8::Localv8::Value’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate_, int)’
mini_racer_extension.cc:186:57: error: cannot convert ‘v8::Localv8::Value’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate_, int)’
mini_racer_extension.cc:193:26: error: ‘value’ was not declared in this scope
mini_racer_extension.cc: At global scope:
mini_racer_extension.cc:197:8: error: ‘Handle’ does not name a type
mini_racer_extension.cc: In function ‘VALUE rb_context_eval_unsafe(VALUE, VALUE)’:
mini_racer_extension.cc:299:61: error: cannot convert ‘v8::Localv8::Value’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate_, int)’
mini_racer_extension.cc:306:63: error: cannot convert ‘v8::Localv8::Value’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate_, int)’
mini_racer_extension.cc:348:56: error: cannot convert ‘v8::Localv8::Value’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate_, int)’
mini_racer_extension.cc: In function ‘void_ gvl_ruby_callback(void_)’:
mini_racer_extension.cc:396:2: error: ‘Handle’ was not declared in this scope
mini_racer_extension.cc:396:17: error: expected primary-expression before ‘>’ token
mini_racer_extension.cc:396:19: error: ‘external’ was not declared in this scope
mini_racer_extension.cc:396:45: error: expected primary-expression before ‘>’ token
mini_racer_extension.cc:396:46: error: ‘::Cast’ has not been declared
mini_racer_extension.cc:409:65: error: cannot convert ‘v8::Localv8::Value’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate_, int)’
mini_racer_extension.cc:430:2: error: ‘Handle’ was not declared in this scope
mini_racer_extension.cc:430:14: error: expected primary-expression before ‘>’ token
mini_racer_extension.cc:430:16: error: ‘v8_result’ was not declared in this scope
mini_racer_extension.cc:430:73: error: ‘convert_ruby_to_v8’ was not declared in this scope
make: *** [mini_racer_extension.o] Error 1

make failed, exit code 2

Gem files will remain installed in /var/lib/gems/2.2.0/gems/mini_racer-0.1.3 for inspection.
Results logged to /var/lib/gems/2.2.0/extensions/x86-linux/2.2.0/mini_racer-0.1.3/gem_make.out

Windows 10, 64 bit
Ruby 2.2.2p95

Questions regarding Sidekiq+MiniRacer

Hello, I apologize in advance if this is not a good place to open a support-style question, I read the CoC and the notes at that end of the README and didn't see an alternative.

I've developed a spreadsheet application which uses (the wonderful) MathJS library on the frontend to calculate the results of user defined formulas. However, rather than shipping these results to the backend, I re-calculate them on the fly with a job executed by Sidekiq.

The job was originally using ExecJS w/TheRubyRacer, but I of course ran into a mysterious dead-locking issue and realized it wasn't threadsafe, and then switched to MiniRacer as a result.

However, I am still observing memory usage growing until Heroku terminates this 1Gb RAM instance. I suspect my implementation is causing the issue and it isn't related to sidekiq/sidekiq#3756 for example. Being that this is on Heroku and not a real VPS, it is hard for me to attach rbtrace and dump the heap and find out myself.

I am considering using MiniRacer directly w/o the ExecJS shim, but I am having trouble understanding a few topics covered in the README.

First, in "GIL free JavaScript execution", the example says:

context = MiniRacer::Context.new
Thread.new do
  sleep 1
  context.stop
end
context.eval 'while(true){}'
# => exception is raised

Do I need to explicitly stop my context?

Next, snapshots:

snapshot = MiniRacer::Snapshot.new('function hello() { return "world!"; }')

context = MiniRacer::Context.new(snapshot: snapshot)

Since this is running in Sidekiq, can I stash my snapshot in say memcached/dalli, and then pull it out during the jobs runtime? I assume this would be fine.

Finally, some abbreviated code, it's a little hacked together...

class MathJS
  MATHJS_SOURCE = Rails.root.join('vendor', 'mathjs-3.20.1.min.js')

  def self.context
    @context ||= ExecJS.compile(File.read(MATHJS_SOURCE))
  end

  def self.call(function, *args)
    Rails.logger.info("calling mathjs #{function} on #{args}")
    MathJS.context.call(function, *args)
  end
end

and then the job, again abbreviated:

class SurveyWorker
  include Sidekiq::Worker
  def perform(survey_id)
    @survey = Survey.find(survey_id)
  
    Formula.cache.each do |formula|
      build_and_evaluate(formula)
    end
  end

  def build_and_evaluate(formula)
    # some business logic to build up the formulas variables, it's 'scope'
    scope = ...
    evaluation = MathJS.call('math.eval', formula.formula, scope)
  end
end

and finally, for the sake of completion, the Formula class, abbreviated

class Formula < ApplicationRecord
  def self.cache
    Rails.cache.fetch('parsed_formula') do
      Formula.all.order(execution_order: :asc).each(&:parse)
    end
  end

  def self.expire_cache!
    Rails.cache.write('parsed_formula', nil)
  end

  def parse
    @parsed_formula ||= MathJS.call("math.parse", formula)
  end
end

Sorry the length of this all and a very specific issue for me, though I suspect that using MiniRacer w/Sidekiq is a great use case, so maybe it'll help others.

Timeouts during marshalling are sending FailedV8Conversion objects instead of raising

Timeouts are happening during marshalling, and are just sending FailedV8Conversion objects into rubyland (where I'm currently just assuming that they are timeouts)

test with consistent repro:

  def test_timeout_during_marshall
    context = MiniRacer::Context.new({timeout: 1000})
    context.attach("long_running_proc", proc do |a|
      a[rand(10000).to_s] = "a"
      a
    end)
    assert_raises(MiniRacer::ScriptTerminatedError) do
      context.eval("var a = {}; while(true) { a = long_running_proc(a); }")
    end
  end

Time for a release?

there are a lot of fixes since 0.1.4 including the patch that would allow using a v8 newer than 5.1.11.

anything blocking a release atm?

Call passed JavaScript anonymous function from Ruby

Example:

context = MiniRacer::Context.new
context.attach('each', ->(f) { [1,2,3].each { |i| f.call(i); } })
context.eval 'i = 0; each(function(i2) { i += i2 }); i' // => 6

Is such a thing being considered?

Can't marshal DateTimes

I looked into this a bit, and it seems there are some performance considerations,
I was not able to find a rb_cDateTime const in the c api for ruby, so we have to make one for ourselves by doing "DateTime.new.class" or something and saving that
I don't know the code well enough to know where to put that so that it wouldn't get called every serialization

global exception management

My players have written JS that looks like the following:

function(context, args)
{
    var o={};
    o.__defineGetter__('bar',function(){

        for(var i=0;i<10;++i)
            some_rb_attached_method({data:"foo"});
        return 2
    });
    return o
}

which gets evaluated after the .eval() block on the context. e.g:

result = ctx.eval(above_code)
ctx.stop
ActiveSupport::JSON.encode(result) # or something similar

This will throw a c-extension exception in mini_racer
/mini_racer.rb:96: [BUG] rb_thread_call_with_gvl: called by a thread which has GVL.

I can fix this error (several solutions), but what I really want is to be able to catch these and log them somehow on the server, so that I can fix them. Right now I think they disappear into the void.

Ideally, I'd like this code to be safe, (catch in c, safe & consistent log, and rethrow; to terminate if it's a fatal issue)

Any thoughts?

Callstacks for EvalErrors

Currently this information is not provided. I'd love to have line-numbers & function names. @SamSaffron you mentioned some memory ownership concerns with this: How do we marshall this information across the ruby / v8 barrier?

Memory management

Hi, this project looks exciting. I'm a long-time therubyracer user and I use it for long-running contexts. Memory management is an open issue with trr, see issue.

So I'd like to know, is there any reason to believe that mini_racer might do better than trr at conserving memory?

javascript parse errors get eaten

First off, thank you for putting this together. My game uses racer to run all of its game code, and the memory leaks made it impossible to ship / scale. It's got a chance now.

therubyracer has callstacks for where in the execution errors happened, but with mini_racer I don't get them:

var f = function(a, ) {};
"Unknown JavaScript Error during parse"

Is this because rubyracer does extra work on the other side of v8, or are these turned off on purpose by mini_racer-

any help is very much appreciated!

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

Can you help me with this issue? I need that for react on rails.
ruby 2.3.1p112 (2016-04-26) [x86_64-linux-gnu]
Rails 4.2.6
gcc (Ubuntu 4.8.5-4ubuntu2) 4.8.5

Issue:
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

current directory: /tmp/bundler20180402-4622-17ue5rwmini_racer-0.1.15/gems/mini_racer-0.1.15/ext/mini_racer_extension

/usr/bin/ruby2.3 -r ./siteconf20180402-4622-1pv3sy3.rb extconf.rb
checking for main() in -lpthread... *** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers. Check the mkmf.log file for more details. You may
need configuration options.

Provided configuration options:
--with-opt-dir
--without-opt-dir
--with-opt-include
--without-opt-include=${opt-dir}/include
--with-opt-lib
--without-opt-lib=${opt-dir}/lib
--with-make-prog
--without-make-prog
--srcdir=.
--curdir
--ruby=/usr/bin/$(RUBY_BASE_NAME)2.3
--with-pthreadlib
--without-pthreadlib
/usr/lib/ruby/2.3.0/mkmf.rb:456:in `try_do': The compiler failed to generate an executable file. (RuntimeError)

You have to install development tools first.
from /usr/lib/ruby/2.3.0/mkmf.rb:541:in `try_link0'

from /usr/lib/ruby/2.3.0/mkmf.rb:556:in `try_link'

from /usr/lib/ruby/2.3.0/mkmf.rb:765:in `try_func'

from /usr/lib/ruby/2.3.0/mkmf.rb:997:in `block in have_library'

from /usr/lib/ruby/2.3.0/mkmf.rb:942:in `block in checking_for'

from /usr/lib/ruby/2.3.0/mkmf.rb:350:in `block (2 levels) in postpone'

from /usr/lib/ruby/2.3.0/mkmf.rb:320:in `open'

from /usr/lib/ruby/2.3.0/mkmf.rb:350:in `block in postpone'

from /usr/lib/ruby/2.3.0/mkmf.rb:320:in `open'

from /usr/lib/ruby/2.3.0/mkmf.rb:346:in `postpone'

from /usr/lib/ruby/2.3.0/mkmf.rb:941:in `checking_for'

from /usr/lib/ruby/2.3.0/mkmf.rb:992:in `have_library'

from extconf.rb:4:in `<main>'

To see why this extension failed to compile, please check the mkmf.log which can be found here:

/tmp/bundler20180402-4622-17ue5rwmini_racer-0.1.15/extensions/x86_64-linux/2.3.0/mini_racer-0.1.15/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /tmp/bundler20180402-4622-17ue5rwmini_racer-0.1.15/gems/mini_racer-0.1.15 for inspection.
Results logged to /tmp/bundler20180402-4622-17ue5rwmini_racer-0.1.15/extensions/x86_64-linux/2.3.0/mini_racer-0.1.15/gem_make.out

Error linking during bundle on MacOS

ld: unknown option: --start-group
clang: error: linker command failed with exit code 1

Apparently macos treats unknown command line options as errors. I don't know if this is a libv8 issue or mini_racer.
Isolating which revision this was introduced now.

Date / Time types are not marshalled

This one I think I might be able to do.
This is related to mongodb usage across ruby / js bridge --
I've already serialized BSON::ObjectId as a preprocess, but I think rbTime <-> jsDate is more generic and might be worth it for general consumption.
(also I can't do this one outside of the shim w/o some serious hackery)

Is Time a reasonable class to use on the ruby side?

able to catch ruby proc exceptions with try/catch in JS, but they have no information

Would love to prevent the 'catch' and forward them out to ruby if possible.

  def test_catch_rb
    context = MiniRacer::Context.new(timeout: 50)
    context.attach('crash', proc{ raise ArgumentError.new('???') })

    code = "function a() { \
              try { \
                crash(); \
              } catch(e) { return e; } \
            }\
            a();"

    assert_raises(ArgumentError) do
      context.eval(code)
    end
  end

trying to swap in mini_racer

Hi!

I've started looking at replacing therubyracer from a large old project with mini_racer. One of the issues i've run into is that common.js is trying to call the js runtime using a method that is not available in mini_racer

Do you have any comments or suggestions w.r.t the general issue of compatibility? At the moment, it looks like i may need to hack mini_racer to be more api compatible with therubyracer, or should i update the dependencies (commonjs, less.rb, etc) to be mini_racer friendly? What is your thoughts on accepting potential pr's that attempt to make the api compatible with therubyracer?

Thanks!

Setting max mem size for v8 instance?

Is there a way currently to set the heap size to a specific amount? Maybe from a config, or on the context object? Found this online for v8:
--max-old-space-size

Disposing contexts

Maybe I'm missing it, but there doesn't seem to be a way to release a context and free memory.

This would be very handy given that timeouts can leave the context in an inconsistent state (finally blocks aren't called, etc.)

Thanks again for your work on miniracer.

Dispose context with shared isolate

When holding a shared isolate to pass to future context, calling dispose on the last remaining context kills the isolate too, so then next time you go to use the isolate, you get a segfault.

Received signal 11 SEGV_MAPERR 000000000ea0

==== C stack trace ===============================

 [0x00010c22e874]
 [0x7fff7ced1f5a]
 [0x00010f96a968]
 [0x00010bae7b1b]
 [0x00010bab45d0]
 [0x00010a80610b]
 [0x00010a7ef864]
 [0x00010a8009de]
 [0x00010a7ff4be]
 [0x00010a80754f]
 [0x00010a7ef864]
 [0x00010a8009de]
 [0x00010a80e104]
 [0x00010a7fd572]
 [0x00010a80610b]
 [0x00010a80710b]
 [0x00010a7eedc4]
 [0x00010a8009de]
 [0x00010a7ff4be]
 [0x00010a80754f]
 [0x00010a7ef864]
 [0x00010a8009de]
 [0x00010a80e104]
 [0x00010a7fbcee]
 [0x00010a628bc9]
 [0x00010a80610b]
 [0x00010a7eedc4]
 [0x00010a8009de]
 [0x00010a80e104]
 [0x00010a80f10e]
 [0x00010a7fd81d]
 [0x00010a7fded2]
 [0x00010a80610b]
 [0x00010a7eedc4]
 [0x00010a8009de]
 [0x00010a80e104]
 [0x00010a80f10e]
 [0x00010a7fd81d]
 [0x00010a7fded2]
 [0x00010a80610b]
 [0x00010a7eedc4]
 [0x00010a8009de]
 [0x00010a7ff4be]
 [0x00010a80754f]
 [0x00010a7ef864]
 [0x00010a8009de]
 [0x00010a7ff4be]
 [0x00010a80754f]
 [0x00010a7ef864]
 [0x00010a8009de]
 [0x00010a7ff4be]
 [0x00010a7c6265]
 [0x00010a7c5bcf]
 [0x7fff7cedb6c1]
 [0x7fff7cedb56d]
 [0x7fff7cedac5d]
[end of stack trace]

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

Issue with rbx-3.70

Building native extensions.  This could take a while...
ERROR:  Error installing mini_racer:
	ERROR: Failed to build gem native extension.

    current directory: /Users/alexfalkowski/.gem/rbx/2.3.1/gems/mini_racer-0.1.7/ext/mini_racer_extension
/Users/alexfalkowski/.rubies/rbx-3.70/bin/rbx -r ./siteconf20170204-26481-m4fqsh.rb extconf.rb
checking for main() in -lpthread... yes
checking for main() in -lobjc... yes
creating Makefile

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /Users/alexfalkowski/.gem/rbx/2.3.1/extensions/x86_64-darwin-16/2.3/mini_racer-0.1.7/mkmf.log

current directory: /Users/alexfalkowski/.gem/rbx/2.3.1/gems/mini_racer-0.1.7/ext/mini_racer_extension
make "DESTDIR=" clean

current directory: /Users/alexfalkowski/.gem/rbx/2.3.1/gems/mini_racer-0.1.7/ext/mini_racer_extension
make "DESTDIR="
compiling mini_racer_extension.cc
clang: warning: argument unused during compilation: '-rdynamic'
mini_racer_extension.cc:235:36: error: use of undeclared identifier 'floor'
        long nanos = round((secs - floor(secs)) * 1000000);
                                   ^
1 error generated.
make: *** [mini_racer_extension.o] Error 1

make failed, exit code 2

Gem files will remain installed in /Users/alexfalkowski/.gem/rbx/2.3.1/gems/mini_racer-0.1.7 for inspection.
Results logged to /Users/alexfalkowski/.gem/rbx/2.3.1/extensions/x86_64-darwin-16/2.3/mini_racer-0.1.7/gem_make.out

timeout can be bypassed by returning an object with a property.

This one's real bad. Can't even write a test case that properly fails & doesn't hang:

  def test_timeout_break
    context = MiniRacer::Context.new(timeout: 10)

    status = Timeout::timeout(0.05) do # this doesn't even work
      context.eval('var a = {ok:true, get msg(){ while(true); }}; a')
    end
  end

In the interim, I'll be wrapping return values in a stringify/parse block to remove getters from post-return execution.

Ruby 1.9 incompatibiliby (missing thread.h)

Hello,

When trying to install on Ruby 1.9 the build fails with a cryptic error about a missing thread.h. AFAIK this is related to lack of support of calling threads without a GVL.

IMO an explicit Ruby version requirement should be added to the gemspec in order to save some debugging time of people trying to use the gem with 1.9. See http://guides.rubygems.org/specification-reference/#required_ruby_version=

It seems that Ruby 1.9 is the default in Ubuntu 14.04 which will be supported until 2020, and 1.8 is the default in 12.04 which will be supported until 2018 😮.

passing invalid utf8 out to attached ruby proc causes extension-level crash

#
# Fatal error in v8::Isolate::Dispose()
# Disposing the isolate that is entered by a thread.
#

/Users/seangubelman/mini_racer/test/mini_racer_test.rb:448: [BUG] Illegal instruction at 0x0000010a1deb42
  def test_invalid_utf8_proc
    context = MiniRacer::Context.new
    context.attach('echo', proc{|v| return v })
    assert_raises(MiniRacer::ParseError) do
      context.eval('echo("\uDC00");')
    end
  end

JS is natively utf16, so the code being eval'd is valid. I figure we raise something like 'Invalid UTF8 string passed to attached proc'

P.S. My players are excellent at making my life difficult. ;P

Fail to install gem 'mini_racer'

In my Gemfile:
gem 'mini_racer'

bundle install

Fetching libv8 5.9.211.38.1
Installing libv8 5.9.211.38.1 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/ext/libv8
/home/ruby/.rbenv/versions/2.5.0/bin/ruby -r ./siteconf20171227-18139-z6o7p5.rb extconf.rb
creating Makefile

v8 (ERROR)
----------------------------------------
[0:00:00] Started.
[0:00:00]

________ running 'git -c core.deltaBaseCacheLimit=2g clone --no-checkout --progress https://chromium.googlesource.com/v8/v8.git
/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/_gclient_v8_vqSwQh' in
'/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor'
[0:00:00] Cloning into '/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/_gclient_v8_vqSwQh'...
[0:00:02] remote: Sending approximately 533.65 MiB ...
[0:00:43] remote: Counting objects: 1
[0:00:44] remote: Counting objects: 1115
[0:00:45] remote: Counting objects: 7665, done
[0:00:45] remote: Finding sources:  20% (1/5)
[0:00:45] remote: Finding sources: 100% (5/5)
[0:00:45] Receiving objects:   0% (1/518315)
[0:00:46] Receiving objects:   6% (31099/518315), 10.38 MiB | 10.35 MiB/s
[0:00:47] Receiving objects:  10% (51832/518315), 15.99 MiB | 10.64 MiB/s
[0:00:48] Receiving objects:  13% (72171/518315), 27.16 MiB | 10.86 MiB/s
[0:00:49] Receiving objects:  19% (98480/518315), 43.99 MiB | 10.97 MiB/s
[0:00:50] Receiving objects:  25% (129579/518315), 55.24 MiB | 11.38 MiB/s
[0:00:51] Receiving objects:  31% (160678/518315), 66.48 MiB | 11.18 MiB/s
[0:00:52] Receiving objects:  36% (186594/518315), 77.73 MiB | 11.18 MiB/s
[0:00:54] Receiving objects:  53% (279768/518315), 94.56 MiB | 11.18 MiB/s
[0:00:55] Receiving objects:  54% (283568/518315), 105.77 MiB | 11.18 MiB/s
[0:00:57] Receiving objects:  56% (295017/518315), 127.53 MiB | 10.60 MiB/s
[0:00:59] Receiving objects:  57% (299185/518315), 149.96 MiB | 10.60 MiB/s
[0:01:00] Receiving objects:  58% (302347/518315), 161.14 MiB | 11.18 MiB/s
[0:01:01] Receiving objects:  58% (303692/518315), 172.39 MiB | 11.18 MiB/s
[0:01:02] Receiving objects:  58% (305578/518315), 183.63 MiB | 11.18 MiB/s
[0:01:03] Receiving objects:  59% (309233/518315), 194.85 MiB | 11.18 MiB/s
[0:01:04] Receiving objects:  59% (310845/518315), 206.06 MiB | 11.18 MiB/s
[0:01:06] Receiving objects:  61% (316173/518315), 222.81 MiB | 10.67 MiB/s
[0:01:07] Receiving objects:  61% (321205/518315), 233.65 MiB | 10.60 MiB/s
[0:01:08] Receiving objects:  62% (324120/518315), 244.86 MiB | 10.60 MiB/s
[0:01:10] Receiving objects:  64% (331722/518315), 267.36 MiB | 10.61 MiB/s
[0:01:11] Receiving objects:  65% (338957/518315), 278.59 MiB | 11.20 MiB/s
[0:01:12] Receiving objects:  65% (341590/518315), 289.72 MiB | 11.18 MiB/s
[0:01:13] Receiving objects:  66% (344386/518315), 300.91 MiB | 11.17 MiB/s
[0:01:14] Receiving objects:  67% (349175/518315), 312.15 MiB | 11.18 MiB/s
[0:01:15] Receiving objects:  69% (357638/518315), 328.96 MiB | 11.17 MiB/s
[0:01:17] Receiving objects:  70% (367143/518315), 343.08 MiB | 10.57 MiB/s
[0:01:18] Receiving objects:  72% (373187/518315), 360.26 MiB | 10.58 MiB/s
[0:01:20] Receiving objects:  73% (380342/518315), 376.93 MiB | 10.54 MiB/s
[0:01:21] Receiving objects:  75% (388737/518315), 393.32 MiB | 11.05 MiB/s
[0:01:23] Receiving objects:  77% (399103/518315), 410.18 MiB | 11.05 MiB/s
[0:01:24] Receiving objects:  77% (403442/518315), 421.37 MiB | 11.07 MiB/s
[0:01:25] Receiving objects:  78% (408013/518315), 432.62 MiB | 11.16 MiB/s
[0:01:26] Receiving objects:  79% (412574/518315), 443.86 MiB | 11.20 MiB/s
[0:01:27] Receiving objects:  81% (419836/518315), 457.86 MiB | 10.57 MiB/s
[0:01:29] Receiving objects:  82% (429265/518315), 474.73 MiB | 10.57 MiB/s
[0:01:30] Receiving objects:  85% (441656/518315), 485.91 MiB | 10.57 MiB/s
[0:01:31] Receiving objects:  89% (461301/518315), 497.16 MiB | 11.17 MiB/s
[0:01:32] Receiving objects:  93% (482033/518315), 514.02 MiB | 11.19 MiB/s
[0:01:33] Receiving objects:  97% (502766/518315), 525.21 MiB | 11.18 MiB/s
[0:01:34] remote: Total 518315 (delta 423617), reused 518311 (delta 423617)
[0:01:34] Receiving objects: 100% (518315/518315), 530.83 MiB | 11.18 MiB/s
[0:01:34] Resolving deltas:   0% (0/423617)
[0:01:35] Resolving deltas:  10% (42373/423617)
[0:01:36] Resolving deltas:  25% (105919/423617)
[0:01:37] Resolving deltas:  39% (166842/423617)
[0:01:38] Resolving deltas:  52% (222216/423617)
[0:01:39] Resolving deltas:  56% (237344/423617)
[0:01:40] Resolving deltas:  63% (266879/423617)
[0:01:41] Resolving deltas:  65% (275368/423617)
[0:01:42] Resolving deltas:  67% (283828/423617)
[0:01:44] Resolving deltas:  69% (292440/423617)
[0:01:45] Resolving deltas:  72% (305069/423617)
[0:01:46] Resolving deltas:  75% (317718/423617)
[0:01:47] Resolving deltas:  77% (329721/423617)
[0:01:48] Resolving deltas:  79% (337099/423617)
[0:01:49] Resolving deltas:  82% (348371/423617)
[0:01:50] Resolving deltas:  85% (360075/423617)
[0:01:51] Resolving deltas:  88% (372785/423617)
[0:01:53] Resolving deltas:  91% (385931/423617)
[0:01:54] Resolving deltas:  93% (393980/423617)
[0:01:55] Resolving deltas:  96% (406910/423617)
[0:01:56] Resolving deltas:  99% (421514/423617)
[0:01:57] Resolving deltas: 100% (423617/423617)
[0:01:57] Checking connectivity... done.
[0:02:27] From https://chromium.googlesource.com/v8/v8
[0:02:27]  * [new ref]         refs/branch-heads/0.1 -> branch-heads/0.1
[0:02:27]  * [new ref]         refs/branch-heads/0.3 -> branch-heads/0.3
[0:02:27]  * [new ref]         refs/branch-heads/1.1 -> branch-heads/1.1
[0:02:27]  * [new ref]         refs/branch-heads/1.2 -> branch-heads/1.2
[0:02:27]  * [new ref]         refs/branch-heads/1.3 -> branch-heads/1.3
[0:02:27]  * [new ref]         refs/branch-heads/2.0 -> branch-heads/2.0
[0:02:27]  * [new ref]         refs/branch-heads/2.1 -> branch-heads/2.1
[0:02:27]  * [new ref]         refs/branch-heads/2.2 -> branch-heads/2.2
[0:02:27]  * [new ref]         refs/branch-heads/2.3 -> branch-heads/2.3
[0:02:27]  * [new ref]         refs/branch-heads/2.4 -> branch-heads/2.4
[0:02:27]  * [new ref]         refs/branch-heads/2.5 -> branch-heads/2.5
[0:02:27]  * [new ref]         refs/branch-heads/3.0 -> branch-heads/3.0
[0:02:27]  * [new ref]         refs/branch-heads/3.1 -> branch-heads/3.1
[0:02:27]  * [new ref]         refs/branch-heads/3.10 -> branch-heads/3.10
[0:02:27]  * [new ref]         refs/branch-heads/3.11 -> branch-heads/3.11
[0:02:27]  * [new ref]         refs/branch-heads/3.12 -> branch-heads/3.12
[0:02:27]  * [new ref]         refs/branch-heads/3.13 -> branch-heads/3.13
[0:02:27]  * [new ref]         refs/branch-heads/3.14 -> branch-heads/3.14
[0:02:27]  * [new ref]         refs/branch-heads/3.15 -> branch-heads/3.15
[0:02:27]  * [new ref]         refs/branch-heads/3.16 -> branch-heads/3.16
[0:02:27]  * [new ref]         refs/branch-heads/3.17 -> branch-heads/3.17
[0:02:27]  * [new ref]         refs/branch-heads/3.18 -> branch-heads/3.18
[0:02:27]  * [new ref]         refs/branch-heads/3.19 -> branch-heads/3.19
[0:02:27]  * [new ref]         refs/branch-heads/3.2 -> branch-heads/3.2
[0:02:27]  * [new ref]         refs/branch-heads/3.20 -> branch-heads/3.20
[0:02:27]  * [new ref]         refs/branch-heads/3.20.15.5 -> branch-heads/3.20.15.5
[0:02:27]  * [new ref]         refs/branch-heads/3.21 -> branch-heads/3.21
[0:02:27]  * [new ref]         refs/branch-heads/3.22 -> branch-heads/3.22
[0:02:27]  * [new ref]         refs/branch-heads/3.23 -> branch-heads/3.23
[0:02:27]  * [new ref]         refs/branch-heads/3.24 -> branch-heads/3.24
[0:02:27]  * [new ref]         refs/branch-heads/3.25 -> branch-heads/3.25
[0:02:27]  * [new ref]         refs/branch-heads/3.26 -> branch-heads/3.26
[0:02:28]  * [new ref]         refs/branch-heads/3.27 -> branch-heads/3.27
[0:02:28]  * [new ref]         refs/branch-heads/3.28 -> branch-heads/3.28
[0:02:28]  * [new ref]         refs/branch-heads/3.29 -> branch-heads/3.29
[0:02:28]  * [new ref]         refs/branch-heads/3.3 -> branch-heads/3.3
[0:02:28]  * [new ref]         refs/branch-heads/3.30 -> branch-heads/3.30
[0:02:28]  * [new ref]         refs/branch-heads/3.31 -> branch-heads/3.31
[0:02:28]  * [new ref]         refs/branch-heads/3.4 -> branch-heads/3.4
[0:02:28]  * [new ref]         refs/branch-heads/3.5 -> branch-heads/3.5
[0:02:28]  * [new ref]         refs/branch-heads/3.6 -> branch-heads/3.6
[0:02:28]  * [new ref]         refs/branch-heads/3.7 -> branch-heads/3.7
[0:02:28]  * [new ref]         refs/branch-heads/3.8 -> branch-heads/3.8
[0:02:28]  * [new ref]         refs/branch-heads/3.9 -> branch-heads/3.9
[0:02:28]  * [new ref]         refs/branch-heads/4.1 -> branch-heads/4.1
[0:02:28]  * [new ref]         refs/branch-heads/4.2 -> branch-heads/4.2
[0:02:28]  * [new ref]         refs/branch-heads/4.2.39 -> branch-heads/4.2.39
[0:02:28]  * [new ref]         refs/branch-heads/4.3 -> branch-heads/4.3
[0:02:28]  * [new ref]         refs/branch-heads/4.4 -> branch-heads/4.4
[0:02:28]  * [new ref]         refs/branch-heads/4.5 -> branch-heads/4.5
[0:02:28]  * [new ref]         refs/branch-heads/4.6 -> branch-heads/4.6
[0:02:28]  * [new ref]         refs/branch-heads/4.7 -> branch-heads/4.7
[0:02:28]  * [new ref]         refs/branch-heads/4.8 -> branch-heads/4.8
[0:02:28]  * [new ref]         refs/branch-heads/4.9 -> branch-heads/4.9
[0:02:28]  * [new ref]         refs/branch-heads/5.0 -> branch-heads/5.0
[0:02:28]  * [new ref]         refs/branch-heads/5.1 -> branch-heads/5.1
[0:02:28]  * [new ref]         refs/branch-heads/5.2 -> branch-heads/5.2
[0:02:28]  * [new ref]         refs/branch-heads/5.3 -> branch-heads/5.3
[0:02:28]  * [new ref]         refs/branch-heads/5.4 -> branch-heads/5.4
[0:02:28]  * [new ref]         refs/branch-heads/5.5 -> branch-heads/5.5
[0:02:28]  * [new ref]         refs/branch-heads/5.6 -> branch-heads/5.6
[0:02:28]  * [new ref]         refs/branch-heads/5.7 -> branch-heads/5.7
[0:02:28]  * [new ref]         refs/branch-heads/5.8 -> branch-heads/5.8
[0:02:28]  * [new ref]         refs/branch-heads/5.9 -> branch-heads/5.9
[0:02:28]  * [new ref]         refs/branch-heads/6.0 -> branch-heads/6.0
[0:02:28]  * [new ref]         refs/branch-heads/6.1 -> branch-heads/6.1
[0:02:28]  * [new ref]         refs/branch-heads/6.2 -> branch-heads/6.2
[0:02:28]  * [new ref]         refs/branch-heads/6.3 -> branch-heads/6.3
[0:02:28]  * [new ref]         refs/branch-heads/6.4 -> branch-heads/6.4
[0:02:28]  * [new ref]         refs/branch-heads/experimental -> branch-heads/experimental
[0:02:28]  * [new ref]         refs/branch-heads/test-gnumbd -> branch-heads/test-gnumbd
[0:02:28] Checked out refs/remotes/origin/master to a detached HEAD. Before making any commits
in this repo, you should use 'git checkout <branch>' to switch to
an existing branch or use 'git checkout origin -b <branch>' to
create a new branch for your work.
[0:02:28]
----------------------------------------
Traceback (most recent call last):
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/gclient.py", line 2523, in <module>
    sys.exit(main(sys.argv[1:]))
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/gclient.py", line 2509, in main
    return dispatcher.execute(OptionParser(), argv)
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/subcommand.py", line 252, in execute
    return command(parser, args[1:])
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/gclient.py", line 2270, in CMDsync
    ret = client.RunOnDeps('update', args)
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/gclient.py", line 1464, in RunOnDeps
    work_queue.flush(revision_overrides, command, args, options=self._options)
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/gclient_utils.py", line 1050, in run
    self.item.run(*self.args, **self.kwargs)
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/gclient.py", line 902, in run
    self.ParseDepsFile()
File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/gclient.py", line 700, in
ParseDepsFile
    gclient_eval.Exec(deps_content, global_scope, local_scope, filepath)
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/gclient_eval.py", line 218, in Exec
    _GCLIENT_SCHEMA.validate(local_scope)
File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/third_party/schema/schema.py", line
254, in validate
    raise SchemaError([k] + x.autos, [e] + x.errors)
third_party.schema.schema.SchemaError: Key 'vars' error:
Key 'checkout_instrumented_libraries' error:
False should be instance of 'basestring'
Running: gclient root
Running: gclient config --spec 'solutions = [
  {
    "url": "https://chromium.googlesource.com/v8/v8.git",
    "managed": False,
    "name": "v8",
    "deps_file": "DEPS",
    "custom_deps": {},
  },
]
'
Running: gclient sync --with_branch_heads
Traceback (most recent call last):
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/fetch.py", line 299, in <module>
    sys.exit(main())
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/fetch.py", line 294, in main
    return run(options, spec, root)
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/fetch.py", line 288, in run
    return checkout.init()
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/fetch.py", line 131, in init
    self.run_gclient(*sync_cmd)
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/fetch.py", line 78, in run_gclient
    return self.run(cmd_prefix + cmd, **kwargs)
  File "/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/vendor/depot_tools/fetch.py", line 68, in run
    return subprocess.check_output(cmd, **kwargs)
  File "/usr/lib/python2.7/subprocess.py", line 573, in check_output
    raise CalledProcessError(retcode, cmd, output=output)
subprocess.CalledProcessError: Command '('gclient', 'sync', '--with_branch_heads')' returned non-zero exit status 1
/home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/ext/libv8/builder.rb:117:in `block in setup_build_deps!':
unable to fetch v8 source (RuntimeError)
        from /home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/ext/libv8/builder.rb:115:in `chdir'
        from /home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/ext/libv8/builder.rb:115:in `setup_build_deps!'
        from /home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/ext/libv8/builder.rb:71:in `build_libv8!'
        from /home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1/ext/libv8/location.rb:24:in `install!'
        from extconf.rb:7:in `<main>'

extconf failed, exit code 1

Gem files will remain installed in /home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/libv8-5.9.211.38.1 for inspection.
Results logged to /home/ruby/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/extensions/x86_64-linux/2.5.0-static/libv8-5.9.211.38.1/gem_make.out

An error occurred while installing libv8 (5.9.211.38.1), and Bundler cannot continue.
Make sure that `gem install libv8 -v '5.9.211.38.1'` succeeds before bundling.

In Gemfile:
  mini_racer was resolved to 0.1.14, which depends on
    libv8

I try gem install libv8 -v '5.9.211.38.1' - all Ok.
But error install gem exists.

Config:
Ruby 2.5.0
Server version: Apache/2.4.10 (Debian)
Linux Debian 8.10

mini_racer_extension.so: ELF file OS ABI invalid

While doing DB migration, it just raises such exception:

-----> Migrating database
       rake aborted!
       LoadError: /app_path/tmp/build-147814187614736/vendor/bundle/ruby/2.3.0/gems/mini_racer-0.1.
7/lib/mini_racer_extension.so: ELF file OS ABI invalid - /app_path/tmp/build-147814187614736/vendor
/bundle/ruby/2.3.0/gems/mini_racer-0.1.7/lib/mini_racer_extension.so

Is it because my OS is too old? Linux 2.6.18-411.el5.centos.plus

Mini_racer equivalent for therubyracer .call() method?

I'm trying to use mini_racer in place of therubyracer for this project, but I'm not sure how to substitute the following logic (see below). There is no .call() method for a mini_racer context function. Is there some sort of equivalency for this functionality or workaround for this?

        # Build lunr based on config
        lunr = context.eval('lunr')
        lunr_conf = proc do |this|

          # Use autogenerated id field as reference
          this.ref('id')

          # Add functions to pipeline (just registering them isn't enough)
          @pipeline.each do |name, function|
            this.pipeline.add(context[name])
          end

          # Define fields with boost
          this.use(lunr_lang) if @language != 'en'
          @fields.each do |field, opts|
            next if opts[:index] == false
            this.field(field, {:boost => opts[:boost]})
          end
        end

        # Get lunr index
        index = lunr.call(lunr_conf)

Above code here

index = lunr.call(lunr_conf) results in the error:
undefined method 'call' for #<MiniRacer::JavaScriptFunction:0x007fc392b4a778>

Different can't build native extension issue

I'm trying to setup Rails on native Windows 10 (since WSL is 10x slower).

Installing mini_racer gem fails with the pasted output, it says it cannot find python 2, although I have it installed and in the PATH (python --version works)

D:\projects\app>gem install mini_racer
Temporarily enhancing PATH to include DevKit...
Building native extensions.  This could take a while...
ERROR:  Error installing mini_racer:
        ERROR: Failed to build gem native extension.

    current directory: C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/libv8-5.3.332.38.5/ext/libv8
C:/Ruby23-x64/bin/ruby.exe -r ./siteconf20170425-12504-za1opv.rb extconf.rb
creating Makefile
The system cannot find the path specified.
The system cannot find the path specified.
The system cannot find the path specified.
C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/libv8-5.3.332.38.5/ext/libv8/builder.rb:84:in `setup_python!': libv8 requires python 2 to be installed in order to build, but it is currently not available (RuntimeError)
        from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/libv8-5.3.332.38.5/ext/libv8/builder.rb:62:in `build_libv8!'
        from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/libv8-5.3.332.38.5/ext/libv8/location.rb:24:in `install!'
        from extconf.rb:7:in `<main>'

extconf failed, exit code 1

Gem files will remain installed in C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/libv8-5.3.332.38.5 for inspection.
Results logged to C:/Ruby23-x64/lib/ruby/gems/2.3.0/extensions/x64-mingw32/2.3.0/libv8-5.3.332.38.5/gem_make.out

If I install libv8 first, then I get different error while installing mini_racer:

Temporarily enhancing PATH to include DevKit...
Building native extensions.  This could take a while...
ERROR:  Error installing mini_racer:
        ERROR: Failed to build gem native extension.

    current directory: C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/mini_racer-0.1.9/ext/mini_racer_extension
C:/Ruby23-x64/bin/ruby.exe -r ./siteconf20170425-11740-43a86w.rb extconf.rb
checking for main() in -lpthread... yes
SETTING CXX
checking for v8.h... no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=C:/Ruby23-x64/bin/$(RUBY_BASE_NAME)
        --with-pthreadlib
        --without-pthreadlib
        --enable-debug
        --disable-debug
        --with-v8-dir
        --without-v8-dir
        --with-v8-include
        --without-v8-include=${v8-dir}/include
        --with-v8-lib
        --without-v8-lib=${v8-dir}/lib
C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/libv8-5.3.332.38.5/ext/libv8/location.rb:57:in `configure': By using --with-system-v8, you have chosen to use the version (Libv8::Location::System::NotFoundError)
of V8 found on your system and *not* the one that is bundled with
the libv8 rubygem.

However, your system version of v8 could not be located.

Please make sure your system version of v8 that is compatible
with 5.3.332.38.5 installed. You may need to use the
--with-v8-dir option if it is installed in a non-standard location
        from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/libv8-5.3.332.38.5/lib/libv8.rb:7:in `configure_makefile'
        from extconf.rb:52:in `<main>'

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  C:/Ruby23-x64/lib/ruby/gems/2.3.0/extensions/x64-mingw32/2.3.0/mini_racer-0.1.9/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/mini_racer-0.1.9 for inspection.
Results logged to C:/Ruby23-x64/lib/ruby/gems/2.3.0/extensions/x64-mingw32/2.3.0/mini_racer-0.1.9/gem_make.out

If I try to install libv8 without the system attribute, then I get the first error again for no python.

Is there a solution?

bundle install error (fatal error: include/v8.h: No such file or directory)

Duh, what dumb thing am I doing?

% bundle install
...
Installing mini_racer 0.1.4 with native extensions

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /home/dm/.rvm/gems/ruby-2.3.0/gems/mini_racer-0.1.4/ext/mini_racer_extension
/home/dm/.rvm/rubies/ruby-2.3.0/bin/ruby -r ./siteconf20160810-16826-25q93g.rb extconf.rb
checking for main() in -lpthread... yes
creating Makefile

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /home/dm/.rvm/gems/ruby-2.3.0/extensions/x86_64-linux/2.3.0/mini_racer-0.1.4/mkmf.log

current directory: /home/dm/.rvm/gems/ruby-2.3.0/gems/mini_racer-0.1.4/ext/mini_racer_extension
make "DESTDIR=" clean

current directory: /home/dm/.rvm/gems/ruby-2.3.0/gems/mini_racer-0.1.4/ext/mini_racer_extension
make "DESTDIR="
compiling mini_racer_extension.cc
mini_racer_extension.cc:4:24: fatal error: include/v8.h: No such file or directory
compilation terminated.
Makefile:206: recipe for target 'mini_racer_extension.o' failed
make: *** [mini_racer_extension.o] Error 1

make failed, exit code 2

Gem files will remain installed in /home/dm/.rvm/gems/ruby-2.3.0/gems/mini_racer-0.1.4 for inspection.
Results logged to /home/dm/.rvm/gems/ruby-2.3.0/extensions/x86_64-linux/2.3.0/mini_racer-0.1.4/gem_make.out

clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
Target: x86_64-pc-linux-gnu
Thread model: posix

gcc (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609

/home/dm/.rvm/gems/ruby-2.3.0/extensions/x86_64-linux/2.3.0/mini_racer-0.1.4/mkmf.log looks like:

have_library: checking for main() in -lpthread... -------------------- yes

"gcc -o conftest -I/home/dm/.rvm/rubies/ruby-2.3.0/include/ruby-2.3.0/x86_64-linux -I/home/dm/.rvm/rubies/ruby-2.3.0/include/ruby-2.3.0/ruby/backward -I/home/dm/.rvm/rubies/ruby-2.3.0/include/ruby-2.3.0 -I.     -O3 -fno-fast-math -ggdb3 -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wimplicit-function-declaration -Wdeprecated-declarations -Wno-packed-bitfield-compat -Wno-maybe-uninitialized  -fPIC conftest.c  -L. -L/home/dm/.rvm/rubies/ruby-2.3.0/lib -Wl,-R/home/dm/.rvm/rubies/ruby-2.3.0/lib -L. -fstack-protector -rdynamic -Wl,-export-dynamic     -Wl,-R/home/dm/.rvm/rubies/ruby-2.3.0/lib -L/home/dm/.rvm/rubies/ruby-2.3.0/lib -lruby  -lpthread -lgmp -ldl -lcrypt -lm   -lc"
checked program was:
/* begin */
1: #include "ruby.h"
2: 
3: int main(int argc, char **argv)
4: {
5:   return 0;
6: }
/* end */

"gcc -o conftest -I/home/dm/.rvm/rubies/ruby-2.3.0/include/ruby-2.3.0/x86_64-linux -I/home/dm/.rvm/rubies/ruby-2.3.0/include/ruby-2.3.0/ruby/backward -I/home/dm/.rvm/rubies/ruby-2.3.0/include/ruby-2.3.0 -I.     -O3 -fno-fast-math -ggdb3 -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wimplicit-function-declaration -Wdeprecated-declarations -Wno-packed-bitfield-compat -Wno-maybe-uninitialized  -fPIC conftest.c  -L. -L/home/dm/.rvm/rubies/ruby-2.3.0/lib -Wl,-R/home/dm/.rvm/rubies/ruby-2.3.0/lib -L. -fstack-protector -rdynamic -Wl,-export-dynamic     -Wl,-R/home/dm/.rvm/rubies/ruby-2.3.0/lib -L/home/dm/.rvm/rubies/ruby-2.3.0/lib -lruby -lpthread  -lpthread -lgmp -ldl -lcrypt -lm   -lc"
checked program was:
/* begin */
 1: #include "ruby.h"
 2: 
 3: /*top*/
 4: extern int t(void);
 5: int main(int argc, char **argv)
 6: {
 7:   if (argc > 1000000) {
 8:     printf("%p", &t);
 9:   }
10: 
11:   return 0;
12: }
13: int t(void) { void ((*volatile p)()); p = (void ((*)()))main; return !p; }
/* end */

--------------------

Gemfile:

source 'https://rubygems.org'
source 'https://rails-assets.org' do
  gem 'rails-assets-angucomplete-alt'
end

gem 'angularjs-rails', '~> 1.4', '>= 1.4.7'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.3'


gem 'pg'


# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.1.0'

# See https://github.com/rails/execjs#readme for more supported runtimes
# gem 'therubyracer'
gem 'mini_racer'

# Use jquery as the JavaScript library
gem 'jquery-rails'
gem 'jquery-ui-rails'

# Turbolinks is more hassle than it's worth right now
# gem 'turbolinks'
# this fixed some turbolinks bugs, but didn't play with angular
# gem 'jquery-turbolinks'

# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0', group: :doc

# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

group :development do
  gem 'pry'
  gem 'pry-doc'
end

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug'

  # Access an IRB console on exception pages or by using <%= console %> in views
  gem 'web-console', '~> 2.0'

  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'


  gem 'rspec-rails'

end

group :test do
  gem 'capybara'
  gem 'poltergeist'
  gem 'phantomjs', require: 'phantomjs/poltergeist'
  gem 'database_cleaner'
  gem 'factory_girl_rails'

end


# Helpers for Twitter Bootstrap
gem 'bootstrap-sass', '~> 3.3.5'
gem 'sprockets-rails', '~> 2.3.2'

gem 'devise'

gem 'redcarpet'

Can't install on Travis

I'm experimenting with switching from therubyracer to mini_racer.
It works locally on OS X, but it fails on Travis (MRI 2.2):

Installing mini_racer 0.1.3 with native extensions

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    /home/travis/.rvm/rubies/ruby-2.2.3/bin/ruby -r ./siteconf20160524-6880-z39ic2.rb extconf.rb
checking for main() in -lpthread... yes
creating Makefile

make "DESTDIR=" clean

make "DESTDIR="
compiling mini_racer_extension.cc
In file included from mini_racer_extension.cc:4:0:
/home/travis/build/---/---/vendor/bundle/ruby/2.2.0/gems/libv8-5.0.71.48.3-x86_64-linux/vendor/v8/include/v8.h:341:1: error: expected unqualified-id before ‘using’
/home/travis/build/---/---/vendor/bundle/ruby/2.2.0/gems/libv8-5.0.71.48.3-x86_64-linux/vendor/v8/include/v8.h:477:1: error: expected unqualified-id before ‘using’
/home/travis/build/---/---/vendor/bundle/ruby/2.2.0/gems/libv8-5.0.71.48.3-x86_64-linux/vendor/v8/include/v8.h:871:1: error: expected unqualified-id before ‘using’
mini_racer_extension.cc:136:51: error: ‘Handle’ has not been declared
mini_racer_extension.cc:136:57: error: expected ‘,’ or ‘...’ before ‘<’ token
mini_racer_extension.cc: In function ‘VALUE convert_v8_to_ruby(v8::Isolate*, int)’:
mini_racer_extension.cc:140:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:144:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:148:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:152:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:156:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:160:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:165:55: error: cannot convert ‘v8::Local<v8::Value>’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate*, int)’
mini_racer_extension.cc:171:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:175:9: error: ‘value’ was not declared in this scope
mini_racer_extension.cc:184:53: error: cannot convert ‘v8::Local<v8::Value>’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate*, int)’
mini_racer_extension.cc:186:57: error: cannot convert ‘v8::Local<v8::Value>’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate*, int)’
mini_racer_extension.cc:193:26: error: ‘value’ was not declared in this scope
mini_racer_extension.cc: At global scope:
mini_racer_extension.cc:197:8: error: ‘Handle’ does not name a type
mini_racer_extension.cc: In function ‘VALUE rb_context_eval_unsafe(VALUE, VALUE)’:
mini_racer_extension.cc:299:61: error: cannot convert ‘v8::Local<v8::Value>’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate*, int)’
mini_racer_extension.cc:306:63: error: cannot convert ‘v8::Local<v8::Value>’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate*, int)’
mini_racer_extension.cc:348:56: error: cannot convert ‘v8::Local<v8::Value>’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate*, int)’
mini_racer_extension.cc: In function ‘void* gvl_ruby_callback(void*)’:
mini_racer_extension.cc:396:2: error: ‘Handle’ was not declared in this scope
mini_racer_extension.cc:396:17: error: expected primary-expression before ‘>’ token
mini_racer_extension.cc:396:19: error: ‘external’ was not declared in this scope
mini_racer_extension.cc:396:45: error: expected primary-expression before ‘>’ token
mini_racer_extension.cc:396:46: error: ‘::Cast’ has not been declared
mini_racer_extension.cc:409:65: error: cannot convert ‘v8::Local<v8::Value>’ to ‘int’ for argument ‘2’ to ‘VALUE convert_v8_to_ruby(v8::Isolate*, int)’
mini_racer_extension.cc:430:2: error: ‘Handle’ was not declared in this scope
mini_racer_extension.cc:430:14: error: expected primary-expression before ‘>’ token
mini_racer_extension.cc:430:16: error: ‘v8_result’ was not declared in this scope
mini_racer_extension.cc:430:73: error: ‘convert_ruby_to_v8’ was not declared in this scope
make: *** [mini_racer_extension.o] Error 1

make failed, exit code 2

Gem files will remain installed in /home/travis/build/---/---/vendor/bundle/ruby/2.2.0/gems/mini_racer-0.1.3 for inspection.
Results logged to /home/travis/build/---/---/vendor/bundle/ruby/2.2.0/extensions/x86_64-linux/2.2.0/mini_racer-0.1.3/gem_make.out
An error occurred while installing mini_racer (0.1.3), and Bundler cannot continue.

Make sure that `gem install mini_racer -v '0.1.3'` succeeds before bundling.

Is there any specific configuration I should add?

Most common segfault

Here's the top of the stack. It happens at 0x18 or 0x30. Line 41 is accessing a variable that has been marshalled from JS (collection_name):
41: if collection_name.is_a?(MiniRacer::FailedV8Conversion)

app/models/database_connection.rb:41: [BUG] Segmentation fault at 0x00000000000018
ruby 2.2.4p230 (2015-12-16 revision 53155) [x86_64-linux]

-- Control frame information -----------------------------------------------
c:0127 p:0017 s:0529 e:000526 METHOD  app/models/database_connection.rb:41
c:0126 p:0070 s:0523 e:000522 METHOD  app/models/database_connection.rb:55
c:0125 p:0017 s:0518 e:000517 BLOCK  app/models/database_connection.rb:14 [FINISH]
c:0124 p:---- s:0514 e:000513 CFUNC  :call
c:0123 p:---- s:0512 e:000511 CFUNC  :eval_unsafe
c:0122 p:0015 s:0508 e:000507 BLOCK  bundle/ruby/2.2.0/bundler/gems/mini_racer-bcb3027e8f79/lib/mini_racer.rb:162
c:0121 p:0006 s:0506 e:000505 BLOCK  bundle/ruby/2.2.0/bundler/gems/mini_racer-bcb3027e8f79/lib/mini_racer.rb:63 [FINISH]
c:0120 p:---- s:0504 e:000503 CFUNC  :synchronize
c:0119 p:0009 s:0501 e:000500 METHOD bundle/ruby/2.2.0/bundler/gems/mini_racer-bcb3027e8f79/lib/mini_racer.rb:63
c:0118 p:0009 s:0498 e:000497 METHOD bundle/ruby/2.2.0/bundler/gems/mini_racer-bcb3027e8f79/lib/mini_racer.rb:160

Found this article, which looks like a similar issue:
http://blog.packagecloud.io/eng/2014/11/17/debugging-ruby-gem-segfault/

Going to try for a repro in mini_racer using GC.start with a simpler case. Any thoughts in the interim?

Detect unhandled promise rejections

When working with promises, one important aspect of them is that an unhandled rejected promise is an error. However, V8 will drop notifications by default.

I think that mini_racer should consider this an error and raise an exception, though possibly it should be configurable how these are handled (e.g. via a callback where the user can decide to re-raise?).

To do so, it's necessary to register for unhandled promise rejections via SetPromiseRejectCallback.

The callback will receive a PromiseRejectMessage that should probably (by default) raise a exception in ruby, although I suppose it could be configurable.


Comparisons for reference:

Running this code:

var x = async () => { throw "failure"; };
var y = async () => { x() /* ignore the rejected result */ }; 
y().then(() => console.log("done")).catch(e => console.log(e));

In node:

> var x = async () => { throw "failure"; }; var y = async () => { x() /* ignore the rejected result */ }; y().then(() => console.log("done")).catch(e => console.log(e));
Promise {
  <pending>,
  domain:
   Domain {
     domain: null,
     _events:
      { removeListener: [Function: updateExceptionCapture],
        newListener: [Function: updateExceptionCapture],
        error: [Function: debugDomainError] },
     _eventsCount: 3,
     _maxListeners: undefined,
     members: [] } }
> done
(node:83056) UnhandledPromiseRejectionWarning: failure
(node:83056) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 3)

In chrome:

var x = async () => { throw "failure"; }; var y = async () => { x() /* ignore the rejected result */ }; y().then(() => console.log("done")).catch(e => console.log(e));
VM131:1 done
Promise {<resolved>: undefined}
VM131:1 Uncaught (in promise) failure

In mini_racer:

irb(main):001:0> require 'mini_racer'
=> true
irb(main):002:0> vm = MiniRacer::Context.new
=> #<MiniRacer::Context:0x00007ff4350f1438 @functions={}, @timeout=nil, @max_memory=nil, @current_exception=nil, @isolate=#<MiniRacer::Isolate:0x00007ff4350f12f8 @lock=#<Thread::Mutex:0x00007ff4350f12a8>>, @disposed=false, @callback_mutex=#<Thread::Mutex:0x00007ff4350f1280>, @callback_running=false, @thread_raise_called=false, @eval_thread=nil>
irb(main):003:0> vm.attach('console.log', proc{ |*args| puts('LOG> ' + args.map(&:to_s).join(' ')) })
=> #<MiniRacer::Context::ExternalFunction:0x00007ff43602b1b0 @name="log", @callback=#<Proc:0x00007ff43602b200@/usr/local/lib/ruby/gems/2.5.0/gems/mini_racer-0.1.15/lib/mini_racer.rb:201 (lambda)>, @parent=#<MiniRacer::Context:0x00007ff4350f1438 @functions={"console.log"=>#<MiniRacer::Context::ExternalFunction:0x00007ff43602b1b0 ...>}, @timeout=nil, @max_memory=nil, @current_exception=nil, @isolate=#<MiniRacer::Isolate:0x00007ff4350f12f8 @lock=#<Thread::Mutex:0x00007ff4350f12a8>>, @disposed=false, @callback_mutex=#<Thread::Mutex:0x00007ff4350f1280>, @callback_running=false, @thread_raise_called=false, @eval_thread=nil>, @parent_object_eval="if (typeof console === 'undefined') { console = {} };\nconsole;", @parent_object="console">
irb(main):004:0> vm.eval('var x = async () => { throw "failure"; }; var y = async () => { x() /* ignore the rejected result */ }; y().then(() => console.log("done")).catch(e => console.log(e));')
LOG> done
=> {}
irb(main):005:0>

Better Error Backtraces

(only slightly related to #58).

I was wondering, if there is a way to load JavaScript files, instead of evaluating them by passing a string. Or to give some source/context name to V8.

At the current case I'm working on, there is some base code, that is always loaded. Then some semi-user input is evaluated on top of that code. I'm having a hard time to filter and massage error back traces so that they are meaningful to my users.

Is there a way to provide some names for sources or contexts, so that unknown source and <anonymous> are more helpful?

ReferenceError: meh is not defined
    at bar (eval at execute (unknown source), <anonymous>:4:3)
    at eval (eval at execute (unknown source), <anonymous>:7:1)
    at Function.execute (<anonymous>:24:5)
    at eval_wrapper (<anonymous>:2:31)
    at <anonymous>:1:1

Alpine linux - symbol not found while launch

Gem was installed, but when rails is launching I get the error:

LoadError: Error relocating /usr/local/bundle/gems/mini_racer-0.1.12/lib/mini_racer_extension.so: __fprintf_chk: symbol not found - /usr/local/bundle/gems/mini_racer-0.1.12/lib/mini_racer_extension.so
/usr/local/bundle/gems/mini_racer-0.1.12/lib/mini_racer.rb:2:in `require'
/usr/local/bundle/gems/mini_racer-0.1.12/lib/mini_racer.rb:2:in `<top (required)>'
....

Context#eval not synchronous

We're loading a big JS runtime into a mini_racer context via Context.eval(File.load('renderer.js')) (which defines Renderer in the current scope), then immediately after we .eval('Renderer.default({ some: 'big object' }). We cache the Context in a singleton to avoid parsing the renderer.js more often that necessary.

During tests, the first method to our Context singleton occasionally fails on the second .eval call with a MiniRacer/V8 error: Renderer is not defined. Subsequent calls (which re-use the Context, skipping the .eval(File.load()) dance) succeed. It seems like the Renderer is not available immediately after its #eval call returns.

Is this expected behaviour? Currently our workaround is to call (typeof Renderer !== 'undefined') until it's true, then proceed with calls against our Renderer.

Meaningful errors with inlined sourcemaps

Hi

I'm using webpack to compile a server side js bundle with inlined sourcemaps, used to render server side views. Everything's going well except errors. The stack trace given back is reasonable, eg:

ExecJS::ProgramError - ReferenceError: func is not defined:
  Widget.vtree (eval at <anonymous> ((execjs):357:in `'
  Widget.render (eval at <anonymous> ((execjs):391:in `'
  Object.render (eval at <anonymous> ((execjs):1379:in `'

This error is okay, i can follow it from the entry point but I don't get a strong gauge on which line in which file, which would be available in chrome, for example.

Is there a way to do that, to get more specific information about which line and which file is causing the exception?

Error parsing Javascript

Since it's parsing a line that's several megabytes, I can't narrow down the specific area causing the problem. Here's the stack:

Caused by:
MiniRacer::RuntimeError: Error
JavaScript at new JS_Parse_Error (<anonymous>:3572:11870)
JavaScript at js_error (<anonymous>:3572:12089)
JavaScript at croak (<anonymous>:3572:20898)
JavaScript at token_error (<anonymous>:3572:21035)
JavaScript at unexpected (<anonymous>:3572:21123)
JavaScript at semicolon (<anonymous>:3572:21615)
JavaScript at simple_statement (<anonymous>:3572:24478)
JavaScript at <anonymous>:3572:22447
JavaScript at <anonymous>:3572:21788
JavaScript at block_ (<anonymous>:3572:26497)

Need a way to prevent timeouts from halting execution in specific regions

This is a pretty specific use-case, but I need a way to make certain sets of operations 'atomic' -- that is to say, I need them to not be terminated by execution timer until after they are completed.
I would probably use attached procs to control on/off. Currently, I'd need to rescue the termination exception and undo/replay things, which is a mess.
Any ideas on how to implement this in mini_racer (or outside)?

mini_racer_extension.so: undefined symbol: _ZNKSt8__detail20_Prime_rehash_policy11_M_next_bktEm

When running MiniRacer::Context.new I get the following error:

ruby: symbol lookup error: /usr/local/lib/ruby/gems/2.3.0/gems/mini_racer-0.1.6/lib/mini_racer_extension.so: undefined symbol: _ZNKSt8__detail20_Prime_rehash_policy11_M_next_bktEm

I'm using ruby 2.3.1 and bundler within a Docker container running debian:wheezy on an Ubuntu 16.04 Docker host and an Arch Linux Docker host. Natively on Arch it works.

uname -a
Linux lfm-docker-8 4.4.0-45-generic #66-Ubuntu SMP Wed Oct 19 14:12:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
ruby -v
ruby 2.3.1p112 (2016-04-26) [x86_64-linux-gnu]

It happens with mini_racer 0.1.6 and 0.1.7.

Could not find libv8-5.0.71.48.3 in any of the sources

Hello, I'm having a problem installing this gem with bundler. It fails when resolving dependencies, with the error: Could not find libv8-5.0.71.48.3 in any of the sources

I'm not sure if this is an issue with mini_racer or with libv8 versions on rubygems, so can report there if you'd prefer?

Thanks!

GVL lock issue with recursive attached proc calls

rb_thread_call_with_gvl: called by a thread which has GVL

Here's a test case:

  def test_attached_recursion
    context = MiniRacer::Context.new(timeout: 20)
    context.attach("a", proc{|a| a})
    context.attach("b", proc{|a| a})

    context.eval('const obj = {get r(){ b() }}; a(obj);')
  end

Ideally this would be some sort of exception instead of a c-level crash. What do you think @SamSaffron?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.