aboutsummaryrefslogtreecommitdiff
path: root/tools/addon-sdk-1.12/lib/sdk/system/unload.js
blob: 4d2575bdcb0fad5cac2287450fd77b53e57066b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Parts of this module were taken from narwhal:
//
// http://narwhaljs.org

module.metadata = {
  "stability": "experimental"
};

const { on, off } = require('./events');
const unloadSubject = require('@loader/unload');

const observers = [];
const unloaders = [];

var when = exports.when = function when(observer) {
  if (observers.indexOf(observer) != -1)
    return;
  observers.unshift(observer);
};

var ensure = exports.ensure = function ensure(obj, destructorName) {
  if (!destructorName)
    destructorName = "unload";
  if (!(destructorName in obj))
    throw new Error("object has no '" + destructorName + "' property");

  let called = false;
  let originalDestructor = obj[destructorName];

  function unloadWrapper(reason) {
    if (!called) {
      called = true;
      let index = unloaders.indexOf(unloadWrapper);
      if (index == -1)
        throw new Error("internal error: unloader not found");
      unloaders.splice(index, 1);
      originalDestructor.call(obj, reason);
      originalDestructor = null;
      destructorName = null;
      obj = null;
    }
  };

  // TODO: Find out why the order is inverted here. It seems that
  // it may be causing issues!
  unloaders.push(unloadWrapper);

  obj[destructorName] = unloadWrapper;
};

function unload(reason) {
  observers.forEach(function(observer) {
    try {
      observer(reason);
    }
    catch (error) {
      console.exception(error);
    }
  });
}

when(function(reason) {
  unloaders.slice().forEach(function(unloadWrapper) {
    unloadWrapper(reason);
  });
});

on('sdk:loader:destroy', function onunload({ subject, data: reason }) {
  // If this loader is unload then `subject.wrappedJSObject` will be
  // `destructor`.
  if (subject.wrappedJSObject === unloadSubject) {
    off('sdk:loader:destroy', onunload);
    unload(reason);
  }
// Note that we use strong reference to listener here to make sure it's not
// GC-ed, which may happen otherwise since nothing keeps reference to `onunolad`
// function.
}, true);