Dereference remote objects with native code
Previously we rely on the v8util.setDestructor to dereference the remote objects in JavaScript, however as documented in V8, it is forbidden to call V8 APIs in object's destructor (e.g. the weak callback), and doing so would result in crashs. This commit removes the JavaScript setDestructor method, and avoids doing the dereference work with V8.
This commit is contained in:
parent
570dc7ca9b
commit
06cf0406fe
12 changed files with 272 additions and 61 deletions
|
@ -12,8 +12,19 @@ const FUNCTION_PROPERTIES = [
|
|||
]
|
||||
|
||||
// The remote functions in renderer processes.
|
||||
// (webContentsId) => {id: Function}
|
||||
let rendererFunctions = {}
|
||||
// id => Function
|
||||
let rendererFunctions = new IDWeakMap()
|
||||
|
||||
// Merge two IDs together.
|
||||
let mergeIds = function (webContentsId, metaId) {
|
||||
const PADDING_BITS = 20
|
||||
if ((webContentsId << PADDING_BITS) < 0) {
|
||||
throw new Error(`webContents ID is too large: ${webContentsId}`)
|
||||
} else if (metaId > (1 << PADDING_BITS)) {
|
||||
throw new Error(`Object ID is too large: ${metaId}`)
|
||||
}
|
||||
return (webContentsId << PADDING_BITS) + metaId
|
||||
}
|
||||
|
||||
// Return the description of object's members:
|
||||
let getObjectMembers = function (object) {
|
||||
|
@ -165,32 +176,26 @@ var unwrapArgs = function (sender, args) {
|
|||
return returnValue
|
||||
}
|
||||
case 'function': {
|
||||
// Merge webContentsId and meta.id, since meta.id can be the same in
|
||||
// different webContents.
|
||||
const webContentsId = sender.getId()
|
||||
const objectId = mergeIds(webContentsId, meta.id)
|
||||
|
||||
// Cache the callbacks in renderer.
|
||||
let webContentsId = sender.getId()
|
||||
let callbacks = rendererFunctions[webContentsId]
|
||||
if (!callbacks) {
|
||||
callbacks = rendererFunctions[webContentsId] = new IDWeakMap()
|
||||
sender.once('render-view-deleted', function (event, id) {
|
||||
callbacks.clear()
|
||||
delete rendererFunctions[id]
|
||||
})
|
||||
if (rendererFunctions.has(objectId)) {
|
||||
return rendererFunctions.get(objectId)
|
||||
}
|
||||
|
||||
if (callbacks.has(meta.id)) return callbacks.get(meta.id)
|
||||
|
||||
let callIntoRenderer = function (...args) {
|
||||
if ((webContentsId in rendererFunctions) && !sender.isDestroyed()) {
|
||||
if (!sender.isDestroyed() && webContentsId === sender.getId()) {
|
||||
sender.send('ELECTRON_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args))
|
||||
} else {
|
||||
throw new Error(`Attempting to call a function in a renderer window that has been closed or released. Function provided here: ${meta.location}.`)
|
||||
}
|
||||
}
|
||||
v8Util.setDestructor(callIntoRenderer, function () {
|
||||
if ((webContentsId in rendererFunctions) && !sender.isDestroyed()) {
|
||||
sender.send('ELECTRON_RENDERER_RELEASE_CALLBACK', meta.id)
|
||||
}
|
||||
})
|
||||
callbacks.set(meta.id, callIntoRenderer)
|
||||
|
||||
v8Util.setRemoteCallbackFreer(callIntoRenderer, meta.id, sender)
|
||||
rendererFunctions.set(objectId, callIntoRenderer)
|
||||
return callIntoRenderer
|
||||
}
|
||||
default:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue