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