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

feat(core): JsRuntime::replace_op #13219

Closed
wants to merge 3 commits into from

Conversation

bartlomieju
Copy link
Member

Adds a new API to "JsRuntime" that allows to replace (or overwrite) an existing op
with a new handler.

This is kind of "very unsafe, but I know what I'm doing, please leave me alone" API,
but has actual use cases in:

@bartlomieju bartlomieju changed the title [WIP] core: JsRuntime::replace_op core: JsRuntime::replace_op Dec 29, 2021
@bartlomieju bartlomieju requested a review from AaronO December 29, 2021 02:45
@bartlomieju bartlomieju changed the title core: JsRuntime::replace_op feat(core): JsRuntime::replace_op Dec 29, 2021
Copy link
Member

@satyarohith satyarohith left a comment

Choose a reason for hiding this comment

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

LGTM.

Copy link
Contributor

@AaronO AaronO left a comment

Choose a reason for hiding this comment

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

I'm not in favour of this.

Op-middleware allows wrapping/replacing/disabling ops with a single primitive, e.g:

  let my_ext = Extension::builder()
    .middleware(|name, opfn| match name {
      "op_print" => deno_core::void_op_sync(),
      _ => opfn,
    })
    .build();

Any reason why this pattern doesn't work for your aforementioned use-cases ?

Comment on lines +208 to +211
pub fn replace_op<F>(&mut self, name: &str, op_fn: F) -> OpId
where
F: Fn(Rc<RefCell<OpState>>, OpPayload) -> Op + 'static,
{
Copy link
Contributor

Choose a reason for hiding this comment

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

Side discussion: it might makes sense to someday rewrite these (replace_op, register_op, etc.) to:

pub fn frob_op(&mut self, name: &str, op_fn: Rc<OpFn>) {
  // ...
}

Because right now they turn into a combinatorial explosion of monomorphized calls.

Truthfully, that's probably more relevant for op_sync() and op_async() because they're called way more often than register_op() - approx. 300 vs. 35 calls.

Copy link
Contributor

Choose a reason for hiding this comment

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

Mid-term I would be in favour of only allowing ops to be registered declaratively at init via Extensions.

AaronO added a commit to AaronO/deno that referenced this pull request Dec 29, 2021
Enabling op-middleware for overrides in lieu of imperative .replace_op() etc...

Impacts denoland#13219,  denoland#12938, denoland#13122
@bnoordhuis
Copy link
Contributor

Any reason why this pattern doesn't work for your aforementioned use-cases ?

The goal of this PR is clearly to replace ops at runtime and without overhead.

@AaronO
Copy link
Contributor

AaronO commented Dec 29, 2021

Any reason why this pattern doesn't work for your aforementioned use-cases ?

The goal of this PR is clearly to replace ops at runtime and without overhead.

#13122 and #12938 both replace ops at isolate-boot time. Op-middleware handles precisely this use-case and there's no difference in opcall overhead for the replaced ops.

@bnoordhuis
Copy link
Contributor

At isolate creation time isn't at runtime but maybe that's sufficient for the two linked use cases.

@AaronO
Copy link
Contributor

AaronO commented Dec 29, 2021

At isolate creation time isn't at runtime but maybe that's sufficient for the two linked use cases.

It is sufficient for the aforementioned use-cases and dynamically replacing ops at runtime is an anti-pattern IMO unless we're discussing "plugins" but that's off the table.

So in short unless there's a very clear use-case that middleware doesn't already solve, we should not add this API.

I refactored the CLI code in #13223 so @bartlomieju can easily slot in his op_exit override for #12938

@tim-palmer
Copy link

Possible additional use-case: #12918

If it's not possible to move op_apply_source_map, op_format_diagnostic and op_format_file_name into deno_runtime due to dependencies on cli then presumably deno_runtime will need alternative implementations that are then replaced in cli?

AaronO added a commit that referenced this pull request Dec 29, 2021
Enabling op-middleware for overrides in lieu of imperative .replace_op() etc...

Impacts #13219,  #12938, #13122
bartlomieju pushed a commit that referenced this pull request Jan 5, 2022
Enabling op-middleware for overrides in lieu of imperative .replace_op() etc...

Impacts #13219,  #12938, #13122
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants