Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to V8 12.9 #342

Merged
merged 2 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 1 addition & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,19 +97,6 @@ context.eval("var a = new Array(10000); while(true) {a = a.concat(new Array(1000
# => 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.

```ruby
# 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:
Expand Down Expand Up @@ -208,25 +195,7 @@ context.eval("counter")

### Garbage collection

Re-using the same context 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 context 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:

```ruby
context = MiniRacer::Context.new

# do stuff with that context...

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

# force V8 to perform a full GC
context.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`](http://bespin.cz/~ondras/html/classv8_1_1Isolate.html#aea16cbb2e351de9a3ae7be2b7cb48297), 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::Context.new(ensure_gc_after_idle: 1000)`. Using this will ensure V8 will run a full GC using `context.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 contexts use minimal amounts of memory.
You can make the garbage collector more aggressive by defining the context with `MiniRacer::Context.new(ensure_gc_after_idle: 1000)`. Using this will ensure V8 will run a full GC using `context.low_memory_notification` 1 second after the last eval on the context. Low memory notifications ensure long living contexts use minimal amounts of memory.

### V8 Runtime flags

Expand Down
24 changes: 1 addition & 23 deletions ext/mini_racer_extension/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
$CXXFLAGS += " -g" unless $CXXFLAGS.split.include? "-g"
$CXXFLAGS += " -rdynamic" unless $CXXFLAGS.split.include? "-rdynamic"
$CXXFLAGS += " -fPIC" unless $CXXFLAGS.split.include? "-rdynamic" or IS_DARWIN
$CXXFLAGS += " -std=c++17"
$CXXFLAGS += " -std=c++20"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to update the README for compiler requirements too? https://github.com/rubyjs/mini_racer?tab=readme-ov-file#installation

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, those are way out of date. Updated with the compiler recommendations from node's BUILDING.md

$CXXFLAGS += " -fpermissive"
$CXXFLAGS += " -fno-rtti"
$CXXFLAGS += " -fno-exceptions"
Expand Down Expand Up @@ -47,28 +47,6 @@
CONFIG['CXX'] = ENV['CXX']
end

CXX11_TEST = <<EOS
#if __cplusplus <= 199711L
# error A compiler that supports at least C++11 is required in order to compile this project.
#endif
EOS

`echo "#{CXX11_TEST}" | #{CONFIG['CXX']} -std=c++0x -x c++ -E -`
unless $?.success?
warn <<EOS


WARNING: C++11 support is required for compiling mini_racer. Please make sure
you are using a compiler that supports at least C++11. Examples of such
compilers are GCC 4.7+ and Clang 3.2+.

If you are using Travis, consider either migrating your build to Ubuntu Trusty or
installing GCC 4.8. See mini_racer's README.md for more information.


EOS
end

CONFIG['LDSHARED'] = '$(CXX) -shared' unless IS_DARWIN
if CONFIG['warnflags']
CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '')
Expand Down
16 changes: 0 additions & 16 deletions ext/mini_racer_extension/mini_racer_extension.c
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,6 @@ static void dispatch1(Context *c, const uint8_t *p, size_t n)
case 'C': return v8_timedwait(c, p+1, n-1, v8_call);
case 'E': return v8_timedwait(c, p+1, n-1, v8_eval);
case 'H': return v8_heap_snapshot(c->pst);
case 'I': return v8_idle_notification(c->pst, p+1, n-1);
case 'P': return v8_pump_message_loop(c->pst);
case 'S': return v8_heap_stats(c->pst);
case 'T': return v8_snapshot(c->pst, p+1, n-1);
Expand Down Expand Up @@ -1301,20 +1300,6 @@ static VALUE context_pump_message_loop(VALUE self)
return rendezvous(c, &b); // takes ownership of |b|
}

static VALUE context_idle_notification(VALUE self, VALUE arg)
{
Context *c;
Ser s;

Check_Type(arg, T_FIXNUM);
TypedData_Get_Struct(self, Context, &context_type, c);
// request is (I)dle notification, idle_time_in_seconds
ser_init1(&s, 'I');
ser_num(&s, LONG2FIX(arg) / 1e3);
// response is |undefined|
return rendezvous(c, &s.b); // takes ownership of |s.b|
}

static VALUE context_low_memory_notification(VALUE self)
{
Buf req, res;
Expand Down Expand Up @@ -1638,7 +1623,6 @@ void Init_mini_racer_extension(void)
rb_define_method(c, "heap_stats", context_heap_stats, 0);
rb_define_method(c, "heap_snapshot", context_heap_snapshot, 0);
rb_define_method(c, "pump_message_loop", context_pump_message_loop, 0);
rb_define_method(c, "idle_notification", context_idle_notification, 1);
rb_define_method(c, "low_memory_notification", context_low_memory_notification, 0);
rb_define_alloc_func(c, context_alloc);

Expand Down
20 changes: 0 additions & 20 deletions ext/mini_racer_extension/mini_racer_v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -834,26 +834,6 @@ extern "C" void v8_warmup(State *pst, const uint8_t *p, size_t n)
}
}

extern "C" void v8_idle_notification(State *pst, const uint8_t *p, size_t n)
{
State& st = *pst;
v8::TryCatch try_catch(st.isolate);
v8::HandleScope handle_scope(st.isolate);
v8::ValueDeserializer des(st.isolate, p, n);
des.ReadHeader(st.context).Check();
double idle_time_in_seconds = .01;
{
v8::Local<v8::Value> idle_time_in_seconds_v;
if (!des.ReadValue(st.context).ToLocal(&idle_time_in_seconds_v)) goto fail;
if (!idle_time_in_seconds_v->NumberValue(st.context).To(&idle_time_in_seconds)) goto fail;
}
fail:
double now = platform->MonotonicallyIncreasingTime();
bool stop = st.isolate->IdleNotificationDeadline(now + idle_time_in_seconds);
auto result = v8::Boolean::New(st.isolate, stop);
if (!reply(st, result)) abort();
}

extern "C" void v8_low_memory_notification(State *pst)
{
pst->isolate->LowMemoryNotification();
Expand Down
1 change: 0 additions & 1 deletion ext/mini_racer_extension/mini_racer_v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ void v8_heap_snapshot(struct State *pst);
void v8_pump_message_loop(struct State *pst);
void v8_snapshot(struct State *pst, const uint8_t *p, size_t n);
void v8_warmup(struct State *pst, const uint8_t *p, size_t n);
void v8_idle_notification(struct State *pst, const uint8_t *p, size_t n);
void v8_low_memory_notification(struct State *pst);
void v8_terminate_execution(struct State *pst); // called from ruby or watchdog thread
void v8_single_threaded_enter(struct State *pst, struct Context *c, void (*f)(struct Context *c));
Expand Down
4 changes: 0 additions & 4 deletions lib/mini_racer/truffleruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,6 @@ def low_memory_notification
GC.start
end

def idle_notification(idle_time)
true
end

private

@context_initialized = false
Expand Down
4 changes: 2 additions & 2 deletions lib/mini_racer/version.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

module MiniRacer
VERSION = "0.17.0.pre13"
LIBV8_NODE_VERSION = "~> 22.7.0.4"
VERSION = "0.18.0.pre1"
LIBV8_NODE_VERSION = "~> 23.6.1.0"
end
7 changes: 0 additions & 7 deletions test/mini_racer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -594,13 +594,6 @@ def test_isolates_from_snapshot_dont_get_corrupted_if_the_snapshot_gets_warmed_u
assert_equal "function", context2.eval("typeof(Math.sin)")
end

def test_isolate_can_be_notified_of_idle_time
context = MiniRacer::Context.new

# returns true if embedder should stop calling
assert(context.idle_notification(1000))
end

def test_platform_set_flags_raises_an_exception_if_already_initialized
# makes sure it's initialized
MiniRacer::Snapshot.new
Expand Down
Loading