mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
chore(core): Make OpCtx
instances be realm-specific (#17174)
This commit is contained in:
parent
1a3665b612
commit
a67fd3e23e
3 changed files with 50 additions and 15 deletions
|
@ -153,8 +153,10 @@ pub fn to_op_result<R: Serialize + 'static>(
|
|||
pub struct OpCtx {
|
||||
pub id: OpId,
|
||||
pub state: Rc<RefCell<OpState>>,
|
||||
pub decl: OpDecl,
|
||||
pub decl: Rc<OpDecl>,
|
||||
pub runtime_state: Weak<RefCell<JsRuntimeState>>,
|
||||
// Index of the current realm into `JsRuntimeState::known_realms`.
|
||||
pub realm_idx: usize,
|
||||
}
|
||||
|
||||
/// Maintains the resources and ops inside a JS runtime.
|
||||
|
|
|
@ -9,6 +9,7 @@ use crate::ops_builtin::WasmStreamingResource;
|
|||
use crate::resolve_url_or_path;
|
||||
use crate::serde_v8::from_v8;
|
||||
use crate::source_map::apply_source_map as apply_source_map_;
|
||||
use crate::JsRealm;
|
||||
use crate::JsRuntime;
|
||||
use crate::OpDecl;
|
||||
use crate::ZeroCopyBuf;
|
||||
|
@ -782,7 +783,7 @@ fn op_dispatch_exception(
|
|||
|
||||
#[op(v8)]
|
||||
fn op_op_names(scope: &mut v8::HandleScope) -> Vec<String> {
|
||||
let state_rc = JsRuntime::state(scope);
|
||||
let state_rc = JsRealm::state_from_scope(scope);
|
||||
let state = state_rc.borrow();
|
||||
state
|
||||
.op_ctxs
|
||||
|
|
|
@ -151,6 +151,9 @@ pub type CompiledWasmModuleStore = CrossIsolateStore<v8::CompiledWasmModule>;
|
|||
#[derive(Default)]
|
||||
pub(crate) struct ContextState {
|
||||
pub(crate) js_build_custom_error_cb: Option<v8::Global<v8::Function>>,
|
||||
// We don't explicitly re-read this prop but need the slice to live alongside
|
||||
// the context
|
||||
pub(crate) op_ctxs: Box<[OpCtx]>,
|
||||
}
|
||||
|
||||
/// Internal state for JsRuntime which is stored in one of v8::Isolate's
|
||||
|
@ -178,9 +181,6 @@ pub struct JsRuntimeState {
|
|||
pub(crate) unrefed_ops: HashSet<i32>,
|
||||
pub(crate) have_unpolled_ops: bool,
|
||||
pub(crate) op_state: Rc<RefCell<OpState>>,
|
||||
#[allow(dead_code)]
|
||||
// We don't explicitly re-read this prop but need the slice to live alongside the isolate
|
||||
pub(crate) op_ctxs: Box<[OpCtx]>,
|
||||
pub(crate) shared_array_buffer_store: Option<SharedArrayBufferStore>,
|
||||
pub(crate) compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
|
||||
/// The error that was passed to an `op_dispatch_exception` call.
|
||||
|
@ -407,7 +407,6 @@ impl JsRuntime {
|
|||
dispatched_exceptions: Default::default(),
|
||||
// Some fields are initialized later after isolate is created
|
||||
inspector: None,
|
||||
op_ctxs: vec![].into_boxed_slice(),
|
||||
global_realm: None,
|
||||
known_realms: Vec::with_capacity(1),
|
||||
}));
|
||||
|
@ -420,7 +419,8 @@ impl JsRuntime {
|
|||
id,
|
||||
state: op_state.clone(),
|
||||
runtime_state: weak.clone(),
|
||||
decl,
|
||||
decl: Rc::new(decl),
|
||||
realm_idx: 0,
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice();
|
||||
|
@ -522,9 +522,13 @@ impl JsRuntime {
|
|||
(isolate, snapshot_options)
|
||||
};
|
||||
|
||||
global_context
|
||||
.open(&mut isolate)
|
||||
.set_slot(&mut isolate, Rc::<RefCell<ContextState>>::default());
|
||||
global_context.open(&mut isolate).set_slot(
|
||||
&mut isolate,
|
||||
Rc::new(RefCell::new(ContextState {
|
||||
js_build_custom_error_cb: None,
|
||||
op_ctxs,
|
||||
})),
|
||||
);
|
||||
|
||||
op_state.borrow_mut().put(isolate_ptr);
|
||||
let inspector = if options.inspector {
|
||||
|
@ -543,7 +547,6 @@ impl JsRuntime {
|
|||
{
|
||||
let mut state = state_rc.borrow_mut();
|
||||
state.global_realm = Some(JsRealm(global_context.clone()));
|
||||
state.op_ctxs = op_ctxs;
|
||||
state.inspector = inspector;
|
||||
state
|
||||
.known_realms
|
||||
|
@ -631,6 +634,23 @@ impl JsRuntime {
|
|||
/// constructed.
|
||||
pub fn create_realm(&mut self) -> Result<JsRealm, Error> {
|
||||
let realm = {
|
||||
let realm_idx = self.state.borrow().known_realms.len();
|
||||
|
||||
let op_ctxs: Box<[OpCtx]> = self
|
||||
.global_realm()
|
||||
.state(self.v8_isolate())
|
||||
.borrow()
|
||||
.op_ctxs
|
||||
.iter()
|
||||
.map(|op_ctx| OpCtx {
|
||||
id: op_ctx.id,
|
||||
state: op_ctx.state.clone(),
|
||||
decl: op_ctx.decl.clone(),
|
||||
runtime_state: op_ctx.runtime_state.clone(),
|
||||
realm_idx,
|
||||
})
|
||||
.collect();
|
||||
|
||||
// SAFETY: Having the scope tied to self's lifetime makes it impossible to
|
||||
// reference JsRuntimeState::op_ctxs while the scope is alive. Here we
|
||||
// turn it into an unbound lifetime, which is sound because 1. it only
|
||||
|
@ -639,12 +659,15 @@ impl JsRuntime {
|
|||
let scope = &mut v8::HandleScope::new(unsafe {
|
||||
&mut *(self.v8_isolate() as *mut v8::OwnedIsolate)
|
||||
});
|
||||
let context = bindings::initialize_context(
|
||||
let context =
|
||||
bindings::initialize_context(scope, &op_ctxs, self.snapshot_options);
|
||||
context.set_slot(
|
||||
scope,
|
||||
&self.state.borrow().op_ctxs,
|
||||
self.snapshot_options,
|
||||
Rc::new(RefCell::new(ContextState {
|
||||
js_build_custom_error_cb: None,
|
||||
op_ctxs,
|
||||
})),
|
||||
);
|
||||
context.set_slot(scope, Rc::<RefCell<ContextState>>::default());
|
||||
|
||||
self
|
||||
.state
|
||||
|
@ -2408,6 +2431,15 @@ pub fn queue_async_op(
|
|||
None => unreachable!(),
|
||||
};
|
||||
|
||||
// An op's realm (as given by `OpCtx::realm_idx`) must match the realm in
|
||||
// which it is invoked. Otherwise, we might have cross-realm object exposure.
|
||||
// deno_core doesn't currently support such exposure, even though embedders
|
||||
// can cause them, so we panic in debug mode (since the check is expensive).
|
||||
debug_assert_eq!(
|
||||
runtime_state.borrow().known_realms[ctx.realm_idx].to_local(scope),
|
||||
Some(scope.get_current_context())
|
||||
);
|
||||
|
||||
match OpCall::eager(op) {
|
||||
// This calls promise.resolve() before the control goes back to userland JS. It works something
|
||||
// along the lines of:
|
||||
|
|
Loading…
Reference in a new issue