2010-05-18 19:21:43 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
* vim: set ts=4 sw=4 et tw=99:
|
|
|
|
*
|
|
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
|
|
|
* May 28, 2008.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Mozilla Foundation
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2009
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Andreas Gal <gal@mozilla.com>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include "jsapi.h"
|
|
|
|
#include "jscntxt.h"
|
2011-04-15 16:56:08 -07:00
|
|
|
#include "jsgc.h"
|
|
|
|
#include "jsgcmark.h"
|
2010-05-18 19:21:43 -07:00
|
|
|
#include "jsprvtd.h"
|
|
|
|
#include "jsnum.h"
|
|
|
|
#include "jsobj.h"
|
|
|
|
#include "jsproxy.h"
|
|
|
|
#include "jsscope.h"
|
|
|
|
|
2011-04-30 00:19:26 -07:00
|
|
|
#include "jsatominlines.h"
|
2010-05-18 19:21:43 -07:00
|
|
|
#include "jsobjinlines.h"
|
|
|
|
|
|
|
|
using namespace js;
|
2010-09-24 10:54:39 -07:00
|
|
|
using namespace js::gc;
|
2010-05-18 19:21:43 -07:00
|
|
|
|
2010-05-24 14:33:03 -07:00
|
|
|
namespace js {
|
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
static inline const Value &
|
2010-06-23 14:35:10 -07:00
|
|
|
GetCall(JSObject *proxy) {
|
|
|
|
JS_ASSERT(proxy->isFunctionProxy());
|
|
|
|
return proxy->getSlot(JSSLOT_PROXY_CALL);
|
|
|
|
}
|
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
static inline Value
|
2010-06-23 14:35:10 -07:00
|
|
|
GetConstruct(JSObject *proxy) {
|
|
|
|
if (proxy->numSlots() <= JSSLOT_PROXY_CONSTRUCT)
|
2010-07-14 23:19:36 -07:00
|
|
|
return UndefinedValue();
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getSlot(JSSLOT_PROXY_CONSTRUCT);
|
|
|
|
}
|
|
|
|
|
2010-06-03 18:12:01 -07:00
|
|
|
static bool
|
|
|
|
OperationInProgress(JSContext *cx, JSObject *proxy)
|
|
|
|
{
|
2011-03-13 07:45:02 -07:00
|
|
|
PendingProxyOperation *op = JS_THREAD_DATA(cx)->pendingProxyOperation;
|
2010-06-03 18:12:01 -07:00
|
|
|
while (op) {
|
|
|
|
if (op->object == proxy)
|
|
|
|
return true;
|
|
|
|
op = op->next;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-06-24 14:45:32 -07:00
|
|
|
JSProxyHandler::JSProxyHandler(void *family) : mFamily(family)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-05-18 19:21:43 -07:00
|
|
|
JSProxyHandler::~JSProxyHandler()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
JSProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JS_ASSERT(OperationInProgress(cx, proxy));
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoPropertyDescriptorRooter desc(cx);
|
2010-09-17 14:54:41 -07:00
|
|
|
if (!getPropertyDescriptor(cx, proxy, id, false, &desc))
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
*bp = !!desc.obj;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
JSProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JS_ASSERT(OperationInProgress(cx, proxy));
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoPropertyDescriptorRooter desc(cx);
|
2010-09-17 14:54:41 -07:00
|
|
|
if (!getOwnPropertyDescriptor(cx, proxy, id, false, &desc))
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
*bp = !!desc.obj;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JS_ASSERT(OperationInProgress(cx, proxy));
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoPropertyDescriptorRooter desc(cx);
|
2010-09-17 14:54:41 -07:00
|
|
|
if (!getPropertyDescriptor(cx, proxy, id, false, &desc))
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
if (!desc.obj) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setUndefined();
|
2010-05-18 19:21:43 -07:00
|
|
|
return true;
|
|
|
|
}
|
2010-09-16 11:40:59 -07:00
|
|
|
if (!desc.getter ||
|
|
|
|
(!(desc.attrs & JSPROP_GETTER) && desc.getter == PropertyStub)) {
|
2010-05-18 19:21:43 -07:00
|
|
|
*vp = desc.value;
|
|
|
|
return true;
|
|
|
|
}
|
2010-05-19 14:43:17 -07:00
|
|
|
if (desc.attrs & JSPROP_GETTER) {
|
2010-10-29 10:42:35 -07:00
|
|
|
return ExternalGetOrSet(cx, receiver, id, CastAsObjectJsval(desc.getter),
|
2010-09-16 11:43:33 -07:00
|
|
|
JSACC_READ, 0, NULL, vp);
|
2010-05-19 14:43:17 -07:00
|
|
|
}
|
2010-09-16 11:45:55 -07:00
|
|
|
if (!(desc.attrs & JSPROP_SHARED))
|
|
|
|
*vp = desc.value;
|
2010-10-10 15:46:34 -07:00
|
|
|
else
|
|
|
|
vp->setUndefined();
|
2010-05-19 14:43:17 -07:00
|
|
|
if (desc.attrs & JSPROP_SHORTID)
|
|
|
|
id = INT_TO_JSID(desc.shortid);
|
2010-10-29 10:42:35 -07:00
|
|
|
return CallJSPropertyOp(cx, desc.getter, receiver, id, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2011-02-09 11:31:40 -08:00
|
|
|
JSProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
|
|
|
|
Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JS_ASSERT(OperationInProgress(cx, proxy));
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoPropertyDescriptorRooter desc(cx);
|
2010-09-17 14:54:41 -07:00
|
|
|
if (!getOwnPropertyDescriptor(cx, proxy, id, true, &desc))
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
2010-05-19 14:43:17 -07:00
|
|
|
/* The control-flow here differs from ::get() because of the fall-through case below. */
|
2010-05-18 19:21:43 -07:00
|
|
|
if (desc.obj) {
|
2010-05-19 14:43:17 -07:00
|
|
|
if (desc.attrs & JSPROP_READONLY)
|
|
|
|
return true;
|
2011-03-08 18:08:59 -08:00
|
|
|
if (!desc.setter) {
|
|
|
|
desc.setter = StrictPropertyStub;
|
|
|
|
} else if ((desc.attrs & JSPROP_SETTER) || desc.setter != StrictPropertyStub) {
|
2011-02-09 11:31:40 -08:00
|
|
|
if (!CallSetter(cx, receiver, id, desc.setter, desc.attrs, desc.shortid, strict, vp))
|
2011-02-03 20:13:18 -08:00
|
|
|
return false;
|
2011-03-08 15:05:11 -08:00
|
|
|
if (!proxy->isProxy() || proxy->getProxyHandler() != this)
|
|
|
|
return true;
|
2011-02-03 20:13:18 -08:00
|
|
|
if (desc.attrs & JSPROP_SHARED)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!desc.getter)
|
|
|
|
desc.getter = PropertyStub;
|
2010-05-19 14:43:17 -07:00
|
|
|
desc.value = *vp;
|
2010-10-29 10:42:35 -07:00
|
|
|
return defineProperty(cx, receiver, id, &desc);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
2010-09-17 14:54:41 -07:00
|
|
|
if (!getPropertyDescriptor(cx, proxy, id, true, &desc))
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
if (desc.obj) {
|
2010-05-19 14:43:17 -07:00
|
|
|
if (desc.attrs & JSPROP_READONLY)
|
|
|
|
return true;
|
2011-03-08 18:08:59 -08:00
|
|
|
if (!desc.setter) {
|
|
|
|
desc.setter = StrictPropertyStub;
|
|
|
|
} else if ((desc.attrs & JSPROP_SETTER) || desc.setter != StrictPropertyStub) {
|
2011-02-09 11:31:40 -08:00
|
|
|
if (!CallSetter(cx, receiver, id, desc.setter, desc.attrs, desc.shortid, strict, vp))
|
2011-02-03 20:13:18 -08:00
|
|
|
return false;
|
2011-03-08 15:05:11 -08:00
|
|
|
if (!proxy->isProxy() || proxy->getProxyHandler() != this)
|
|
|
|
return true;
|
2011-02-03 20:13:18 -08:00
|
|
|
if (desc.attrs & JSPROP_SHARED)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!desc.getter)
|
|
|
|
desc.getter = PropertyStub;
|
2011-02-07 16:06:24 -08:00
|
|
|
return defineProperty(cx, receiver, id, &desc);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
2011-02-03 20:13:18 -08:00
|
|
|
|
2010-10-29 10:42:35 -07:00
|
|
|
desc.obj = receiver;
|
2010-05-18 19:21:43 -07:00
|
|
|
desc.value = *vp;
|
2010-10-10 15:49:08 -07:00
|
|
|
desc.attrs = JSPROP_ENUMERATE;
|
2010-05-18 19:21:43 -07:00
|
|
|
desc.shortid = 0;
|
2011-02-11 09:56:19 -08:00
|
|
|
desc.getter = NULL;
|
|
|
|
desc.setter = NULL; // Pick up the class getter/setter.
|
2010-10-29 10:42:35 -07:00
|
|
|
return defineProperty(cx, receiver, id, &desc);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2011-01-10 11:42:11 -08:00
|
|
|
JSProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JS_ASSERT(OperationInProgress(cx, proxy));
|
2010-06-16 16:11:13 -07:00
|
|
|
JS_ASSERT(props.length() == 0);
|
|
|
|
|
2010-06-17 14:37:33 -07:00
|
|
|
if (!getOwnPropertyNames(cx, proxy, props))
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
2010-06-16 16:11:13 -07:00
|
|
|
|
2010-06-17 14:37:33 -07:00
|
|
|
/* Select only the enumerable properties through in-place iteration. */
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoPropertyDescriptorRooter desc(cx);
|
2010-06-17 14:37:33 -07:00
|
|
|
size_t i = 0;
|
|
|
|
for (size_t j = 0, len = props.length(); j < len; j++) {
|
|
|
|
JS_ASSERT(i <= j);
|
|
|
|
jsid id = props[j];
|
2010-09-17 14:54:41 -07:00
|
|
|
if (!getOwnPropertyDescriptor(cx, proxy, id, false, &desc))
|
2010-06-16 16:11:13 -07:00
|
|
|
return false;
|
2010-06-17 14:37:33 -07:00
|
|
|
if (desc.obj && (desc.attrs & JSPROP_ENUMERATE))
|
|
|
|
props[i++] = id;
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
2010-06-16 16:11:13 -07:00
|
|
|
|
2010-06-17 14:37:33 -07:00
|
|
|
JS_ASSERT(i <= props.length());
|
|
|
|
props.resize(i);
|
|
|
|
|
2010-05-18 19:21:43 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-05-27 12:03:25 -07:00
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxyHandler::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JS_ASSERT(OperationInProgress(cx, proxy));
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoIdVector props(cx);
|
2010-11-10 14:08:44 -08:00
|
|
|
if ((flags & JSITER_OWNONLY)
|
2011-01-10 11:42:11 -08:00
|
|
|
? !keys(cx, proxy, props)
|
2010-11-10 14:08:44 -08:00
|
|
|
: !enumerate(cx, proxy, props)) {
|
2010-05-27 12:03:25 -07:00
|
|
|
return false;
|
2010-11-10 14:08:44 -08:00
|
|
|
}
|
2010-07-14 23:19:36 -07:00
|
|
|
return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
2010-09-28 00:16:59 -07:00
|
|
|
|
2010-06-23 14:35:10 -07:00
|
|
|
JSString *
|
|
|
|
JSProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
|
|
|
|
{
|
|
|
|
JS_ASSERT(proxy->isProxy());
|
|
|
|
|
|
|
|
return JS_NewStringCopyZ(cx, proxy->isFunctionProxy()
|
|
|
|
? "[object Function]"
|
|
|
|
: "[object Object]");
|
|
|
|
}
|
|
|
|
|
|
|
|
JSString *
|
|
|
|
JSProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, uintN indent)
|
|
|
|
{
|
|
|
|
JS_ASSERT(proxy->isProxy());
|
2010-07-14 23:19:36 -07:00
|
|
|
Value fval = GetCall(proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
if (proxy->isFunctionProxy() &&
|
2010-07-14 23:19:36 -07:00
|
|
|
(fval.isPrimitive() || !fval.toObject().isFunction())) {
|
2010-06-23 14:35:10 -07:00
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
|
|
JSMSG_INCOMPATIBLE_PROTO,
|
|
|
|
js_Function_str, js_toString_str,
|
|
|
|
"object");
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-14 23:19:36 -07:00
|
|
|
return fun_toStringHelper(cx, &fval.toObject(), indent);
|
2010-06-23 14:35:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxyHandler::call(JSContext *cx, JSObject *proxy, uintN argc, Value *vp)
|
2010-06-23 14:35:10 -07:00
|
|
|
{
|
|
|
|
JS_ASSERT(OperationInProgress(cx, proxy));
|
|
|
|
AutoValueRooter rval(cx);
|
2010-08-16 12:35:04 -07:00
|
|
|
JSBool ok = ExternalInvoke(cx, vp[1], GetCall(proxy), argc, JS_ARGV(cx, vp),
|
2010-07-14 23:19:36 -07:00
|
|
|
rval.addr());
|
2010-06-23 14:35:10 -07:00
|
|
|
if (ok)
|
|
|
|
JS_SET_RVAL(cx, vp, rval.value());
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-02 14:51:42 -07:00
|
|
|
JSProxyHandler::construct(JSContext *cx, JSObject *proxy,
|
2010-07-14 23:19:36 -07:00
|
|
|
uintN argc, Value *argv, Value *rval)
|
2010-06-23 14:35:10 -07:00
|
|
|
{
|
|
|
|
JS_ASSERT(OperationInProgress(cx, proxy));
|
2010-07-14 23:19:36 -07:00
|
|
|
Value fval = GetConstruct(proxy);
|
2010-11-02 17:39:05 -07:00
|
|
|
if (fval.isUndefined())
|
|
|
|
return ExternalInvokeConstructor(cx, GetCall(proxy), argc, argv, rval);
|
2011-01-26 13:37:45 -08:00
|
|
|
return ExternalInvoke(cx, UndefinedValue(), fval, argc, argv, rval);
|
2010-06-23 14:35:10 -07:00
|
|
|
}
|
2010-05-27 12:03:25 -07:00
|
|
|
|
2010-10-10 15:39:26 -07:00
|
|
|
bool
|
|
|
|
JSProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
|
|
|
|
{
|
|
|
|
JS_ASSERT(OperationInProgress(cx, proxy));
|
|
|
|
js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
|
|
|
|
JSDVG_SEARCH_STACK, ObjectValue(*proxy), NULL);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-11-10 15:56:00 -08:00
|
|
|
JSType
|
|
|
|
JSProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
|
|
|
|
{
|
|
|
|
JS_ASSERT(OperationInProgress(cx, proxy));
|
|
|
|
return proxy->isFunctionProxy() ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
|
|
|
|
}
|
|
|
|
|
2010-05-18 19:21:43 -07:00
|
|
|
void
|
|
|
|
JSProxyHandler::finalize(JSContext *cx, JSObject *proxy)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-05-24 14:26:36 -07:00
|
|
|
void
|
|
|
|
JSProxyHandler::trace(JSTracer *trc, JSObject *proxy)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-05-18 19:21:43 -07:00
|
|
|
static bool
|
2010-07-14 23:19:36 -07:00
|
|
|
GetTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-10-03 14:59:26 -07:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
|
|
|
|
2010-05-27 12:03:25 -07:00
|
|
|
return handler->getProperty(cx, ATOM_TO_JSID(atom), fvalp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2010-10-03 14:59:26 -07:00
|
|
|
GetFundamentalTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-05-27 12:03:25 -07:00
|
|
|
if (!GetTrap(cx, handler, atom, fvalp))
|
|
|
|
return false;
|
2010-05-19 00:13:02 -07:00
|
|
|
|
2010-05-27 12:03:25 -07:00
|
|
|
if (!js_IsCallable(*fvalp)) {
|
2010-11-11 12:40:29 -08:00
|
|
|
JSAutoByteString bytes;
|
|
|
|
if (js_AtomToPrintableString(cx, atom, &bytes))
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_FUNCTION, bytes.ptr());
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2010-10-03 14:59:26 -07:00
|
|
|
GetDerivedTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
|
|
|
JS_ASSERT(atom == ATOM(has) ||
|
|
|
|
atom == ATOM(hasOwn) ||
|
|
|
|
atom == ATOM(get) ||
|
|
|
|
atom == ATOM(set) ||
|
2011-01-10 11:42:11 -08:00
|
|
|
atom == ATOM(keys) ||
|
2010-05-27 12:03:25 -07:00
|
|
|
atom == ATOM(iterate));
|
2010-09-28 00:16:59 -07:00
|
|
|
|
2010-05-27 12:03:25 -07:00
|
|
|
return GetTrap(cx, handler, atom, fvalp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2010-07-14 23:19:36 -07:00
|
|
|
Trap(JSContext *cx, JSObject *handler, Value fval, uintN argc, Value* argv, Value *rval)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2011-01-26 13:37:45 -08:00
|
|
|
return ExternalInvoke(cx, ObjectValue(*handler), fval, argc, argv, rval);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
2010-05-27 12:01:55 -07:00
|
|
|
static bool
|
2010-07-14 23:19:36 -07:00
|
|
|
Trap1(JSContext *cx, JSObject *handler, Value fval, jsid id, Value *rval)
|
2010-05-27 12:01:55 -07:00
|
|
|
{
|
2010-07-14 23:19:36 -07:00
|
|
|
JSString *str = js_ValueToString(cx, IdToValue(id));
|
2010-05-27 12:01:55 -07:00
|
|
|
if (!str)
|
|
|
|
return false;
|
2010-07-14 23:19:36 -07:00
|
|
|
rval->setString(str);
|
2010-05-27 12:03:25 -07:00
|
|
|
return Trap(cx, handler, fval, 1, rval, rval);
|
2010-05-27 12:01:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2010-07-14 23:19:36 -07:00
|
|
|
Trap2(JSContext *cx, JSObject *handler, Value fval, jsid id, Value v, Value *rval)
|
2010-05-27 12:01:55 -07:00
|
|
|
{
|
2010-07-14 23:19:36 -07:00
|
|
|
JSString *str = js_ValueToString(cx, IdToValue(id));
|
2010-05-27 12:01:55 -07:00
|
|
|
if (!str)
|
|
|
|
return false;
|
2010-07-14 23:19:36 -07:00
|
|
|
rval->setString(str);
|
|
|
|
Value argv[2] = { *rval, v };
|
2010-05-27 12:03:25 -07:00
|
|
|
return Trap(cx, handler, fval, 2, argv, rval);
|
2010-05-27 12:01:55 -07:00
|
|
|
}
|
|
|
|
|
2010-05-18 19:21:43 -07:00
|
|
|
static bool
|
2010-07-14 23:19:36 -07:00
|
|
|
ParsePropertyDescriptorObject(JSContext *cx, JSObject *obj, jsid id, const Value &v,
|
|
|
|
PropertyDescriptor *desc)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoPropDescArrayRooter descs(cx);
|
|
|
|
PropDesc *d = descs.append();
|
2011-03-04 17:24:15 -08:00
|
|
|
if (!d || !d->initialize(cx, v))
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
desc->obj = obj;
|
|
|
|
desc->value = d->value;
|
|
|
|
JS_ASSERT(!(d->attrs & JSPROP_SHORTID));
|
|
|
|
desc->attrs = d->attrs;
|
|
|
|
desc->getter = d->getter();
|
|
|
|
desc->setter = d->setter();
|
|
|
|
desc->shortid = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-01-26 10:43:10 -08:00
|
|
|
static bool
|
|
|
|
IndicatePropertyNotFound(JSContext *cx, PropertyDescriptor *desc)
|
|
|
|
{
|
|
|
|
desc->obj = NULL;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-05-18 19:21:43 -07:00
|
|
|
static bool
|
2010-07-14 23:19:36 -07:00
|
|
|
MakePropertyDescriptorObject(JSContext *cx, jsid id, PropertyDescriptor *desc, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
|
|
|
if (!desc->obj) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setUndefined();
|
2010-05-18 19:21:43 -07:00
|
|
|
return true;
|
|
|
|
}
|
2010-05-19 14:43:17 -07:00
|
|
|
uintN attrs = desc->attrs;
|
2010-07-14 23:19:36 -07:00
|
|
|
Value getter = (attrs & JSPROP_GETTER) ? CastAsObjectJsval(desc->getter) : UndefinedValue();
|
|
|
|
Value setter = (attrs & JSPROP_SETTER) ? CastAsObjectJsval(desc->setter) : UndefinedValue();
|
2010-05-19 14:43:17 -07:00
|
|
|
return js_NewPropertyDescriptorObject(cx, id, attrs, getter, setter, desc->value, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
2010-05-27 12:03:25 -07:00
|
|
|
static bool
|
2010-07-14 23:19:36 -07:00
|
|
|
ValueToBool(JSContext *cx, const Value &v, bool *bp)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-07-14 23:19:36 -07:00
|
|
|
*bp = !!js_ValueToBoolean(v);
|
2010-05-27 12:03:25 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
ArrayToIdVector(JSContext *cx, const Value &array, AutoIdVector &props)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-06-16 16:11:13 -07:00
|
|
|
JS_ASSERT(props.length() == 0);
|
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
if (array.isPrimitive())
|
2010-06-16 16:11:13 -07:00
|
|
|
return true;
|
2010-05-27 12:03:25 -07:00
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
JSObject *obj = &array.toObject();
|
2010-05-27 12:03:25 -07:00
|
|
|
jsuint length;
|
2010-12-21 02:21:26 -08:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &length))
|
2010-05-27 12:03:25 -07:00
|
|
|
return false;
|
2010-06-16 16:11:13 -07:00
|
|
|
|
|
|
|
AutoIdRooter idr(cx);
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter tvr(cx);
|
|
|
|
for (jsuint n = 0; n < length; ++n) {
|
2010-12-21 02:21:26 -08:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
|
|
|
return false;
|
2011-04-30 00:19:26 -07:00
|
|
|
if (!IndexToId(cx, n, idr.addr()))
|
2010-05-27 12:03:25 -07:00
|
|
|
return false;
|
2010-06-16 16:11:13 -07:00
|
|
|
if (!obj->getProperty(cx, idr.id(), tvr.addr()))
|
2010-05-27 12:03:25 -07:00
|
|
|
return false;
|
2010-07-14 23:19:36 -07:00
|
|
|
if (!ValueToId(cx, tvr.value(), idr.addr()))
|
2010-06-16 16:11:13 -07:00
|
|
|
return false;
|
|
|
|
if (!props.append(js_CheckForStringIndex(idr.id())))
|
2010-05-27 12:03:25 -07:00
|
|
|
return false;
|
|
|
|
}
|
2010-06-16 16:11:13 -07:00
|
|
|
|
2010-05-27 12:03:25 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Derived class for all scripted proxy handlers. */
|
|
|
|
class JSScriptedProxyHandler : public JSProxyHandler {
|
|
|
|
public:
|
|
|
|
JSScriptedProxyHandler();
|
|
|
|
virtual ~JSScriptedProxyHandler();
|
|
|
|
|
|
|
|
/* ES5 Harmony fundamental proxy traps. */
|
2010-09-17 14:54:41 -07:00
|
|
|
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
|
2010-07-14 23:19:36 -07:00
|
|
|
PropertyDescriptor *desc);
|
2010-09-17 14:54:41 -07:00
|
|
|
virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
|
2010-07-14 23:19:36 -07:00
|
|
|
PropertyDescriptor *desc);
|
2010-05-27 12:03:25 -07:00
|
|
|
virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id,
|
2010-07-14 23:19:36 -07:00
|
|
|
PropertyDescriptor *desc);
|
|
|
|
virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props);
|
2010-05-27 12:03:25 -07:00
|
|
|
virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
2010-07-14 23:19:36 -07:00
|
|
|
virtual bool enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props);
|
|
|
|
virtual bool fix(JSContext *cx, JSObject *proxy, Value *vp);
|
2010-05-27 12:03:25 -07:00
|
|
|
|
|
|
|
/* ES5 Harmony derived proxy traps. */
|
|
|
|
virtual bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
|
|
|
virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
2010-07-14 23:19:36 -07:00
|
|
|
virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp);
|
2011-02-09 11:31:40 -08:00
|
|
|
virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
|
|
|
|
Value *vp);
|
2011-01-10 11:42:11 -08:00
|
|
|
virtual bool keys(JSContext *cx, JSObject *proxy, AutoIdVector &props);
|
2010-07-14 23:19:36 -07:00
|
|
|
virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp);
|
2010-05-27 12:03:25 -07:00
|
|
|
|
|
|
|
static JSScriptedProxyHandler singleton;
|
|
|
|
};
|
|
|
|
|
2010-06-24 14:45:32 -07:00
|
|
|
static int sScriptedProxyHandlerFamily = 0;
|
|
|
|
|
|
|
|
JSScriptedProxyHandler::JSScriptedProxyHandler() : JSProxyHandler(&sScriptedProxyHandlerFamily)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
JSScriptedProxyHandler::~JSScriptedProxyHandler()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-05-29 19:04:01 -07:00
|
|
|
static bool
|
2010-07-14 23:19:36 -07:00
|
|
|
ReturnedValueMustNotBePrimitive(JSContext *cx, JSObject *proxy, JSAtom *atom, const Value &v)
|
2010-05-29 19:04:01 -07:00
|
|
|
{
|
2010-07-14 23:19:36 -07:00
|
|
|
if (v.isPrimitive()) {
|
2010-11-11 12:40:29 -08:00
|
|
|
JSAutoByteString bytes;
|
|
|
|
if (js_AtomToPrintableString(cx, atom, &bytes)) {
|
|
|
|
js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
|
|
|
|
JSDVG_SEARCH_STACK, ObjectOrNullValue(proxy), NULL, bytes.ptr());
|
|
|
|
}
|
2010-05-29 19:04:01 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-06-03 18:12:01 -07:00
|
|
|
static JSObject *
|
|
|
|
GetProxyHandlerObject(JSContext *cx, JSObject *proxy)
|
|
|
|
{
|
|
|
|
JS_ASSERT(OperationInProgress(cx, proxy));
|
2010-07-14 23:19:36 -07:00
|
|
|
return proxy->getProxyPrivate().toObjectOrNull();
|
2010-06-03 18:12:01 -07:00
|
|
|
}
|
|
|
|
|
2010-05-27 12:03:25 -07:00
|
|
|
bool
|
2010-09-17 14:54:41 -07:00
|
|
|
JSScriptedProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
|
2010-07-14 23:19:36 -07:00
|
|
|
PropertyDescriptor *desc)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter tvr(cx);
|
2010-10-03 14:59:26 -07:00
|
|
|
return GetFundamentalTrap(cx, handler, ATOM(getPropertyDescriptor), tvr.addr()) &&
|
2010-06-03 18:12:01 -07:00
|
|
|
Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
|
2011-01-26 10:43:10 -08:00
|
|
|
((tvr.value().isUndefined() && IndicatePropertyNotFound(cx, desc)) ||
|
2011-02-03 20:13:18 -08:00
|
|
|
(ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), tvr.value()) &&
|
|
|
|
ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc)));
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-09-17 14:54:41 -07:00
|
|
|
JSScriptedProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
|
2010-07-14 23:19:36 -07:00
|
|
|
PropertyDescriptor *desc)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter tvr(cx);
|
2010-10-03 14:59:26 -07:00
|
|
|
return GetFundamentalTrap(cx, handler, ATOM(getOwnPropertyDescriptor), tvr.addr()) &&
|
2010-06-03 18:12:01 -07:00
|
|
|
Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
|
2011-01-26 10:43:10 -08:00
|
|
|
((tvr.value().isUndefined() && IndicatePropertyNotFound(cx, desc)) ||
|
2011-02-03 20:13:18 -08:00
|
|
|
(ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), tvr.value()) &&
|
|
|
|
ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc)));
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
JSScriptedProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id,
|
2010-07-14 23:19:36 -07:00
|
|
|
PropertyDescriptor *desc)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter tvr(cx);
|
|
|
|
AutoValueRooter fval(cx);
|
2010-10-03 14:59:26 -07:00
|
|
|
return GetFundamentalTrap(cx, handler, ATOM(defineProperty), fval.addr()) &&
|
2010-05-27 12:03:25 -07:00
|
|
|
MakePropertyDescriptorObject(cx, id, desc, tvr.addr()) &&
|
2010-06-03 18:12:01 -07:00
|
|
|
Trap2(cx, handler, fval.value(), id, tvr.value(), tvr.addr());
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSScriptedProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter tvr(cx);
|
2010-10-03 14:59:26 -07:00
|
|
|
return GetFundamentalTrap(cx, handler, ATOM(getOwnPropertyNames), tvr.addr()) &&
|
2010-06-03 18:12:01 -07:00
|
|
|
Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) &&
|
2010-06-16 16:11:13 -07:00
|
|
|
ArrayToIdVector(cx, tvr.value(), props);
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
JSScriptedProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter tvr(cx);
|
2010-10-03 14:59:26 -07:00
|
|
|
return GetFundamentalTrap(cx, handler, ATOM(delete), tvr.addr()) &&
|
2010-06-03 18:12:01 -07:00
|
|
|
Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
|
2010-05-27 12:03:25 -07:00
|
|
|
ValueToBool(cx, tvr.value(), bp);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSScriptedProxyHandler::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter tvr(cx);
|
2010-10-03 14:59:26 -07:00
|
|
|
return GetFundamentalTrap(cx, handler, ATOM(enumerate), tvr.addr()) &&
|
2010-06-03 18:12:01 -07:00
|
|
|
Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) &&
|
2010-06-16 16:11:13 -07:00
|
|
|
ArrayToIdVector(cx, tvr.value(), props);
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSScriptedProxyHandler::fix(JSContext *cx, JSObject *proxy, Value *vp)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-10-03 14:59:26 -07:00
|
|
|
return GetFundamentalTrap(cx, handler, ATOM(fix), vp) &&
|
2010-05-27 12:03:25 -07:00
|
|
|
Trap(cx, handler, *vp, 0, NULL, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
JSScriptedProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter tvr(cx);
|
2010-10-03 14:59:26 -07:00
|
|
|
if (!GetDerivedTrap(cx, handler, ATOM(has), tvr.addr()))
|
2010-05-27 12:03:25 -07:00
|
|
|
return false;
|
|
|
|
if (!js_IsCallable(tvr.value()))
|
|
|
|
return JSProxyHandler::has(cx, proxy, id, bp);
|
2010-06-03 18:12:01 -07:00
|
|
|
return Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
|
2010-05-27 12:03:25 -07:00
|
|
|
ValueToBool(cx, tvr.value(), bp);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
JSScriptedProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter tvr(cx);
|
2010-10-03 14:59:26 -07:00
|
|
|
if (!GetDerivedTrap(cx, handler, ATOM(hasOwn), tvr.addr()))
|
2010-05-27 12:03:25 -07:00
|
|
|
return false;
|
|
|
|
if (!js_IsCallable(tvr.value()))
|
|
|
|
return JSProxyHandler::hasOwn(cx, proxy, id, bp);
|
2010-06-03 18:12:01 -07:00
|
|
|
return Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
|
2010-05-27 12:03:25 -07:00
|
|
|
ValueToBool(cx, tvr.value(), bp);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSScriptedProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-07-14 23:19:36 -07:00
|
|
|
JSString *str = js_ValueToString(cx, IdToValue(id));
|
2010-05-27 12:03:25 -07:00
|
|
|
if (!str)
|
|
|
|
return false;
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoValueRooter tvr(cx, StringValue(str));
|
|
|
|
Value argv[] = { ObjectOrNullValue(receiver), tvr.value() };
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter fval(cx);
|
2010-10-03 14:59:26 -07:00
|
|
|
if (!GetDerivedTrap(cx, handler, ATOM(get), fval.addr()))
|
2010-05-27 12:03:25 -07:00
|
|
|
return false;
|
|
|
|
if (!js_IsCallable(fval.value()))
|
|
|
|
return JSProxyHandler::get(cx, proxy, receiver, id, vp);
|
2010-06-03 18:12:01 -07:00
|
|
|
return Trap(cx, handler, fval.value(), 2, argv, vp);
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2011-02-09 11:31:40 -08:00
|
|
|
JSScriptedProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
|
|
|
|
Value *vp)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-07-14 23:19:36 -07:00
|
|
|
JSString *str = js_ValueToString(cx, IdToValue(id));
|
2010-05-27 12:03:25 -07:00
|
|
|
if (!str)
|
|
|
|
return false;
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoValueRooter tvr(cx, StringValue(str));
|
|
|
|
Value argv[] = { ObjectOrNullValue(receiver), tvr.value(), *vp };
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter fval(cx);
|
2010-10-03 14:59:26 -07:00
|
|
|
if (!GetDerivedTrap(cx, handler, ATOM(set), fval.addr()))
|
2010-05-27 12:03:25 -07:00
|
|
|
return false;
|
|
|
|
if (!js_IsCallable(fval.value()))
|
2011-02-09 11:31:40 -08:00
|
|
|
return JSProxyHandler::set(cx, proxy, receiver, id, strict, vp);
|
2010-06-03 18:12:01 -07:00
|
|
|
return Trap(cx, handler, fval.value(), 3, argv, tvr.addr());
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2011-01-10 11:42:11 -08:00
|
|
|
JSScriptedProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter tvr(cx);
|
2011-01-10 11:42:11 -08:00
|
|
|
if (!GetDerivedTrap(cx, handler, ATOM(keys), tvr.addr()))
|
2010-05-27 12:03:25 -07:00
|
|
|
return false;
|
|
|
|
if (!js_IsCallable(tvr.value()))
|
2011-01-10 11:42:11 -08:00
|
|
|
return JSProxyHandler::keys(cx, proxy, props);
|
2010-06-03 18:12:01 -07:00
|
|
|
return Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) &&
|
2010-06-16 16:11:13 -07:00
|
|
|
ArrayToIdVector(cx, tvr.value(), props);
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSScriptedProxyHandler::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
JSObject *handler = GetProxyHandlerObject(cx, proxy);
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter tvr(cx);
|
2010-10-03 14:59:26 -07:00
|
|
|
if (!GetDerivedTrap(cx, handler, ATOM(iterate), tvr.addr()))
|
2010-05-27 12:03:25 -07:00
|
|
|
return false;
|
|
|
|
if (!js_IsCallable(tvr.value()))
|
|
|
|
return JSProxyHandler::iterate(cx, proxy, flags, vp);
|
2010-06-03 18:12:01 -07:00
|
|
|
return Trap(cx, handler, tvr.value(), 0, NULL, vp) &&
|
2010-05-29 19:04:01 -07:00
|
|
|
ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(iterate), *vp);
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
JSScriptedProxyHandler JSScriptedProxyHandler::singleton;
|
|
|
|
|
2010-06-03 18:12:01 -07:00
|
|
|
class AutoPendingProxyOperation {
|
2011-03-13 07:45:02 -07:00
|
|
|
ThreadData *data;
|
|
|
|
PendingProxyOperation op;
|
2010-06-03 18:12:01 -07:00
|
|
|
public:
|
|
|
|
AutoPendingProxyOperation(JSContext *cx, JSObject *proxy) : data(JS_THREAD_DATA(cx)) {
|
|
|
|
op.next = data->pendingProxyOperation;
|
|
|
|
op.object = proxy;
|
|
|
|
data->pendingProxyOperation = &op;
|
|
|
|
}
|
|
|
|
|
|
|
|
~AutoPendingProxyOperation() {
|
|
|
|
JS_ASSERT(data->pendingProxyOperation == &op);
|
|
|
|
data->pendingProxyOperation = op.next;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-05-18 19:21:43 -07:00
|
|
|
bool
|
2010-09-17 14:54:41 -07:00
|
|
|
JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
|
|
|
|
PropertyDescriptor *desc)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-09-17 14:54:41 -07:00
|
|
|
return proxy->getProxyHandler()->getPropertyDescriptor(cx, proxy, id, set, desc);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-09-17 14:54:41 -07:00
|
|
|
JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoPropertyDescriptorRooter desc(cx);
|
2010-09-17 14:54:41 -07:00
|
|
|
return JSProxy::getPropertyDescriptor(cx, proxy, id, set, &desc) &&
|
2010-05-27 12:01:55 -07:00
|
|
|
MakePropertyDescriptorObject(cx, id, &desc, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-09-17 14:54:41 -07:00
|
|
|
JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
|
2010-07-14 23:19:36 -07:00
|
|
|
PropertyDescriptor *desc)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-09-17 14:54:41 -07:00
|
|
|
return proxy->getProxyHandler()->getOwnPropertyDescriptor(cx, proxy, id, set, desc);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-09-17 14:54:41 -07:00
|
|
|
JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoPropertyDescriptorRooter desc(cx);
|
2010-09-17 14:54:41 -07:00
|
|
|
return JSProxy::getOwnPropertyDescriptor(cx, proxy, id, set, &desc) &&
|
2010-05-27 12:01:55 -07:00
|
|
|
MakePropertyDescriptorObject(cx, id, &desc, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->defineProperty(cx, proxy, id, desc);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, const Value &v)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoPropertyDescriptorRooter desc(cx);
|
2010-05-27 12:01:55 -07:00
|
|
|
return ParsePropertyDescriptorObject(cx, proxy, id, v, &desc) &&
|
2010-05-27 12:03:25 -07:00
|
|
|
JSProxy::defineProperty(cx, proxy, id, &desc);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->getOwnPropertyNames(cx, proxy, props);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
JSProxy::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->delete_(cx, proxy, id, bp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->enumerate(cx, proxy, props);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::fix(JSContext *cx, JSObject *proxy, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->fix(cx, proxy, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
JSProxy::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->has(cx, proxy, id, bp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
JSProxy::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->hasOwn(cx, proxy, id, bp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->get(cx, proxy, receiver, id, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2011-02-09 11:31:40 -08:00
|
|
|
JSProxy::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2011-02-09 11:31:40 -08:00
|
|
|
return proxy->getProxyHandler()->set(cx, proxy, receiver, id, strict, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2011-01-10 11:42:11 -08:00
|
|
|
JSProxy::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2011-01-10 11:42:11 -08:00
|
|
|
return proxy->getProxyHandler()->keys(cx, proxy, props);
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp)
|
2010-05-27 12:03:25 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->iterate(cx, proxy, flags, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
2010-06-23 14:35:10 -07:00
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::call(JSContext *cx, JSObject *proxy, uintN argc, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-23 14:35:10 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
|
|
|
return proxy->getProxyHandler()->call(cx, proxy, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::construct(JSContext *cx, JSObject *proxy, uintN argc, Value *argv, Value *rval)
|
2010-06-23 14:35:10 -07:00
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-06-23 14:35:10 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-07-02 14:51:42 -07:00
|
|
|
return proxy->getProxyHandler()->construct(cx, proxy, argc, argv, rval);
|
2010-06-23 14:35:10 -07:00
|
|
|
}
|
|
|
|
|
2010-11-10 15:56:00 -08:00
|
|
|
bool
|
|
|
|
JSProxy::hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *bp)
|
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
2010-11-10 15:56:00 -08:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
|
|
|
return proxy->getProxyHandler()->hasInstance(cx, proxy, vp, bp);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSType
|
|
|
|
JSProxy::typeOf(JSContext *cx, JSObject *proxy)
|
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
// FIXME: API doesn't allow us to report error (bug 618906).
|
|
|
|
JS_CHECK_RECURSION(cx, return JSTYPE_OBJECT);
|
2010-11-10 15:56:00 -08:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
|
|
|
return proxy->getProxyHandler()->typeOf(cx, proxy);
|
|
|
|
}
|
|
|
|
|
2010-06-23 14:35:10 -07:00
|
|
|
JSString *
|
|
|
|
JSProxy::obj_toString(JSContext *cx, JSObject *proxy)
|
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return NULL);
|
2010-06-23 14:35:10 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
|
|
|
return proxy->getProxyHandler()->obj_toString(cx, proxy);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSString *
|
|
|
|
JSProxy::fun_toString(JSContext *cx, JSObject *proxy, uintN indent)
|
|
|
|
{
|
2010-12-13 14:53:44 -08:00
|
|
|
JS_CHECK_RECURSION(cx, return NULL);
|
2010-06-23 14:35:10 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
|
|
|
return proxy->getProxyHandler()->fun_toString(cx, proxy, indent);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
2010-08-23 15:34:11 -07:00
|
|
|
static JSObject *
|
|
|
|
proxy_innerObject(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
|
|
|
return obj->getProxyPrivate().toObjectOrNull();
|
|
|
|
}
|
|
|
|
|
2010-05-18 19:21:43 -07:00
|
|
|
static JSBool
|
|
|
|
proxy_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
|
|
|
JSProperty **propp)
|
|
|
|
{
|
|
|
|
bool found;
|
|
|
|
if (!JSProxy::has(cx, obj, id, &found))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (found) {
|
2010-07-14 23:19:36 -07:00
|
|
|
*propp = (JSProperty *)0x1;
|
2010-05-18 19:21:43 -07:00
|
|
|
*objp = obj;
|
|
|
|
} else {
|
|
|
|
*objp = NULL;
|
|
|
|
*propp = NULL;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2010-07-14 23:19:36 -07:00
|
|
|
proxy_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
2011-02-09 11:31:40 -08:00
|
|
|
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoPropertyDescriptorRooter desc(cx);
|
2010-05-18 19:21:43 -07:00
|
|
|
desc.obj = obj;
|
2010-07-14 23:19:36 -07:00
|
|
|
desc.value = *value;
|
2010-05-18 19:21:43 -07:00
|
|
|
desc.attrs = (attrs & (~JSPROP_SHORTID));
|
|
|
|
desc.getter = getter;
|
|
|
|
desc.setter = setter;
|
|
|
|
desc.shortid = 0;
|
|
|
|
return JSProxy::defineProperty(cx, obj, id, &desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2010-10-29 10:42:35 -07:00
|
|
|
proxy_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-10-29 10:42:35 -07:00
|
|
|
return JSProxy::get(cx, obj, receiver, id, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2010-09-15 13:43:55 -07:00
|
|
|
proxy_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2011-02-09 11:31:40 -08:00
|
|
|
return JSProxy::set(cx, obj, obj, id, strict, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2010-06-05 14:24:54 -07:00
|
|
|
proxy_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoPropertyDescriptorRooter desc(cx);
|
2010-09-17 14:54:41 -07:00
|
|
|
if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, false, &desc))
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
*attrsp = desc.attrs;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2010-06-05 14:24:54 -07:00
|
|
|
proxy_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
|
|
|
/* Lookup the current property descriptor so we have setter/getter/value. */
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoPropertyDescriptorRooter desc(cx);
|
2010-09-17 14:54:41 -07:00
|
|
|
if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, true, &desc))
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
desc.attrs = (*attrsp & (~JSPROP_SHORTID));
|
|
|
|
return JSProxy::defineProperty(cx, obj, id, &desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2010-09-15 13:43:55 -07:00
|
|
|
proxy_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-09-15 13:43:55 -07:00
|
|
|
// TODO: throwing away strict
|
2010-05-18 19:21:43 -07:00
|
|
|
bool deleted;
|
2011-04-16 14:51:18 -07:00
|
|
|
if (!JSProxy::delete_(cx, obj, id, &deleted) || !js_SuppressDeletedProperty(cx, obj, id))
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
2010-07-14 23:19:36 -07:00
|
|
|
rval->setBoolean(deleted);
|
2010-05-18 19:21:43 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
proxy_TraceObject(JSTracer *trc, JSObject *obj)
|
|
|
|
{
|
2010-06-23 14:35:10 -07:00
|
|
|
obj->getProxyHandler()->trace(trc, obj);
|
2010-07-14 23:19:36 -07:00
|
|
|
MarkValue(trc, obj->getProxyPrivate(), "private");
|
2010-09-20 14:48:01 -07:00
|
|
|
MarkValue(trc, obj->getProxyExtra(), "extra");
|
2010-05-18 19:21:43 -07:00
|
|
|
if (obj->isFunctionProxy()) {
|
2010-07-14 23:19:36 -07:00
|
|
|
MarkValue(trc, GetCall(obj), "call");
|
|
|
|
MarkValue(trc, GetConstruct(obj), "construct");
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-06 22:31:43 -08:00
|
|
|
static void
|
|
|
|
proxy_TraceFunction(JSTracer *trc, JSObject *obj)
|
|
|
|
{
|
|
|
|
proxy_TraceObject(trc, obj);
|
|
|
|
MarkValue(trc, GetCall(obj), "call");
|
|
|
|
MarkValue(trc, GetConstruct(obj), "construct");
|
|
|
|
}
|
|
|
|
|
2011-04-16 14:14:10 -07:00
|
|
|
static JSBool
|
|
|
|
proxy_Fix(JSContext *cx, JSObject *obj, bool *fixed, AutoIdVector *props)
|
|
|
|
{
|
|
|
|
JS_ASSERT(obj->isProxy());
|
|
|
|
JSBool isFixed;
|
|
|
|
bool ok = FixProxy(cx, obj, &isFixed);
|
|
|
|
if (ok) {
|
|
|
|
*fixed = isFixed;
|
|
|
|
return GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, props);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-11-10 15:56:00 -08:00
|
|
|
static void
|
2010-06-23 14:35:10 -07:00
|
|
|
proxy_Finalize(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
|
|
|
JS_ASSERT(obj->isProxy());
|
2010-07-14 23:19:36 -07:00
|
|
|
if (!obj->getSlot(JSSLOT_PROXY_HANDLER).isUndefined())
|
2010-06-23 14:35:10 -07:00
|
|
|
obj->getProxyHandler()->finalize(cx, obj);
|
|
|
|
}
|
|
|
|
|
2010-10-10 15:39:26 -07:00
|
|
|
static JSBool
|
|
|
|
proxy_HasInstance(JSContext *cx, JSObject *proxy, const Value *v, JSBool *bp)
|
|
|
|
{
|
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
|
|
|
bool b;
|
2010-11-10 15:56:00 -08:00
|
|
|
if (!JSProxy::hasInstance(cx, proxy, v, &b))
|
2010-10-10 15:39:26 -07:00
|
|
|
return false;
|
|
|
|
*bp = !!b;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-11-10 15:56:00 -08:00
|
|
|
static JSType
|
|
|
|
proxy_TypeOf(JSContext *cx, JSObject *proxy)
|
|
|
|
{
|
|
|
|
JS_ASSERT(proxy->isProxy());
|
|
|
|
return JSProxy::typeOf(cx, proxy);
|
|
|
|
}
|
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
JS_FRIEND_API(Class) ObjectProxyClass = {
|
2010-05-27 12:03:25 -07:00
|
|
|
"Proxy",
|
2010-09-20 14:48:01 -07:00
|
|
|
Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(3),
|
2011-02-09 11:31:40 -08:00
|
|
|
PropertyStub, /* addProperty */
|
|
|
|
PropertyStub, /* delProperty */
|
|
|
|
PropertyStub, /* getProperty */
|
|
|
|
StrictPropertyStub, /* setProperty */
|
2010-07-07 00:53:50 -07:00
|
|
|
EnumerateStub,
|
|
|
|
ResolveStub,
|
|
|
|
ConvertStub,
|
2011-03-05 15:30:37 -08:00
|
|
|
proxy_Finalize, /* finalize */
|
2011-02-09 11:31:40 -08:00
|
|
|
NULL, /* reserved0 */
|
|
|
|
NULL, /* checkAccess */
|
|
|
|
NULL, /* call */
|
|
|
|
NULL, /* construct */
|
|
|
|
NULL, /* xdrObject */
|
|
|
|
proxy_HasInstance, /* hasInstance */
|
2011-03-06 22:31:43 -08:00
|
|
|
proxy_TraceObject, /* trace */
|
2010-06-12 09:29:04 -07:00
|
|
|
JS_NULL_CLASS_EXT,
|
|
|
|
{
|
|
|
|
proxy_LookupProperty,
|
|
|
|
proxy_DefineProperty,
|
|
|
|
proxy_GetProperty,
|
|
|
|
proxy_SetProperty,
|
|
|
|
proxy_GetAttributes,
|
|
|
|
proxy_SetAttributes,
|
|
|
|
proxy_DeleteProperty,
|
2011-02-09 11:31:40 -08:00
|
|
|
NULL, /* enumerate */
|
2010-11-10 15:56:00 -08:00
|
|
|
proxy_TypeOf,
|
2011-04-16 14:14:10 -07:00
|
|
|
proxy_Fix, /* fix */
|
2011-02-09 11:31:40 -08:00
|
|
|
NULL, /* thisObject */
|
2011-03-05 15:30:37 -08:00
|
|
|
NULL, /* clear */
|
2010-06-12 09:29:04 -07:00
|
|
|
}
|
2010-05-18 19:21:43 -07:00
|
|
|
};
|
|
|
|
|
2010-08-23 15:34:11 -07:00
|
|
|
JS_FRIEND_API(Class) OuterWindowProxyClass = {
|
|
|
|
"Proxy",
|
2010-09-20 14:48:01 -07:00
|
|
|
Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(3),
|
2011-02-09 11:31:40 -08:00
|
|
|
PropertyStub, /* addProperty */
|
|
|
|
PropertyStub, /* delProperty */
|
|
|
|
PropertyStub, /* getProperty */
|
|
|
|
StrictPropertyStub, /* setProperty */
|
2010-08-23 15:34:11 -07:00
|
|
|
EnumerateStub,
|
|
|
|
ResolveStub,
|
|
|
|
ConvertStub,
|
2011-03-05 15:30:37 -08:00
|
|
|
proxy_Finalize, /* finalize */
|
2011-02-09 11:31:40 -08:00
|
|
|
NULL, /* reserved0 */
|
|
|
|
NULL, /* checkAccess */
|
|
|
|
NULL, /* call */
|
|
|
|
NULL, /* construct */
|
|
|
|
NULL, /* xdrObject */
|
|
|
|
NULL, /* hasInstance */
|
2011-03-06 22:31:43 -08:00
|
|
|
proxy_TraceObject, /* trace */
|
2010-08-23 15:34:11 -07:00
|
|
|
{
|
2011-02-09 11:31:40 -08:00
|
|
|
NULL, /* equality */
|
|
|
|
NULL, /* outerObject */
|
2010-08-23 15:34:11 -07:00
|
|
|
proxy_innerObject,
|
2010-10-22 15:40:11 -07:00
|
|
|
NULL /* unused */
|
2010-08-23 15:34:11 -07:00
|
|
|
},
|
|
|
|
{
|
|
|
|
proxy_LookupProperty,
|
|
|
|
proxy_DefineProperty,
|
|
|
|
proxy_GetProperty,
|
|
|
|
proxy_SetProperty,
|
|
|
|
proxy_GetAttributes,
|
|
|
|
proxy_SetAttributes,
|
|
|
|
proxy_DeleteProperty,
|
2011-02-09 11:31:40 -08:00
|
|
|
NULL, /* enumerate */
|
|
|
|
NULL, /* typeof */
|
|
|
|
NULL, /* fix */
|
|
|
|
NULL, /* thisObject */
|
2011-03-05 15:30:37 -08:00
|
|
|
NULL, /* clear */
|
2010-08-23 15:34:11 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-05-18 19:21:43 -07:00
|
|
|
JSBool
|
2010-07-14 23:19:36 -07:00
|
|
|
proxy_Call(JSContext *cx, uintN argc, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-07-14 23:19:36 -07:00
|
|
|
JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
|
2010-05-18 19:21:43 -07:00
|
|
|
JS_ASSERT(proxy->isProxy());
|
2010-06-23 14:35:10 -07:00
|
|
|
return JSProxy::call(cx, proxy, argc, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
JSBool
|
2010-08-16 12:35:04 -07:00
|
|
|
proxy_Construct(JSContext *cx, uintN argc, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-08-16 12:35:04 -07:00
|
|
|
JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
|
2010-05-18 19:21:43 -07:00
|
|
|
JS_ASSERT(proxy->isProxy());
|
2010-08-16 12:35:04 -07:00
|
|
|
Value rval;
|
|
|
|
bool ok = JSProxy::construct(cx, proxy, argc, JS_ARGV(cx, vp), &rval);
|
|
|
|
*vp = rval;
|
|
|
|
return ok;
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
JS_FRIEND_API(Class) FunctionProxyClass = {
|
2010-05-27 12:03:25 -07:00
|
|
|
"Proxy",
|
2010-09-20 14:48:01 -07:00
|
|
|
Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(5),
|
2011-02-09 11:31:40 -08:00
|
|
|
PropertyStub, /* addProperty */
|
|
|
|
PropertyStub, /* delProperty */
|
|
|
|
PropertyStub, /* getProperty */
|
|
|
|
StrictPropertyStub, /* setProperty */
|
2010-07-07 00:53:50 -07:00
|
|
|
EnumerateStub,
|
|
|
|
ResolveStub,
|
|
|
|
ConvertStub,
|
2011-02-09 11:31:40 -08:00
|
|
|
NULL, /* finalize */
|
|
|
|
NULL, /* reserved0 */
|
|
|
|
NULL, /* checkAccess */
|
2010-08-16 12:35:04 -07:00
|
|
|
proxy_Call,
|
2010-07-07 00:53:50 -07:00
|
|
|
proxy_Construct,
|
2011-02-09 11:31:40 -08:00
|
|
|
NULL, /* xdrObject */
|
2010-10-10 15:39:26 -07:00
|
|
|
js_FunctionClass.hasInstance,
|
2011-03-06 22:31:43 -08:00
|
|
|
proxy_TraceFunction, /* trace */
|
2010-06-12 09:29:04 -07:00
|
|
|
JS_NULL_CLASS_EXT,
|
|
|
|
{
|
|
|
|
proxy_LookupProperty,
|
|
|
|
proxy_DefineProperty,
|
|
|
|
proxy_GetProperty,
|
|
|
|
proxy_SetProperty,
|
|
|
|
proxy_GetAttributes,
|
|
|
|
proxy_SetAttributes,
|
|
|
|
proxy_DeleteProperty,
|
2011-02-09 11:31:40 -08:00
|
|
|
NULL, /* enumerate */
|
2010-11-10 15:56:00 -08:00
|
|
|
proxy_TypeOf,
|
2011-02-09 11:31:40 -08:00
|
|
|
NULL, /* fix */
|
|
|
|
NULL, /* thisObject */
|
|
|
|
NULL, /* clear */
|
2010-06-12 09:29:04 -07:00
|
|
|
}
|
2010-05-18 19:21:43 -07:00
|
|
|
};
|
|
|
|
|
2010-05-24 14:33:03 -07:00
|
|
|
JS_FRIEND_API(JSObject *)
|
2010-07-07 00:53:50 -07:00
|
|
|
NewProxyObject(JSContext *cx, JSProxyHandler *handler, const Value &priv, JSObject *proto,
|
|
|
|
JSObject *parent, JSObject *call, JSObject *construct)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-06-23 14:35:10 -07:00
|
|
|
bool fun = call || construct;
|
2010-08-23 15:34:11 -07:00
|
|
|
Class *clasp;
|
|
|
|
if (fun)
|
|
|
|
clasp = &FunctionProxyClass;
|
|
|
|
else
|
|
|
|
clasp = handler->isOuterWindow() ? &OuterWindowProxyClass : &ObjectProxyClass;
|
2010-10-13 11:49:22 -07:00
|
|
|
|
2010-08-09 09:11:22 -07:00
|
|
|
JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
|
2010-10-13 11:49:22 -07:00
|
|
|
if (!obj || !obj->ensureInstanceReservedSlots(cx, 0))
|
2010-05-18 19:21:43 -07:00
|
|
|
return NULL;
|
2010-07-14 23:19:36 -07:00
|
|
|
obj->setSlot(JSSLOT_PROXY_HANDLER, PrivateValue(handler));
|
2010-06-23 14:35:10 -07:00
|
|
|
obj->setSlot(JSSLOT_PROXY_PRIVATE, priv);
|
|
|
|
if (fun) {
|
2010-07-14 23:19:36 -07:00
|
|
|
obj->setSlot(JSSLOT_PROXY_CALL, call ? ObjectValue(*call) : UndefinedValue());
|
2010-08-29 11:57:08 -07:00
|
|
|
if (construct) {
|
2010-12-07 10:56:42 -08:00
|
|
|
obj->setSlot(JSSLOT_PROXY_CONSTRUCT, ObjectValue(*construct));
|
2010-08-29 11:57:08 -07:00
|
|
|
}
|
2010-06-23 14:35:10 -07:00
|
|
|
}
|
2010-05-18 19:21:43 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2010-07-14 23:19:36 -07:00
|
|
|
proxy_create(JSContext *cx, uintN argc, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
|
|
|
if (argc < 1) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
2010-05-27 12:03:25 -07:00
|
|
|
"create", "0", "s");
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
}
|
2010-09-28 00:16:59 -07:00
|
|
|
JSObject *handler = NonNullObject(cx, vp[2]);
|
|
|
|
if (!handler)
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
2010-07-07 12:32:36 -07:00
|
|
|
JSObject *proto, *parent = NULL;
|
2010-07-14 23:19:36 -07:00
|
|
|
if (argc > 1 && vp[3].isObject()) {
|
|
|
|
proto = &vp[3].toObject();
|
2010-05-18 19:21:43 -07:00
|
|
|
parent = proto->getParent();
|
|
|
|
} else {
|
2010-07-14 23:19:36 -07:00
|
|
|
JS_ASSERT(IsFunctionObject(vp[0]));
|
2010-05-18 19:21:43 -07:00
|
|
|
proto = NULL;
|
|
|
|
}
|
2010-07-07 12:32:36 -07:00
|
|
|
if (!parent)
|
2010-07-14 23:19:36 -07:00
|
|
|
parent = vp[0].toObject().getParent();
|
|
|
|
JSObject *proxy = NewProxyObject(cx, &JSScriptedProxyHandler::singleton, ObjectValue(*handler),
|
2010-06-23 14:35:10 -07:00
|
|
|
proto, parent);
|
2010-05-18 19:21:43 -07:00
|
|
|
if (!proxy)
|
|
|
|
return false;
|
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setObject(*proxy);
|
2010-05-18 19:21:43 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2010-07-14 23:19:36 -07:00
|
|
|
proxy_createFunction(JSContext *cx, uintN argc, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
|
|
|
if (argc < 2) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
2010-05-27 12:03:25 -07:00
|
|
|
"createFunction", "1", "");
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
}
|
2010-09-28 00:16:59 -07:00
|
|
|
JSObject *handler = NonNullObject(cx, vp[2]);
|
|
|
|
if (!handler)
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
JSObject *proto, *parent;
|
2010-07-14 23:19:36 -07:00
|
|
|
parent = vp[0].toObject().getParent();
|
2010-05-18 19:21:43 -07:00
|
|
|
if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto))
|
|
|
|
return false;
|
|
|
|
parent = proto->getParent();
|
|
|
|
|
|
|
|
JSObject *call = js_ValueToCallableObject(cx, &vp[3], JSV2F_SEARCH_STACK);
|
|
|
|
if (!call)
|
|
|
|
return false;
|
|
|
|
JSObject *construct = NULL;
|
|
|
|
if (argc > 2) {
|
|
|
|
construct = js_ValueToCallableObject(cx, &vp[4], JSV2F_SEARCH_STACK);
|
|
|
|
if (!construct)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
JSObject *proxy = NewProxyObject(cx, &JSScriptedProxyHandler::singleton,
|
|
|
|
ObjectValue(*handler),
|
2010-06-23 14:35:10 -07:00
|
|
|
proto, parent, call, construct);
|
2010-05-18 19:21:43 -07:00
|
|
|
if (!proxy)
|
|
|
|
return false;
|
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setObject(*proxy);
|
2010-05-18 19:21:43 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
static JSBool
|
2010-07-14 23:19:36 -07:00
|
|
|
proxy_isTrapping(JSContext *cx, uintN argc, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
|
|
|
if (argc < 1) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
2010-05-27 12:03:25 -07:00
|
|
|
"isTrapping", "0", "s");
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
}
|
2010-09-28 00:16:59 -07:00
|
|
|
JSObject *obj = NonNullObject(cx, vp[2]);
|
|
|
|
if (!obj)
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setBoolean(obj->isProxy());
|
2010-05-18 19:21:43 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2010-07-14 23:19:36 -07:00
|
|
|
proxy_fix(JSContext *cx, uintN argc, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
|
|
|
if (argc < 1) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
2010-05-27 12:03:25 -07:00
|
|
|
"fix", "0", "s");
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
}
|
2010-09-28 00:16:59 -07:00
|
|
|
JSObject *obj = NonNullObject(cx, vp[2]);
|
|
|
|
if (!obj)
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
if (obj->isProxy()) {
|
|
|
|
JSBool flag;
|
2010-05-24 14:33:03 -07:00
|
|
|
if (!FixProxy(cx, obj, &flag))
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setBoolean(flag);
|
2010-05-18 19:21:43 -07:00
|
|
|
} else {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setBoolean(true);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static JSFunctionSpec static_methods[] = {
|
|
|
|
JS_FN("create", proxy_create, 2, 0),
|
|
|
|
JS_FN("createFunction", proxy_createFunction, 3, 0),
|
|
|
|
#ifdef DEBUG
|
|
|
|
JS_FN("isTrapping", proxy_isTrapping, 1, 0),
|
|
|
|
JS_FN("fix", proxy_fix, 1, 0),
|
|
|
|
#endif
|
|
|
|
JS_FS_END
|
|
|
|
};
|
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
extern Class CallableObjectClass;
|
2010-05-18 19:21:43 -07:00
|
|
|
|
2010-10-13 11:49:22 -07:00
|
|
|
static const uint32 JSSLOT_CALLABLE_CALL = 0;
|
|
|
|
static const uint32 JSSLOT_CALLABLE_CONSTRUCT = 1;
|
2010-05-18 19:21:43 -07:00
|
|
|
|
|
|
|
static JSBool
|
2010-08-16 12:35:04 -07:00
|
|
|
callable_Call(JSContext *cx, uintN argc, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-08-16 12:35:04 -07:00
|
|
|
JSObject *callable = &JS_CALLEE(cx, vp).toObject();
|
2010-05-24 14:33:03 -07:00
|
|
|
JS_ASSERT(callable->getClass() == &CallableObjectClass);
|
2010-10-13 11:49:22 -07:00
|
|
|
const Value &fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
|
2011-01-26 13:37:45 -08:00
|
|
|
const Value &thisval = vp[1];
|
2010-08-16 12:35:04 -07:00
|
|
|
Value rval;
|
2011-01-26 13:37:45 -08:00
|
|
|
bool ok = ExternalInvoke(cx, thisval, fval, argc, JS_ARGV(cx, vp), &rval);
|
2010-08-16 12:35:04 -07:00
|
|
|
*vp = rval;
|
|
|
|
return ok;
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2010-08-16 12:35:04 -07:00
|
|
|
callable_Construct(JSContext *cx, uintN argc, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-10-04 14:13:33 -07:00
|
|
|
JSObject *thisobj = js_CreateThis(cx, &JS_CALLEE(cx, vp).toObject());
|
2010-08-16 12:35:04 -07:00
|
|
|
if (!thisobj)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
JSObject *callable = &vp[0].toObject();
|
2010-05-24 14:33:03 -07:00
|
|
|
JS_ASSERT(callable->getClass() == &CallableObjectClass);
|
2010-10-13 11:49:22 -07:00
|
|
|
Value fval = callable->getSlot(JSSLOT_CALLABLE_CONSTRUCT);
|
2010-07-14 23:19:36 -07:00
|
|
|
if (fval.isUndefined()) {
|
2010-05-18 19:21:43 -07:00
|
|
|
/* We don't have an explicit constructor so allocate a new object and use the call. */
|
2010-10-13 11:49:22 -07:00
|
|
|
fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
|
2010-07-14 23:19:36 -07:00
|
|
|
JS_ASSERT(fval.isObject());
|
2010-05-18 19:21:43 -07:00
|
|
|
|
|
|
|
/* callable is the constructor, so get callable.prototype is the proto of the new object. */
|
2010-08-16 12:35:04 -07:00
|
|
|
Value protov;
|
|
|
|
if (!callable->getProperty(cx, ATOM_TO_JSID(ATOM(classPrototype)), &protov))
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
|
2010-06-18 17:43:02 -07:00
|
|
|
JSObject *proto;
|
2010-08-16 12:35:04 -07:00
|
|
|
if (protov.isObject()) {
|
|
|
|
proto = &protov.toObject();
|
2010-06-18 17:43:02 -07:00
|
|
|
} else {
|
|
|
|
if (!js_GetClassPrototype(cx, NULL, JSProto_Object, &proto))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject *newobj = NewNativeClassInstance(cx, &js_ObjectClass, proto, proto->getParent());
|
2010-07-14 23:19:36 -07:00
|
|
|
if (!newobj)
|
|
|
|
return false;
|
|
|
|
|
2010-05-18 19:21:43 -07:00
|
|
|
/* If the call returns an object, return that, otherwise the original newobj. */
|
2010-08-16 12:35:04 -07:00
|
|
|
Value rval;
|
2011-01-26 13:37:45 -08:00
|
|
|
if (!ExternalInvoke(cx, ObjectValue(*newobj), callable->getSlot(JSSLOT_CALLABLE_CALL),
|
2010-08-16 12:35:04 -07:00
|
|
|
argc, vp + 2, &rval)) {
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
2010-06-23 10:08:34 -07:00
|
|
|
}
|
2010-08-16 12:35:04 -07:00
|
|
|
if (rval.isPrimitive())
|
|
|
|
vp->setObject(*newobj);
|
|
|
|
else
|
|
|
|
*vp = rval;
|
2010-05-18 19:21:43 -07:00
|
|
|
return true;
|
|
|
|
}
|
2010-08-16 12:35:04 -07:00
|
|
|
|
|
|
|
Value rval;
|
2011-01-26 13:37:45 -08:00
|
|
|
bool ok = ExternalInvoke(cx, ObjectValue(*thisobj), fval, argc, vp + 2, &rval);
|
2010-08-16 12:35:04 -07:00
|
|
|
*vp = rval;
|
|
|
|
return ok;
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
Class CallableObjectClass = {
|
2010-05-27 12:03:25 -07:00
|
|
|
"Function",
|
|
|
|
JSCLASS_HAS_RESERVED_SLOTS(2),
|
2011-02-09 11:31:40 -08:00
|
|
|
PropertyStub, /* addProperty */
|
|
|
|
PropertyStub, /* delProperty */
|
|
|
|
PropertyStub, /* getProperty */
|
|
|
|
StrictPropertyStub, /* setProperty */
|
2010-06-12 09:29:04 -07:00
|
|
|
EnumerateStub,
|
|
|
|
ResolveStub,
|
|
|
|
ConvertStub,
|
2011-02-09 11:31:40 -08:00
|
|
|
NULL, /* finalize */
|
|
|
|
NULL, /* reserved0 */
|
|
|
|
NULL, /* checkAccess */
|
2010-06-12 09:29:04 -07:00
|
|
|
callable_Call,
|
|
|
|
callable_Construct,
|
2010-05-18 19:21:43 -07:00
|
|
|
};
|
|
|
|
|
2010-05-24 14:33:03 -07:00
|
|
|
JS_FRIEND_API(JSBool)
|
|
|
|
FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
|
|
|
AutoValueRooter tvr(cx);
|
|
|
|
if (!JSProxy::fix(cx, proxy, tvr.addr()))
|
|
|
|
return false;
|
2010-07-14 23:19:36 -07:00
|
|
|
if (tvr.value().isUndefined()) {
|
2010-05-18 19:21:43 -07:00
|
|
|
*bp = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-06-03 18:12:01 -07:00
|
|
|
if (OperationInProgress(cx, proxy)) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROXY_FIX);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-09-28 00:16:59 -07:00
|
|
|
JSObject *props = NonNullObject(cx, tvr.value());
|
|
|
|
if (!props)
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
JSObject *proto = proxy->getProto();
|
|
|
|
JSObject *parent = proxy->getParent();
|
2010-07-14 23:19:36 -07:00
|
|
|
Class *clasp = proxy->isFunctionProxy() ? &CallableObjectClass : &js_ObjectClass;
|
2010-05-18 19:21:43 -07:00
|
|
|
|
2010-10-13 11:49:22 -07:00
|
|
|
/*
|
|
|
|
* Make a blank object from the recipe fix provided to us. This must have
|
|
|
|
* number of fixed slots as the proxy so that we can swap their contents.
|
|
|
|
*/
|
2011-04-19 22:30:10 -07:00
|
|
|
gc::FinalizeKind kind = gc::FinalizeKind(proxy->arenaHeader()->getThingKind());
|
2010-10-13 11:49:22 -07:00
|
|
|
JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
|
2010-05-18 19:21:43 -07:00
|
|
|
if (!newborn)
|
2010-11-08 14:06:38 -08:00
|
|
|
return false;
|
2010-07-14 23:19:36 -07:00
|
|
|
AutoObjectRooter tvr2(cx, newborn);
|
2010-05-18 19:21:43 -07:00
|
|
|
|
2010-05-24 14:33:03 -07:00
|
|
|
if (clasp == &CallableObjectClass) {
|
2010-10-13 11:49:22 -07:00
|
|
|
newborn->setSlot(JSSLOT_CALLABLE_CALL, GetCall(proxy));
|
|
|
|
newborn->setSlot(JSSLOT_CALLABLE_CONSTRUCT, GetConstruct(proxy));
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
2010-06-03 18:12:01 -07:00
|
|
|
{
|
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
|
|
|
if (!js_PopulateObject(cx, newborn, props))
|
|
|
|
return false;
|
|
|
|
}
|
2010-05-18 19:21:43 -07:00
|
|
|
|
2010-09-28 00:16:59 -07:00
|
|
|
/* Trade contents between the newborn object and the proxy. */
|
2010-10-13 11:49:22 -07:00
|
|
|
if (!proxy->swap(cx, newborn))
|
|
|
|
return false;
|
2010-05-18 19:21:43 -07:00
|
|
|
|
|
|
|
/* The GC will dispose of the proxy object. */
|
|
|
|
|
|
|
|
*bp = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-05-24 14:33:03 -07:00
|
|
|
}
|
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
Class js_ProxyClass = {
|
2010-06-02 01:18:50 -07:00
|
|
|
"Proxy",
|
|
|
|
JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy),
|
2011-02-09 11:31:40 -08:00
|
|
|
PropertyStub, /* addProperty */
|
|
|
|
PropertyStub, /* delProperty */
|
|
|
|
PropertyStub, /* getProperty */
|
|
|
|
StrictPropertyStub, /* setProperty */
|
2010-06-12 09:29:04 -07:00
|
|
|
EnumerateStub,
|
|
|
|
ResolveStub,
|
|
|
|
ConvertStub
|
2010-06-02 01:18:50 -07:00
|
|
|
};
|
|
|
|
|
2010-05-24 14:33:03 -07:00
|
|
|
JS_FRIEND_API(JSObject *)
|
|
|
|
js_InitProxyClass(JSContext *cx, JSObject *obj)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-08-09 09:11:22 -07:00
|
|
|
JSObject *module = NewNonFunction<WithProto::Class>(cx, &js_ProxyClass, NULL, obj);
|
2010-05-24 14:33:03 -07:00
|
|
|
if (!module)
|
|
|
|
return NULL;
|
|
|
|
if (!JS_DefineProperty(cx, obj, "Proxy", OBJECT_TO_JSVAL(module),
|
2011-02-09 11:31:40 -08:00
|
|
|
JS_PropertyStub, JS_StrictPropertyStub, 0)) {
|
2010-05-24 14:33:03 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (!JS_DefineFunctions(cx, module, static_methods))
|
|
|
|
return NULL;
|
Bug 642772: Don't recreate a class during enumeration, if it has been deleted (r=bhackett)
In SM, classes are lazily resolved. If we detect that a class about to be used
has not yet been resolved, then we resolve it. However, the way that we decided
that they were resolved was broken. If the global object had a String property,
then it had been resolved. So what happened when we deleted the String
property? Well, it got resolved again.
Instead of using the String property of the global object, we now use the
contructor slot on the global object. This works fine for String, but some
classes don't have a constructor, like Math and JSON. For those classes, we set
the constructor slot to True. In either case, we can now tell that a class is
resolved if the constructor slot in not Undefined.
2011-04-27 04:13:56 -07:00
|
|
|
|
|
|
|
MarkStandardClassInitializedNoProto(obj, &js_ProxyClass);
|
|
|
|
|
2010-06-18 17:43:02 -07:00
|
|
|
return module;
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|