@@ -57,6 +57,7 @@ class Interface {
57
57
58
58
this . iterable = null ;
59
59
this . _analyzed = false ;
60
+ this . _needsUnforgeablesObject = false ;
60
61
61
62
this . _outputMethods = new Map ( ) ;
62
63
this . _outputStaticMethods = new Map ( ) ;
@@ -109,14 +110,14 @@ class Interface {
109
110
}
110
111
}
111
112
112
- // whence is either "instance" or "prototype "
113
+ // whence is either "instance", "prototype" or "unforgeables "
113
114
// type is either "regular", "get", or "set"
114
115
addMethod ( whence , propName , args , body , type = "regular" , {
115
116
configurable = true ,
116
117
enumerable = typeof propName === "string" ,
117
118
writable = type === "regular" ? true : undefined
118
119
} = { } ) {
119
- if ( whence !== "instance" && whence !== "prototype" ) {
120
+ if ( whence !== "instance" && whence !== "prototype" && whence !== "unforgeables" ) {
120
121
throw new Error ( `Internal error: Invalid whence ${ whence } ` ) ;
121
122
}
122
123
if ( type !== "regular" ) {
@@ -139,6 +140,10 @@ class Interface {
139
140
140
141
const descriptor = { configurable, enumerable, writable } ;
141
142
this . _outputMethods . set ( propName , { whence, type, args, body, descriptor } ) ;
143
+
144
+ if ( whence === "unforgeables" && ! this . isGlobal ) {
145
+ this . _needsUnforgeablesObject = true ;
146
+ }
142
147
}
143
148
144
149
// type is either "regular", "get", or "set"
@@ -1205,6 +1210,8 @@ class Interface {
1205
1210
}
1206
1211
1207
1212
generateIface ( ) {
1213
+ const { _needsUnforgeablesObject } = this ;
1214
+
1208
1215
this . str += `
1209
1216
function makeWrapper(globalObject, newTarget) {
1210
1217
let proto;
@@ -1252,7 +1259,13 @@ class Interface {
1252
1259
const wrapper = exports.create(globalObject, constructorArgs, privateData);
1253
1260
return utils.implForWrapper(wrapper);
1254
1261
};
1262
+ ` ;
1263
+
1264
+ if ( _needsUnforgeablesObject ) {
1265
+ this . generateUnforgeablesObject ( ) ;
1266
+ }
1255
1267
1268
+ this . str += `
1256
1269
exports._internalSetup = (wrapper, globalObject) => {
1257
1270
` ;
1258
1271
@@ -1262,6 +1275,16 @@ class Interface {
1262
1275
` ;
1263
1276
}
1264
1277
1278
+ if ( _needsUnforgeablesObject ) {
1279
+ this . str += `
1280
+ const unforgeables = getUnforgeables(globalObject);
1281
+ for (const key of Reflect.ownKeys(unforgeables)) {
1282
+ const descriptor = Reflect.getOwnPropertyDescriptor(unforgeables, key);
1283
+ Object.defineProperty(wrapper, key, descriptor);
1284
+ }
1285
+ ` ;
1286
+ }
1287
+
1265
1288
this . generateOnInstance ( ) ;
1266
1289
1267
1290
this . str += `
@@ -1496,6 +1519,7 @@ class Interface {
1496
1519
}
1497
1520
1498
1521
generateOnInstance ( ) {
1522
+ const { isGlobal } = this ;
1499
1523
const methods = [ ] ;
1500
1524
const props = new Map ( ) ;
1501
1525
@@ -1506,7 +1530,7 @@ class Interface {
1506
1530
}
1507
1531
1508
1532
for ( const [ name , { whence, type, args, body, descriptor } ] of this . _outputMethods ) {
1509
- if ( whence !== "instance" ) {
1533
+ if ( whence !== "instance" && ( whence !== "unforgeables" || ! isGlobal ) ) {
1510
1534
continue ;
1511
1535
}
1512
1536
@@ -1564,9 +1588,78 @@ class Interface {
1564
1588
}
1565
1589
}
1566
1590
1591
+ generateUnforgeablesObject ( ) {
1592
+ const methods = [ ] ;
1593
+ const props = new Map ( ) ;
1594
+
1595
+ function addOne ( name , args , body ) {
1596
+ methods . push ( `
1597
+ ${ name } (${ utils . formatArgs ( args ) } ) {${ body } }
1598
+ ` ) ;
1599
+ }
1600
+
1601
+ for ( const [ name , { whence, type, args, body, descriptor } ] of this . _outputMethods ) {
1602
+ if ( whence !== "unforgeables" ) {
1603
+ continue ;
1604
+ }
1605
+
1606
+ const propName = utils . stringifyPropertyKey ( name ) ;
1607
+ if ( type === "regular" ) {
1608
+ addOne ( propName , args , body ) ;
1609
+ } else {
1610
+ if ( body [ 0 ] !== undefined ) {
1611
+ addOne ( `get ${ propName } ` , [ ] , body [ 0 ] ) ;
1612
+ }
1613
+ if ( body [ 1 ] !== undefined ) {
1614
+ addOne ( `set ${ propName } ` , args , body [ 1 ] ) ;
1615
+ }
1616
+ }
1617
+
1618
+ const descriptorModifier = utils . getPropertyDescriptorModifier ( defaultObjectLiteralDescriptor , descriptor , type ) ;
1619
+ if ( descriptorModifier === undefined ) {
1620
+ continue ;
1621
+ }
1622
+ props . set ( utils . stringifyPropertyKey ( name ) , descriptorModifier ) ;
1623
+ }
1624
+
1625
+ this . str += `
1626
+ function getUnforgeables(globalObject) {
1627
+ let unforgeables = unforgeablesMap.get(globalObject);
1628
+ if (unforgeables === undefined) {
1629
+ unforgeables = Object.create(
1630
+ null,
1631
+ ` ;
1632
+
1633
+ if ( methods . length > 0 ) {
1634
+ this . str += `Object.getOwnPropertyDescriptors({ ${ methods . join ( ", " ) } }),` ;
1635
+ }
1636
+
1637
+ this . str += ");" ;
1638
+
1639
+ if ( props . size > 0 ) {
1640
+ const propStrs = [ ...props ] . map ( ( [ name , body ] ) => `${ name } : ${ body } ` ) ;
1641
+ this . str += `
1642
+ Object.defineProperties(unforgeables, {
1643
+ ${ propStrs . join ( ", " ) }
1644
+ });` ;
1645
+ }
1646
+
1647
+ this . str += `
1648
+ unforgeablesMap.set(globalObject, unforgeables);
1649
+ }
1650
+ return unforgeables;
1651
+ }
1652
+ ` ;
1653
+ }
1654
+
1567
1655
generateInstall ( ) {
1568
1656
const { idl, name } = this ;
1569
1657
1658
+ if ( this . _needsUnforgeablesObject ) {
1659
+ this . str += `
1660
+ const unforgeablesMap = new WeakMap();` ;
1661
+ }
1662
+
1570
1663
this . str += `
1571
1664
const exposed = new Set(${ JSON . stringify ( [ ...this . exposed ] ) } );
1572
1665
@@ -1640,6 +1733,7 @@ class Interface {
1640
1733
this . generateExport ( ) ;
1641
1734
this . generateIface ( ) ;
1642
1735
this . generateInstall ( ) ;
1736
+
1643
1737
if ( this . isLegacyPlatformObj ) {
1644
1738
this . generateLegacyProxyHandler ( ) ;
1645
1739
}
0 commit comments