Browse Source

refactor: replace V8 hidden values with WeakMap / WeakSet (#26659)

Milan Burda 4 years ago
parent
commit
c8d77cae4a

+ 5 - 5
lib/browser/remote/objects-registry.ts

@@ -1,11 +1,11 @@
 import { WebContents } from 'electron/main';
 
-const v8Util = process._linkedBinding('electron_common_v8_util');
-
 const getOwnerKey = (webContents: WebContents, contextId: string) => {
   return `${webContents.id}-${contextId}`;
 };
 
+const electronIds = new WeakMap<Object, number>();
+
 class ObjectsRegistry {
   private nextId: number = 0
 
@@ -81,14 +81,14 @@ class ObjectsRegistry {
 
   // Private: Saves the object into storage and assigns an ID for it.
   saveToStorage (object: any) {
-    let id: number = v8Util.getHiddenValue(object, 'electronId');
+    let id = electronIds.get(object);
     if (!id) {
       id = ++this.nextId;
       this.storage[id] = {
         count: 0,
         object: object
       };
-      v8Util.setHiddenValue(object, 'electronId', id);
+      electronIds.set(object, id);
     }
     return id;
   }
@@ -101,7 +101,7 @@ class ObjectsRegistry {
     }
     pointer.count -= 1;
     if (pointer.count === 0) {
-      v8Util.deleteHiddenValue(pointer.object, 'electronId');
+      electronIds.delete(pointer.object);
       delete this.storage[id];
     }
   }

+ 4 - 2
lib/browser/remote/server.ts

@@ -56,6 +56,8 @@ function setCachedRendererFunction (id: RendererFunctionId, wc: electron.WebCont
   return value;
 }
 
+const locationInfo = new WeakMap<Object, string>();
+
 // Return the description of object's members:
 const getObjectMembers = function (object: any): ObjectMember[] {
   let names = Object.getOwnPropertyNames(object);
@@ -186,7 +188,7 @@ const throwRPCError = function (message: string) {
 };
 
 const removeRemoteListenersAndLogWarning = (sender: any, callIntoRenderer: (...args: any[]) => void) => {
-  const location = v8Util.getHiddenValue(callIntoRenderer, 'location');
+  const location = locationInfo.get(callIntoRenderer);
   let message = 'Attempting to call a function in a renderer window that has been closed or released.' +
     `\nFunction provided here: ${location}`;
 
@@ -269,7 +271,7 @@ const unwrapArgs = function (sender: electron.WebContents, frameId: number, cont
             removeRemoteListenersAndLogWarning(this, callIntoRenderer);
           }
         };
-        v8Util.setHiddenValue(callIntoRenderer, 'location', meta.location);
+        locationInfo.set(callIntoRenderer, meta.location);
         Object.defineProperty(callIntoRenderer, 'length', { value: meta.length });
 
         setCachedRendererFunction(objectId, sender, frameId, callIntoRenderer);

+ 9 - 6
lib/renderer/api/remote.ts

@@ -23,6 +23,9 @@ const finalizationRegistry = new (window as any).FinalizationRegistry((id: numbe
   }
 });
 
+const electronIds = new WeakMap<Object, number>();
+const isReturnValue = new WeakSet<Object>();
+
 function getCachedRemoteObject (id: number) {
   const ref = remoteObjectCache.get(id);
   if (ref !== undefined) {
@@ -90,10 +93,10 @@ function wrapArgs (args: any[], visited = new Set()): any {
             value.then(onFulfilled, onRejected);
           })
         };
-      } else if (v8Util.getHiddenValue(value, 'electronId')) {
+      } else if (electronIds.has(value)) {
         return {
           type: 'remote-object',
-          id: v8Util.getHiddenValue(value, 'electronId')
+          id: electronIds.get(value)
         };
       }
 
@@ -111,7 +114,7 @@ function wrapArgs (args: any[], visited = new Set()): any {
       }
       visited.delete(value);
       return meta;
-    } else if (typeof value === 'function' && v8Util.getHiddenValue(value, 'returnValue')) {
+    } else if (typeof value === 'function' && isReturnValue.has(value)) {
       return {
         type: 'function-with-return-value',
         value: valueToMeta(value())
@@ -120,7 +123,7 @@ function wrapArgs (args: any[], visited = new Set()): any {
       return {
         type: 'function',
         id: callbacksRegistry.add(value),
-        location: v8Util.getHiddenValue(value, 'location'),
+        location: callbacksRegistry.getLocation(value),
         length: value.length
       };
     } else {
@@ -287,7 +290,7 @@ function metaToValue (meta: MetaType): any {
     }
 
     // Track delegate obj's lifetime & tell browser to clean up when object is GCed.
-    v8Util.setHiddenValue(ret, 'electronId', meta.id);
+    electronIds.set(ret, meta.id);
     setCachedRemoteObject(meta.id, ret);
     return ret;
   }
@@ -373,7 +376,7 @@ Object.defineProperty(exports, 'process', {
 // Create a function that will return the specified value when called in browser.
 export function createFunctionWithReturnValue<T> (returnValue: T): () => T {
   const func = () => returnValue;
-  v8Util.setHiddenValue(func, 'returnValue', true);
+  isReturnValue.add(func);
   return func;
 }
 

+ 11 - 6
lib/renderer/remote/callbacks-registry.ts

@@ -1,4 +1,5 @@
-const v8Util = process._linkedBinding('electron_common_v8_util');
+const callbackIds = new WeakMap<Function, number>();
+const locationInfo = new WeakMap<Function, string>();
 
 export class CallbacksRegistry {
   private nextId: number = 0
@@ -6,7 +7,7 @@ export class CallbacksRegistry {
 
   add (callback: Function) {
     // The callback is already added.
-    let id = v8Util.getHiddenValue<number>(callback, 'callbackId');
+    let id = callbackIds.get(callback);
     if (id != null) return id;
 
     id = this.nextId += 1;
@@ -17,7 +18,7 @@ export class CallbacksRegistry {
     const stackString = (new Error()).stack;
     if (!stackString) return;
 
-    let filenameAndLine;
+    let filenameAndLine: string;
     let match;
 
     while ((match = regexp.exec(stackString)) !== null) {
@@ -32,8 +33,8 @@ export class CallbacksRegistry {
     }
 
     this.callbacks.set(id, callback);
-    v8Util.setHiddenValue(callback, 'callbackId', id);
-    v8Util.setHiddenValue(callback, 'location', filenameAndLine);
+    callbackIds.set(callback, id);
+    locationInfo.set(callback, filenameAndLine!);
     return id;
   }
 
@@ -41,6 +42,10 @@ export class CallbacksRegistry {
     return this.callbacks.get(id) || function () {};
   }
 
+  getLocation (callback: Function) {
+    return locationInfo.get(callback);
+  }
+
   apply (id: number, ...args: any[]) {
     return this.get(id).apply(global, ...args);
   }
@@ -48,7 +53,7 @@ export class CallbacksRegistry {
   remove (id: number) {
     const callback = this.callbacks.get(id);
     if (callback) {
-      v8Util.deleteHiddenValue(callback, 'callbackId');
+      callbackIds.delete(callback);
       this.callbacks.delete(id);
     }
   }