[ML][Pipeline] Invalidate CustomFilter arguments after return 24/254924/4
authorPawel Wasowski <p.wasowski2@samsung.com>
Wed, 10 Mar 2021 12:38:22 +0000 (13:38 +0100)
committerPawel Wasowski <p.wasowski2@samsung.com>
Fri, 12 Mar 2021 10:07:53 +0000 (10:07 +0000)
ACR: TWDAPI-274

This commit makes input and output of a JS CustomFilter act as if they
were disposed after the callback's return.

[Verification] Change was tested in Chrome DevTools with the snippets
below. It works fine.

var inputTI = new tizen.ml.TensorsInfo();
inputTI.addTensorInfo('ti1', 'UINT8', [4, 20, 15, 1]);
var outputTI = new tizen.ml.TensorsInfo();
outputTI.addTensorInfo('ti1', 'UINT8', [1200]);
var flattenAndSet123 = function(input, output) {
    console.log("Custom filter called");

    var rawOutputData = new Uint8Array(1200);
    for (var i = 0; i < rawOutputData.length; ++i) {
        rawOutputData[i] = 123;
    }

    output.setTensorRawData(0, rawOutputData);

    console.log(input);

    return 0;
}

tizen.ml.pipeline.registerCustomFilter('testfilter2', flattenAndSet123, inputTI,
    outputTI, function errorCallback(error) {
        console.warn('custom filter error:') ; console.warn(error);
    });

var pipeline_def = "videotestsrc num-buffers=3 "
                   + "! video/x-raw,width=20,height=15,format=BGRA "
                   + "! tensor_converter "
                   + "! tensor_filter framework=custom-easy model=testfilter2 "
                   + "! appsink name=mysink";

var pipeline = tizen.ml.pipeline.createPipeline(pipeline_def,
                                                state => {console.log(state);})

pipeline.registerSinkListener('mysink', function(sinkName, data) {
    console.log('SinkListener for "' + sinkName + '" sink called');
    console.log(data);
})

// READY
// Custom filter called
// TensorsData {_id: 0, _tensorsInfo: TensorsInfo, _disposable: false}
// PAUSED

pipeline.start()

// CustomFilter is called 3 times

inputFromCustomFilter.getTensorRawData(0)
inputFromCustomFilter.tensorsInfo
outputFromCustomFilter.getTensorRawData(0)
outputFromCustomFilter.tensorsInfo
// The 4 lines above result in the following exception
// WebAPIException {name: "AbortError", message: "TensorsData is disposed"}
// as expected

//////////////////////////////////////////////////////////////////////////

var inputTI = new tizen.ml.TensorsInfo();
inputTI.addTensorInfo('ti1', 'UINT8', [4, 20, 15, 1]);
var inputTD = inputTI.getTensorsData()

inputTD.dispose()

inputTD.tensorsInfo
inputTD.getTensorRawData(0)
// The 2 lines above result in the following exception
// WebAPIException {name: "AbortError", message: "TensorsData is disposed"}
// as expected - the behavior of TensorsData.dispose() did not change

Change-Id: Ib6c6afc4bb09ad2ce04bb85650b79868e9923b7b
Signed-off-by: Pawel Wasowski <p.wasowski2@samsung.com>
src/ml/js/ml_common.js
src/ml/js/ml_pipeline.js

index cb863c8..649a214 100755 (executable)
@@ -113,6 +113,18 @@ function _CheckIfTensorsDataNotDisposed(id) {
     }
 }
 
+/*
+ * TensorsData objects invalidated by this function cannot be used
+ * in JS. However, this function does not release any resources allocated
+ * in C++ layer - if any action is needed in C++, another piece of
+ * code should do it (e.g. TensorsData::dispose()).
+ */
+function _InvalidateTensorsData(data) {
+    _ValidTensorsDataIds['delete'](data._id);
+    // underlying tensorsInfo_ is also invalid
+    _ValidTensorsInfoIds['delete'](data._tensorsInfo._id);
+}
+
 var TensorsData = function(id, tensorsInfoId, disposable) {
     Object.defineProperties(this, {
         count: {
@@ -308,9 +320,8 @@ TensorsData.prototype.dispose = function() {
     if (native_.isFailure(result)) {
         return;
     }
-    _ValidTensorsDataIds['delete'](this._id);
-    // underlying tensorsInfo_ is also invalid
-    _ValidTensorsInfoIds['delete'](this._tensorsInfo._id);
+
+    _InvalidateTensorsData(this);
 };
 
 // TensorsInfo
index f9a285f..7673d81 100755 (executable)
@@ -838,6 +838,10 @@ MachineLearningPipeline.prototype.registerCustomFilter = function() {
             jsResponse.status = -1;
         }
 
+        // Ensuring that these TensorsData cannot be used outside of the callback
+        _InvalidateTensorsData(inputData);
+        _InvalidateTensorsData(outputData);
+
         /*
          * Entering stage 3.
          */