diff --git a/src/node_blob.cc b/src/node_blob.cc index e8c0795fcaac60..9ac6f42962b2f3 100644 --- a/src/node_blob.cc +++ b/src/node_blob.cc @@ -5,12 +5,15 @@ #include "env-inl.h" #include "memory_tracker-inl.h" #include "node_bob-inl.h" +#include "node_debug.h" #include "node_errors.h" #include "node_external_reference.h" #include "node_file.h" #include "path.h" #include "permission/permission.h" #include "util.h" +#include "v8-fast-api-calls.h" +#include "v8-value.h" #include "v8.h" #include @@ -22,7 +25,9 @@ using v8::ArrayBuffer; using v8::ArrayBufferView; using v8::BackingStore; using v8::BackingStoreInitializationMode; +using v8::CFunction; using v8::Context; +using v8::FastApiCallbackOptions; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -130,7 +135,11 @@ void Blob::CreatePerIsolateProperties(IsolateData* isolate_data, SetMethod(isolate, target, "createBlob", New); SetMethod(isolate, target, "storeDataObject", StoreDataObject); SetMethod(isolate, target, "getDataObject", GetDataObject); - SetMethod(isolate, target, "revokeObjectURL", RevokeObjectURL); + SetFastMethod(isolate, + target, + "revokeObjectURL", + RevokeObjectURL, + &fast_revoke_object_url_method); SetMethod(isolate, target, "concat", Concat); SetMethod(isolate, target, "createBlobFromFilePath", BlobFromFilePath); } @@ -450,15 +459,11 @@ void Blob::StoreDataObject(const FunctionCallbackInfo& args) { std::string(*type, type.length()))); } -// TODO(@anonrig): Add V8 Fast API to the following function -void Blob::RevokeObjectURL(const FunctionCallbackInfo& args) { - CHECK_GE(args.Length(), 1); - CHECK(args[0]->IsString()); - Realm* realm = Realm::GetCurrent(args); +void RevokeObjectURLImpl(Realm* realm, Local input_str) { BlobBindingData* binding_data = realm->GetBindingData(); Isolate* isolate = realm->isolate(); - Utf8Value input(isolate, args[0].As()); + Utf8Value input(isolate, input_str); auto out = ada::parse(input.ToStringView()); if (!out) { @@ -477,6 +482,27 @@ void Blob::RevokeObjectURL(const FunctionCallbackInfo& args) { } } +void Blob::RevokeObjectURL(const FunctionCallbackInfo& args) { + CHECK_GE(args.Length(), 1); + CHECK(args[0]->IsString()); + Realm* realm = Realm::GetCurrent(args); + RevokeObjectURLImpl(realm, args[0].As()); +} + +void Blob::FastRevokeObjectURL(Local receiver, + Local raw_input, + FastApiCallbackOptions& options) { + TRACK_V8_FAST_API_CALL("blob.revokeObjectURL"); + CHECK(raw_input->IsString()); + auto isolate = options.isolate; + HandleScope handleScope(isolate); + Realm* realm = Realm::GetCurrent(isolate->GetCurrentContext()); + RevokeObjectURLImpl(realm, raw_input.As()); +} + +CFunction Blob::fast_revoke_object_url_method = + CFunction::Make(Blob::FastRevokeObjectURL); + void Blob::GetDataObject(const FunctionCallbackInfo& args) { CHECK(args[0]->IsString()); Realm* realm = Realm::GetCurrent(args); @@ -584,9 +610,11 @@ void Blob::RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(Blob::StoreDataObject); registry->Register(Blob::GetDataObject); registry->Register(Blob::RevokeObjectURL); + registry->Register(Blob::FastRevokeObjectURL); registry->Register(Blob::Reader::Pull); registry->Register(Concat); registry->Register(BlobFromFilePath); + registry->Register(fast_revoke_object_url_method.GetTypeInfo()); } } // namespace node diff --git a/src/node_blob.h b/src/node_blob.h index c601015d9af47b..f4baa8d0297d54 100644 --- a/src/node_blob.h +++ b/src/node_blob.h @@ -5,6 +5,9 @@ #include "v8-template.h" #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS +#include +#include +#include #include "async_wrap.h" #include "base_object.h" #include "dataqueue/queue.h" @@ -13,12 +16,9 @@ #include "node_internals.h" #include "node_snapshotable.h" #include "node_worker.h" +#include "v8-fast-api-calls.h" #include "v8.h" -#include -#include -#include - namespace node { class Blob : public BaseObject { @@ -39,6 +39,13 @@ class Blob : public BaseObject { static void StoreDataObject(const v8::FunctionCallbackInfo& args); static void GetDataObject(const v8::FunctionCallbackInfo& args); static void RevokeObjectURL(const v8::FunctionCallbackInfo& args); + static void FastRevokeObjectURL( + v8::Local receiver, + v8::Local raw_input, + // NOLINTNEXTLINE(runtime/references) This is V8 api. + v8::FastApiCallbackOptions& options); + + static v8::CFunction fast_revoke_object_url_method; static v8::Local GetConstructorTemplate( Environment* env); diff --git a/src/node_external_reference.h b/src/node_external_reference.h index 5981e9db9c3bc4..d2867a6cad1bb9 100644 --- a/src/node_external_reference.h +++ b/src/node_external_reference.h @@ -10,7 +10,9 @@ namespace node { -using CFunctionCallbackWithalueAndOptions = bool (*)( +using CFunctionCallbackWithValueAndOptions = void (*)( + v8::Local, v8::Local, v8::FastApiCallbackOptions&); +using CFunctionCallbackWithValueAndOptionsReturnBool = bool (*)( v8::Local, v8::Local, v8::FastApiCallbackOptions&); using CFunctionCallbackWithMultipleValueAndOptions = bool (*)(v8::Local, @@ -46,6 +48,7 @@ using CFunctionCallbackWithInt64 = void (*)(v8::Local unused, using CFunctionCallbackWithBool = void (*)(v8::Local unused, v8::Local receiver, bool); + using CFunctionCallbackWithString = bool (*)(v8::Local, const v8::FastOneByteString& input); using CFunctionCallbackWithStrings = @@ -103,7 +106,8 @@ class ExternalReferenceRegistry { #define ALLOWED_EXTERNAL_REFERENCE_TYPES(V) \ V(CFunctionA) \ V(CFunctionCallback) \ - V(CFunctionCallbackWithalueAndOptions) \ + V(CFunctionCallbackWithValueAndOptions) \ + V(CFunctionCallbackWithValueAndOptionsReturnBool) \ V(CFunctionCallbackWithMultipleValueAndOptions) \ V(CFunctionCallbackWithOneByteString) \ V(CFunctionCallbackReturnBool) \ diff --git a/test/parallel/test-url-revokeobjecturl-fast.js b/test/parallel/test-url-revokeobjecturl-fast.js new file mode 100644 index 00000000000000..ec023571831c17 --- /dev/null +++ b/test/parallel/test-url-revokeobjecturl-fast.js @@ -0,0 +1,32 @@ +// Flags: --expose-internals --allow-natives-syntax +'use strict'; +const common = require('../common'); +const assert = require('node:assert'); + +const { internalBinding } = require('internal/test/binding'); + +// Because registering a Blob URL requires generating a random +// UUID, it can only be done if crypto support is enabled. +if (!common.hasCrypto) { + common.skip('missing crypto'); +} + +const blob = new Blob([JSON.stringify({ hello: 'world' }, null, 2)], { + type: 'application/json', +}); + +function testFastPath() { + const objURL = URL.createObjectURL(blob); + URL.revokeObjectURL(objURL); +} + +eval('%PrepareFunctionForOptimization(URL.revokeObjectURL)'); +testFastPath(); + +eval('%OptimizeFunctionOnNextCall(URL.revokeObjectURL)'); +testFastPath(); + +if (common.isDebug) { + const { getV8FastApiCallCount } = internalBinding('debug'); + assert.strictEqual(getV8FastApiCallCount('blob.revokeObjectURL'), 1); +}