Add binding for v8__internal__GetIsolateFromHeapObject() (#348)

This commit is contained in:
Bert Belder 2020-04-13 02:18:05 +02:00
parent 2b08fd1651
commit 675d585977
No known key found for this signature in database
GPG Key ID: 7A77887B2E2ED461
4 changed files with 120 additions and 0 deletions

View File

@ -24,6 +24,13 @@ config("rusty_v8_config") {
configs = [ "//v8:external_config" ]
cflags = []
# We need these directories in the search path to be able to include some
# internal V8 headers.
include_dirs = [
"v8",
"$target_gen_dir/v8",
]
if (is_debug) {
defines = [ "DEBUG" ]
}

View File

@ -8,6 +8,9 @@
#include "v8/include/v8-platform.h"
#include "v8/include/v8-profiler.h"
#include "v8/include/v8.h"
#include "v8/src/execution/isolate-utils-inl.h"
#include "v8/src/execution/isolate-utils.h"
#include "v8/src/objects/maybe-object.h"
using namespace support;
@ -1652,4 +1655,28 @@ void v8__HeapProfiler__TakeHeapSnapshot(v8::Isolate* isolate,
const_cast<v8::HeapSnapshot*>(snapshot)->Delete();
}
// This is necessary for v8__internal__GetIsolateFromHeapObject() to be
// reliable enough for our purposes.
#if !(defined V8_SHARED_RO_HEAP or defined V8_COMPRESS_POINTERS)
#error V8 must be built with either the 'v8_enable_pointer_compression' or \
'v8_enable_shared_ro_heap' feature enabled.
#endif
v8::Isolate* v8__internal__GetIsolateFromHeapObject(const v8::Data* location) {
if (location == nullptr) {
return nullptr;
}
auto address = *reinterpret_cast<const v8::internal::Address*>(location);
auto maybe_object = v8::internal::MaybeObject(address);
if (maybe_object.IsSmi() || maybe_object.IsCleared()) {
return nullptr;
}
auto heap_object = maybe_object.GetHeapObject();
v8::internal::Isolate* isolate;
if (!v8::internal::GetIsolateFromHeapObject(heap_object, &isolate)) {
return nullptr;
}
return reinterpret_cast<v8::Isolate*>(isolate);
}
} // extern "C"

View File

@ -99,6 +99,7 @@ impl Error for TryFromTypeError {}
#[repr(C)]
pub struct Context(Opaque);
impl_deref! { Data for Context }
impl_eq! { for Context }
impl_partial_eq! { Context for Context use identity }
@ -107,6 +108,7 @@ impl_partial_eq! { Context for Context use identity }
pub struct Data(Opaque);
impl_from! { AccessorSignature for Data }
impl_from! { Context for Data }
impl_from! { Module for Data }
impl_from! { Private for Data }
impl_from! { Signature for Data }

View File

@ -4,6 +4,7 @@
extern crate lazy_static;
use std::convert::{Into, TryFrom, TryInto};
use std::ptr::NonNull;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
@ -287,6 +288,89 @@ fn microtasks() {
}
}
#[test]
fn get_isolate_from_handle() {
extern "C" {
fn v8__internal__GetIsolateFromHeapObject(
handle: *const v8::Data,
) -> *mut v8::Isolate;
}
fn check_handle_helper(
isolate_ptr: NonNull<v8::Isolate>,
expect_some: Option<bool>,
local: v8::Local<v8::Data>,
) {
let maybe_ptr = unsafe { v8__internal__GetIsolateFromHeapObject(&*local) };
let maybe_ptr = NonNull::new(maybe_ptr);
if let Some(ptr) = maybe_ptr {
assert_eq!(ptr, isolate_ptr);
}
if let Some(expected_some) = expect_some {
assert_eq!(maybe_ptr.is_some(), expected_some);
}
};
fn check_handle<'s, S, F, D>(scope: &mut S, expect_some: Option<bool>, f: F)
where
S: v8::ToLocal<'s>,
F: Fn(&mut S) -> D,
D: Into<v8::Local<'s, v8::Data>>,
{
let isolate_ptr = NonNull::from(scope.isolate());
let local = f(scope).into();
// Check that we can get the isolate from a Local.
check_handle_helper(isolate_ptr, expect_some, local);
// Check that we can still get it after converting it to a Global and back.
let global = v8::Global::new_from(scope, local);
let local = global.get(scope).unwrap();
check_handle_helper(isolate_ptr, expect_some, local);
};
fn check_eval<'s, S>(scope: &mut S, expect_some: Option<bool>, code: &str)
where
S: v8::ToLocal<'s>,
{
let context = scope.get_current_context().unwrap();
check_handle(scope, expect_some, |scope| {
eval(scope, context, code).unwrap()
});
}
let _setup_guard = setup();
let mut params = v8::Isolate::create_params();
params.set_array_buffer_allocator(v8::new_default_allocator());
let mut isolate = v8::Isolate::new(params);
let mut hs = v8::HandleScope::new(&mut isolate);
let scope = hs.enter();
let context = v8::Context::new(scope);
let mut cs = v8::ContextScope::new(scope, context);
let s = cs.enter();
check_handle(s, None, |s| v8::null(s));
check_handle(s, None, |s| v8::undefined(s));
check_handle(s, None, |s| v8::Boolean::new(s, true));
check_handle(s, None, |s| v8::Boolean::new(s, false));
check_handle(s, None, |s| v8::String::new(s, "").unwrap());
check_eval(s, None, "''");
check_handle(s, Some(true), |s| v8::String::new(s, "Words").unwrap());
check_eval(s, Some(true), "'Hello'");
check_eval(s, Some(true), "Symbol()");
check_handle(s, Some(true), |s| v8::Object::new(s));
check_eval(s, Some(true), "this");
check_handle(s, Some(true), |s| s.get_current_context().unwrap());
check_eval(s, Some(true), "({ foo: 'bar' })");
check_eval(s, Some(true), "() => {}");
check_handle(s, Some(true), |s| v8::Number::new(s, 4.2f64));
check_handle(s, Some(true), |s| v8::Number::new(s, -0f64));
check_handle(s, Some(false), |s| v8::Integer::new(s, 0));
check_eval(s, Some(true), "3.3");
check_eval(s, Some(false), "3.3 / 3.3");
}
#[test]
fn array_buffer() {
let _setup_guard = setup();