bridge.js 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. 'use strict';
  2. /**
  3. * __ ___ ____ _ _ ___ _ _ ____
  4. * \ \ / / \ | _ \| \ | |_ _| \ | |/ ___|
  5. * \ \ /\ / / _ \ | |_) | \| || || \| | | _
  6. * \ V V / ___ \| _ <| |\ || || |\ | |_| |
  7. * \_/\_/_/ \_\_| \_\_| \_|___|_| \_|\____|
  8. *
  9. * This file is critical for vm2. It implements the bridge between the host and the sandbox.
  10. * If you do not know exactly what you are doing, you should NOT edit this file.
  11. *
  12. * The file is loaded in the host and sandbox to handle objects in both directions.
  13. * This is done to ensure that RangeErrors are from the correct context.
  14. * The boundary between the sandbox and host might throw RangeErrors from both contexts.
  15. * Therefore, thisFromOther and friends can handle objects from both domains.
  16. *
  17. * Method parameters have comments to tell from which context they came.
  18. *
  19. */
  20. const globalsList = [
  21. 'Number',
  22. 'String',
  23. 'Boolean',
  24. 'Date',
  25. 'RegExp',
  26. 'Map',
  27. 'WeakMap',
  28. 'Set',
  29. 'WeakSet',
  30. 'Promise',
  31. 'Function'
  32. ];
  33. const errorsList = [
  34. 'RangeError',
  35. 'ReferenceError',
  36. 'SyntaxError',
  37. 'TypeError',
  38. 'EvalError',
  39. 'URIError',
  40. 'Error'
  41. ];
  42. const OPNA = 'Operation not allowed on contextified object.';
  43. const thisGlobalPrototypes = {
  44. __proto__: null,
  45. Object: Object.prototype,
  46. Array: Array.prototype
  47. };
  48. for (let i = 0; i < globalsList.length; i++) {
  49. const key = globalsList[i];
  50. const g = global[key];
  51. if (g) thisGlobalPrototypes[key] = g.prototype;
  52. }
  53. for (let i = 0; i < errorsList.length; i++) {
  54. const key = errorsList[i];
  55. const g = global[key];
  56. if (g) thisGlobalPrototypes[key] = g.prototype;
  57. }
  58. const {
  59. getPrototypeOf: thisReflectGetPrototypeOf,
  60. setPrototypeOf: thisReflectSetPrototypeOf,
  61. defineProperty: thisReflectDefineProperty,
  62. deleteProperty: thisReflectDeleteProperty,
  63. getOwnPropertyDescriptor: thisReflectGetOwnPropertyDescriptor,
  64. isExtensible: thisReflectIsExtensible,
  65. preventExtensions: thisReflectPreventExtensions,
  66. apply: thisReflectApply,
  67. construct: thisReflectConstruct,
  68. set: thisReflectSet,
  69. get: thisReflectGet,
  70. has: thisReflectHas,
  71. ownKeys: thisReflectOwnKeys,
  72. enumerate: thisReflectEnumerate,
  73. } = Reflect;
  74. const thisObject = Object;
  75. const {
  76. freeze: thisObjectFreeze,
  77. prototype: thisObjectPrototype
  78. } = thisObject;
  79. const thisObjectHasOwnProperty = thisObjectPrototype.hasOwnProperty;
  80. const ThisProxy = Proxy;
  81. const ThisWeakMap = WeakMap;
  82. const {
  83. get: thisWeakMapGet,
  84. set: thisWeakMapSet
  85. } = ThisWeakMap.prototype;
  86. const ThisMap = Map;
  87. const thisMapGet = ThisMap.prototype.get;
  88. const thisMapSet = ThisMap.prototype.set;
  89. const thisFunction = Function;
  90. const thisFunctionBind = thisFunction.prototype.bind;
  91. const thisArrayIsArray = Array.isArray;
  92. const thisErrorCaptureStackTrace = Error.captureStackTrace;
  93. const thisSymbolToString = Symbol.prototype.toString;
  94. const thisSymbolToStringTag = Symbol.toStringTag;
  95. /**
  96. * VMError.
  97. *
  98. * @public
  99. * @extends {Error}
  100. */
  101. class VMError extends Error {
  102. /**
  103. * Create VMError instance.
  104. *
  105. * @public
  106. * @param {string} message - Error message.
  107. * @param {string} code - Error code.
  108. */
  109. constructor(message, code) {
  110. super(message);
  111. this.name = 'VMError';
  112. this.code = code;
  113. thisErrorCaptureStackTrace(this, this.constructor);
  114. }
  115. }
  116. thisGlobalPrototypes['VMError'] = VMError.prototype;
  117. function thisUnexpected() {
  118. return new VMError('Unexpected');
  119. }
  120. if (!thisReflectSetPrototypeOf(exports, null)) throw thisUnexpected();
  121. function thisSafeGetOwnPropertyDescriptor(obj, key) {
  122. const desc = thisReflectGetOwnPropertyDescriptor(obj, key);
  123. if (!desc) return desc;
  124. if (!thisReflectSetPrototypeOf(desc, null)) throw thisUnexpected();
  125. return desc;
  126. }
  127. function thisThrowCallerCalleeArgumentsAccess(key) {
  128. 'use strict';
  129. thisThrowCallerCalleeArgumentsAccess[key];
  130. return thisUnexpected();
  131. }
  132. function thisIdMapping(factory, other) {
  133. return other;
  134. }
  135. const thisThrowOnKeyAccessHandler = thisObjectFreeze({
  136. __proto__: null,
  137. get(target, key, receiver) {
  138. if (typeof key === 'symbol') {
  139. key = thisReflectApply(thisSymbolToString, key, []);
  140. }
  141. throw new VMError(`Unexpected access to key '${key}'`);
  142. }
  143. });
  144. const emptyForzenObject = thisObjectFreeze({
  145. __proto__: null
  146. });
  147. const thisThrowOnKeyAccess = new ThisProxy(emptyForzenObject, thisThrowOnKeyAccessHandler);
  148. function SafeBase() {}
  149. if (!thisReflectDefineProperty(SafeBase, 'prototype', {
  150. __proto__: null,
  151. value: thisThrowOnKeyAccess
  152. })) throw thisUnexpected();
  153. function SHARED_FUNCTION() {}
  154. const TEST_PROXY_HANDLER = thisObjectFreeze({
  155. __proto__: thisThrowOnKeyAccess,
  156. construct() {
  157. return this;
  158. }
  159. });
  160. function thisIsConstructor(obj) {
  161. // Note: obj@any(unsafe)
  162. const Func = new ThisProxy(obj, TEST_PROXY_HANDLER);
  163. try {
  164. // eslint-disable-next-line no-new
  165. new Func();
  166. return true;
  167. } catch (e) {
  168. return false;
  169. }
  170. }
  171. function thisCreateTargetObject(obj, proto) {
  172. // Note: obj@any(unsafe) proto@any(unsafe) returns@this(unsafe) throws@this(unsafe)
  173. let base;
  174. if (typeof obj === 'function') {
  175. if (thisIsConstructor(obj)) {
  176. // Bind the function since bound functions do not have a prototype property.
  177. base = thisReflectApply(thisFunctionBind, SHARED_FUNCTION, [null]);
  178. } else {
  179. base = () => {};
  180. }
  181. } else if (thisArrayIsArray(obj)) {
  182. base = [];
  183. } else {
  184. return {__proto__: proto};
  185. }
  186. if (!thisReflectSetPrototypeOf(base, proto)) throw thisUnexpected();
  187. return base;
  188. }
  189. function createBridge(otherInit, registerProxy) {
  190. const mappingOtherToThis = new ThisWeakMap();
  191. const protoMappings = new ThisMap();
  192. const protoName = new ThisMap();
  193. function thisAddProtoMapping(proto, other, name) {
  194. // Note: proto@this(unsafe) other@other(unsafe) name@this(unsafe) throws@this(unsafe)
  195. thisReflectApply(thisMapSet, protoMappings, [proto, thisIdMapping]);
  196. thisReflectApply(thisMapSet, protoMappings, [other,
  197. (factory, object) => thisProxyOther(factory, object, proto)]);
  198. if (name) thisReflectApply(thisMapSet, protoName, [proto, name]);
  199. }
  200. function thisAddProtoMappingFactory(protoFactory, other, name) {
  201. // Note: protoFactory@this(unsafe) other@other(unsafe) name@this(unsafe) throws@this(unsafe)
  202. let proto;
  203. thisReflectApply(thisMapSet, protoMappings, [other,
  204. (factory, object) => {
  205. if (!proto) {
  206. proto = protoFactory();
  207. thisReflectApply(thisMapSet, protoMappings, [proto, thisIdMapping]);
  208. if (name) thisReflectApply(thisMapSet, protoName, [proto, name]);
  209. }
  210. return thisProxyOther(factory, object, proto);
  211. }]);
  212. }
  213. const result = {
  214. __proto__: null,
  215. globalPrototypes: thisGlobalPrototypes,
  216. safeGetOwnPropertyDescriptor: thisSafeGetOwnPropertyDescriptor,
  217. fromArguments: thisFromOtherArguments,
  218. from: thisFromOther,
  219. fromWithFactory: thisFromOtherWithFactory,
  220. ensureThis: thisEnsureThis,
  221. mapping: mappingOtherToThis,
  222. connect: thisConnect,
  223. reflectSet: thisReflectSet,
  224. reflectGet: thisReflectGet,
  225. reflectDefineProperty: thisReflectDefineProperty,
  226. reflectDeleteProperty: thisReflectDeleteProperty,
  227. reflectApply: thisReflectApply,
  228. reflectConstruct: thisReflectConstruct,
  229. reflectHas: thisReflectHas,
  230. reflectOwnKeys: thisReflectOwnKeys,
  231. reflectEnumerate: thisReflectEnumerate,
  232. reflectGetPrototypeOf: thisReflectGetPrototypeOf,
  233. reflectIsExtensible: thisReflectIsExtensible,
  234. reflectPreventExtensions: thisReflectPreventExtensions,
  235. objectHasOwnProperty: thisObjectHasOwnProperty,
  236. weakMapSet: thisWeakMapSet,
  237. addProtoMapping: thisAddProtoMapping,
  238. addProtoMappingFactory: thisAddProtoMappingFactory,
  239. defaultFactory,
  240. protectedFactory,
  241. readonlyFactory,
  242. VMError
  243. };
  244. const isHost = typeof otherInit !== 'object';
  245. if (isHost) {
  246. otherInit = otherInit(result, registerProxy);
  247. }
  248. result.other = otherInit;
  249. const {
  250. globalPrototypes: otherGlobalPrototypes,
  251. safeGetOwnPropertyDescriptor: otherSafeGetOwnPropertyDescriptor,
  252. fromArguments: otherFromThisArguments,
  253. from: otherFromThis,
  254. mapping: mappingThisToOther,
  255. reflectSet: otherReflectSet,
  256. reflectGet: otherReflectGet,
  257. reflectDefineProperty: otherReflectDefineProperty,
  258. reflectDeleteProperty: otherReflectDeleteProperty,
  259. reflectApply: otherReflectApply,
  260. reflectConstruct: otherReflectConstruct,
  261. reflectHas: otherReflectHas,
  262. reflectOwnKeys: otherReflectOwnKeys,
  263. reflectEnumerate: otherReflectEnumerate,
  264. reflectGetPrototypeOf: otherReflectGetPrototypeOf,
  265. reflectIsExtensible: otherReflectIsExtensible,
  266. reflectPreventExtensions: otherReflectPreventExtensions,
  267. objectHasOwnProperty: otherObjectHasOwnProperty,
  268. weakMapSet: otherWeakMapSet
  269. } = otherInit;
  270. function thisOtherHasOwnProperty(object, key) {
  271. // Note: object@other(safe) key@prim throws@this(unsafe)
  272. try {
  273. return otherReflectApply(otherObjectHasOwnProperty, object, [key]) === true;
  274. } catch (e) { // @other(unsafe)
  275. throw thisFromOtherForThrow(e);
  276. }
  277. }
  278. function thisDefaultGet(handler, object, key, desc) {
  279. // Note: object@other(unsafe) key@prim desc@other(safe)
  280. let ret; // @other(unsafe)
  281. if (desc.get || desc.set) {
  282. const getter = desc.get;
  283. if (!getter) return undefined;
  284. try {
  285. ret = otherReflectApply(getter, object, [key]);
  286. } catch (e) {
  287. throw thisFromOtherForThrow(e);
  288. }
  289. } else {
  290. ret = desc.value;
  291. }
  292. return handler.fromOtherWithContext(ret);
  293. }
  294. function otherFromThisIfAvailable(to, from, key) {
  295. // Note: to@other(safe) from@this(safe) key@prim throws@this(unsafe)
  296. if (!thisReflectApply(thisObjectHasOwnProperty, from, [key])) return false;
  297. try {
  298. to[key] = otherFromThis(from[key]);
  299. } catch (e) { // @other(unsafe)
  300. throw thisFromOtherForThrow(e);
  301. }
  302. return true;
  303. }
  304. class BaseHandler extends SafeBase {
  305. constructor(object) {
  306. // Note: object@other(unsafe) throws@this(unsafe)
  307. super();
  308. this.object = object;
  309. }
  310. getFactory() {
  311. return defaultFactory;
  312. }
  313. fromOtherWithContext(other) {
  314. // Note: other@other(unsafe) throws@this(unsafe)
  315. return thisFromOtherWithFactory(this.getFactory(), other);
  316. }
  317. doPreventExtensions(target, object, factory) {
  318. // Note: target@this(unsafe) object@other(unsafe) throws@this(unsafe)
  319. let keys; // @other(safe-array-of-prim)
  320. try {
  321. keys = otherReflectOwnKeys(object);
  322. } catch (e) { // @other(unsafe)
  323. throw thisFromOtherForThrow(e);
  324. }
  325. for (let i = 0; i < keys.length; i++) {
  326. const key = keys[i]; // @prim
  327. let desc;
  328. try {
  329. desc = otherSafeGetOwnPropertyDescriptor(object, key);
  330. } catch (e) { // @other(unsafe)
  331. throw thisFromOtherForThrow(e);
  332. }
  333. if (!desc) continue;
  334. if (!desc.configurable) {
  335. const current = thisSafeGetOwnPropertyDescriptor(target, key);
  336. if (current && !current.configurable) continue;
  337. if (desc.get || desc.set) {
  338. desc.get = this.fromOtherWithContext(desc.get);
  339. desc.set = this.fromOtherWithContext(desc.set);
  340. } else if (typeof object === 'function' && (key === 'caller' || key === 'callee' || key === 'arguments')) {
  341. desc.value = null;
  342. } else {
  343. desc.value = this.fromOtherWithContext(desc.value);
  344. }
  345. } else {
  346. if (desc.get || desc.set) {
  347. desc = {
  348. __proto__: null,
  349. configurable: true,
  350. enumerable: desc.enumerable,
  351. writable: true,
  352. value: null
  353. };
  354. } else {
  355. desc.value = null;
  356. }
  357. }
  358. if (!thisReflectDefineProperty(target, key, desc)) throw thisUnexpected();
  359. }
  360. if (!thisReflectPreventExtensions(target)) throw thisUnexpected();
  361. }
  362. get(target, key, receiver) {
  363. // Note: target@this(unsafe) key@prim receiver@this(unsafe) throws@this(unsafe)
  364. const object = this.object; // @other(unsafe)
  365. switch (key) {
  366. case 'constructor': {
  367. const desc = otherSafeGetOwnPropertyDescriptor(object, key);
  368. if (desc) return thisDefaultGet(this, object, key, desc);
  369. const proto = thisReflectGetPrototypeOf(target);
  370. return proto === null ? undefined : proto.constructor;
  371. }
  372. case '__proto__': {
  373. const desc = otherSafeGetOwnPropertyDescriptor(object, key);
  374. if (desc) return thisDefaultGet(this, object, key, desc);
  375. return thisReflectGetPrototypeOf(target);
  376. }
  377. case thisSymbolToStringTag:
  378. if (!thisOtherHasOwnProperty(object, thisSymbolToStringTag)) {
  379. const proto = thisReflectGetPrototypeOf(target);
  380. const name = thisReflectApply(thisMapGet, protoName, [proto]);
  381. if (name) return name;
  382. }
  383. break;
  384. case 'arguments':
  385. case 'caller':
  386. case 'callee':
  387. if (typeof object === 'function' && thisOtherHasOwnProperty(object, key)) {
  388. throw thisThrowCallerCalleeArgumentsAccess(key);
  389. }
  390. break;
  391. }
  392. let ret; // @other(unsafe)
  393. try {
  394. ret = otherReflectGet(object, key);
  395. } catch (e) { // @other(unsafe)
  396. throw thisFromOtherForThrow(e);
  397. }
  398. return this.fromOtherWithContext(ret);
  399. }
  400. set(target, key, value, receiver) {
  401. // Note: target@this(unsafe) key@prim value@this(unsafe) receiver@this(unsafe) throws@this(unsafe)
  402. const object = this.object; // @other(unsafe)
  403. if (key === '__proto__' && !thisOtherHasOwnProperty(object, key)) {
  404. return this.setPrototypeOf(target, value);
  405. }
  406. try {
  407. value = otherFromThis(value);
  408. return otherReflectSet(object, key, value) === true;
  409. } catch (e) { // @other(unsafe)
  410. throw thisFromOtherForThrow(e);
  411. }
  412. }
  413. getPrototypeOf(target) {
  414. // Note: target@this(unsafe)
  415. return thisReflectGetPrototypeOf(target);
  416. }
  417. setPrototypeOf(target, value) {
  418. // Note: target@this(unsafe) throws@this(unsafe)
  419. throw new VMError(OPNA);
  420. }
  421. apply(target, context, args) {
  422. // Note: target@this(unsafe) context@this(unsafe) args@this(safe-array) throws@this(unsafe)
  423. const object = this.object; // @other(unsafe)
  424. let ret; // @other(unsafe)
  425. try {
  426. context = otherFromThis(context);
  427. args = otherFromThisArguments(args);
  428. ret = otherReflectApply(object, context, args);
  429. } catch (e) { // @other(unsafe)
  430. throw thisFromOtherForThrow(e);
  431. }
  432. return thisFromOther(ret);
  433. }
  434. construct(target, args, newTarget) {
  435. // Note: target@this(unsafe) args@this(safe-array) newTarget@this(unsafe) throws@this(unsafe)
  436. const object = this.object; // @other(unsafe)
  437. let ret; // @other(unsafe)
  438. try {
  439. args = otherFromThisArguments(args);
  440. ret = otherReflectConstruct(object, args);
  441. } catch (e) { // @other(unsafe)
  442. throw thisFromOtherForThrow(e);
  443. }
  444. return thisFromOtherWithFactory(this.getFactory(), ret, thisFromOther(object));
  445. }
  446. getOwnPropertyDescriptorDesc(target, prop, desc) {
  447. // Note: target@this(unsafe) prop@prim desc@other{safe} throws@this(unsafe)
  448. const object = this.object; // @other(unsafe)
  449. if (desc && typeof object === 'function' && (prop === 'arguments' || prop === 'caller' || prop === 'callee')) desc.value = null;
  450. return desc;
  451. }
  452. getOwnPropertyDescriptor(target, prop) {
  453. // Note: target@this(unsafe) prop@prim throws@this(unsafe)
  454. const object = this.object; // @other(unsafe)
  455. let desc; // @other(safe)
  456. try {
  457. desc = otherSafeGetOwnPropertyDescriptor(object, prop);
  458. } catch (e) { // @other(unsafe)
  459. throw thisFromOtherForThrow(e);
  460. }
  461. desc = this.getOwnPropertyDescriptorDesc(target, prop, desc);
  462. if (!desc) return undefined;
  463. let thisDesc;
  464. if (desc.get || desc.set) {
  465. thisDesc = {
  466. __proto__: null,
  467. get: this.fromOtherWithContext(desc.get),
  468. set: this.fromOtherWithContext(desc.set),
  469. enumerable: desc.enumerable === true,
  470. configurable: desc.configurable === true
  471. };
  472. } else {
  473. thisDesc = {
  474. __proto__: null,
  475. value: this.fromOtherWithContext(desc.value),
  476. writable: desc.writable === true,
  477. enumerable: desc.enumerable === true,
  478. configurable: desc.configurable === true
  479. };
  480. }
  481. if (!thisDesc.configurable) {
  482. const oldDesc = thisSafeGetOwnPropertyDescriptor(target, prop);
  483. if (!oldDesc || oldDesc.configurable || oldDesc.writable !== thisDesc.writable) {
  484. if (!thisReflectDefineProperty(target, prop, thisDesc)) throw thisUnexpected();
  485. }
  486. }
  487. return thisDesc;
  488. }
  489. definePropertyDesc(target, prop, desc) {
  490. // Note: target@this(unsafe) prop@prim desc@this(safe) throws@this(unsafe)
  491. return desc;
  492. }
  493. defineProperty(target, prop, desc) {
  494. // Note: target@this(unsafe) prop@prim desc@this(unsafe) throws@this(unsafe)
  495. const object = this.object; // @other(unsafe)
  496. if (!thisReflectSetPrototypeOf(desc, null)) throw thisUnexpected();
  497. desc = this.definePropertyDesc(target, prop, desc);
  498. if (!desc) return false;
  499. let otherDesc = {__proto__: null};
  500. let hasFunc = true;
  501. let hasValue = true;
  502. let hasBasic = true;
  503. hasFunc &= otherFromThisIfAvailable(otherDesc, desc, 'get');
  504. hasFunc &= otherFromThisIfAvailable(otherDesc, desc, 'set');
  505. hasValue &= otherFromThisIfAvailable(otherDesc, desc, 'value');
  506. hasValue &= otherFromThisIfAvailable(otherDesc, desc, 'writable');
  507. hasBasic &= otherFromThisIfAvailable(otherDesc, desc, 'enumerable');
  508. hasBasic &= otherFromThisIfAvailable(otherDesc, desc, 'configurable');
  509. try {
  510. if (!otherReflectDefineProperty(object, prop, otherDesc)) return false;
  511. if (otherDesc.configurable !== true && (!hasBasic || !(hasFunc || hasValue))) {
  512. otherDesc = otherSafeGetOwnPropertyDescriptor(object, prop);
  513. }
  514. } catch (e) { // @other(unsafe)
  515. throw thisFromOtherForThrow(e);
  516. }
  517. if (!otherDesc.configurable) {
  518. let thisDesc;
  519. if (otherDesc.get || otherDesc.set) {
  520. thisDesc = {
  521. __proto__: null,
  522. get: this.fromOtherWithContext(otherDesc.get),
  523. set: this.fromOtherWithContext(otherDesc.set),
  524. enumerable: otherDesc.enumerable,
  525. configurable: otherDesc.configurable
  526. };
  527. } else {
  528. thisDesc = {
  529. __proto__: null,
  530. value: this.fromOtherWithContext(otherDesc.value),
  531. writable: otherDesc.writable,
  532. enumerable: otherDesc.enumerable,
  533. configurable: otherDesc.configurable
  534. };
  535. }
  536. if (!thisReflectDefineProperty(target, prop, thisDesc)) throw thisUnexpected();
  537. }
  538. return true;
  539. }
  540. deleteProperty(target, prop) {
  541. // Note: target@this(unsafe) prop@prim throws@this(unsafe)
  542. const object = this.object; // @other(unsafe)
  543. try {
  544. return otherReflectDeleteProperty(object, prop) === true;
  545. } catch (e) { // @other(unsafe)
  546. throw thisFromOtherForThrow(e);
  547. }
  548. }
  549. has(target, key) {
  550. // Note: target@this(unsafe) key@prim throws@this(unsafe)
  551. const object = this.object; // @other(unsafe)
  552. try {
  553. return otherReflectHas(object, key) === true;
  554. } catch (e) { // @other(unsafe)
  555. throw thisFromOtherForThrow(e);
  556. }
  557. }
  558. isExtensible(target) {
  559. // Note: target@this(unsafe) throws@this(unsafe)
  560. const object = this.object; // @other(unsafe)
  561. try {
  562. if (otherReflectIsExtensible(object)) return true;
  563. } catch (e) { // @other(unsafe)
  564. throw thisFromOtherForThrow(e);
  565. }
  566. if (thisReflectIsExtensible(target)) {
  567. this.doPreventExtensions(target, object, this);
  568. }
  569. return false;
  570. }
  571. ownKeys(target) {
  572. // Note: target@this(unsafe) throws@this(unsafe)
  573. const object = this.object; // @other(unsafe)
  574. let res; // @other(unsafe)
  575. try {
  576. res = otherReflectOwnKeys(object);
  577. } catch (e) { // @other(unsafe)
  578. throw thisFromOtherForThrow(e);
  579. }
  580. return thisFromOther(res);
  581. }
  582. preventExtensions(target) {
  583. // Note: target@this(unsafe) throws@this(unsafe)
  584. const object = this.object; // @other(unsafe)
  585. try {
  586. if (!otherReflectPreventExtensions(object)) return false;
  587. } catch (e) { // @other(unsafe)
  588. throw thisFromOtherForThrow(e);
  589. }
  590. if (thisReflectIsExtensible(target)) {
  591. this.doPreventExtensions(target, object, this);
  592. }
  593. return true;
  594. }
  595. enumerate(target) {
  596. // Note: target@this(unsafe) throws@this(unsafe)
  597. const object = this.object; // @other(unsafe)
  598. let res; // @other(unsafe)
  599. try {
  600. res = otherReflectEnumerate(object);
  601. } catch (e) { // @other(unsafe)
  602. throw thisFromOtherForThrow(e);
  603. }
  604. return this.fromOtherWithContext(res);
  605. }
  606. }
  607. function defaultFactory(object) {
  608. // Note: other@other(unsafe) returns@this(unsafe) throws@this(unsafe)
  609. return new BaseHandler(object);
  610. }
  611. class ProtectedHandler extends BaseHandler {
  612. getFactory() {
  613. return protectedFactory;
  614. }
  615. set(target, key, value, receiver) {
  616. // Note: target@this(unsafe) key@prim value@this(unsafe) receiver@this(unsafe) throws@this(unsafe)
  617. if (typeof value === 'function') {
  618. return thisReflectDefineProperty(receiver, key, {
  619. __proto__: null,
  620. value: value,
  621. writable: true,
  622. enumerable: true,
  623. configurable: true
  624. }) === true;
  625. }
  626. return super.set(target, key, value, receiver);
  627. }
  628. definePropertyDesc(target, prop, desc) {
  629. // Note: target@this(unsafe) prop@prim desc@this(safe) throws@this(unsafe)
  630. if (desc && (desc.set || desc.get || typeof desc.value === 'function')) return undefined;
  631. return desc;
  632. }
  633. }
  634. function protectedFactory(object) {
  635. // Note: other@other(unsafe) returns@this(unsafe) throws@this(unsafe)
  636. return new ProtectedHandler(object);
  637. }
  638. class ReadOnlyHandler extends BaseHandler {
  639. getFactory() {
  640. return readonlyFactory;
  641. }
  642. set(target, key, value, receiver) {
  643. // Note: target@this(unsafe) key@prim value@this(unsafe) receiver@this(unsafe) throws@this(unsafe)
  644. return thisReflectDefineProperty(receiver, key, {
  645. __proto__: null,
  646. value: value,
  647. writable: true,
  648. enumerable: true,
  649. configurable: true
  650. });
  651. }
  652. setPrototypeOf(target, value) {
  653. // Note: target@this(unsafe) throws@this(unsafe)
  654. return false;
  655. }
  656. defineProperty(target, prop, desc) {
  657. // Note: target@this(unsafe) prop@prim desc@this(unsafe) throws@this(unsafe)
  658. return false;
  659. }
  660. deleteProperty(target, prop) {
  661. // Note: target@this(unsafe) prop@prim throws@this(unsafe)
  662. return false;
  663. }
  664. isExtensible(target) {
  665. // Note: target@this(unsafe) throws@this(unsafe)
  666. return false;
  667. }
  668. preventExtensions(target) {
  669. // Note: target@this(unsafe) throws@this(unsafe)
  670. return false;
  671. }
  672. }
  673. function readonlyFactory(object) {
  674. // Note: other@other(unsafe) returns@this(unsafe) throws@this(unsafe)
  675. return new ReadOnlyHandler(object);
  676. }
  677. class ReadOnlyMockHandler extends ReadOnlyHandler {
  678. constructor(object, mock) {
  679. // Note: object@other(unsafe) mock:this(unsafe) throws@this(unsafe)
  680. super(object);
  681. this.mock = mock;
  682. }
  683. get(target, key, receiver) {
  684. // Note: target@this(unsafe) key@prim receiver@this(unsafe) throws@this(unsafe)
  685. const object = this.object; // @other(unsafe)
  686. const mock = this.mock;
  687. if (thisReflectApply(thisObjectHasOwnProperty, mock, key) && !thisOtherHasOwnProperty(object, key)) {
  688. return mock[key];
  689. }
  690. return super.get(target, key, receiver);
  691. }
  692. }
  693. function thisFromOther(other) {
  694. // Note: other@other(unsafe) returns@this(unsafe) throws@this(unsafe)
  695. return thisFromOtherWithFactory(defaultFactory, other);
  696. }
  697. function thisProxyOther(factory, other, proto) {
  698. const target = thisCreateTargetObject(other, proto);
  699. const handler = factory(other);
  700. const proxy = new ThisProxy(target, handler);
  701. try {
  702. otherReflectApply(otherWeakMapSet, mappingThisToOther, [proxy, other]);
  703. registerProxy(proxy, handler);
  704. } catch (e) {
  705. throw new VMError('Unexpected error');
  706. }
  707. if (!isHost) {
  708. thisReflectApply(thisWeakMapSet, mappingOtherToThis, [other, proxy]);
  709. return proxy;
  710. }
  711. const proxy2 = new ThisProxy(proxy, emptyForzenObject);
  712. try {
  713. otherReflectApply(otherWeakMapSet, mappingThisToOther, [proxy2, other]);
  714. registerProxy(proxy2, handler);
  715. } catch (e) {
  716. throw new VMError('Unexpected error');
  717. }
  718. thisReflectApply(thisWeakMapSet, mappingOtherToThis, [other, proxy2]);
  719. return proxy2;
  720. }
  721. function thisEnsureThis(other) {
  722. const type = typeof other;
  723. switch (type) {
  724. case 'object':
  725. if (other === null) {
  726. return null;
  727. }
  728. // fallthrough
  729. case 'function':
  730. let proto = thisReflectGetPrototypeOf(other);
  731. if (!proto) {
  732. return other;
  733. }
  734. while (proto) {
  735. const mapping = thisReflectApply(thisMapGet, protoMappings, [proto]);
  736. if (mapping) {
  737. const mapped = thisReflectApply(thisWeakMapGet, mappingOtherToThis, [other]);
  738. if (mapped) return mapped;
  739. return mapping(defaultFactory, other);
  740. }
  741. proto = thisReflectGetPrototypeOf(proto);
  742. }
  743. return other;
  744. case 'undefined':
  745. case 'string':
  746. case 'number':
  747. case 'boolean':
  748. case 'symbol':
  749. case 'bigint':
  750. return other;
  751. default: // new, unknown types can be dangerous
  752. throw new VMError(`Unknown type '${type}'`);
  753. }
  754. }
  755. function thisFromOtherForThrow(other) {
  756. for (let loop = 0; loop < 10; loop++) {
  757. const type = typeof other;
  758. switch (type) {
  759. case 'object':
  760. if (other === null) {
  761. return null;
  762. }
  763. // fallthrough
  764. case 'function':
  765. const mapped = thisReflectApply(thisWeakMapGet, mappingOtherToThis, [other]);
  766. if (mapped) return mapped;
  767. let proto;
  768. try {
  769. proto = otherReflectGetPrototypeOf(other);
  770. } catch (e) { // @other(unsafe)
  771. other = e;
  772. break;
  773. }
  774. if (!proto) {
  775. return thisProxyOther(defaultFactory, other, null);
  776. }
  777. for (;;) {
  778. const mapping = thisReflectApply(thisMapGet, protoMappings, [proto]);
  779. if (mapping) return mapping(defaultFactory, other);
  780. try {
  781. proto = otherReflectGetPrototypeOf(proto);
  782. } catch (e) { // @other(unsafe)
  783. other = e;
  784. break;
  785. }
  786. if (!proto) return thisProxyOther(defaultFactory, other, thisObjectPrototype);
  787. }
  788. break;
  789. case 'undefined':
  790. case 'string':
  791. case 'number':
  792. case 'boolean':
  793. case 'symbol':
  794. case 'bigint':
  795. return other;
  796. default: // new, unknown types can be dangerous
  797. throw new VMError(`Unknown type '${type}'`);
  798. }
  799. }
  800. throw new VMError('Exception recursion depth');
  801. }
  802. function thisFromOtherWithFactory(factory, other, proto) {
  803. const type = typeof other;
  804. switch (type) {
  805. case 'object':
  806. if (other === null) {
  807. return null;
  808. }
  809. // fallthrough
  810. case 'function':
  811. const mapped = thisReflectApply(thisWeakMapGet, mappingOtherToThis, [other]);
  812. if (mapped) return mapped;
  813. if (proto) {
  814. return thisProxyOther(factory, other, proto);
  815. }
  816. try {
  817. proto = otherReflectGetPrototypeOf(other);
  818. } catch (e) { // @other(unsafe)
  819. throw thisFromOtherForThrow(e);
  820. }
  821. if (!proto) {
  822. return thisProxyOther(factory, other, null);
  823. }
  824. do {
  825. const mapping = thisReflectApply(thisMapGet, protoMappings, [proto]);
  826. if (mapping) return mapping(factory, other);
  827. try {
  828. proto = otherReflectGetPrototypeOf(proto);
  829. } catch (e) { // @other(unsafe)
  830. throw thisFromOtherForThrow(e);
  831. }
  832. } while (proto);
  833. return thisProxyOther(factory, other, thisObjectPrototype);
  834. case 'undefined':
  835. case 'string':
  836. case 'number':
  837. case 'boolean':
  838. case 'symbol':
  839. case 'bigint':
  840. return other;
  841. default: // new, unknown types can be dangerous
  842. throw new VMError(`Unknown type '${type}'`);
  843. }
  844. }
  845. function thisFromOtherArguments(args) {
  846. // Note: args@other(safe-array) returns@this(safe-array) throws@this(unsafe)
  847. const arr = [];
  848. for (let i = 0; i < args.length; i++) {
  849. const value = thisFromOther(args[i]);
  850. thisReflectDefineProperty(arr, i, {
  851. __proto__: null,
  852. value: value,
  853. writable: true,
  854. enumerable: true,
  855. configurable: true
  856. });
  857. }
  858. return arr;
  859. }
  860. function thisConnect(obj, other) {
  861. // Note: obj@this(unsafe) other@other(unsafe) throws@this(unsafe)
  862. try {
  863. otherReflectApply(otherWeakMapSet, mappingThisToOther, [obj, other]);
  864. } catch (e) {
  865. throw new VMError('Unexpected error');
  866. }
  867. thisReflectApply(thisWeakMapSet, mappingOtherToThis, [other, obj]);
  868. }
  869. thisAddProtoMapping(thisGlobalPrototypes.Object, otherGlobalPrototypes.Object);
  870. thisAddProtoMapping(thisGlobalPrototypes.Array, otherGlobalPrototypes.Array);
  871. for (let i = 0; i < globalsList.length; i++) {
  872. const key = globalsList[i];
  873. const tp = thisGlobalPrototypes[key];
  874. const op = otherGlobalPrototypes[key];
  875. if (tp && op) thisAddProtoMapping(tp, op, key);
  876. }
  877. for (let i = 0; i < errorsList.length; i++) {
  878. const key = errorsList[i];
  879. const tp = thisGlobalPrototypes[key];
  880. const op = otherGlobalPrototypes[key];
  881. if (tp && op) thisAddProtoMapping(tp, op, 'Error');
  882. }
  883. thisAddProtoMapping(thisGlobalPrototypes.VMError, otherGlobalPrototypes.VMError, 'Error');
  884. result.BaseHandler = BaseHandler;
  885. result.ProtectedHandler = ProtectedHandler;
  886. result.ReadOnlyHandler = ReadOnlyHandler;
  887. result.ReadOnlyMockHandler = ReadOnlyMockHandler;
  888. return result;
  889. }
  890. exports.createBridge = createBridge;
  891. exports.VMError = VMError;