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"
|
|
|
|
#include "jsprvtd.h"
|
|
|
|
#include "jsnum.h"
|
|
|
|
#include "jsobj.h"
|
|
|
|
#include "jsproxy.h"
|
|
|
|
#include "jsscope.h"
|
|
|
|
|
|
|
|
#include "jsobjinlines.h"
|
|
|
|
|
|
|
|
using namespace js;
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
JSPendingProxyOperation *op = JS_THREAD_DATA(cx)->pendingProxyOperation;
|
|
|
|
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-05-18 19:21:43 -07:00
|
|
|
if (!getPropertyDescriptor(cx, proxy, id, &desc))
|
|
|
|
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-05-18 19:21:43 -07:00
|
|
|
if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
|
|
|
|
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-05-18 19:21:43 -07:00
|
|
|
if (!getPropertyDescriptor(cx, proxy, id, &desc))
|
|
|
|
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-08-16 12:35:04 -07:00
|
|
|
return ExternalGetOrSet(cx, proxy, 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
|
|
|
}
|
|
|
|
if (desc.attrs & JSPROP_SHORTID)
|
|
|
|
id = INT_TO_JSID(desc.shortid);
|
2010-08-29 11:57:08 -07:00
|
|
|
return CallJSPropertyOp(cx, desc.getter, proxy, id, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxyHandler::set(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-05-18 19:21:43 -07:00
|
|
|
if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
|
|
|
|
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-09-16 11:40:59 -07:00
|
|
|
if (desc.setter && ((desc.attrs & JSPROP_SETTER) || desc.setter != PropertyStub)) {
|
2010-05-19 14:43:17 -07:00
|
|
|
if (desc.attrs & JSPROP_SETTER) {
|
2010-08-16 12:35:04 -07:00
|
|
|
return ExternalGetOrSet(cx, proxy, id, CastAsObjectJsval(desc.setter),
|
2010-09-16 11:43:33 -07:00
|
|
|
JSACC_WRITE, 1, vp, vp);
|
2010-05-19 14:43:17 -07:00
|
|
|
}
|
|
|
|
if (desc.attrs & JSPROP_SHORTID)
|
|
|
|
id = INT_TO_JSID(desc.shortid);
|
2010-08-29 11:57:08 -07:00
|
|
|
return CallJSPropertyOpSetter(cx, desc.setter, proxy, id, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
2010-05-19 14:43:17 -07:00
|
|
|
if (desc.attrs & JSPROP_READONLY)
|
|
|
|
return true;
|
|
|
|
desc.value = *vp;
|
|
|
|
return defineProperty(cx, proxy, id, &desc);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
if (!getPropertyDescriptor(cx, proxy, id, &desc))
|
|
|
|
return false;
|
|
|
|
if (desc.obj) {
|
2010-09-16 11:40:59 -07:00
|
|
|
if (desc.setter && ((desc.attrs & JSPROP_SETTER) || desc.setter != PropertyStub)) {
|
2010-05-19 14:43:17 -07:00
|
|
|
if (desc.attrs & JSPROP_SETTER) {
|
2010-08-16 12:35:04 -07:00
|
|
|
return ExternalGetOrSet(cx, proxy, id, CastAsObjectJsval(desc.setter),
|
2010-09-16 11:43:33 -07:00
|
|
|
JSACC_WRITE, 1, vp, vp);
|
2010-05-19 14:43:17 -07:00
|
|
|
}
|
|
|
|
if (desc.attrs & JSPROP_SHORTID)
|
|
|
|
id = INT_TO_JSID(desc.shortid);
|
2010-08-29 11:57:08 -07:00
|
|
|
return CallJSPropertyOpSetter(cx, desc.setter, proxy, id, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
2010-05-19 14:43:17 -07:00
|
|
|
if (desc.attrs & JSPROP_READONLY)
|
|
|
|
return true;
|
|
|
|
/* fall through */
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
desc.obj = proxy;
|
|
|
|
desc.value = *vp;
|
|
|
|
desc.attrs = 0;
|
2010-07-14 23:19:36 -07:00
|
|
|
desc.getter = NULL;
|
|
|
|
desc.setter = NULL;
|
2010-05-18 19:21:43 -07:00
|
|
|
desc.shortid = 0;
|
|
|
|
return defineProperty(cx, proxy, id, &desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxyHandler::enumerateOwn(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-06-16 16:11:13 -07:00
|
|
|
if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
|
|
|
|
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-06-16 16:11:13 -07:00
|
|
|
if (!enumerate(cx, proxy, props))
|
2010-05-27 12:03:25 -07:00
|
|
|
return false;
|
2010-07-14 23:19:36 -07:00
|
|
|
return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
|
2010-05-27 12:03:25 -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);
|
|
|
|
if (fval.isUndefined()) {
|
2010-07-02 14:51:42 -07:00
|
|
|
fval = GetCall(proxy);
|
2010-07-14 23:19:36 -07:00
|
|
|
JSObject *obj = JS_New(cx, &fval.toObject(), argc, Jsvalify(argv));
|
2010-07-02 14:51:42 -07:00
|
|
|
if (!obj)
|
2010-06-23 14:35:10 -07:00
|
|
|
return false;
|
2010-07-14 23:19:36 -07:00
|
|
|
rval->setObject(*obj);
|
2010-06-23 14:35:10 -07:00
|
|
|
return true;
|
|
|
|
}
|
2010-07-02 14:51:42 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: The Proxy proposal says to pass undefined as the this argument,
|
|
|
|
* but primitive this is not supported yet. See bug 576644.
|
|
|
|
*/
|
2010-07-14 23:19:36 -07:00
|
|
|
JS_ASSERT(fval.isObject());
|
|
|
|
JSObject *thisobj = fval.toObject().getGlobal();
|
2010-08-16 12:35:04 -07:00
|
|
|
return ExternalInvoke(cx, thisobj, fval, argc, argv, rval);
|
2010-06-23 14:35:10 -07:00
|
|
|
}
|
2010-05-27 12:03:25 -07:00
|
|
|
|
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-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-07-14 23:19:36 -07:00
|
|
|
FundamentalTrap(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)) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_FUNCTION,
|
|
|
|
js_AtomToPrintableString(cx, atom));
|
2010-05-18 19:21:43 -07:00
|
|
|
return false;
|
2010-05-27 12:03:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2010-07-14 23:19:36 -07:00
|
|
|
DerivedTrap(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) ||
|
|
|
|
atom == ATOM(enumerateOwn) ||
|
|
|
|
atom == ATOM(iterate));
|
|
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
|
|
|
|
2010-08-16 12:35:04 -07:00
|
|
|
return ExternalInvoke(cx, 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();
|
2010-05-18 19:21:43 -07:00
|
|
|
if (!d || !d->initialize(cx, id, v))
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
if (!js_GetLengthProperty(cx, obj, &length)) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
|
|
|
|
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-06-16 16:11:13 -07:00
|
|
|
if (!js_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. */
|
|
|
|
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
2010-07-14 23:19:36 -07:00
|
|
|
PropertyDescriptor *desc);
|
2010-05-27 12:03:25 -07:00
|
|
|
virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
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);
|
|
|
|
virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp);
|
|
|
|
virtual bool enumerateOwn(JSContext *cx, JSObject *proxy, AutoIdVector &props);
|
|
|
|
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-05-29 19:04:01 -07:00
|
|
|
js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
|
2010-07-14 23:19:36 -07:00
|
|
|
JSDVG_SEARCH_STACK, ObjectOrNullValue(proxy), NULL,
|
2010-05-29 19:04:01 -07:00
|
|
|
js_AtomToPrintableString(cx, atom));
|
|
|
|
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
|
|
|
|
JSScriptedProxyHandler::getPropertyDescriptor(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);
|
|
|
|
return FundamentalTrap(cx, handler, ATOM(getPropertyDescriptor), tvr.addr()) &&
|
2010-06-03 18:12:01 -07:00
|
|
|
Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
|
2010-05-29 19:04:01 -07:00
|
|
|
ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), tvr.value()) &&
|
2010-05-27 12:03:25 -07:00
|
|
|
ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
JSScriptedProxyHandler::getOwnPropertyDescriptor(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);
|
|
|
|
return FundamentalTrap(cx, handler, ATOM(getOwnPropertyDescriptor), tvr.addr()) &&
|
2010-06-03 18:12:01 -07:00
|
|
|
Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
|
2010-05-29 19:04:01 -07:00
|
|
|
ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), tvr.value()) &&
|
2010-05-27 12:03:25 -07:00
|
|
|
ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
return FundamentalTrap(cx, handler, ATOM(defineProperty), fval.addr()) &&
|
|
|
|
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);
|
|
|
|
return FundamentalTrap(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);
|
|
|
|
return FundamentalTrap(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);
|
|
|
|
return FundamentalTrap(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-05-27 12:03:25 -07:00
|
|
|
return FundamentalTrap(cx, handler, ATOM(fix), vp) &&
|
|
|
|
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);
|
|
|
|
if (!DerivedTrap(cx, handler, ATOM(has), tvr.addr()))
|
|
|
|
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);
|
|
|
|
if (!DerivedTrap(cx, handler, ATOM(hasOwn), tvr.addr()))
|
|
|
|
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);
|
|
|
|
if (!DerivedTrap(cx, handler, ATOM(get), fval.addr()))
|
|
|
|
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
|
2010-07-14 23:19:36 -07:00
|
|
|
JSScriptedProxyHandler::set(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(), *vp };
|
2010-05-27 12:03:25 -07:00
|
|
|
AutoValueRooter fval(cx);
|
|
|
|
if (!DerivedTrap(cx, handler, ATOM(set), fval.addr()))
|
|
|
|
return false;
|
|
|
|
if (!js_IsCallable(fval.value()))
|
|
|
|
return JSProxyHandler::set(cx, proxy, receiver, id, 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
|
2010-07-14 23:19:36 -07:00
|
|
|
JSScriptedProxyHandler::enumerateOwn(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);
|
|
|
|
if (!DerivedTrap(cx, handler, ATOM(enumerateOwn), tvr.addr()))
|
|
|
|
return false;
|
|
|
|
if (!js_IsCallable(tvr.value()))
|
2010-06-16 16:11:13 -07:00
|
|
|
return JSProxyHandler::enumerateOwn(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);
|
|
|
|
if (!DerivedTrap(cx, handler, ATOM(iterate), tvr.addr()))
|
|
|
|
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 {
|
|
|
|
JSThreadData *data;
|
|
|
|
JSPendingProxyOperation op;
|
|
|
|
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-07-14 23:19:36 -07:00
|
|
|
JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->getPropertyDescriptor(cx, proxy, id, desc);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
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:03:25 -07:00
|
|
|
return JSProxy::getPropertyDescriptor(cx, proxy, id, &desc) &&
|
2010-05-27 12:01:55 -07:00
|
|
|
MakePropertyDescriptorObject(cx, id, &desc, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-05-27 12:03:25 -07:00
|
|
|
JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
2010-07-14 23:19:36 -07:00
|
|
|
PropertyDescriptor *desc)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->getOwnPropertyDescriptor(cx, proxy, id, desc);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
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:03:25 -07:00
|
|
|
return JSProxy::getOwnPropertyDescriptor(cx, proxy, id, &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-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-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-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-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-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-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-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-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-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
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::set(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
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->set(cx, proxy, receiver, id, vp);
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-07-14 23:19:36 -07:00
|
|
|
JSProxy::enumerateOwn(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-06-03 18:12:01 -07:00
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
2010-06-23 14:35:10 -07:00
|
|
|
return proxy->getProxyHandler()->enumerateOwn(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-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-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
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
JSString *
|
|
|
|
JSProxy::obj_toString(JSContext *cx, JSObject *proxy)
|
|
|
|
{
|
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
|
|
|
return proxy->getProxyHandler()->obj_toString(cx, proxy);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSString *
|
|
|
|
JSProxy::fun_toString(JSContext *cx, JSObject *proxy, uintN indent)
|
|
|
|
{
|
|
|
|
AutoPendingProxyOperation pending(cx, proxy);
|
|
|
|
return proxy->getProxyHandler()->fun_toString(cx, proxy, indent);
|
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,
|
|
|
|
PropertyOp getter, PropertyOp 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-07-14 23:19:36 -07:00
|
|
|
proxy_GetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
|
|
|
return JSProxy::get(cx, obj, obj, id, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2010-09-15 13:43:55 -07:00
|
|
|
// TODO: throwing away strict
|
2010-05-18 19:21:43 -07:00
|
|
|
return JSProxy::set(cx, obj, obj, id, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
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-05-18 19:21:43 -07:00
|
|
|
if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, &desc))
|
|
|
|
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-05-18 19:21:43 -07:00
|
|
|
if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, &desc))
|
|
|
|
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;
|
|
|
|
if (!JSProxy::delete_(cx, obj, id, &deleted))
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
JSContext *cx = trc->context;
|
|
|
|
|
|
|
|
if (!JS_CLIST_IS_EMPTY(&cx->runtime->watchPointList))
|
|
|
|
js_TraceWatchPoints(trc, 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-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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-23 14:35:10 -07:00
|
|
|
void
|
|
|
|
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-07-14 23:19:36 -07:00
|
|
|
JS_FRIEND_API(Class) ObjectProxyClass = {
|
2010-05-27 12:03:25 -07:00
|
|
|
"Proxy",
|
2010-06-12 09:29:04 -07:00
|
|
|
Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(2),
|
|
|
|
PropertyStub, /* addProperty */
|
|
|
|
PropertyStub, /* delProperty */
|
|
|
|
PropertyStub, /* getProperty */
|
|
|
|
PropertyStub, /* setProperty */
|
2010-07-07 00:53:50 -07:00
|
|
|
EnumerateStub,
|
|
|
|
ResolveStub,
|
|
|
|
ConvertStub,
|
2010-06-12 09:29:04 -07:00
|
|
|
NULL, /* finalize */
|
|
|
|
NULL, /* reserved0 */
|
|
|
|
NULL, /* checkAccess */
|
|
|
|
NULL, /* call */
|
|
|
|
NULL, /* construct */
|
|
|
|
NULL, /* xdrObject */
|
|
|
|
NULL, /* hasInstance */
|
|
|
|
NULL, /* mark */
|
|
|
|
JS_NULL_CLASS_EXT,
|
|
|
|
{
|
|
|
|
proxy_LookupProperty,
|
|
|
|
proxy_DefineProperty,
|
|
|
|
proxy_GetProperty,
|
|
|
|
proxy_SetProperty,
|
|
|
|
proxy_GetAttributes,
|
|
|
|
proxy_SetAttributes,
|
|
|
|
proxy_DeleteProperty,
|
|
|
|
NULL, /* enumerate */
|
|
|
|
NULL, /* typeof */
|
|
|
|
proxy_TraceObject,
|
|
|
|
NULL, /* thisObject */
|
|
|
|
proxy_Finalize, /* clear */
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
|
|
|
static JSType
|
|
|
|
proxy_TypeOf_fun(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
|
|
|
return JSTYPE_FUNCTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define proxy_HasInstance js_FunctionClass.hasInstance
|
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
JS_FRIEND_API(Class) FunctionProxyClass = {
|
2010-05-27 12:03:25 -07:00
|
|
|
"Proxy",
|
2010-08-16 12:35:04 -07:00
|
|
|
Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(4),
|
2010-06-12 09:29:04 -07:00
|
|
|
PropertyStub, /* addProperty */
|
|
|
|
PropertyStub, /* delProperty */
|
|
|
|
PropertyStub, /* getProperty */
|
|
|
|
PropertyStub, /* setProperty */
|
2010-07-07 00:53:50 -07:00
|
|
|
EnumerateStub,
|
|
|
|
ResolveStub,
|
|
|
|
ConvertStub,
|
2010-06-12 09:29:04 -07: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,
|
2010-06-12 09:29:04 -07:00
|
|
|
NULL, /* xdrObject */
|
2010-07-07 00:53:50 -07:00
|
|
|
proxy_HasInstance,
|
2010-06-12 09:29:04 -07:00
|
|
|
NULL, /* mark */
|
|
|
|
JS_NULL_CLASS_EXT,
|
|
|
|
{
|
|
|
|
proxy_LookupProperty,
|
|
|
|
proxy_DefineProperty,
|
|
|
|
proxy_GetProperty,
|
|
|
|
proxy_SetProperty,
|
|
|
|
proxy_GetAttributes,
|
|
|
|
proxy_SetAttributes,
|
|
|
|
proxy_DeleteProperty,
|
|
|
|
NULL, /* enumerate */
|
|
|
|
proxy_TypeOf_fun,
|
|
|
|
proxy_TraceObject,
|
|
|
|
NULL, /* thisObject */
|
|
|
|
NULL, /* clear */
|
|
|
|
}
|
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-07-14 23:19:36 -07:00
|
|
|
Class *clasp = fun ? &FunctionProxyClass : &ObjectProxyClass;
|
2010-08-09 09:11:22 -07:00
|
|
|
JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
|
2010-08-29 11:57:08 -07:00
|
|
|
if (!obj || (construct && !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) {
|
|
|
|
obj->setSlot(JSSLOT_PROXY_CONSTRUCT,
|
|
|
|
construct ? ObjectValue(*construct) : UndefinedValue());
|
|
|
|
}
|
2010-06-23 14:35:10 -07:00
|
|
|
}
|
2010-05-18 19:21:43 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSObject *
|
2010-07-14 23:19:36 -07:00
|
|
|
NonNullObject(JSContext *cx, const Value &v)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-07-14 23:19:36 -07:00
|
|
|
if (v.isPrimitive()) {
|
2010-05-18 19:21:43 -07:00
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-14 23:19:36 -07:00
|
|
|
return &v.toObject();
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
JSObject *handler;
|
|
|
|
if (!(handler = NonNullObject(cx, vp[2])))
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
JSObject *handler;
|
|
|
|
if (!(handler = NonNullObject(cx, vp[2])))
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
JSObject *obj;
|
|
|
|
if (!(obj = NonNullObject(cx, vp[2])))
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
JSObject *obj;
|
|
|
|
if (!(obj = NonNullObject(cx, vp[2])))
|
|
|
|
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
|
|
|
|
|
|
|
static const uint32 JSSLOT_CALLABLE_CALL = JSSLOT_PRIVATE;
|
|
|
|
static const uint32 JSSLOT_CALLABLE_CONSTRUCT = JSSLOT_PRIVATE + 1;
|
|
|
|
|
|
|
|
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 *thisobj = ComputeThisFromVp(cx, vp);
|
|
|
|
if (!thisobj)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
JSObject *callable = &JS_CALLEE(cx, vp).toObject();
|
2010-05-24 14:33:03 -07:00
|
|
|
JS_ASSERT(callable->getClass() == &CallableObjectClass);
|
2010-07-14 23:19:36 -07:00
|
|
|
const Value &fval = callable->fslots[JSSLOT_CALLABLE_CALL];
|
2010-08-16 12:35:04 -07:00
|
|
|
Value rval;
|
|
|
|
bool ok = ExternalInvoke(cx, thisobj, fval, argc, JS_ARGV(cx, vp), &rval);
|
|
|
|
*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-08-16 12:35:04 -07:00
|
|
|
JSObject *thisobj = js_NewInstance(cx, &JS_CALLEE(cx, vp).toObject());
|
|
|
|
if (!thisobj)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
JSObject *callable = &vp[0].toObject();
|
2010-05-24 14:33:03 -07:00
|
|
|
JS_ASSERT(callable->getClass() == &CallableObjectClass);
|
2010-07-14 23:19:36 -07:00
|
|
|
Value fval = callable->fslots[JSSLOT_CALLABLE_CONSTRUCT];
|
|
|
|
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. */
|
|
|
|
fval = callable->fslots[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;
|
|
|
|
if (!ExternalInvoke(cx, newobj, callable->fslots[JSSLOT_CALLABLE_CALL],
|
|
|
|
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;
|
|
|
|
bool ok = ExternalInvoke(cx, thisobj, fval, argc, vp + 2, &rval);
|
|
|
|
*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),
|
2010-06-12 09:29:04 -07:00
|
|
|
PropertyStub, /* addProperty */
|
|
|
|
PropertyStub, /* delProperty */
|
|
|
|
PropertyStub, /* getProperty */
|
|
|
|
PropertyStub, /* setProperty */
|
|
|
|
EnumerateStub,
|
|
|
|
ResolveStub,
|
|
|
|
ConvertStub,
|
|
|
|
NULL, /* finalize */
|
|
|
|
NULL, /* reserved0 */
|
|
|
|
NULL, /* checkAccess */
|
|
|
|
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-05-18 19:21:43 -07:00
|
|
|
JSObject *props;
|
|
|
|
if (!(props = NonNullObject(cx, tvr.value())))
|
|
|
|
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
|
|
|
|
|
|
|
/* Make a blank object from the recipe fix provided to us. */
|
2010-08-09 09:11:22 -07:00
|
|
|
JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
|
2010-05-18 19:21:43 -07:00
|
|
|
if (!newborn)
|
|
|
|
return NULL;
|
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-06-23 14:35:10 -07:00
|
|
|
newborn->fslots[JSSLOT_CALLABLE_CALL] = GetCall(proxy);
|
|
|
|
newborn->fslots[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
|
|
|
|
|
|
|
/* Trade spaces between the newborn object and the proxy. */
|
|
|
|
proxy->swap(newborn);
|
|
|
|
|
|
|
|
/* 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),
|
2010-06-12 09:29:04 -07:00
|
|
|
PropertyStub, /* addProperty */
|
|
|
|
PropertyStub, /* delProperty */
|
|
|
|
PropertyStub, /* getProperty */
|
|
|
|
PropertyStub, /* setProperty */
|
|
|
|
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),
|
|
|
|
JS_PropertyStub, JS_PropertyStub, 0)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (!JS_DefineFunctions(cx, module, static_methods))
|
|
|
|
return NULL;
|
2010-06-18 17:43:02 -07:00
|
|
|
return module;
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|