objects-registry.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. 'use strict'
  2. const v8Util = process.atomBinding('v8_util')
  3. class ObjectsRegistry {
  4. constructor () {
  5. this.nextId = 0
  6. // Stores all objects by ref-counting.
  7. // (id) => {object, count}
  8. this.storage = {}
  9. // Stores the IDs of objects referenced by WebContents.
  10. // (webContentsContextId) => [id]
  11. this.owners = {}
  12. }
  13. // Register a new object and return its assigned ID. If the object is already
  14. // registered then the already assigned ID would be returned.
  15. add (webContents, contextId, obj) {
  16. // Get or assign an ID to the object.
  17. const id = this.saveToStorage(obj)
  18. // Add object to the set of referenced objects.
  19. const webContentsContextId = `${webContents.id}-${contextId}`
  20. let owner = this.owners[webContentsContextId]
  21. if (!owner) {
  22. owner = this.owners[webContentsContextId] = new Set()
  23. this.registerDeleteListener(webContents, contextId)
  24. }
  25. if (!owner.has(id)) {
  26. owner.add(id)
  27. // Increase reference count if not referenced before.
  28. this.storage[id].count++
  29. }
  30. return id
  31. }
  32. // Get an object according to its ID.
  33. get (id) {
  34. const pointer = this.storage[id]
  35. if (pointer != null) return pointer.object
  36. }
  37. // Dereference an object according to its ID.
  38. // Note that an object may be double-freed (cleared when page is reloaded, and
  39. // then garbage collected in old page).
  40. remove (webContents, contextId, id) {
  41. const webContentsContextId = `${webContents.id}-${contextId}`
  42. let owner = this.owners[webContentsContextId]
  43. if (owner) {
  44. // Remove the reference in owner.
  45. owner.delete(id)
  46. // Dereference from the storage.
  47. this.dereference(id)
  48. }
  49. }
  50. // Clear all references to objects refrenced by the WebContents.
  51. clear (webContents, contextId) {
  52. const webContentsContextId = `${webContents.id}-${contextId}`
  53. let owner = this.owners[webContentsContextId]
  54. if (!owner) return
  55. for (let id of owner) this.dereference(id)
  56. delete this.owners[webContentsContextId]
  57. }
  58. // Private: Saves the object into storage and assigns an ID for it.
  59. saveToStorage (object) {
  60. let id = v8Util.getHiddenValue(object, 'atomId')
  61. if (!id) {
  62. id = ++this.nextId
  63. this.storage[id] = {
  64. count: 0,
  65. object: object
  66. }
  67. v8Util.setHiddenValue(object, 'atomId', id)
  68. }
  69. return id
  70. }
  71. // Private: Dereference the object from store.
  72. dereference (id) {
  73. if (process.env.ELECTRON_DISABLE_REMOTE_DEREFERENCING) return
  74. let pointer = this.storage[id]
  75. if (pointer == null) {
  76. return
  77. }
  78. pointer.count -= 1
  79. if (pointer.count === 0) {
  80. v8Util.deleteHiddenValue(pointer.object, 'atomId')
  81. delete this.storage[id]
  82. }
  83. }
  84. // Private: Clear the storage when renderer process is destoryed.
  85. registerDeleteListener (webContents, contextId) {
  86. const processId = webContents.getProcessId()
  87. const listener = (event, deletedProcessId) => {
  88. if (deletedProcessId === processId) {
  89. webContents.removeListener('render-view-deleted', listener)
  90. this.clear(webContents, contextId)
  91. }
  92. }
  93. webContents.on('render-view-deleted', listener)
  94. }
  95. }
  96. module.exports = new ObjectsRegistry()