diff --git a/js/node/lib/backend.ts b/js/node/lib/backend.ts index 5f5ad49a2dea8..e8eb0e9babf5a 100644 --- a/js/node/lib/backend.ts +++ b/js/node/lib/backend.ts @@ -20,7 +20,7 @@ class OnnxruntimeSessionHandler implements InferenceSessionHandler { } async dispose(): Promise { - return Promise.resolve(); + this.#inferenceSession.dispose(); } readonly inputNames: string[]; diff --git a/js/node/lib/binding.ts b/js/node/lib/binding.ts index 8a0ce89abfa64..54b5767139904 100644 --- a/js/node/lib/binding.ts +++ b/js/node/lib/binding.ts @@ -28,6 +28,8 @@ export declare namespace Binding { readonly outputNames: string[]; run(feeds: FeedsType, fetches: FetchesType, options: RunOptions): ReturnType; + + dispose(): void; } export interface InferenceSessionConstructor { diff --git a/js/node/src/inference_session_wrap.cc b/js/node/src/inference_session_wrap.cc index c409fdc8895f7..1bbb6df1ce1c8 100644 --- a/js/node/src/inference_session_wrap.cc +++ b/js/node/src/inference_session_wrap.cc @@ -31,6 +31,7 @@ Napi::Object InferenceSessionWrap::Init(Napi::Env env, Napi::Object exports) { Napi::Function func = DefineClass( env, "InferenceSession", {InstanceMethod("loadModel", &InferenceSessionWrap::LoadModel), InstanceMethod("run", &InferenceSessionWrap::Run), + InstanceMethod("dispose", &InferenceSessionWrap::Dispose), InstanceAccessor("inputNames", &InferenceSessionWrap::GetInputNames, nullptr, napi_default, nullptr), InstanceAccessor("outputNames", &InferenceSessionWrap::GetOutputNames, nullptr, napi_default, nullptr)}); @@ -45,7 +46,7 @@ Napi::Object InferenceSessionWrap::Init(Napi::Env env, Napi::Object exports) { } InferenceSessionWrap::InferenceSessionWrap(const Napi::CallbackInfo &info) - : Napi::ObjectWrap(info), initialized_(false), session_(nullptr), + : Napi::ObjectWrap(info), initialized_(false), disposed_(false), session_(nullptr), defaultRunOptions_(nullptr) {} Napi::Value InferenceSessionWrap::LoadModel(const Napi::CallbackInfo &info) { @@ -53,6 +54,7 @@ Napi::Value InferenceSessionWrap::LoadModel(const Napi::CallbackInfo &info) { Napi::HandleScope scope(env); ORT_NAPI_THROW_ERROR_IF(this->initialized_, env, "Model already loaded. Cannot load model multiple times."); + ORT_NAPI_THROW_ERROR_IF(this->disposed_, env, "Session already disposed."); size_t argsLength = info.Length(); ORT_NAPI_THROW_TYPEERROR_IF(argsLength == 0, env, "Expect argument: model file path or buffer."); @@ -129,6 +131,7 @@ Napi::Value InferenceSessionWrap::LoadModel(const Napi::CallbackInfo &info) { Napi::Value InferenceSessionWrap::GetInputNames(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); ORT_NAPI_THROW_ERROR_IF(!this->initialized_, env, "Session is not initialized."); + ORT_NAPI_THROW_ERROR_IF(this->disposed_, env, "Session already disposed."); Napi::EscapableHandleScope scope(env); return scope.Escape(CreateNapiArrayFrom(env, inputNames_)); @@ -137,6 +140,7 @@ Napi::Value InferenceSessionWrap::GetInputNames(const Napi::CallbackInfo &info) Napi::Value InferenceSessionWrap::GetOutputNames(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); ORT_NAPI_THROW_ERROR_IF(!this->initialized_, env, "Session is not initialized."); + ORT_NAPI_THROW_ERROR_IF(this->disposed_, env, "Session already disposed."); Napi::EscapableHandleScope scope(env); return scope.Escape(CreateNapiArrayFrom(env, outputNames_)); @@ -145,6 +149,7 @@ Napi::Value InferenceSessionWrap::GetOutputNames(const Napi::CallbackInfo &info) Napi::Value InferenceSessionWrap::Run(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); ORT_NAPI_THROW_ERROR_IF(!this->initialized_, env, "Session is not initialized."); + ORT_NAPI_THROW_ERROR_IF(this->disposed_, env, "Session already disposed."); ORT_NAPI_THROW_TYPEERROR_IF(info.Length() < 2, env, "Expect argument: inputs(feed) and outputs(fetch)."); ORT_NAPI_THROW_TYPEERROR_IF(!info[0].IsObject() || !info[1].IsObject(), env, "Expect inputs(feed) and outputs(fetch) to be objects."); @@ -209,6 +214,18 @@ Napi::Value InferenceSessionWrap::Run(const Napi::CallbackInfo &info) { } } +Napi::Value InferenceSessionWrap::Dispose(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + ORT_NAPI_THROW_ERROR_IF(!this->initialized_, env, "Session is not initialized."); + ORT_NAPI_THROW_ERROR_IF(this->disposed_, env, "Session already disposed."); + + this->defaultRunOptions_.reset(nullptr); + this->session_.reset(nullptr); + + this->disposed_ = true; + return env.Undefined(); +} + Napi::Value InferenceSessionWrap::ListSupportedBackends(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); Napi::EscapableHandleScope scope(env); diff --git a/js/node/src/inference_session_wrap.h b/js/node/src/inference_session_wrap.h index 9eee45b72dcb1..1e789c4814cd6 100644 --- a/js/node/src/inference_session_wrap.h +++ b/js/node/src/inference_session_wrap.h @@ -55,6 +55,14 @@ class InferenceSessionWrap : public Napi::ObjectWrap { */ Napi::Value Run(const Napi::CallbackInfo &info); + /** + * [sync] dispose the session. + * @param nothing + * @returns nothing + * @throw nothing + */ + Napi::Value Dispose(const Napi::CallbackInfo &info); + // private members // persistent constructor @@ -62,6 +70,7 @@ class InferenceSessionWrap : public Napi::ObjectWrap { // session objects bool initialized_; + bool disposed_; std::unique_ptr session_; std::unique_ptr defaultRunOptions_;