Skip to content

Commit

Permalink
Update to V8 12.9 (#342)
Browse files Browse the repository at this point in the history
* Update to V8 12.9

Removes context.idle_notification because the V8 API it uses has been
removed with no real replacement.

V8 suggests to use Isolate::MemoryPressureNotification() instead
but that's not really the same thing and overlaps significantly
with context.low_memory_notification.

Remove the stale object marshalling section from the README.

* squash! update compiler req
  • Loading branch information
bnoordhuis authored Feb 6, 2025
1 parent edaa9e8 commit 69b8f17
Show file tree
Hide file tree
Showing 8 changed files with 6 additions and 106 deletions.
36 changes: 3 additions & 33 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 Expand Up @@ -395,7 +364,8 @@ Or install it yourself as:
$ 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).
**Note** using v8.h and compiling MiniRacer requires a C++20 capable compiler.
gcc >= 12.2 and Xcode >= 13 are, at the time of writing, known to work.

## Similar Projects

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"
$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

0 comments on commit 69b8f17

Please sign in to comment.