objects-registry.js 3.2 KB

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