PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/js/src/jsproxy.cpp

http://github.com/zpao/v8monkey
C++ | 1821 lines | 1552 code | 200 blank | 69 comment | 173 complexity | 11c588c768d4872c0722d362edc57afc MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, AGPL-1.0, LGPL-2.1, BSD-3-Clause, GPL-2.0, JSON, Apache-2.0, 0BSD
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=4 sw=4 et tw=99:
  3. *
  4. * ***** BEGIN LICENSE BLOCK *****
  5. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6. *
  7. * The contents of this file are subject to the Mozilla Public License Version
  8. * 1.1 (the "License"); you may not use this file except in compliance with
  9. * the License. You may obtain a copy of the License at
  10. * http://www.mozilla.org/MPL/
  11. *
  12. * Software distributed under the License is distributed on an "AS IS" basis,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. * for the specific language governing rights and limitations under the
  15. * License.
  16. *
  17. * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
  18. * May 28, 2008.
  19. *
  20. * The Initial Developer of the Original Code is
  21. * Mozilla Foundation
  22. * Portions created by the Initial Developer are Copyright (C) 2009
  23. * the Initial Developer. All Rights Reserved.
  24. *
  25. * Contributor(s):
  26. * Andreas Gal <gal@mozilla.com>
  27. *
  28. * Alternatively, the contents of this file may be used under the terms of
  29. * either of the GNU General Public License Version 2 or later (the "GPL"),
  30. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  31. * in which case the provisions of the GPL or the LGPL are applicable instead
  32. * of those above. If you wish to allow use of your version of this file only
  33. * under the terms of either the GPL or the LGPL, and not to allow others to
  34. * use your version of this file under the terms of the MPL, indicate your
  35. * decision by deleting the provisions above and replace them with the notice
  36. * and other provisions required by the GPL or the LGPL. If you do not delete
  37. * the provisions above, a recipient may use your version of this file under
  38. * the terms of any one of the MPL, the GPL or the LGPL.
  39. *
  40. * ***** END LICENSE BLOCK ***** */
  41. #include <string.h>
  42. #include "jsapi.h"
  43. #include "jscntxt.h"
  44. #include "jsgc.h"
  45. #include "jsgcmark.h"
  46. #include "jsprvtd.h"
  47. #include "jsnum.h"
  48. #include "jsobj.h"
  49. #include "jsproxy.h"
  50. #include "jsscope.h"
  51. #include "jsatominlines.h"
  52. #include "jsinferinlines.h"
  53. #include "jsobjinlines.h"
  54. using namespace js;
  55. using namespace js::gc;
  56. static inline const HeapValue &
  57. GetCall(JSObject *proxy)
  58. {
  59. JS_ASSERT(IsFunctionProxy(proxy));
  60. return proxy->getSlotRef(JSSLOT_PROXY_CALL);
  61. }
  62. static inline Value
  63. GetConstruct(JSObject *proxy)
  64. {
  65. if (proxy->slotSpan() <= JSSLOT_PROXY_CONSTRUCT)
  66. return UndefinedValue();
  67. return proxy->getSlot(JSSLOT_PROXY_CONSTRUCT);
  68. }
  69. static inline const HeapValue &
  70. GetFunctionProxyConstruct(JSObject *proxy)
  71. {
  72. JS_ASSERT(IsFunctionProxy(proxy));
  73. JS_ASSERT(proxy->slotSpan() > JSSLOT_PROXY_CONSTRUCT);
  74. return proxy->getSlotRef(JSSLOT_PROXY_CONSTRUCT);
  75. }
  76. static bool
  77. OperationInProgress(JSContext *cx, JSObject *proxy)
  78. {
  79. PendingProxyOperation *op = cx->runtime->pendingProxyOperation;
  80. while (op) {
  81. if (op->object == proxy)
  82. return true;
  83. op = op->next;
  84. }
  85. return false;
  86. }
  87. ProxyHandler::ProxyHandler(void *family) : mFamily(family)
  88. {
  89. }
  90. ProxyHandler::~ProxyHandler()
  91. {
  92. }
  93. bool
  94. ProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
  95. {
  96. JS_ASSERT(OperationInProgress(cx, proxy));
  97. AutoPropertyDescriptorRooter desc(cx);
  98. if (!getPropertyDescriptor(cx, proxy, id, false, &desc))
  99. return false;
  100. *bp = !!desc.obj;
  101. return true;
  102. }
  103. bool
  104. ProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
  105. {
  106. JS_ASSERT(OperationInProgress(cx, proxy));
  107. AutoPropertyDescriptorRooter desc(cx);
  108. if (!getOwnPropertyDescriptor(cx, proxy, id, false, &desc))
  109. return false;
  110. *bp = !!desc.obj;
  111. return true;
  112. }
  113. bool
  114. ProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
  115. {
  116. JS_ASSERT(OperationInProgress(cx, proxy));
  117. AutoPropertyDescriptorRooter desc(cx);
  118. if (!getPropertyDescriptor(cx, proxy, id, false, &desc))
  119. return false;
  120. if (!desc.obj) {
  121. vp->setUndefined();
  122. return true;
  123. }
  124. if (!desc.getter ||
  125. (!(desc.attrs & JSPROP_GETTER) && desc.getter == JS_PropertyStub)) {
  126. *vp = desc.value;
  127. return true;
  128. }
  129. if (desc.attrs & JSPROP_GETTER)
  130. return InvokeGetterOrSetter(cx, receiver, CastAsObjectJsval(desc.getter), 0, NULL, vp);
  131. if (!(desc.attrs & JSPROP_SHARED))
  132. *vp = desc.value;
  133. else
  134. vp->setUndefined();
  135. if (desc.attrs & JSPROP_SHORTID)
  136. id = INT_TO_JSID(desc.shortid);
  137. return CallJSPropertyOp(cx, desc.getter, receiver, id, vp);
  138. }
  139. bool
  140. ProxyHandler::getElementIfPresent(JSContext *cx, JSObject *proxy, JSObject *receiver, uint32_t index, Value *vp, bool *present)
  141. {
  142. jsid id;
  143. if (!IndexToId(cx, index, &id))
  144. return false;
  145. if (!has(cx, proxy, id, present))
  146. return false;
  147. if (!*present) {
  148. Debug_SetValueRangeToCrashOnTouch(vp, 1);
  149. return true;
  150. }
  151. return get(cx, proxy, receiver, id, vp);
  152. }
  153. bool
  154. ProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
  155. Value *vp)
  156. {
  157. JS_ASSERT(OperationInProgress(cx, proxy));
  158. AutoPropertyDescriptorRooter desc(cx);
  159. if (!getOwnPropertyDescriptor(cx, proxy, id, true, &desc))
  160. return false;
  161. /* The control-flow here differs from ::get() because of the fall-through case below. */
  162. if (desc.obj) {
  163. if (desc.attrs & JSPROP_READONLY)
  164. return true;
  165. if (!desc.setter) {
  166. // Be wary of the odd explicit undefined setter case possible through
  167. // Object.defineProperty.
  168. if (!(desc.attrs & JSPROP_SETTER))
  169. desc.setter = JS_StrictPropertyStub;
  170. } else if ((desc.attrs & JSPROP_SETTER) || desc.setter != JS_StrictPropertyStub) {
  171. if (!CallSetter(cx, receiver, id, desc.setter, desc.attrs, desc.shortid, strict, vp))
  172. return false;
  173. if (!proxy->isProxy() || GetProxyHandler(proxy) != this)
  174. return true;
  175. if (desc.attrs & JSPROP_SHARED)
  176. return true;
  177. }
  178. if (!desc.getter) {
  179. // Same as above for the null setter case.
  180. if (!(desc.attrs & JSPROP_GETTER))
  181. desc.getter = JS_PropertyStub;
  182. }
  183. desc.value = *vp;
  184. return defineProperty(cx, receiver, id, &desc);
  185. }
  186. if (!getPropertyDescriptor(cx, proxy, id, true, &desc))
  187. return false;
  188. if (desc.obj) {
  189. if (desc.attrs & JSPROP_READONLY)
  190. return true;
  191. if (!desc.setter) {
  192. // Be wary of the odd explicit undefined setter case possible through
  193. // Object.defineProperty.
  194. if (!(desc.attrs & JSPROP_SETTER))
  195. desc.setter = JS_StrictPropertyStub;
  196. } else if ((desc.attrs & JSPROP_SETTER) || desc.setter != JS_StrictPropertyStub) {
  197. if (!CallSetter(cx, receiver, id, desc.setter, desc.attrs, desc.shortid, strict, vp))
  198. return false;
  199. if (!proxy->isProxy() || GetProxyHandler(proxy) != this)
  200. return true;
  201. if (desc.attrs & JSPROP_SHARED)
  202. return true;
  203. }
  204. if (!desc.getter) {
  205. // Same as above for the null setter case.
  206. if (!(desc.attrs & JSPROP_GETTER))
  207. desc.getter = JS_PropertyStub;
  208. }
  209. return defineProperty(cx, receiver, id, &desc);
  210. }
  211. desc.obj = receiver;
  212. desc.value = *vp;
  213. desc.attrs = JSPROP_ENUMERATE;
  214. desc.shortid = 0;
  215. desc.getter = NULL;
  216. desc.setter = NULL; // Pick up the class getter/setter.
  217. return defineProperty(cx, receiver, id, &desc);
  218. }
  219. bool
  220. ProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
  221. {
  222. JS_ASSERT(OperationInProgress(cx, proxy));
  223. JS_ASSERT(props.length() == 0);
  224. if (!getOwnPropertyNames(cx, proxy, props))
  225. return false;
  226. /* Select only the enumerable properties through in-place iteration. */
  227. AutoPropertyDescriptorRooter desc(cx);
  228. size_t i = 0;
  229. for (size_t j = 0, len = props.length(); j < len; j++) {
  230. JS_ASSERT(i <= j);
  231. jsid id = props[j];
  232. if (!getOwnPropertyDescriptor(cx, proxy, id, false, &desc))
  233. return false;
  234. if (desc.obj && (desc.attrs & JSPROP_ENUMERATE))
  235. props[i++] = id;
  236. }
  237. JS_ASSERT(i <= props.length());
  238. props.resize(i);
  239. return true;
  240. }
  241. bool
  242. ProxyHandler::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp)
  243. {
  244. JS_ASSERT(OperationInProgress(cx, proxy));
  245. AutoIdVector props(cx);
  246. if ((flags & JSITER_OWNONLY)
  247. ? !keys(cx, proxy, props)
  248. : !enumerate(cx, proxy, props)) {
  249. return false;
  250. }
  251. return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
  252. }
  253. JSString *
  254. ProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
  255. {
  256. JS_ASSERT(proxy->isProxy());
  257. return JS_NewStringCopyZ(cx, IsFunctionProxy(proxy)
  258. ? "[object Function]"
  259. : "[object Object]");
  260. }
  261. JSString *
  262. ProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, uintN indent)
  263. {
  264. JS_ASSERT(proxy->isProxy());
  265. Value fval = GetCall(proxy);
  266. if (IsFunctionProxy(proxy) &&
  267. (fval.isPrimitive() || !fval.toObject().isFunction())) {
  268. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
  269. JSMSG_INCOMPATIBLE_PROTO,
  270. js_Function_str, js_toString_str,
  271. "object");
  272. return NULL;
  273. }
  274. return fun_toStringHelper(cx, &fval.toObject(), indent);
  275. }
  276. RegExpShared *
  277. ProxyHandler::regexp_toShared(JSContext *cx, JSObject *proxy)
  278. {
  279. JS_NOT_REACHED("This should have been a wrapped regexp");
  280. return (RegExpShared *)NULL;
  281. }
  282. bool
  283. ProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint, Value *vp)
  284. {
  285. return DefaultValue(cx, proxy, hint, vp);
  286. }
  287. bool
  288. ProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
  289. {
  290. vp->setMagic(JS_NO_ITER_VALUE);
  291. return true;
  292. }
  293. bool
  294. ProxyHandler::call(JSContext *cx, JSObject *proxy, uintN argc, Value *vp)
  295. {
  296. JS_ASSERT(OperationInProgress(cx, proxy));
  297. AutoValueRooter rval(cx);
  298. JSBool ok = Invoke(cx, vp[1], GetCall(proxy), argc, JS_ARGV(cx, vp), rval.addr());
  299. if (ok)
  300. JS_SET_RVAL(cx, vp, rval.value());
  301. return ok;
  302. }
  303. bool
  304. ProxyHandler::construct(JSContext *cx, JSObject *proxy,
  305. uintN argc, Value *argv, Value *rval)
  306. {
  307. JS_ASSERT(OperationInProgress(cx, proxy));
  308. Value fval = GetConstruct(proxy);
  309. if (fval.isUndefined())
  310. return InvokeConstructor(cx, GetCall(proxy), argc, argv, rval);
  311. return Invoke(cx, UndefinedValue(), fval, argc, argv, rval);
  312. }
  313. bool
  314. ProxyHandler::nativeCall(JSContext *cx, JSObject *proxy, Class *clasp, Native native, CallArgs args)
  315. {
  316. JS_ASSERT(OperationInProgress(cx, proxy));
  317. ReportIncompatibleMethod(cx, args, clasp);
  318. return false;
  319. }
  320. bool
  321. ProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
  322. {
  323. JS_ASSERT(OperationInProgress(cx, proxy));
  324. js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
  325. JSDVG_SEARCH_STACK, ObjectValue(*proxy), NULL);
  326. return false;
  327. }
  328. JSType
  329. ProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
  330. {
  331. JS_ASSERT(OperationInProgress(cx, proxy));
  332. return IsFunctionProxy(proxy) ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
  333. }
  334. bool
  335. ProxyHandler::objectClassIs(JSObject *proxy, ESClassValue classValue, JSContext *cx)
  336. {
  337. JS_ASSERT(OperationInProgress(cx, proxy));
  338. return false;
  339. }
  340. void
  341. ProxyHandler::finalize(JSContext *cx, JSObject *proxy)
  342. {
  343. }
  344. void
  345. ProxyHandler::trace(JSTracer *trc, JSObject *proxy)
  346. {
  347. }
  348. static bool
  349. GetTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp)
  350. {
  351. JS_CHECK_RECURSION(cx, return false);
  352. return handler->getGeneric(cx, ATOM_TO_JSID(atom), fvalp);
  353. }
  354. static bool
  355. GetFundamentalTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp)
  356. {
  357. if (!GetTrap(cx, handler, atom, fvalp))
  358. return false;
  359. if (!js_IsCallable(*fvalp)) {
  360. JSAutoByteString bytes;
  361. if (js_AtomToPrintableString(cx, atom, &bytes))
  362. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_FUNCTION, bytes.ptr());
  363. return false;
  364. }
  365. return true;
  366. }
  367. static bool
  368. GetDerivedTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp)
  369. {
  370. JS_ASSERT(atom == ATOM(has) ||
  371. atom == ATOM(hasOwn) ||
  372. atom == ATOM(get) ||
  373. atom == ATOM(set) ||
  374. atom == ATOM(keys) ||
  375. atom == ATOM(iterate));
  376. return GetTrap(cx, handler, atom, fvalp);
  377. }
  378. static bool
  379. Trap(JSContext *cx, JSObject *handler, Value fval, uintN argc, Value* argv, Value *rval)
  380. {
  381. return Invoke(cx, ObjectValue(*handler), fval, argc, argv, rval);
  382. }
  383. static bool
  384. Trap1(JSContext *cx, JSObject *handler, Value fval, jsid id, Value *rval)
  385. {
  386. JSString *str = ToString(cx, IdToValue(id));
  387. if (!str)
  388. return false;
  389. rval->setString(str);
  390. return Trap(cx, handler, fval, 1, rval, rval);
  391. }
  392. static bool
  393. Trap2(JSContext *cx, JSObject *handler, Value fval, jsid id, Value v, Value *rval)
  394. {
  395. JSString *str = ToString(cx, IdToValue(id));
  396. if (!str)
  397. return false;
  398. rval->setString(str);
  399. Value argv[2] = { *rval, v };
  400. return Trap(cx, handler, fval, 2, argv, rval);
  401. }
  402. static bool
  403. ParsePropertyDescriptorObject(JSContext *cx, JSObject *obj, jsid id, const Value &v,
  404. PropertyDescriptor *desc)
  405. {
  406. AutoPropDescArrayRooter descs(cx);
  407. PropDesc *d = descs.append();
  408. if (!d || !d->initialize(cx, v))
  409. return false;
  410. desc->obj = obj;
  411. desc->value = d->value;
  412. JS_ASSERT(!(d->attrs & JSPROP_SHORTID));
  413. desc->attrs = d->attrs;
  414. desc->getter = d->getter();
  415. desc->setter = d->setter();
  416. desc->shortid = 0;
  417. return true;
  418. }
  419. static bool
  420. IndicatePropertyNotFound(JSContext *cx, PropertyDescriptor *desc)
  421. {
  422. desc->obj = NULL;
  423. return true;
  424. }
  425. static bool
  426. ValueToBool(JSContext *cx, const Value &v, bool *bp)
  427. {
  428. *bp = !!js_ValueToBoolean(v);
  429. return true;
  430. }
  431. static bool
  432. ArrayToIdVector(JSContext *cx, const Value &array, AutoIdVector &props)
  433. {
  434. JS_ASSERT(props.length() == 0);
  435. if (array.isPrimitive())
  436. return true;
  437. JSObject *obj = &array.toObject();
  438. jsuint length;
  439. if (!js_GetLengthProperty(cx, obj, &length))
  440. return false;
  441. for (jsuint n = 0; n < length; ++n) {
  442. if (!JS_CHECK_OPERATION_LIMIT(cx))
  443. return false;
  444. Value v;
  445. if (!obj->getElement(cx, n, &v))
  446. return false;
  447. jsid id;
  448. if (!ValueToId(cx, v, &id))
  449. return false;
  450. if (!props.append(js_CheckForStringIndex(id)))
  451. return false;
  452. }
  453. return true;
  454. }
  455. /* Derived class for all scripted proxy handlers. */
  456. class ScriptedProxyHandler : public ProxyHandler {
  457. public:
  458. ScriptedProxyHandler();
  459. virtual ~ScriptedProxyHandler();
  460. /* ES5 Harmony fundamental proxy traps. */
  461. virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
  462. PropertyDescriptor *desc);
  463. virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
  464. PropertyDescriptor *desc);
  465. virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id,
  466. PropertyDescriptor *desc);
  467. virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props);
  468. virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
  469. virtual bool enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props);
  470. virtual bool fix(JSContext *cx, JSObject *proxy, Value *vp);
  471. /* ES5 Harmony derived proxy traps. */
  472. virtual bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
  473. virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
  474. virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp);
  475. virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
  476. Value *vp);
  477. virtual bool keys(JSContext *cx, JSObject *proxy, AutoIdVector &props);
  478. virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp);
  479. static ScriptedProxyHandler singleton;
  480. };
  481. static int sScriptedProxyHandlerFamily = 0;
  482. ScriptedProxyHandler::ScriptedProxyHandler() : ProxyHandler(&sScriptedProxyHandlerFamily)
  483. {
  484. }
  485. ScriptedProxyHandler::~ScriptedProxyHandler()
  486. {
  487. }
  488. static bool
  489. ReturnedValueMustNotBePrimitive(JSContext *cx, JSObject *proxy, JSAtom *atom, const Value &v)
  490. {
  491. if (v.isPrimitive()) {
  492. JSAutoByteString bytes;
  493. if (js_AtomToPrintableString(cx, atom, &bytes)) {
  494. js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
  495. JSDVG_SEARCH_STACK, ObjectOrNullValue(proxy), NULL, bytes.ptr());
  496. }
  497. return false;
  498. }
  499. return true;
  500. }
  501. static JSObject *
  502. GetProxyHandlerObject(JSContext *cx, JSObject *proxy)
  503. {
  504. JS_ASSERT(OperationInProgress(cx, proxy));
  505. return GetProxyPrivate(proxy).toObjectOrNull();
  506. }
  507. bool
  508. ScriptedProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
  509. PropertyDescriptor *desc)
  510. {
  511. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  512. AutoValueRooter tvr(cx);
  513. return GetFundamentalTrap(cx, handler, ATOM(getPropertyDescriptor), tvr.addr()) &&
  514. Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
  515. ((tvr.value().isUndefined() && IndicatePropertyNotFound(cx, desc)) ||
  516. (ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), tvr.value()) &&
  517. ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc)));
  518. }
  519. bool
  520. ScriptedProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
  521. PropertyDescriptor *desc)
  522. {
  523. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  524. AutoValueRooter tvr(cx);
  525. return GetFundamentalTrap(cx, handler, ATOM(getOwnPropertyDescriptor), tvr.addr()) &&
  526. Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
  527. ((tvr.value().isUndefined() && IndicatePropertyNotFound(cx, desc)) ||
  528. (ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), tvr.value()) &&
  529. ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc)));
  530. }
  531. bool
  532. ScriptedProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id,
  533. PropertyDescriptor *desc)
  534. {
  535. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  536. AutoValueRooter tvr(cx);
  537. AutoValueRooter fval(cx);
  538. return GetFundamentalTrap(cx, handler, ATOM(defineProperty), fval.addr()) &&
  539. NewPropertyDescriptorObject(cx, desc, tvr.addr()) &&
  540. Trap2(cx, handler, fval.value(), id, tvr.value(), tvr.addr());
  541. }
  542. bool
  543. ScriptedProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
  544. {
  545. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  546. AutoValueRooter tvr(cx);
  547. return GetFundamentalTrap(cx, handler, ATOM(getOwnPropertyNames), tvr.addr()) &&
  548. Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) &&
  549. ArrayToIdVector(cx, tvr.value(), props);
  550. }
  551. bool
  552. ScriptedProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
  553. {
  554. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  555. AutoValueRooter tvr(cx);
  556. return GetFundamentalTrap(cx, handler, ATOM(delete), tvr.addr()) &&
  557. Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
  558. ValueToBool(cx, tvr.value(), bp);
  559. }
  560. bool
  561. ScriptedProxyHandler::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
  562. {
  563. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  564. AutoValueRooter tvr(cx);
  565. return GetFundamentalTrap(cx, handler, ATOM(enumerate), tvr.addr()) &&
  566. Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) &&
  567. ArrayToIdVector(cx, tvr.value(), props);
  568. }
  569. bool
  570. ScriptedProxyHandler::fix(JSContext *cx, JSObject *proxy, Value *vp)
  571. {
  572. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  573. return GetFundamentalTrap(cx, handler, ATOM(fix), vp) &&
  574. Trap(cx, handler, *vp, 0, NULL, vp);
  575. }
  576. bool
  577. ScriptedProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
  578. {
  579. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  580. AutoValueRooter tvr(cx);
  581. if (!GetDerivedTrap(cx, handler, ATOM(has), tvr.addr()))
  582. return false;
  583. if (!js_IsCallable(tvr.value()))
  584. return ProxyHandler::has(cx, proxy, id, bp);
  585. return Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
  586. ValueToBool(cx, tvr.value(), bp);
  587. }
  588. bool
  589. ScriptedProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
  590. {
  591. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  592. AutoValueRooter tvr(cx);
  593. if (!GetDerivedTrap(cx, handler, ATOM(hasOwn), tvr.addr()))
  594. return false;
  595. if (!js_IsCallable(tvr.value()))
  596. return ProxyHandler::hasOwn(cx, proxy, id, bp);
  597. return Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
  598. ValueToBool(cx, tvr.value(), bp);
  599. }
  600. bool
  601. ScriptedProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
  602. {
  603. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  604. JSString *str = ToString(cx, IdToValue(id));
  605. if (!str)
  606. return false;
  607. AutoValueRooter tvr(cx, StringValue(str));
  608. Value argv[] = { ObjectOrNullValue(receiver), tvr.value() };
  609. AutoValueRooter fval(cx);
  610. if (!GetDerivedTrap(cx, handler, ATOM(get), fval.addr()))
  611. return false;
  612. if (!js_IsCallable(fval.value()))
  613. return ProxyHandler::get(cx, proxy, receiver, id, vp);
  614. return Trap(cx, handler, fval.value(), 2, argv, vp);
  615. }
  616. bool
  617. ScriptedProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
  618. Value *vp)
  619. {
  620. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  621. JSString *str = ToString(cx, IdToValue(id));
  622. if (!str)
  623. return false;
  624. AutoValueRooter tvr(cx, StringValue(str));
  625. Value argv[] = { ObjectOrNullValue(receiver), tvr.value(), *vp };
  626. AutoValueRooter fval(cx);
  627. if (!GetDerivedTrap(cx, handler, ATOM(set), fval.addr()))
  628. return false;
  629. if (!js_IsCallable(fval.value()))
  630. return ProxyHandler::set(cx, proxy, receiver, id, strict, vp);
  631. return Trap(cx, handler, fval.value(), 3, argv, tvr.addr());
  632. }
  633. bool
  634. ScriptedProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
  635. {
  636. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  637. AutoValueRooter tvr(cx);
  638. if (!GetDerivedTrap(cx, handler, ATOM(keys), tvr.addr()))
  639. return false;
  640. if (!js_IsCallable(tvr.value()))
  641. return ProxyHandler::keys(cx, proxy, props);
  642. return Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) &&
  643. ArrayToIdVector(cx, tvr.value(), props);
  644. }
  645. bool
  646. ScriptedProxyHandler::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp)
  647. {
  648. JSObject *handler = GetProxyHandlerObject(cx, proxy);
  649. AutoValueRooter tvr(cx);
  650. if (!GetDerivedTrap(cx, handler, ATOM(iterate), tvr.addr()))
  651. return false;
  652. if (!js_IsCallable(tvr.value()))
  653. return ProxyHandler::iterate(cx, proxy, flags, vp);
  654. return Trap(cx, handler, tvr.value(), 0, NULL, vp) &&
  655. ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(iterate), *vp);
  656. }
  657. ScriptedProxyHandler ScriptedProxyHandler::singleton;
  658. class AutoPendingProxyOperation {
  659. JSRuntime *rt;
  660. PendingProxyOperation op;
  661. public:
  662. AutoPendingProxyOperation(JSContext *cx, JSObject *proxy) : rt(cx->runtime) {
  663. op.next = rt->pendingProxyOperation;
  664. op.object = proxy;
  665. rt->pendingProxyOperation = &op;
  666. }
  667. ~AutoPendingProxyOperation() {
  668. JS_ASSERT(rt->pendingProxyOperation == &op);
  669. rt->pendingProxyOperation = op.next;
  670. }
  671. };
  672. bool
  673. Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
  674. PropertyDescriptor *desc)
  675. {
  676. JS_CHECK_RECURSION(cx, return false);
  677. AutoPendingProxyOperation pending(cx, proxy);
  678. return GetProxyHandler(proxy)->getPropertyDescriptor(cx, proxy, id, set, desc);
  679. }
  680. bool
  681. Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
  682. {
  683. JS_CHECK_RECURSION(cx, return false);
  684. AutoPendingProxyOperation pending(cx, proxy);
  685. AutoPropertyDescriptorRooter desc(cx);
  686. return Proxy::getPropertyDescriptor(cx, proxy, id, set, &desc) &&
  687. NewPropertyDescriptorObject(cx, &desc, vp);
  688. }
  689. bool
  690. Proxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
  691. PropertyDescriptor *desc)
  692. {
  693. JS_CHECK_RECURSION(cx, return false);
  694. AutoPendingProxyOperation pending(cx, proxy);
  695. return GetProxyHandler(proxy)->getOwnPropertyDescriptor(cx, proxy, id, set, desc);
  696. }
  697. bool
  698. Proxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
  699. {
  700. JS_CHECK_RECURSION(cx, return false);
  701. AutoPendingProxyOperation pending(cx, proxy);
  702. AutoPropertyDescriptorRooter desc(cx);
  703. return Proxy::getOwnPropertyDescriptor(cx, proxy, id, set, &desc) &&
  704. NewPropertyDescriptorObject(cx, &desc, vp);
  705. }
  706. bool
  707. Proxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc)
  708. {
  709. JS_CHECK_RECURSION(cx, return false);
  710. AutoPendingProxyOperation pending(cx, proxy);
  711. return GetProxyHandler(proxy)->defineProperty(cx, proxy, id, desc);
  712. }
  713. bool
  714. Proxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, const Value &v)
  715. {
  716. JS_CHECK_RECURSION(cx, return false);
  717. AutoPendingProxyOperation pending(cx, proxy);
  718. AutoPropertyDescriptorRooter desc(cx);
  719. return ParsePropertyDescriptorObject(cx, proxy, id, v, &desc) &&
  720. Proxy::defineProperty(cx, proxy, id, &desc);
  721. }
  722. bool
  723. Proxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
  724. {
  725. JS_CHECK_RECURSION(cx, return false);
  726. AutoPendingProxyOperation pending(cx, proxy);
  727. return GetProxyHandler(proxy)->getOwnPropertyNames(cx, proxy, props);
  728. }
  729. bool
  730. Proxy::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
  731. {
  732. JS_CHECK_RECURSION(cx, return false);
  733. AutoPendingProxyOperation pending(cx, proxy);
  734. return GetProxyHandler(proxy)->delete_(cx, proxy, id, bp);
  735. }
  736. bool
  737. Proxy::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
  738. {
  739. JS_CHECK_RECURSION(cx, return false);
  740. AutoPendingProxyOperation pending(cx, proxy);
  741. return GetProxyHandler(proxy)->enumerate(cx, proxy, props);
  742. }
  743. bool
  744. Proxy::fix(JSContext *cx, JSObject *proxy, Value *vp)
  745. {
  746. JS_CHECK_RECURSION(cx, return false);
  747. AutoPendingProxyOperation pending(cx, proxy);
  748. return GetProxyHandler(proxy)->fix(cx, proxy, vp);
  749. }
  750. bool
  751. Proxy::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
  752. {
  753. JS_CHECK_RECURSION(cx, return false);
  754. AutoPendingProxyOperation pending(cx, proxy);
  755. return GetProxyHandler(proxy)->has(cx, proxy, id, bp);
  756. }
  757. bool
  758. Proxy::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
  759. {
  760. JS_CHECK_RECURSION(cx, return false);
  761. AutoPendingProxyOperation pending(cx, proxy);
  762. return GetProxyHandler(proxy)->hasOwn(cx, proxy, id, bp);
  763. }
  764. bool
  765. Proxy::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
  766. {
  767. JS_CHECK_RECURSION(cx, return false);
  768. AutoPendingProxyOperation pending(cx, proxy);
  769. return GetProxyHandler(proxy)->get(cx, proxy, receiver, id, vp);
  770. }
  771. bool
  772. Proxy::getElementIfPresent(JSContext *cx, JSObject *proxy, JSObject *receiver, uint32_t index,
  773. Value *vp, bool *present)
  774. {
  775. JS_CHECK_RECURSION(cx, return false);
  776. AutoPendingProxyOperation pending(cx, proxy);
  777. return GetProxyHandler(proxy)->getElementIfPresent(cx, proxy, receiver, index, vp, present);
  778. }
  779. bool
  780. Proxy::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, Value *vp)
  781. {
  782. JS_CHECK_RECURSION(cx, return false);
  783. AutoPendingProxyOperation pending(cx, proxy);
  784. return GetProxyHandler(proxy)->set(cx, proxy, receiver, id, strict, vp);
  785. }
  786. bool
  787. Proxy::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
  788. {
  789. JS_CHECK_RECURSION(cx, return false);
  790. AutoPendingProxyOperation pending(cx, proxy);
  791. return GetProxyHandler(proxy)->keys(cx, proxy, props);
  792. }
  793. bool
  794. Proxy::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp)
  795. {
  796. JS_CHECK_RECURSION(cx, return false);
  797. AutoPendingProxyOperation pending(cx, proxy);
  798. return GetProxyHandler(proxy)->iterate(cx, proxy, flags, vp);
  799. }
  800. bool
  801. Proxy::call(JSContext *cx, JSObject *proxy, uintN argc, Value *vp)
  802. {
  803. JS_CHECK_RECURSION(cx, return false);
  804. AutoPendingProxyOperation pending(cx, proxy);
  805. return GetProxyHandler(proxy)->call(cx, proxy, argc, vp);
  806. }
  807. bool
  808. Proxy::construct(JSContext *cx, JSObject *proxy, uintN argc, Value *argv, Value *rval)
  809. {
  810. JS_CHECK_RECURSION(cx, return false);
  811. AutoPendingProxyOperation pending(cx, proxy);
  812. return GetProxyHandler(proxy)->construct(cx, proxy, argc, argv, rval);
  813. }
  814. bool
  815. Proxy::nativeCall(JSContext *cx, JSObject *proxy, Class *clasp, Native native, CallArgs args)
  816. {
  817. JS_CHECK_RECURSION(cx, return false);
  818. AutoPendingProxyOperation pending(cx, proxy);
  819. return GetProxyHandler(proxy)->nativeCall(cx, proxy, clasp, native, args);
  820. }
  821. bool
  822. Proxy::hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *bp)
  823. {
  824. JS_CHECK_RECURSION(cx, return false);
  825. AutoPendingProxyOperation pending(cx, proxy);
  826. return GetProxyHandler(proxy)->hasInstance(cx, proxy, vp, bp);
  827. }
  828. JSType
  829. Proxy::typeOf(JSContext *cx, JSObject *proxy)
  830. {
  831. // FIXME: API doesn't allow us to report error (bug 618906).
  832. JS_CHECK_RECURSION(cx, return JSTYPE_OBJECT);
  833. AutoPendingProxyOperation pending(cx, proxy);
  834. return GetProxyHandler(proxy)->typeOf(cx, proxy);
  835. }
  836. bool
  837. Proxy::objectClassIs(JSObject *proxy, ESClassValue classValue, JSContext *cx)
  838. {
  839. AutoPendingProxyOperation pending(cx, proxy);
  840. return GetProxyHandler(proxy)->objectClassIs(proxy, classValue, cx);
  841. }
  842. JSString *
  843. Proxy::obj_toString(JSContext *cx, JSObject *proxy)
  844. {
  845. JS_CHECK_RECURSION(cx, return NULL);
  846. AutoPendingProxyOperation pending(cx, proxy);
  847. return GetProxyHandler(proxy)->obj_toString(cx, proxy);
  848. }
  849. JSString *
  850. Proxy::fun_toString(JSContext *cx, JSObject *proxy, uintN indent)
  851. {
  852. JS_CHECK_RECURSION(cx, return NULL);
  853. AutoPendingProxyOperation pending(cx, proxy);
  854. return GetProxyHandler(proxy)->fun_toString(cx, proxy, indent);
  855. }
  856. RegExpShared *
  857. Proxy::regexp_toShared(JSContext *cx, JSObject *proxy)
  858. {
  859. JS_CHECK_RECURSION(cx, return NULL);
  860. AutoPendingProxyOperation pending(cx, proxy);
  861. return GetProxyHandler(proxy)->regexp_toShared(cx, proxy);
  862. }
  863. bool
  864. Proxy::defaultValue(JSContext *cx, JSObject *proxy, JSType hint, Value *vp)
  865. {
  866. JS_CHECK_RECURSION(cx, return NULL);
  867. AutoPendingProxyOperation pending(cx, proxy);
  868. return GetProxyHandler(proxy)->defaultValue(cx, proxy, hint, vp);
  869. }
  870. bool
  871. Proxy::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
  872. {
  873. JS_CHECK_RECURSION(cx, return NULL);
  874. AutoPendingProxyOperation pending(cx, proxy);
  875. return GetProxyHandler(proxy)->iteratorNext(cx, proxy, vp);
  876. }
  877. static JSObject *
  878. proxy_innerObject(JSContext *cx, JSObject *obj)
  879. {
  880. return GetProxyPrivate(obj).toObjectOrNull();
  881. }
  882. static JSBool
  883. proxy_LookupGeneric(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
  884. JSProperty **propp)
  885. {
  886. id = js_CheckForStringIndex(id);
  887. bool found;
  888. if (!Proxy::has(cx, obj, id, &found))
  889. return false;
  890. if (found) {
  891. *propp = (JSProperty *)0x1;
  892. *objp = obj;
  893. } else {
  894. *objp = NULL;
  895. *propp = NULL;
  896. }
  897. return true;
  898. }
  899. static JSBool
  900. proxy_LookupProperty(JSContext *cx, JSObject *obj, PropertyName *name, JSObject **objp,
  901. JSProperty **propp)
  902. {
  903. return proxy_LookupGeneric(cx, obj, ATOM_TO_JSID(name), objp, propp);
  904. }
  905. static JSBool
  906. proxy_LookupElement(JSContext *cx, JSObject *obj, uint32_t index, JSObject **objp,
  907. JSProperty **propp)
  908. {
  909. jsid id;
  910. if (!IndexToId(cx, index, &id))
  911. return false;
  912. return proxy_LookupGeneric(cx, obj, id, objp, propp);
  913. }
  914. static JSBool
  915. proxy_LookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid, JSObject **objp, JSProperty **propp)
  916. {
  917. return proxy_LookupGeneric(cx, obj, SPECIALID_TO_JSID(sid), objp, propp);
  918. }
  919. static JSBool
  920. proxy_DefineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *value,
  921. PropertyOp getter, StrictPropertyOp setter, uintN attrs)
  922. {
  923. id = js_CheckForStringIndex(id);
  924. AutoPropertyDescriptorRooter desc(cx);
  925. desc.obj = obj;
  926. desc.value = *value;
  927. desc.attrs = (attrs & (~JSPROP_SHORTID));
  928. desc.getter = getter;
  929. desc.setter = setter;
  930. desc.shortid = 0;
  931. return Proxy::defineProperty(cx, obj, id, &desc);
  932. }
  933. static JSBool
  934. proxy_DefineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *value,
  935. PropertyOp getter, StrictPropertyOp setter, uintN attrs)
  936. {
  937. return proxy_DefineGeneric(cx, obj, ATOM_TO_JSID(name), value, getter, setter, attrs);
  938. }
  939. static JSBool
  940. proxy_DefineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *value,
  941. PropertyOp getter, StrictPropertyOp setter, uintN attrs)
  942. {
  943. jsid id;
  944. if (!IndexToId(cx, index, &id))
  945. return false;
  946. return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
  947. }
  948. static JSBool
  949. proxy_DefineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *value,
  950. PropertyOp getter, StrictPropertyOp setter, uintN attrs)
  951. {
  952. return proxy_DefineGeneric(cx, obj, SPECIALID_TO_JSID(sid), value, getter, setter, attrs);
  953. }
  954. static JSBool
  955. proxy_GetGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
  956. {
  957. id = js_CheckForStringIndex(id);
  958. return Proxy::get(cx, obj, receiver, id, vp);
  959. }
  960. static JSBool
  961. proxy_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name, Value *vp)
  962. {
  963. return proxy_GetGeneric(cx, obj, receiver, ATOM_TO_JSID(name), vp);
  964. }
  965. static JSBool
  966. proxy_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
  967. {
  968. jsid id;
  969. if (!IndexToId(cx, index, &id))
  970. return false;
  971. return proxy_GetGeneric(cx, obj, receiver, id, vp);
  972. }
  973. static JSBool
  974. proxy_GetElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index,
  975. Value *vp, bool *present)
  976. {
  977. return Proxy::getElementIfPresent(cx, obj, receiver, index, vp, present);
  978. }
  979. static JSBool
  980. proxy_GetSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp)
  981. {
  982. return proxy_GetGeneric(cx, obj, receiver, SPECIALID_TO_JSID(sid), vp);
  983. }
  984. static JSBool
  985. proxy_SetGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
  986. {
  987. id = js_CheckForStringIndex(id);
  988. return Proxy::set(cx, obj, obj, id, strict, vp);
  989. }
  990. static JSBool
  991. proxy_SetProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
  992. {
  993. return proxy_SetGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict);
  994. }
  995. static JSBool
  996. proxy_SetElement(JSContext *cx, JSObject *obj, uint32_t index, Value *vp, JSBool strict)
  997. {
  998. jsid id;
  999. if (!IndexToId(cx, index, &id))
  1000. return false;
  1001. return proxy_SetGeneric(cx, obj, id, vp, strict);
  1002. }
  1003. static JSBool
  1004. proxy_SetSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
  1005. {
  1006. return proxy_SetGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
  1007. }
  1008. static JSBool
  1009. proxy_GetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
  1010. {
  1011. id = js_CheckForStringIndex(id);
  1012. AutoPropertyDescriptorRooter desc(cx);
  1013. if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, false, &desc))
  1014. return false;
  1015. *attrsp = desc.attrs;
  1016. return true;
  1017. }
  1018. static JSBool
  1019. proxy_GetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
  1020. {
  1021. return proxy_GetGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
  1022. }
  1023. static JSBool
  1024. proxy_GetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, uintN *attrsp)
  1025. {
  1026. jsid id;
  1027. if (!IndexToId(cx, index, &id))
  1028. return false;
  1029. return proxy_GetGenericAttributes(cx, obj, id, attrsp);
  1030. }
  1031. static JSBool
  1032. proxy_GetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
  1033. {
  1034. return proxy_GetGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
  1035. }
  1036. static JSBool
  1037. proxy_SetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
  1038. {
  1039. id = js_CheckForStringIndex(id);
  1040. /* Lookup the current property descriptor so we have setter/getter/value. */
  1041. AutoPropertyDescriptorRooter desc(cx);
  1042. if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, true, &desc))
  1043. return false;
  1044. desc.attrs = (*attrsp & (~JSPROP_SHORTID));
  1045. return Proxy::defineProperty(cx, obj, id, &desc);
  1046. }
  1047. static JSBool
  1048. proxy_SetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
  1049. {
  1050. return proxy_SetGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
  1051. }
  1052. static JSBool
  1053. proxy_SetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, uintN *attrsp)
  1054. {
  1055. jsid id;
  1056. if (!IndexToId(cx, index, &id))
  1057. return false;
  1058. return proxy_SetGenericAttributes(cx, obj, id, attrsp);
  1059. }
  1060. static JSBool
  1061. proxy_SetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
  1062. {
  1063. return proxy_SetGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
  1064. }
  1065. static JSBool
  1066. proxy_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
  1067. {
  1068. JS_ASSERT(id == js_CheckForStringIndex(id));
  1069. // TODO: throwing away strict
  1070. bool deleted;
  1071. if (!Proxy::delete_(cx, obj, id, &deleted) || !js_SuppressDeletedProperty(cx, obj, id))
  1072. return false;
  1073. rval->setBoolean(deleted);
  1074. return true;
  1075. }
  1076. static JSBool
  1077. proxy_DeleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
  1078. {
  1079. return proxy_DeleteGeneric(cx, obj, js_CheckForStringIndex(ATOM_TO_JSID(name)), rval, strict);
  1080. }
  1081. static JSBool
  1082. proxy_DeleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict)
  1083. {
  1084. jsid id;
  1085. if (!IndexToId(cx, index, &id))
  1086. return false;
  1087. return proxy_DeleteGeneric(cx, obj, id, rval, strict);
  1088. }
  1089. static JSBool
  1090. proxy_DeleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
  1091. {
  1092. return proxy_DeleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
  1093. }
  1094. static void
  1095. proxy_TraceObject(JSTracer *trc, JSObject *obj)
  1096. {
  1097. GetProxyHandler(obj)->trace(trc, obj);
  1098. MarkCrossCompartmentValue(trc, obj->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "private");
  1099. MarkCrossCompartmentValue(trc, obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 0), "extra0");
  1100. MarkCrossCompartmentValue(trc, obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 1), "extra1");
  1101. if (IsFunctionProxy(obj)) {
  1102. MarkCrossCompartmentValue(trc, GetCall(obj), "call");
  1103. MarkCrossCompartmentValue(trc, GetFunctionProxyConstruct(obj), "construct");
  1104. }
  1105. }
  1106. static void
  1107. proxy_TraceFunction(JSTracer *trc, JSObject *obj)
  1108. {
  1109. proxy_TraceObject(trc, obj);
  1110. MarkCrossCompartmentValue(trc, GetCall(obj), "call");
  1111. MarkCrossCompartmentValue(trc, GetFunctionProxyConstruct(obj), "construct");
  1112. }
  1113. static JSBool
  1114. proxy_Convert(JSContext *cx, JSObject *proxy, JSType hint, Value *vp)
  1115. {
  1116. JS_ASSERT(proxy->isProxy());
  1117. return Proxy::defaultValue(cx, proxy, hint, vp);
  1118. }
  1119. static JSBool
  1120. proxy_Fix(JSContext *cx, JSObject *obj, bool *fixed, AutoIdVector *props)
  1121. {
  1122. JS_ASSERT(obj->isProxy());
  1123. JSBool isFixed;
  1124. bool ok = FixProxy(cx, obj, &isFixed);
  1125. if (ok) {
  1126. *fixed = isFixed;
  1127. return GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, props);
  1128. }
  1129. return false;
  1130. }
  1131. static void
  1132. proxy_Finalize(JSContext *cx, JSObject *obj)
  1133. {
  1134. JS_ASSERT(obj->isProxy());
  1135. if (!obj->getSlot(JSSLOT_PROXY_HANDLER).isUndefined())
  1136. GetProxyHandler(obj)->finalize(cx, obj);
  1137. }
  1138. static JSBool
  1139. proxy_HasInstance(JSContext *cx, JSObject *proxy, const Value *v, JSBool *bp)
  1140. {
  1141. AutoPendingProxyOperation pending(cx, proxy);
  1142. bool b;
  1143. if (!Proxy::hasInstance(cx, proxy, v, &b))
  1144. return false;
  1145. *bp = !!b;
  1146. return true;
  1147. }
  1148. static JSType
  1149. proxy_TypeOf(JSContext *cx, JSObject *proxy)
  1150. {
  1151. JS_ASSERT(proxy->isProxy());
  1152. return Proxy::typeOf(cx, proxy);
  1153. }
  1154. JS_FRIEND_DATA(Class) js::ObjectProxyClass = {
  1155. "Proxy",
  1156. Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(4),
  1157. JS_PropertyStub, /* addProperty */
  1158. JS_PropertyStub, /* delProperty */
  1159. JS_PropertyStub, /* getProperty */
  1160. JS_StrictPropertyStub, /* setProperty */
  1161. JS_EnumerateStub,
  1162. JS_ResolveStub,
  1163. proxy_Convert,
  1164. proxy_Finalize, /* finalize */
  1165. NULL, /* reserved0 */
  1166. NULL, /* checkAccess */
  1167. NULL, /* call */
  1168. NULL, /* construct */
  1169. NULL, /* xdrObject */
  1170. proxy_HasInstance, /* hasInstance */
  1171. proxy_TraceObject, /* trace */
  1172. JS_NULL_CLASS_EXT,
  1173. {
  1174. proxy_LookupGeneric,
  1175. proxy_LookupProperty,
  1176. proxy_LookupElement,
  1177. proxy_LookupSpecial,
  1178. proxy_DefineGeneric,
  1179. proxy_DefineProperty,
  1180. proxy_DefineElement,
  1181. proxy_DefineSpecial,
  1182. proxy_GetGeneric,
  1183. proxy_GetProperty,
  1184. proxy_GetElement,
  1185. proxy_GetElementIfPresent,
  1186. proxy_GetSpecial,
  1187. proxy_SetGeneric,
  1188. proxy_SetProperty,
  1189. proxy_SetElement,
  1190. proxy_SetSpecial,
  1191. proxy_GetGenericAttributes,
  1192. proxy_GetPropertyAttributes,
  1193. proxy_GetElementAttributes,
  1194. proxy_GetSpecialAttributes,
  1195. proxy_SetGenericAttributes,
  1196. proxy_SetPropertyAttributes,
  1197. proxy_SetElementAttributes,
  1198. proxy_SetSpecialAttributes,
  1199. proxy_DeleteProperty,
  1200. proxy_DeleteElement,
  1201. proxy_DeleteSpecial,
  1202. NULL, /* enumerate */
  1203. proxy_TypeOf,
  1204. proxy_Fix, /* fix */
  1205. NULL, /* thisObject */
  1206. NULL, /* clear */
  1207. }
  1208. };
  1209. JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = {
  1210. "Proxy",
  1211. Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(4),
  1212. JS_PropertyStub, /* addProperty */
  1213. JS_PropertyStub, /* delProperty */
  1214. JS_PropertyStub, /* getProperty */
  1215. JS_StrictPropertyStub, /* setProperty */
  1216. JS_EnumerateStub,
  1217. JS_ResolveStub,
  1218. JS_ConvertStub,
  1219. proxy_Finalize, /* finalize */
  1220. NULL, /* reserved0 */
  1221. NULL, /* checkAccess */
  1222. NULL, /* call */
  1223. NULL, /* construct */
  1224. NULL, /* xdrObject */
  1225. NULL, /* hasInstance */
  1226. proxy_TraceObject, /* trace */
  1227. {
  1228. NULL, /* equality */
  1229. NULL, /* outerObject */
  1230. proxy_innerObject,
  1231. NULL /* unused */
  1232. },
  1233. {
  1234. proxy_LookupGeneric,
  1235. proxy_LookupProperty,
  1236. proxy_LookupElement,
  1237. proxy_LookupSpecial,
  1238. proxy_DefineGeneric,
  1239. proxy_DefineProperty,
  1240. proxy_DefineElement,
  1241. proxy_DefineSpecial,
  1242. proxy_GetGeneric,
  1243. proxy_GetProperty,
  1244. proxy_GetElement,
  1245. proxy_GetElementIfPresent,
  1246. proxy_GetSpecial,
  1247. proxy_SetGeneric,
  1248. proxy_SetProperty,
  1249. proxy_SetElement,
  1250. proxy_SetSpecial,
  1251. proxy_GetGenericAttributes,
  1252. proxy_GetPropertyAttributes,
  1253. proxy_GetElementAttributes,
  1254. proxy_GetSpecialAttributes,
  1255. proxy_SetGenericAttributes,
  1256. proxy_SetPropertyAttributes,
  1257. proxy_SetElementAttributes,
  1258. proxy_SetSpecialAttributes,
  1259. proxy_DeleteProperty,
  1260. proxy_DeleteElement,
  1261. proxy_DeleteSpecial,
  1262. NULL, /* enumerate */
  1263. NULL, /* typeof */
  1264. NULL, /* fix */
  1265. NULL, /* thisObject */
  1266. NULL, /* clear */
  1267. }
  1268. };
  1269. static JSBool
  1270. proxy_Call(JSContext *cx, uintN argc, Value *vp)
  1271. {
  1272. JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
  1273. JS_ASSERT(proxy->isProxy());
  1274. return Proxy::call(cx, proxy, argc, vp);
  1275. }
  1276. static JSBool
  1277. proxy_Construct(JSContext *cx, uintN argc, Value *vp)
  1278. {
  1279. JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
  1280. JS_ASSERT(proxy->isProxy());
  1281. bool ok = Proxy::construct(cx, proxy, argc, JS_ARGV(cx, vp), vp);
  1282. return ok;
  1283. }
  1284. JS_FRIEND_DATA(Class) js::FunctionProxyClass = {
  1285. "Proxy",
  1286. Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(6),
  1287. JS_PropertyStub, /* addProperty */
  1288. JS_PropertyStub, /* delProperty */
  1289. JS_PropertyStub, /* getProperty */
  1290. JS_StrictPropertyStub, /* setProperty */
  1291. JS_EnumerateStub,
  1292. JS_ResolveStub,
  1293. JS_ConvertStub,
  1294. NULL, /* finalize */
  1295. NULL, /* reserved0 */
  1296. NULL, /* checkAccess */
  1297. proxy_Call,
  1298. proxy_Construct,
  1299. NULL, /* xdrObject */
  1300. FunctionClass.hasInstance,
  1301. proxy_TraceFunction, /* trace */
  1302. JS_NULL_CLASS_EXT,
  1303. {
  1304. proxy_LookupGeneric,
  1305. proxy_LookupProperty,
  1306. proxy_LookupElement,
  1307. proxy_LookupSpecial,
  1308. proxy_DefineGeneric,
  1309. proxy_DefineProperty,
  1310. proxy_DefineElement,
  1311. proxy_DefineSpecial,
  1312. proxy_GetGeneric,
  1313. proxy_GetProperty,
  1314. proxy_GetElement,
  1315. proxy_GetElementIfPresent,
  1316. proxy_GetSpecial,
  1317. proxy_SetGeneric,
  1318. proxy_SetProperty,
  1319. proxy_SetElement,
  1320. proxy_SetSpecial,
  1321. proxy_GetGenericAttributes,
  1322. proxy_GetPropertyAttributes,
  1323. proxy_GetElementAttributes,
  1324. proxy_GetSpecialAttributes,
  1325. proxy_SetGenericAttributes,
  1326. proxy_SetPropertyAttributes,
  1327. proxy_SetElementAttributes,
  1328. proxy_SetSpecialAttributes,
  1329. proxy_DeleteProperty,
  1330. proxy_DeleteElement,
  1331. proxy_DeleteSpecial,
  1332. NULL, /* enumerate */
  1333. proxy_TypeOf,
  1334. proxy_Fix, /* fix */
  1335. NULL, /* thisObject */
  1336. NULL, /* clear */
  1337. }
  1338. };
  1339. JS_FRIEND_API(JSObject *)
  1340. js::NewProxyObject(JSContext *cx, ProxyHandler *handler, const Value &priv, JSObject *proto,
  1341. JSObject *parent, JSObject *call, JSObject *construct)
  1342. {
  1343. JS_ASSERT_IF(proto, cx->compartment == proto->compartment());
  1344. JS_ASSERT_IF(parent, cx->compartment == parent->compartment());
  1345. bool fun = call || construct;
  1346. Class *clasp;
  1347. if (fun)
  1348. clasp = &FunctionProxyClass;
  1349. else
  1350. clasp = handler->isOuterWindow() ? &OuterWindowProxyClass : &ObjectProxyClass;
  1351. /*
  1352. * Eagerly mark properties unknown for proxies, so we don't try to track
  1353. * their properties and so that we don't need to walk the compartment if
  1354. * their prototype changes later.
  1355. */
  1356. if (proto && !proto->setNewTypeUnknown(cx))
  1357. return NULL;
  1358. JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent);
  1359. if (!obj)
  1360. return NULL;
  1361. obj->setSlot(JSSLOT_PROXY_HANDLER, PrivateValue(handler));
  1362. obj->setSlot(JSSLOT_PROXY_PRIVATE, priv);
  1363. if (fun) {
  1364. obj->setSlot(JSSLOT_PROXY_CALL, call ? ObjectValue(*call) : UndefinedValue());
  1365. if (construct) {
  1366. obj->setSlot(JSSLOT_PROXY_CONSTRUCT, ObjectValue(*construct));
  1367. }
  1368. }
  1369. /* Don't track types of properties of proxies. */
  1370. MarkTypeObjectUnknownProperties(cx, obj->type());
  1371. return obj;
  1372. }
  1373. static JSBool
  1374. proxy_create(JSContext *cx, uintN argc, Value *vp)
  1375. {
  1376. if (argc < 1) {
  1377. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
  1378. "create", "0", "s");
  1379. return false;
  1380. }
  1381. JSObject *handler = NonNullObject(cx, vp[2]);
  1382. if (!handler)
  1383. return false;
  1384. JSObject *proto, *parent = NULL;
  1385. if (argc > 1 && vp[3].isObject()) {
  1386. proto = &vp[3].toObject();
  1387. parent = proto->getParent();
  1388. } else {
  1389. JS_ASSERT(IsFunctionObject(vp[0]));
  1390. proto = NULL;
  1391. }
  1392. if (!parent)
  1393. parent = vp[0].toObject().getParent();
  1394. JSObject *proxy = NewProxyObject(cx, &ScriptedProxyHandler::singleton, ObjectValue(*handler),
  1395. proto, parent);
  1396. if (!proxy)
  1397. return false;
  1398. vp->setObject(*proxy);
  1399. return true;
  1400. }
  1401. static JSBool
  1402. proxy_createFunction(JSContext *cx, uintN argc, Value *vp)
  1403. {
  1404. if (argc < 2) {
  1405. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
  1406. "createFunction", "1", "");
  1407. return false;
  1408. }
  1409. JSObject *handler = NonNullObject(cx, vp[2]);
  1410. if (!handler)
  1411. return false;
  1412. JSObject *proto, *parent;
  1413. parent = vp[0].toObject().getParent();
  1414. proto = parent->global().getOrCreateFunctionPrototype(cx);
  1415. if (!proto)
  1416. return false;
  1417. parent = proto->getParent();
  1418. JSObject *call = js_ValueToCallableObject(cx, &vp[3], JSV2F_SEARCH_STACK);
  1419. if (!call)
  1420. return false;
  1421. JSObject *construct = NULL;
  1422. if (argc > 2) {
  1423. construct = js_ValueToCallableObject(cx, &vp[4], JSV2F_SEARCH_STACK);
  1424. if (!construct)
  1425. return false;
  1426. }
  1427. JSObject *proxy = NewProxyObject(cx, &ScriptedProxyHandler::singleton,
  1428. ObjectValue(*handler),
  1429. proto, parent, call, construct);
  1430. if (!proxy)
  1431. return false;
  1432. vp->setObject(*proxy);
  1433. return true;
  1434. }
  1435. #ifdef DEBUG
  1436. static JSBool
  1437. proxy_isTrapping(JSContext *cx, uintN argc, Value *vp)
  1438. {
  1439. if (argc < 1) {
  1440. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
  1441. "isTrapping", "0", "s");
  1442. return false;
  1443. }
  1444. JSObject *obj = NonNullObject(cx, vp[2]);
  1445. if (!obj)
  1446. return false;
  1447. vp->setBoolean(obj->isProxy());
  1448. return true;
  1449. }
  1450. static JSBool
  1451. proxy_fix(JSContext *cx, uintN argc, Value *vp)
  1452. {
  1453. if (argc < 1) {
  1454. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
  1455. "fix", "0", "s");
  1456. return false;
  1457. }
  1458. JSObject *obj = NonNullObject(cx, vp[2]);
  1459. if (!obj)
  1460. return false;
  1461. if (obj->isProxy()) {
  1462. JSBool flag;
  1463. if (!FixProxy(cx, obj, &flag))
  1464. return false;
  1465. vp->setBoolean(flag);
  1466. } else {
  1467. vp->setBoolean(true);
  1468. }
  1469. return true;
  1470. }
  1471. #endif
  1472. static JSFunctionSpec static_methods[] = {
  1473. JS_FN("create", proxy_create, 2, 0),
  1474. JS_FN("createFunction", proxy_createFunction, 3, 0),
  1475. #ifdef DEBUG
  1476. JS_FN("isTrapping", proxy_isTrapping, 1, 0),
  1477. JS_FN("fix", proxy_fix, 1, 0),
  1478. #endif
  1479. JS_FS_END
  1480. };
  1481. static const uint32_t JSSLOT_CALLABLE_CALL = 0;
  1482. static const uint32_t JSSLOT_CALLABLE_CONSTRUCT = 1;
  1483. static JSBool
  1484. callable_Call(JSContext *cx, uintN argc, Value *vp)
  1485. {
  1486. JSObject *callable = &JS_CALLEE(cx, vp).toObject();
  1487. JS_ASSERT(callable->getClass() == &CallableObjectClass);
  1488. const Value &fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
  1489. const Value &thisval = vp[1];
  1490. bool ok = Invoke(cx, thisval, fval, argc, JS_ARGV(cx, vp), vp);
  1491. return ok;
  1492. }
  1493. JSBool
  1494. callable_Construct(JSContext *cx, uintN argc, Value *vp)
  1495. {
  1496. JSObject *thisobj = js_CreateThis(cx, &JS_CALLEE(cx, vp).toObject());
  1497. if (!thisobj)
  1498. return false;
  1499. JSObject *callable = &vp[0].toObject();
  1500. JS_ASSERT(callable->getClass() == &CallableObjectClass);
  1501. Value fval = callable->getSlot(JSSLOT_CALLABLE_CONSTRUCT);
  1502. if (fval.isUndefined()) {
  1503. /* We don't have an explicit constructor so allocate a new object and use the call. */
  1504. fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
  1505. JS_ASSERT(fval.isObject());
  1506. /* callable is the constructor, so get callable.prototype is the proto of the new object. */
  1507. Value protov;
  1508. if (!callable->getProperty(cx, ATOM(classPrototype), &protov))
  1509. return false;
  1510. JSObject *proto;
  1511. if (protov.isObject()) {
  1512. proto = &protov.toObject();
  1513. } else {
  1514. proto = callable->global().getOrCreateObjectPrototype(cx);
  1515. if (!proto)
  1516. return false;
  1517. }
  1518. JSObject *newobj = NewObjectWithGivenProto(cx, &ObjectClass, proto, NULL);
  1519. if (!newobj)
  1520. return false;
  1521. /* If the call returns an object, return that, otherwise the original newobj. */
  1522. Value rval;
  1523. if (!Invoke(cx, ObjectValue(*newobj), callable->getSlot(JSSLOT_CALLABLE_CALL),
  1524. argc, vp + 2, &rval)) {
  1525. return false;
  1526. }
  1527. if (rval.isPrimitive())
  1528. vp->setObject(*newobj);
  1529. else
  1530. *vp = rval;
  1531. return true;
  1532. }
  1533. bool ok = Invoke(cx, ObjectValue(*thisobj), fval, argc, vp + 2, vp);
  1534. return ok;
  1535. }
  1536. Class js::CallableObjectClass = {
  1537. "Function",
  1538. JSCLASS_HAS_RESERVED_SLOTS(2),
  1539. JS_PropertyStub, /* addProperty */
  1540. JS_PropertyStub, /* delProperty */
  1541. JS_PropertyStub, /* getProperty */
  1542. JS_StrictPropertyStub, /* setProperty */
  1543. JS_EnumerateStub,
  1544. JS_ResolveStub,
  1545. JS_ConvertStub,
  1546. NULL, /* finalize */
  1547. NULL, /* reserved0 */
  1548. NULL, /* checkAccess */
  1549. callable_Call,
  1550. callable_Construct,
  1551. };
  1552. JS_FRIEND_API(JSBool)
  1553. js::FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
  1554. {
  1555. if (OperationInProgress(cx, proxy)) {
  1556. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROXY_FIX);
  1557. return false;
  1558. }
  1559. AutoValueRooter tvr(cx);
  1560. if (!Proxy::fix(cx, proxy, tvr.addr()))
  1561. return false;
  1562. if (tvr.value().isUndefined()) {
  1563. *bp = false;
  1564. return true;
  1565. }
  1566. JSObject *props = NonNullObject(cx, tvr.value());
  1567. if (!props)
  1568. return false;
  1569. JSObject *proto = proxy->getProto();
  1570. JSObject *parent = proxy->getParent();
  1571. Class *clasp = IsFunctionProxy(proxy) ? &CallableObjectClass : &ObjectClass;
  1572. /*
  1573. * Make a blank object from the recipe fix provided to us. This must have
  1574. * number of fixed slots as the proxy so that we can swap their contents.
  1575. */
  1576. gc::AllocKind kind = proxy->getAllocKind();
  1577. JSObject *newborn = NewObjectWithGivenProto(cx, clasp, proto, parent, kind);
  1578. if (!newborn)
  1579. return false;
  1580. if (clasp == &CallableObjectClass) {
  1581. newborn->setSlot(JSSLOT_CALLABLE_CALL, GetCall(proxy));
  1582. newborn->setSlot(JSSLOT_CALLABLE_CONSTRUCT, GetConstruct(proxy));
  1583. }
  1584. {
  1585. AutoPendingProxyOperation pending(cx, proxy);
  1586. if (!js_PopulateObject(cx, newborn, props))
  1587. return false;
  1588. }
  1589. /* Trade contents between the newborn object and the proxy. */
  1590. if (!proxy->swap(cx, newborn))
  1591. return false;
  1592. /* The GC will dispose of the proxy object. */
  1593. *bp = true;
  1594. return true;
  1595. }
  1596. Class js::ProxyClass = {
  1597. "Proxy",
  1598. JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy),
  1599. JS_PropertyStub, /* addProperty */
  1600. JS_PropertyStub, /* delProperty */
  1601. JS_PropertyStub, /* getProperty */
  1602. JS_StrictPropertyStub, /* setProperty */
  1603. JS_EnumerateStub,
  1604. JS_ResolveStub,
  1605. JS_ConvertStub
  1606. };
  1607. JS_FRIEND_API(JSObject *)
  1608. js_InitProxyClass(JSContext *cx, JSObject *obj)
  1609. {
  1610. JSObject *module = NewObjectWithClassProto(cx, &ProxyClass, NULL, obj);
  1611. if (!module || !module->setSingletonType(cx))
  1612. return NULL;
  1613. if (!JS_DefineProperty(cx, obj, "Proxy", OBJECT_TO_JSVAL(module),
  1614. JS_PropertyStub, JS_StrictPropertyStub, 0)) {
  1615. return NULL;
  1616. }
  1617. if (!JS_DefineFunctions(cx, module, static_methods))
  1618. return NULL;
  1619. MarkStandardClassInitializedNoProto(obj, &ProxyClass);
  1620. return module;
  1621. }