LCOV - app.info - js/src/jswrapper.cpp

LCOV - code coverage report
| Current view: | directory - js/src - jswrapper.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 386 | 266 | 68.9 %
| Date: | 2012-04-07 | Functions: | 89 | 62 | 69.7 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=4 sw=4 et tw=99:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
          18                 :  * May 28, 2008.
          19                 :  *
          20                 :  * The Initial Developer of the Original Code is
          21                 :  *   Mozilla Foundation
          22                 :  * Portions created by the Initial Developer are Copyright (C) 2010
          23                 :  * the Initial Developer. All Rights Reserved.
          24                 :  *
          25                 :  * Contributor(s):
          26                 :  *   Andreas Gal <gal@mozilla.com>
          27                 :  *
          28                 :  * Alternatively, the contents of this file may be used under the terms of
          29                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          30                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          32                 :  * of those above. If you wish to allow use of your version of this file only
          33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          34                 :  * use your version of this file under the terms of the MPL, indicate your
          35                 :  * decision by deleting the provisions above and replace them with the notice
          36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          37                 :  * the provisions above, a recipient may use your version of this file under
          38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          39                 :  *
          40                 :  * ***** END LICENSE BLOCK ***** */
          41                 :
          42                 : #include "jsapi.h"
          43                 : #include "jscntxt.h"
          44                 : #include "jsexn.h"
          45                 : #include "jsgc.h"
          46                 : #include "jsgcmark.h"
          47                 : #include "jsiter.h"
          48                 : #include "jsnum.h"
          49                 : #include "jswrapper.h"
          50                 : #include "methodjit/PolyIC.h"
          51                 : #include "methodjit/MonoIC.h"
          52                 : #ifdef JS_METHODJIT
          53                 : # include "assembler/jit/ExecutableAllocator.h"
          54                 : #endif
          55                 : #include "jscompartment.h"
          56                 :
          57                 : #include "jsobjinlines.h"
          58                 :
          59                 : #include "vm/RegExpObject-inl.h"
          60                 :
          61                 : using namespace js;
          62                 : using namespace js::gc;
          63                 :
          64                 : namespace js {
          65                 : int sWrapperFamily;
          66                 : }
          67                 :
          68                 : void *
          69               0 : Wrapper::getWrapperFamily()
          70                 : {
          71               0 :     return &sWrapperFamily;
          72                 : }
          73                 :
          74                 : JS_FRIEND_API(JSObject *)
          75        59070364 : js::UnwrapObject(JSObject *wrapped, bool stopAtOuter, unsigned *flagsp)
          76                 : {
          77        59070364 :     unsigned flags = 0;
          78       118242904 :     while (wrapped->isWrapper()) {
          79          102176 :         flags |= static_cast<Wrapper *>(GetProxyHandler(wrapped))->flags();
          80          102176 :         wrapped = GetProxyPrivate(wrapped).toObjectOrNull();
          81          102176 :         if (stopAtOuter && wrapped->getClass()->ext.innerObject)
          82               0 :             break;
          83                 :     }
          84        59070364 :     if (flagsp)
          85          194355 :         *flagsp = flags;
          86        59070364 :     return wrapped;
          87                 : }
          88                 :
          89                 : JS_FRIEND_API(JSObject *)
          90               9 : js::UnwrapObjectChecked(JSContext *cx, JSObject *obj)
          91                 : {
          92              18 :     while (obj->isWrapper()) {
          93               0 :         JSObject *wrapper = obj;
          94               0 :         Wrapper *handler = Wrapper::wrapperHandler(obj);
          95                 :         bool rvOnFailure;
          96               0 :         if (!handler->enter(cx, wrapper, JSID_VOID,
          97               0 :                             Wrapper::PUNCTURE, &rvOnFailure))
          98               0 :             return rvOnFailure ? obj : NULL;
          99               0 :         obj = Wrapper::wrappedObject(obj);
         100               0 :         JS_ASSERT(obj);
         101               0 :         handler->leave(cx, wrapper);
         102               0 :         if (obj->getClass()->ext.innerObject)
         103               0 :             break;
         104                 :     }
         105               9 :     return obj;
         106                 : }
         107                 :
         108                 : bool
         109           75046 : js::IsCrossCompartmentWrapper(const JSObject *wrapper)
         110                 : {
         111           75046 :     return wrapper->isWrapper() &&
         112           75046 :            !!(Wrapper::wrapperHandler(wrapper)->flags() & Wrapper::CROSS_COMPARTMENT);
         113                 : }
         114                 :
         115           37335 : Wrapper::Wrapper(unsigned flags) : ProxyHandler(&sWrapperFamily), mFlags(flags)
         116                 : {
         117           37335 : }
         118                 :
         119           37335 : Wrapper::~Wrapper()
         120                 : {
         121           37335 : }
         122                 :
         123                 : #define CHECKED(op, act)                                                     \
         124                 :     JS_BEGIN_MACRO                                                           \
         125                 :         bool status;                                                         \
         126                 :         if (!enter(cx, wrapper, id, act, &status))                           \
         127                 :             return status;                                                   \
         128                 :         bool ok = (op);                                                      \
         129                 :         leave(cx, wrapper);                                                  \
         130                 :         return ok;                                                           \
         131                 :     JS_END_MACRO
         132                 :
         133                 : #define SET(action) CHECKED(action, SET)
         134                 : #define GET(action) CHECKED(action, GET)
         135                 :
         136                 : bool
         137               0 : Wrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set,
         138                 :                                PropertyDescriptor *desc)
         139                 : {
         140               0 :     desc->obj = NULL; // default result if we refuse to perform this action
         141               0 :     CHECKED(JS_GetPropertyDescriptorById(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED, desc),
         142                 :             set ? SET : GET);
         143                 : }
         144                 :
         145                 : static bool
         146              36 : GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, unsigned flags, JSPropertyDescriptor *desc)
         147                 : {
         148                 :     // If obj is a proxy, we can do better than just guessing. This is
         149                 :     // important for certain types of wrappers that wrap other wrappers.
         150              36 :     if (obj->isProxy())
         151               0 :         return Proxy::getOwnPropertyDescriptor(cx, obj, id, flags & JSRESOLVE_ASSIGNING, desc);
         152                 :
         153              36 :     if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc))
         154               0 :         return false;
         155              36 :     if (desc->obj != obj)
         156               0 :         desc->obj = NULL;
         157              36 :     return true;
         158                 : }
         159                 :
         160                 : bool
         161              36 : Wrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set,
         162                 :                                   PropertyDescriptor *desc)
         163                 : {
         164              36 :     desc->obj = NULL; // default result if we refuse to perform this action
         165              36 :     CHECKED(GetOwnPropertyDescriptor(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED, desc),
         166                 :             set ? SET : GET);
         167                 : }
         168                 :
         169                 : bool
         170              36 : Wrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc)
         171                 : {
         172              36 :     SET(JS_DefinePropertyById(cx, wrappedObject(wrapper), id, desc->value,
         173                 :                               desc->getter, desc->setter, desc->attrs));
         174                 : }
         175                 :
         176                 : bool
         177               0 : Wrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
         178                 : {
         179                 :     // if we refuse to perform this action, props remains empty
         180               0 :     jsid id = JSID_VOID;
         181               0 :     GET(GetPropertyNames(cx, wrappedObject(wrapper), JSITER_OWNONLY | JSITER_HIDDEN, &props));
         182                 : }
         183                 :
         184                 : static bool
         185               9 : ValueToBoolean(Value *vp, bool *bp)
         186                 : {
         187               9 :     *bp = js_ValueToBoolean(*vp);
         188               9 :     return true;
         189                 : }
         190                 :
         191                 : bool
         192               9 : Wrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
         193                 : {
         194               9 :     *bp = true; // default result if we refuse to perform this action
         195                 :     Value v;
         196               9 :     SET(JS_DeletePropertyById2(cx, wrappedObject(wrapper), id, &v) &&
         197                 :         ValueToBoolean(&v, bp));
         198                 : }
         199                 :
         200                 : bool
         201               0 : Wrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
         202                 : {
         203                 :     // if we refuse to perform this action, props remains empty
         204               0 :     static jsid id = JSID_VOID;
         205               0 :     GET(GetPropertyNames(cx, wrappedObject(wrapper), 0, &props));
         206                 : }
         207                 :
         208                 : bool
         209               0 : Wrapper::fix(JSContext *cx, JSObject *wrapper, Value *vp)
         210                 : {
         211               0 :     vp->setUndefined();
         212               0 :     return true;
         213                 : }
         214                 :
         215                 : static bool
         216           23751 : Cond(JSBool b, bool *bp)
         217                 : {
         218           23751 :     *bp = !!b;
         219           23751 :     return true;
         220                 : }
         221                 :
         222                 : bool
         223           23751 : Wrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
         224                 : {
         225           23751 :     *bp = false; // default result if we refuse to perform this action
         226                 :     JSBool found;
         227           23751 :     GET(JS_HasPropertyById(cx, wrappedObject(wrapper), id, &found) &&
         228                 :         Cond(found, bp));
         229                 : }
         230                 :
         231                 : bool
         232               0 : Wrapper::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
         233                 : {
         234               0 :     *bp = false; // default result if we refuse to perform this action
         235                 :     PropertyDescriptor desc;
         236               0 :     JSObject *wobj = wrappedObject(wrapper);
         237               0 :     GET(JS_GetPropertyDescriptorById(cx, wobj, id, JSRESOLVE_QUALIFIED, &desc) &&
         238                 :         Cond(desc.obj == wobj, bp));
         239                 : }
         240                 :
         241                 : bool
         242           55241 : Wrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp)
         243                 : {
         244           55241 :     vp->setUndefined(); // default result if we refuse to perform this action
         245           55241 :     GET(wrappedObject(wrapper)->getGeneric(cx, receiver, id, vp));
         246                 : }
         247                 :
         248                 : bool
         249           16790 : Wrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool strict,
         250                 :                Value *vp)
         251                 : {
         252           16790 :     SET(wrappedObject(wrapper)->setGeneric(cx, id, vp, strict));
         253                 : }
         254                 :
         255                 : bool
         256           22419 : Wrapper::keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
         257                 : {
         258                 :     // if we refuse to perform this action, props remains empty
         259           22419 :     const jsid id = JSID_VOID;
         260           22419 :     GET(GetPropertyNames(cx, wrappedObject(wrapper), JSITER_OWNONLY, &props));
         261                 : }
         262                 :
         263                 : bool
         264              45 : Wrapper::iterate(JSContext *cx, JSObject *wrapper, unsigned flags, Value *vp)
         265                 : {
         266              45 :     vp->setUndefined(); // default result if we refuse to perform this action
         267              45 :     const jsid id = JSID_VOID;
         268              45 :     GET(GetIterator(cx, wrappedObject(wrapper), flags, vp));
         269                 : }
         270                 :
         271                 : bool
         272           20866 : Wrapper::call(JSContext *cx, JSObject *wrapper, unsigned argc, Value *vp)
         273                 : {
         274           20866 :     vp->setUndefined(); // default result if we refuse to perform this action
         275           20866 :     const jsid id = JSID_VOID;
         276           20866 :     CHECKED(ProxyHandler::call(cx, wrapper, argc, vp), CALL);
         277                 : }
         278                 :
         279                 : bool
         280             117 : Wrapper::construct(JSContext *cx, JSObject *wrapper, unsigned argc, Value *argv, Value *vp)
         281                 : {
         282             117 :     vp->setUndefined(); // default result if we refuse to perform this action
         283             117 :     const jsid id = JSID_VOID;
         284             117 :     GET(ProxyHandler::construct(cx, wrapper, argc, argv, vp));
         285                 : }
         286                 :
         287                 : bool
         288            2709 : Wrapper::nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args)
         289                 : {
         290            2709 :     const jsid id = JSID_VOID;
         291            2709 :     CHECKED(CallJSNative(cx, native, args), CALL);
         292                 : }
         293                 :
         294                 : bool
         295               0 : Wrapper::hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp)
         296                 : {
         297               0 :     *bp = false; // default result if we refuse to perform this action
         298               0 :     const jsid id = JSID_VOID;
         299               0 :     JSBool b = JS_FALSE;
         300               0 :     GET(JS_HasInstance(cx, wrappedObject(wrapper), *vp, &b) && Cond(b, bp));
         301                 : }
         302                 :
         303                 : JSType
         304             234 : Wrapper::typeOf(JSContext *cx, JSObject *wrapper)
         305                 : {
         306             234 :     return TypeOfValue(cx, ObjectValue(*wrappedObject(wrapper)));
         307                 : }
         308                 :
         309                 : bool
         310             441 : Wrapper::objectClassIs(JSObject *wrapper, ESClassValue classValue, JSContext *cx)
         311                 : {
         312             441 :     return ObjectClassIs(*wrappedObject(wrapper), classValue, cx);
         313                 : }
         314                 :
         315                 : JSString *
         316            1944 : Wrapper::obj_toString(JSContext *cx, JSObject *wrapper)
         317                 : {
         318                 :     bool status;
         319            1944 :     if (!enter(cx, wrapper, JSID_VOID, GET, &status)) {
         320               0 :         if (status) {
         321                 :             // Perform some default behavior that doesn't leak any information.
         322               0 :             return JS_NewStringCopyZ(cx, "[object Object]");
         323                 :         }
         324               0 :         return NULL;
         325                 :     }
         326            1944 :     JSString *str = obj_toStringHelper(cx, wrappedObject(wrapper));
         327            1944 :     leave(cx, wrapper);
         328            1944 :     return str;
         329                 : }
         330                 :
         331                 : JSString *
         332               9 : Wrapper::fun_toString(JSContext *cx, JSObject *wrapper, unsigned indent)
         333                 : {
         334                 :     bool status;
         335               9 :     if (!enter(cx, wrapper, JSID_VOID, GET, &status)) {
         336               0 :         if (status) {
         337                 :             // Perform some default behavior that doesn't leak any information.
         338               0 :             if (wrapper->isCallable())
         339               0 :                 return JS_NewStringCopyZ(cx, "function () {\n    [native code]\n}");
         340               0 :             js::Value v = ObjectValue(*wrapper);
         341               0 :             js_ReportIsNotFunction(cx, &v, 0);
         342               0 :             return NULL;
         343                 :         }
         344               0 :         return NULL;
         345                 :     }
         346               9 :     JSString *str = ProxyHandler::fun_toString(cx, wrapper, indent);
         347               9 :     leave(cx, wrapper);
         348               9 :     return str;
         349                 : }
         350                 :
         351                 : bool
         352              54 : Wrapper::regexp_toShared(JSContext *cx, JSObject *wrapper, RegExpGuard *g)
         353                 : {
         354              54 :     return wrappedObject(wrapper)->asRegExp().getShared(cx, g);
         355                 : }
         356                 :
         357                 : bool
         358             415 : Wrapper::defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, Value *vp)
         359                 : {
         360             415 :     *vp = ObjectValue(*wrappedObject(wrapper));
         361             415 :     if (hint == JSTYPE_VOID)
         362              73 :         return ToPrimitive(cx, vp);
         363             342 :     return ToPrimitive(cx, hint, vp);
         364                 : }
         365                 :
         366                 : bool
         367              54 : Wrapper::iteratorNext(JSContext *cx, JSObject *wrapper, Value *vp)
         368                 : {
         369              54 :     if (!js_IteratorMore(cx, wrappedObject(wrapper), vp))
         370               0 :         return false;
         371                 :
         372              54 :     if (vp->toBoolean()) {
         373              45 :         *vp = cx->iterValue;
         374              45 :         cx->iterValue.setUndefined();
         375                 :     } else {
         376               9 :         vp->setMagic(JS_NO_ITER_VALUE);
         377                 :     }
         378              54 :     return true;
         379                 : }
         380                 :
         381                 : void
         382               6 : Wrapper::trace(JSTracer *trc, JSObject *wrapper)
         383                 : {
         384               6 :     MarkSlot(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "wrappedObject");
         385               6 : }
         386                 :
         387                 : JSObject *
         388          265865 : Wrapper::wrappedObject(const JSObject *wrapper)
         389                 : {
         390          265865 :     return GetProxyPrivate(wrapper).toObjectOrNull();
         391                 : }
         392                 :
         393                 : Wrapper *
         394           72166 : Wrapper::wrapperHandler(const JSObject *wrapper)
         395                 : {
         396           72166 :     return static_cast<Wrapper *>(GetProxyHandler(wrapper));
         397                 : }
         398                 :
         399                 : bool
         400          143972 : Wrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp)
         401                 : {
         402          143972 :     *bp = true;
         403          143972 :     return true;
         404                 : }
         405                 :
         406                 : void
         407          143972 : Wrapper::leave(JSContext *cx, JSObject *wrapper)
         408                 : {
         409          143972 : }
         410                 :
         411           18667 : Wrapper Wrapper::singleton((unsigned)0);
         412                 :
         413                 : JSObject *
         414           34539 : Wrapper::New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, Wrapper *handler)
         415                 : {
         416           34539 :     JS_ASSERT(parent);
         417           34539 :     if (obj->isXML()) {
         418               9 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WRAP_XML_OBJECT);
         419               9 :         return NULL;
         420                 :     }
         421                 :     return NewProxyObject(cx, handler, ObjectValue(*obj), proto, parent,
         422           34530 :                           obj->isCallable() ? obj : NULL, NULL);
         423                 : }
         424                 :
         425                 : /* Compartments. */
         426                 :
         427                 : namespace js {
         428                 :
         429                 : extern JSObject *
         430           34516 : TransparentObjectWrapper(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSObject *parent,
         431                 :                          unsigned flags)
         432                 : {
         433                 :     // Allow wrapping outer window proxies.
         434           34516 :     JS_ASSERT(!obj->isWrapper() || obj->getClass()->ext.innerObject);
         435           34516 :     return Wrapper::New(cx, obj, wrappedProto, parent, &CrossCompartmentWrapper::singleton);
         436                 : }
         437                 :
         438                 : }
         439                 :
         440               0 : ForceFrame::ForceFrame(JSContext *cx, JSObject *target)
         441                 :     : context(cx),
         442                 :       target(target),
         443               0 :       frame(NULL)
         444                 : {
         445               0 : }
         446                 :
         447               0 : ForceFrame::~ForceFrame()
         448                 : {
         449               0 :     context->delete_(frame);
         450               0 : }
         451                 :
         452                 : bool
         453               0 : ForceFrame::enter()
         454                 : {
         455               0 :     frame = context->new_<DummyFrameGuard>();
         456               0 :     if (!frame)
         457               0 :        return false;
         458                 :
         459               0 :     JS_ASSERT(context->compartment == target->compartment());
         460               0 :     JSCompartment *destination = context->compartment;
         461                 :
         462               0 :     JSObject &scopeChain = target->global();
         463               0 :     JS_ASSERT(scopeChain.isNative());
         464                 :
         465               0 :     return context->stack.pushDummyFrame(context, destination, scopeChain, frame);
         466                 : }
         467                 :
         468          215765 : AutoCompartment::AutoCompartment(JSContext *cx, JSObject *target)
         469                 :     : context(cx),
         470                 :       origin(cx->compartment),
         471                 :       target(target),
         472          215765 :       destination(target->compartment()),
         473          431530 :       entered(false)
         474                 : {
         475          215765 : }
         476                 :
         477          431530 : AutoCompartment::~AutoCompartment()
         478                 : {
         479          215765 :     if (entered)
         480           51763 :         leave();
         481          215765 : }
         482                 :
         483                 : bool
         484          215765 : AutoCompartment::enter()
         485                 : {
         486          215765 :     JS_ASSERT(!entered);
         487          215765 :     if (origin != destination) {
         488          210004 :         JSObject &scopeChain = target->global();
         489          210004 :         JS_ASSERT(scopeChain.isNative());
         490                 :
         491          210004 :         frame.construct();
         492          210004 :         if (!context->stack.pushDummyFrame(context, destination, scopeChain, &frame.ref()))
         493               0 :             return false;
         494                 :
         495          210004 :         if (context->isExceptionPending())
         496               0 :             context->wrapPendingException();
         497                 :     }
         498          215765 :     entered = true;
         499          215765 :     return true;
         500                 : }
         501                 :
         502                 : void
         503          215765 : AutoCompartment::leave()
         504                 : {
         505          215765 :     JS_ASSERT(entered);
         506          215765 :     if (origin != destination) {
         507          210004 :         frame.destroy();
         508          210004 :         context->resetCompartment();
         509                 :     }
         510          215765 :     entered = false;
         511          215765 : }
         512                 :
         513            9981 : ErrorCopier::~ErrorCopier()
         514                 : {
         515            9981 :     JSContext *cx = ac.context;
         516           19962 :     if (cx->compartment == ac.destination &&
         517                 :         ac.origin != ac.destination &&
         518            9981 :         cx->isExceptionPending())
         519                 :     {
         520              27 :         Value exc = cx->getPendingException();
         521              27 :         if (exc.isObject() && exc.toObject().isError() && exc.toObject().getPrivate()) {
         522              18 :             cx->clearPendingException();
         523              18 :             ac.leave();
         524              18 :             JSObject *copyobj = js_CopyErrorObject(cx, &exc.toObject(), scope);
         525              18 :             if (copyobj)
         526              18 :                 cx->setPendingException(ObjectValue(*copyobj));
         527                 :         }
         528                 :     }
         529            9981 : }
         530                 :
         531                 : /* Cross compartment wrappers. */
         532                 :
         533           18667 : CrossCompartmentWrapper::CrossCompartmentWrapper(unsigned flags)
         534           18667 :   : Wrapper(CROSS_COMPARTMENT | flags)
         535                 : {
         536           18667 : }
         537                 :
         538           18667 : CrossCompartmentWrapper::~CrossCompartmentWrapper()
         539                 : {
         540           18667 : }
         541                 :
         542                 : #define PIERCE(cx, wrapper, mode, pre, op, post)            \
         543                 :     JS_BEGIN_MACRO                                          \
         544                 :         AutoCompartment call(cx, wrappedObject(wrapper));   \
         545                 :         if (!call.enter())                                  \
         546                 :             return false;                                   \
         547                 :         bool ok = (pre) && (op);                            \
         548                 :         call.leave();                                       \
         549                 :         return ok && (post);                                \
         550                 :     JS_END_MACRO
         551                 :
         552                 : #define NOTHING (true)
         553                 :
         554                 : bool
         555               0 : CrossCompartmentWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
         556                 :                                                bool set, PropertyDescriptor *desc)
         557                 : {
         558               0 :     PIERCE(cx, wrapper, set ? SET : GET,
         559                 :            call.destination->wrapId(cx, &id),
         560                 :            Wrapper::getPropertyDescriptor(cx, wrapper, id, set, desc),
         561                 :            call.origin->wrap(cx, desc));
         562                 : }
         563                 :
         564                 : bool
         565              36 : CrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
         566                 :                                                   bool set, PropertyDescriptor *desc)
         567                 : {
         568              36 :     PIERCE(cx, wrapper, set ? SET : GET,
         569                 :            call.destination->wrapId(cx, &id),
         570                 :            Wrapper::getOwnPropertyDescriptor(cx, wrapper, id, set, desc),
         571                 :            call.origin->wrap(cx, desc));
         572                 : }
         573                 :
         574                 : bool
         575              27 : CrossCompartmentWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc)
         576                 : {
         577              54 :     AutoPropertyDescriptorRooter desc2(cx, desc);
         578              27 :     PIERCE(cx, wrapper, SET,
         579                 :            call.destination->wrapId(cx, &id) && call.destination->wrap(cx, &desc2),
         580                 :            Wrapper::defineProperty(cx, wrapper, id, &desc2),
         581                 :            NOTHING);
         582                 : }
         583                 :
         584                 : bool
         585               0 : CrossCompartmentWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
         586                 : {
         587               0 :     PIERCE(cx, wrapper, GET,
         588                 :            NOTHING,
         589                 :            Wrapper::getOwnPropertyNames(cx, wrapper, props),
         590                 :            call.origin->wrap(cx, props));
         591                 : }
         592                 :
         593                 : bool
         594               9 : CrossCompartmentWrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
         595                 : {
         596               9 :     PIERCE(cx, wrapper, SET,
         597                 :            call.destination->wrapId(cx, &id),
         598                 :            Wrapper::delete_(cx, wrapper, id, bp),
         599                 :            NOTHING);
         600                 : }
         601                 :
         602                 : bool
         603               0 : CrossCompartmentWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
         604                 : {
         605               0 :     PIERCE(cx, wrapper, GET,
         606                 :            NOTHING,
         607                 :            Wrapper::enumerate(cx, wrapper, props),
         608                 :            call.origin->wrap(cx, props));
         609                 : }
         610                 :
         611                 : bool
         612           23751 : CrossCompartmentWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
         613                 : {
         614           23751 :     PIERCE(cx, wrapper, GET,
         615                 :            call.destination->wrapId(cx, &id),
         616                 :            Wrapper::has(cx, wrapper, id, bp),
         617                 :            NOTHING);
         618                 : }
         619                 :
         620                 : bool
         621               0 : CrossCompartmentWrapper::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
         622                 : {
         623               0 :     PIERCE(cx, wrapper, GET,
         624                 :            call.destination->wrapId(cx, &id),
         625                 :            Wrapper::hasOwn(cx, wrapper, id, bp),
         626                 :            NOTHING);
         627                 : }
         628                 :
         629                 : bool
         630           55223 : CrossCompartmentWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp)
         631                 : {
         632           55223 :     PIERCE(cx, wrapper, GET,
         633                 :            call.destination->wrap(cx, &receiver) && call.destination->wrapId(cx, &id),
         634                 :            Wrapper::get(cx, wrapper, receiver, id, vp),
         635                 :            call.origin->wrap(cx, vp));
         636                 : }
         637                 :
         638                 : bool
         639           16790 : CrossCompartmentWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id,
         640                 :                              bool strict, Value *vp)
         641                 : {
         642           33580 :     AutoValueRooter tvr(cx, *vp);
         643           16790 :     PIERCE(cx, wrapper, SET,
         644                 :            call.destination->wrap(cx, &receiver) &&
         645                 :            call.destination->wrapId(cx, &id) &&
         646                 :            call.destination->wrap(cx, tvr.addr()),
         647                 :            Wrapper::set(cx, wrapper, receiver, id, strict, tvr.addr()),
         648                 :            NOTHING);
         649                 : }
         650                 :
         651                 : bool
         652           22419 : CrossCompartmentWrapper::keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
         653                 : {
         654           22419 :     PIERCE(cx, wrapper, GET,
         655                 :            NOTHING,
         656                 :            Wrapper::keys(cx, wrapper, props),
         657                 :            call.origin->wrap(cx, props));
         658                 : }
         659                 :
         660                 : /*
         661                 :  * We can reify non-escaping iterator objects instead of having to wrap them. This
         662                 :  * allows fast iteration over objects across a compartment boundary.
         663                 :  */
         664                 : static bool
         665              36 : CanReify(Value *vp)
         666                 : {
         667                 :     JSObject *obj;
         668              36 :     return vp->isObject() &&
         669              36 :            (obj = &vp->toObject())->getClass() == &IteratorClass &&
         670              72 :            (obj->getNativeIterator()->flags & JSITER_ENUMERATE);
         671                 : }
         672                 :
         673                 : struct AutoCloseIterator
         674                 : {
         675              27 :     AutoCloseIterator(JSContext *cx, JSObject *obj) : cx(cx), obj(obj) {}
         676                 :
         677              27 :     ~AutoCloseIterator() { if (obj) CloseIterator(cx, obj); }
         678                 :
         679              27 :     void clear() { obj = NULL; }
         680                 :
         681                 :   private:
         682                 :     JSContext *cx;
         683                 :     JSObject *obj;
         684                 : };
         685                 :
         686                 : static bool
         687              27 : Reify(JSContext *cx, JSCompartment *origin, Value *vp)
         688                 : {
         689              27 :     JSObject *iterObj = &vp->toObject();
         690              27 :     NativeIterator *ni = iterObj->getNativeIterator();
         691                 :
         692              54 :     AutoCloseIterator close(cx, iterObj);
         693                 :
         694                 :     /* Wrap the iteratee. */
         695              27 :     JSObject *obj = ni->obj;
         696              27 :     if (!origin->wrap(cx, &obj))
         697               0 :         return false;
         698                 :
         699                 :     /*
         700                 :      * Wrap the elements in the iterator's snapshot.
         701                 :      * N.B. the order of closing/creating iterators is important due to the
         702                 :      * implicit cx->enumerators state.
         703                 :      */
         704              27 :     size_t length = ni->numKeys();
         705              27 :     bool isKeyIter = ni->isKeyIter();
         706              54 :     AutoIdVector keys(cx);
         707              27 :     if (length > 0) {
         708              27 :         if (!keys.reserve(length))
         709               0 :             return false;
         710            9054 :         for (size_t i = 0; i < length; ++i) {
         711                 :             jsid id;
         712            9027 :             if (!ValueToId(cx, StringValue(ni->begin()[i]), &id))
         713               0 :                 return false;
         714            9027 :             id = js_CheckForStringIndex(id);
         715            9027 :             keys.infallibleAppend(id);
         716            9027 :             if (!origin->wrapId(cx, &keys[i]))
         717               0 :                 return false;
         718                 :         }
         719                 :     }
         720                 :
         721              27 :     close.clear();
         722              27 :     if (!CloseIterator(cx, iterObj))
         723               0 :         return false;
         724                 :
         725              27 :     if (isKeyIter)
         726              27 :         return VectorToKeyIterator(cx, obj, ni->flags, keys, vp);
         727               0 :     return VectorToValueIterator(cx, obj, ni->flags, keys, vp);
         728                 : }
         729                 :
         730                 : bool
         731              45 : CrossCompartmentWrapper::iterate(JSContext *cx, JSObject *wrapper, unsigned flags, Value *vp)
         732                 : {
         733              45 :     PIERCE(cx, wrapper, GET,
         734                 :            NOTHING,
         735                 :            Wrapper::iterate(cx, wrapper, flags, vp),
         736                 :            CanReify(vp) ? Reify(cx, call.origin, vp) : call.origin->wrap(cx, vp));
         737                 : }
         738                 :
         739                 : bool
         740           20866 : CrossCompartmentWrapper::call(JSContext *cx, JSObject *wrapper, unsigned argc, Value *vp)
         741                 : {
         742           41732 :     AutoCompartment call(cx, wrappedObject(wrapper));
         743           20866 :     if (!call.enter())
         744               0 :         return false;
         745                 :
         746           20866 :     vp[0] = ObjectValue(*call.target);
         747           20866 :     if (!call.destination->wrap(cx, &vp[1]))
         748               0 :         return false;
         749           20866 :     Value *argv = JS_ARGV(cx, vp);
         750           37852 :     for (size_t n = 0; n < argc; ++n) {
         751           16986 :         if (!call.destination->wrap(cx, &argv[n]))
         752               0 :             return false;
         753                 :     }
         754           20866 :     if (!Wrapper::call(cx, wrapper, argc, vp))
         755            2340 :         return false;
         756                 :
         757           18526 :     call.leave();
         758           18526 :     return call.origin->wrap(cx, vp);
         759                 : }
         760                 :
         761                 : bool
         762             108 : CrossCompartmentWrapper::construct(JSContext *cx, JSObject *wrapper, unsigned argc, Value *argv,
         763                 :                                    Value *rval)
         764                 : {
         765             216 :     AutoCompartment call(cx, wrappedObject(wrapper));
         766             108 :     if (!call.enter())
         767               0 :         return false;
         768                 :
         769             108 :     for (size_t n = 0; n < argc; ++n) {
         770               0 :         if (!call.destination->wrap(cx, &argv[n]))
         771               0 :             return false;
         772                 :     }
         773             108 :     if (!Wrapper::construct(cx, wrapper, argc, argv, rval))
         774              45 :         return false;
         775                 :
         776              63 :     call.leave();
         777              63 :     return call.origin->wrap(cx, rval);
         778                 : }
         779                 :
         780                 : extern JSBool
         781                 : js_generic_native_method_dispatcher(JSContext *cx, unsigned argc, Value *vp);
         782                 :
         783                 : bool
         784            2709 : CrossCompartmentWrapper::nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs srcArgs)
         785                 : {
         786            5652 :     JS_ASSERT_IF(!srcArgs.calleev().isUndefined(),
         787                 :                  srcArgs.callee().toFunction()->native() == native ||
         788            5652 :                  srcArgs.callee().toFunction()->native() == js_generic_native_method_dispatcher);
         789            2709 :     JS_ASSERT(&srcArgs.thisv().toObject() == wrapper);
         790            2709 :     JS_ASSERT(!UnwrapObject(wrapper)->isCrossCompartmentWrapper());
         791                 :
         792            2709 :     JSObject *wrapped = wrappedObject(wrapper);
         793            5418 :     AutoCompartment call(cx, wrapped);
         794            2709 :     if (!call.enter())
         795               0 :         return false;
         796                 :
         797            5418 :     InvokeArgsGuard dstArgs;
         798            2709 :     if (!cx->stack.pushInvokeArgs(cx, srcArgs.length(), &dstArgs))
         799               0 :         return false;
         800                 :
         801            2709 :     Value *src = srcArgs.base();
         802            2709 :     Value *srcend = srcArgs.array() + srcArgs.length();
         803            2709 :     Value *dst = dstArgs.base();
         804            8748 :     for (; src != srcend; ++src, ++dst) {
         805            6039 :         *dst = *src;
         806            6039 :         if (!call.destination->wrap(cx, dst))
         807               0 :             return false;
         808                 :     }
         809                 :
         810            2709 :     if (!Wrapper::nativeCall(cx, wrapper, clasp, native, dstArgs))
         811            1800 :         return false;
         812                 :
         813             909 :     srcArgs.rval() = dstArgs.rval();
         814             909 :     dstArgs.pop();
         815             909 :     call.leave();
         816             909 :     return call.origin->wrap(cx, &srcArgs.rval());
         817                 : }
         818                 :
         819                 : bool
         820               0 : CrossCompartmentWrapper::hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp)
         821                 : {
         822               0 :     AutoCompartment call(cx, wrappedObject(wrapper));
         823               0 :     if (!call.enter())
         824               0 :         return false;
         825                 :
         826               0 :     Value v = *vp;
         827               0 :     if (!call.destination->wrap(cx, &v))
         828               0 :         return false;
         829               0 :     return Wrapper::hasInstance(cx, wrapper, &v, bp);
         830                 : }
         831                 :
         832                 : JSString *
         833            1944 : CrossCompartmentWrapper::obj_toString(JSContext *cx, JSObject *wrapper)
         834                 : {
         835            3888 :     AutoCompartment call(cx, wrappedObject(wrapper));
         836            1944 :     if (!call.enter())
         837               0 :         return NULL;
         838                 :
         839            1944 :     JSString *str = Wrapper::obj_toString(cx, wrapper);
         840            1944 :     if (!str)
         841               0 :         return NULL;
         842                 :
         843            1944 :     call.leave();
         844            1944 :     if (!call.origin->wrap(cx, &str))
         845               0 :         return NULL;
         846            1944 :     return str;
         847                 : }
         848                 :
         849                 : JSString *
         850               0 : CrossCompartmentWrapper::fun_toString(JSContext *cx, JSObject *wrapper, unsigned indent)
         851                 : {
         852               0 :     AutoCompartment call(cx, wrappedObject(wrapper));
         853               0 :     if (!call.enter())
         854               0 :         return NULL;
         855                 :
         856               0 :     JSString *str = Wrapper::fun_toString(cx, wrapper, indent);
         857               0 :     if (!str)
         858               0 :         return NULL;
         859                 :
         860               0 :     call.leave();
         861               0 :     if (!call.origin->wrap(cx, &str))
         862               0 :         return NULL;
         863               0 :     return str;
         864                 : }
         865                 :
         866                 : bool
         867             415 : CrossCompartmentWrapper::defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, Value *vp)
         868                 : {
         869             830 :     AutoCompartment call(cx, wrappedObject(wrapper));
         870             415 :     if (!call.enter())
         871               0 :         return false;
         872                 :
         873             415 :     if (!Wrapper::defaultValue(cx, wrapper, hint, vp))
         874              63 :         return false;
         875                 :
         876             352 :     call.leave();
         877             352 :     return call.origin->wrap(cx, vp);
         878                 : }
         879                 :
         880                 : bool
         881              54 : CrossCompartmentWrapper::iteratorNext(JSContext *cx, JSObject *wrapper, Value *vp)
         882                 : {
         883              54 :     PIERCE(cx, wrapper, GET,
         884                 :            NOTHING,
         885                 :            Wrapper::iteratorNext(cx, wrapper, vp),
         886                 :            call.origin->wrap(cx, vp));
         887                 : }
         888                 :
         889                 : void
         890           36713 : CrossCompartmentWrapper::trace(JSTracer *trc, JSObject *wrapper)
         891                 : {
         892           36713 :     MarkCrossCompartmentSlot(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE),
         893           36713 :                              "wrappedObject");
         894           36713 : }
         895                 :
         896           18667 : CrossCompartmentWrapper CrossCompartmentWrapper::singleton(0u);
         897                 :
         898                 : /* Security wrappers. */
         899                 :
         900                 : template <class Base>
         901               0 : SecurityWrapper<Base>::SecurityWrapper(unsigned flags)
         902               0 :   : Base(flags)
         903               0 : {}
         904                 :
         905                 : template <class Base>
         906                 : bool
         907               0 : SecurityWrapper<Base>::nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native,
         908                 :                                   CallArgs args)
         909                 : {
         910                 :     /*
         911                 :      * Let this through until compartment-per-global lets us have stronger
         912                 :      * invariants wrt document.domain (bug 714547).
         913                 :      */
         914               0 :     return Base::nativeCall(cx, wrapper, clasp, native, args);
         915                 : }
         916                 :
         917                 : template <class Base>
         918                 : bool
         919               0 : SecurityWrapper<Base>::objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx)
         920                 : {
         921                 :     /*
         922                 :      * Let this through until compartment-per-global lets us have stronger
         923                 :      * invariants wrt document.domain (bug 714547).
         924                 :      */
         925               0 :     return Base::objectClassIs(obj, classValue, cx);
         926                 : }
         927                 :
         928                 : template <class Base>
         929                 : bool
         930               0 : SecurityWrapper<Base>::regexp_toShared(JSContext *cx, JSObject *obj, RegExpGuard *g)
         931                 : {
         932               0 :     return Base::regexp_toShared(cx, obj, g);
         933                 : }
         934                 :
         935                 :
         936                 : template class js::SecurityWrapper<Wrapper>;
         937           56001 : template class js::SecurityWrapper<CrossCompartmentWrapper>;

Generated by: LCOV version 1.7