Skip to content

Commit

Permalink
perf: pass primitives directly through the context bridge, avoids cop…
Browse files Browse the repository at this point in the history
…ying (#24531)
  • Loading branch information
MarshallOfSound committed Jul 27, 2020
1 parent 9350e93 commit 363213e
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 5 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"ENABLE_DESKTOP_CAPTURER": "readonly",
"ENABLE_ELECTRON_EXTENSIONS": "readonly",
"ENABLE_REMOTE_MODULE": "readonly",
"ENABLE_VIEW_API": "readonly"
"ENABLE_VIEW_API": "readonly",
"BigInt": "readonly"
},
"overrides": [
{
Expand Down
11 changes: 11 additions & 0 deletions shell/renderer/api/electron_api_context_bridge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,17 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
return v8::MaybeLocal<v8::Value>();
}
}

// Certain primitives always use the current contexts prototype and we can
// pass these through directly which is significantly more performant than
// copying them. This list of primitives is based on the classification of
// "primitive value" as defined in the ECMA262 spec
// https://tc39.es/ecma262/#sec-primitive-value
if (value->IsString() || value->IsNumber() || value->IsNullOrUndefined() ||
value->IsBoolean() || value->IsSymbol() || value->IsBigInt()) {
return v8::MaybeLocal<v8::Value>(value);
}

// Check Cache
auto cached_value = object_cache->GetCachedProxiedObject(value);
if (!cached_value.IsEmpty()) {
Expand Down
22 changes: 19 additions & 3 deletions spec-main/api-context-bridge-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ describe('contextBridge', () => {
contextBridge.exposeInMainWorld('example', {
1: 123,
2: 456,
'3': 789
3: 789
});
});
const result = await callWithBindings(async (root: any) => {
Expand All @@ -312,6 +312,20 @@ describe('contextBridge', () => {
expect(result).to.deep.equal(['null', 'undefined']);
});

it('should proxy symbols such that symbol equality works', async () => {
await makeBindingWindow(() => {
const mySymbol = Symbol('unique');
contextBridge.exposeInMainWorld('example', {
getSymbol: () => mySymbol,
isSymbol: (s: Symbol) => s === mySymbol
});
});
const result = await callWithBindings((root: any) => {
return root.example.isSymbol(root.example.getSymbol());
});
expect(result).to.equal(true, 'symbols should be equal across contexts');
});

it('should proxy typed arrays and regexps through the serializer', async () => {
await makeBindingWindow(() => {
contextBridge.exposeInMainWorld('example', {
Expand Down Expand Up @@ -447,7 +461,7 @@ describe('contextBridge', () => {
try {
let a: any = [];
for (let i = 0; i < 999; i++) {
a = [ a ];
a = [a];
}
root.example.doThing(a);
return false;
Expand All @@ -460,7 +474,7 @@ describe('contextBridge', () => {
try {
let a: any = [];
for (let i = 0; i < 1000; i++) {
a = [ a ];
a = [a];
}
root.example.doThing(a);
return false;
Expand All @@ -478,6 +492,7 @@ describe('contextBridge', () => {
string: 'string',
boolean: true,
arr: [123, 'string', true, ['foo']],
symbol: Symbol('foo'),
getObject: () => ({ thing: 123 }),
getNumber: () => 123,
getString: () => 'string',
Expand Down Expand Up @@ -510,6 +525,7 @@ describe('contextBridge', () => {
[example.arr[2], Boolean],
[example.arr[3], Array],
[example.arr[3][0], String],
[example.symbol, Symbol],
[example.getNumber, Function],
[example.getNumber(), Number],
[example.getObject(), Object],
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es2017",
"target": "es2020",
"lib": [
"es2019",
"dom",
Expand Down

0 comments on commit 363213e

Please sign in to comment.