rubyjs / mini_racer

Minimal embedded v8
MIT License
585 stars 91 forks source link

Context has no Isolate available anymore #269

Closed mathieujobin closed 1 year ago

mathieujobin commented 1 year ago

I am upgrading a project that was using V8::Context#load directly with therubyracer. I am trying to replace it with MiniRacer::Context

getting this error

      MiniRacer::RuntimeError:
        Context has no Isolate available anymore
      # ./vendor/bundle/ruby/2.7.0/gems/mini_racer-0.6.3/lib/mini_racer.rb:225:in `isolate_mutex'
      # ./vendor/bundle/ruby/2.7.0/gems/mini_racer-0.6.3/lib/mini_racer.rb:225:in `eval'
      # ./lib/lib_dsl/value/custom_function.rb:27:in `block in <class:CustomFunction>'

with this code

      set_callback :initialize, :after do
        @function_ref = js_context.eval("(#{body})")
      end

I'm not too sure what it means? it crashes here

https://github.com/rubyjs/mini_racer/blob/719abdb1a4881d65831830e6e6fb5ca1bcedbc1e/lib/mini_racer.rb#L225

tisba commented 1 year ago

Hey @mathieujobin. Could you provide a bit more context? Ideally something that is reproducible. With just this three lines of code you provided, it's difficult to help.

mathieujobin commented 1 year ago

Right, thank you for getting back to me... I don't master the code base yet.

We are creating the context in such a way, ...

v8_context ||= MiniRacer::Context.new.tap do |context|
  context.load(LibDSL.root.join("vendor/underscore.js"))
end

it used to be V8::Context from TheRubyRacer.

This is kept in a class instance var, which we .dup for each instance. It used to work fine, but for some reason, I get the above-mentioned error.

I found out I can skip that error by creating a fresh object for each instance. It's unclear why it makes a difference, .dup should start fresh as well for each instance. It is a micro-optimization I can live without.

This moves me to the next problem I have, migrating to mini_racer. Which isn't exactly related to the previous error. But I'll continue here instead of creating a separate issue for now.

It appears TheRubyRacer's V8::Context had the ability to store attributes via a []= method.

I could do

V8:Context.new['rocket'] = 'science'

MiniRacer does not appear to have it, don't think its a big deal, I can store it elsewhere. but if that rings a bell. Feel free to comment.

Next, I do

js_function_ref = V8::Context.new.eval("(function(a,b,c) { return a + '-' + b + '-' + c; })")

which appears to work fine, it returns me a MiniRacer::JavaScriptFunction object. but I cannot call the function, with TheRubyRacer I could do...

js_function_ref.call(*_args)

now I get

undefined method `call' for #<MiniRacer::JavaScriptFunction:0x000055aca580eb00>

any idea what can I do about this one ?

Thanks

mathieujobin commented 1 year ago

Looks like I found the solution to my last problem... reading #224 I realize I now need to make the call to the context, but my functions don't have names as shown... so I am creating anonymous names... such like this.

      set_callback :initialize, :after do
        @fn_name = "custom_#{SecureRandom.hex(5)}"
        @function_ref = js_context.eval("#{@fn_name} = (#{body})")
      end

then I am able to make calls like this

      def call(environment, args)
        initialize_js_context(environment)
        js_context.call(@fn_name, *args)
      end

very happy ! Thank you