js/src/vm/PIC.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "vm/PIC.h"
     8 #include "jscntxt.h"
     9 #include "jsobj.h"
    10 #include "gc/Marking.h"
    12 #include "vm/GlobalObject.h"
    13 #include "vm/ObjectImpl.h"
    14 #include "vm/SelfHosting.h"
    15 #include "jsobjinlines.h"
    16 #include "vm/ObjectImpl-inl.h"
    18 using namespace js;
    19 using namespace js::gc;
    21 bool
    22 js::ForOfPIC::Chain::initialize(JSContext *cx)
    23 {
    24     JS_ASSERT(!initialized_);
    26     // Get the canonical Array.prototype
    27     RootedObject arrayProto(cx, GlobalObject::getOrCreateArrayPrototype(cx, cx->global()));
    28     if (!arrayProto)
    29         return false;
    31     // Get the canonical ArrayIterator.prototype
    32     RootedObject arrayIteratorProto(cx,
    33                     GlobalObject::getOrCreateArrayIteratorPrototype(cx, cx->global()));
    34     if (!arrayIteratorProto)
    35         return false;
    37     // From this point on, we can't fail.  Set initialized and fill the fields
    38     // for the canonical Array.prototype and ArrayIterator.prototype objects.
    39     initialized_ = true;
    40     arrayProto_ = arrayProto;
    41     arrayIteratorProto_ = arrayIteratorProto;
    43     // Shortcut returns below means Array for-of will never be optimizable,
    44     // do set disabled_ now, and clear it later when we succeed.
    45     disabled_ = true;
    47     // Look up '@@iterator' on Array.prototype, ensure it's a slotful shape.
    48     Shape *iterShape = arrayProto->nativeLookup(cx, cx->names().std_iterator);
    49     if (!iterShape || !iterShape->hasSlot() || !iterShape->hasDefaultGetter())
    50         return true;
    52     // Get the referred value, and ensure it holds the canonical ArrayValues function.
    53     Value iterator = arrayProto->getSlot(iterShape->slot());
    54     JSFunction *iterFun;
    55     if (!IsFunctionObject(iterator, &iterFun))
    56         return true;
    57     if (!IsSelfHostedFunctionWithName(iterFun, cx->names().ArrayValues))
    58         return true;
    60     // Look up the 'next' value on ArrayIterator.prototype
    61     Shape *nextShape = arrayIteratorProto->nativeLookup(cx, cx->names().next);
    62     if (!nextShape || !nextShape->hasSlot())
    63         return true;
    65     // Get the referred value, ensure it holds the canonical ArrayIteratorNext function.
    66     Value next = arrayIteratorProto->getSlot(nextShape->slot());
    67     JSFunction *nextFun;
    68     if (!IsFunctionObject(next, &nextFun))
    69         return true;
    70     if (!IsSelfHostedFunctionWithName(nextFun, cx->names().ArrayIteratorNext))
    71         return true;
    73     disabled_ = false;
    74     arrayProtoShape_ = arrayProto->lastProperty();
    75     arrayProtoIteratorSlot_ = iterShape->slot();
    76     canonicalIteratorFunc_ = iterator;
    77     arrayIteratorProtoShape_ = arrayIteratorProto->lastProperty();
    78     arrayIteratorProtoNextSlot_ = nextShape->slot();
    79     canonicalNextFunc_ = next;
    80     return true;
    81 }
    83 js::ForOfPIC::Stub *
    84 js::ForOfPIC::Chain::isArrayOptimized(ArrayObject *obj)
    85 {
    86     Stub *stub = getMatchingStub(obj);
    87     if (!stub)
    88         return nullptr;
    90     // Ensure that this is an otherwise optimizable array.
    91     if (!isOptimizableArray(obj))
    92         return nullptr;
    94     // Not yet enough!  Ensure that the world as we know it remains sane.
    95     if (!isArrayStateStillSane())
    96         return nullptr;
    98     return stub;
    99 }
   101 bool
   102 js::ForOfPIC::Chain::tryOptimizeArray(JSContext *cx, HandleObject array, bool *optimized)
   103 {
   104     JS_ASSERT(array->is<ArrayObject>());
   105     JS_ASSERT(optimized);
   107     *optimized = false;
   109     if (!initialized_) {
   110         // If PIC is not initialized, initialize it.
   111         if (!initialize(cx))
   112             return false;
   114     } else if (!disabled_ && !isArrayStateStillSane()) {
   115         // Otherwise, if array state is no longer sane, reinitialize.
   116         reset(cx);
   118         if (!initialize(cx))
   119             return false;
   120     }
   121     JS_ASSERT(initialized_);
   123     // If PIC is disabled, don't bother trying to optimize.
   124     if (disabled_)
   125         return true;
   127     // By the time we get here, we should have a sane array state to work with.
   128     JS_ASSERT(isArrayStateStillSane());
   130     // Check if stub already exists.
   131     ForOfPIC::Stub *stub = isArrayOptimized(&array->as<ArrayObject>());
   132     if (stub) {
   133         *optimized = true;
   134         return true;
   135     }
   137     // If the number of stubs is about to exceed the limit, throw away entire
   138     // existing cache before adding new stubs.  We shouldn't really have heavy
   139     // churn on these.
   140     if (numStubs() >= MAX_STUBS)
   141         eraseChain();
   143     // Ensure array's prototype is the actual Array.prototype
   144     if (!isOptimizableArray(array))
   145         return true;
   147     // Ensure array doesn't define '@@iterator' directly.
   148     if (array->nativeLookup(cx, cx->names().std_iterator))
   149         return true;
   151     // Good to optimize now, create stub to add.
   152     RootedShape shape(cx, array->lastProperty());
   153     stub = cx->new_<Stub>(shape);
   154     if (!stub)
   155         return false;
   157     // Add the stub.
   158     addStub(stub);
   160     *optimized = true;
   161     return true;
   162 }
   164 js::ForOfPIC::Stub *
   165 js::ForOfPIC::Chain::getMatchingStub(JSObject *obj)
   166 {
   167     // Ensure PIC is initialized and not disabled.
   168     if (!initialized_ || disabled_)
   169         return nullptr;
   171     // Check if there is a matching stub.
   172     for (Stub *stub = stubs(); stub != nullptr; stub = stub->next()) {
   173         if (stub->shape() == obj->lastProperty())
   174             return stub;
   175     }
   177     return nullptr;
   178 }
   180 bool
   181 js::ForOfPIC::Chain::isOptimizableArray(JSObject *obj)
   182 {
   183     JS_ASSERT(obj->is<ArrayObject>());
   185     // Ensure object's prototype is the actual Array.prototype
   186     if (!obj->getTaggedProto().isObject())
   187         return false;
   188     if (obj->getTaggedProto().toObject() != arrayProto_)
   189         return false;
   191     return true;
   192 }
   194 bool
   195 js::ForOfPIC::Chain::isArrayStateStillSane()
   196 {
   197     // Ensure that canonical Array.prototype has matching shape.
   198     if (arrayProto_->lastProperty() != arrayProtoShape_)
   199         return false;
   201     // Ensure that Array.prototype['@@iterator'] contains the
   202     // canonical iterator function.
   203     if (arrayProto_->getSlot(arrayProtoIteratorSlot_) != canonicalIteratorFunc_)
   204         return false;
   206     // Chain to isArrayNextStillSane.
   207     return isArrayNextStillSane();
   208 }
   210 void
   211 js::ForOfPIC::Chain::reset(JSContext *cx)
   212 {
   213     // Should never reset a disabled_ stub.
   214     JS_ASSERT(!disabled_);
   216     // Erase the chain.
   217     eraseChain();
   219     arrayProto_ = nullptr;
   220     arrayIteratorProto_ = nullptr;
   222     arrayProtoShape_ = nullptr;
   223     arrayProtoIteratorSlot_ = -1;
   224     canonicalIteratorFunc_ = UndefinedValue();
   226     arrayIteratorProtoShape_ = nullptr;
   227     arrayIteratorProtoNextSlot_ = -1;
   228     canonicalNextFunc_ = UndefinedValue();
   230     initialized_ = false;
   231 }
   233 void
   234 js::ForOfPIC::Chain::eraseChain()
   235 {
   236     // Should never need to clear the chain of a disabled stub.
   237     JS_ASSERT(!disabled_);
   239     // Free all stubs.
   240     Stub *stub = stubs_;
   241     while (stub) {
   242         Stub *next = stub->next();
   243         js_delete(stub);
   244         stub = next;
   245     }
   246     stubs_ = nullptr;
   247 }
   250 // Trace the pointers stored directly on the stub.
   251 void
   252 js::ForOfPIC::Chain::mark(JSTracer *trc)
   253 {
   254     if (!initialized_ || disabled_)
   255         return;
   257     gc::MarkObject(trc, &arrayProto_, "ForOfPIC Array.prototype.");
   258     gc::MarkObject(trc, &arrayIteratorProto_, "ForOfPIC ArrayIterator.prototype.");
   260     gc::MarkShape(trc, &arrayProtoShape_, "ForOfPIC Array.prototype shape.");
   261     gc::MarkShape(trc, &arrayIteratorProtoShape_, "ForOfPIC ArrayIterator.prototype shape.");
   263     gc::MarkValue(trc, &canonicalIteratorFunc_, "ForOfPIC ArrayValues builtin.");
   264     gc::MarkValue(trc, &canonicalNextFunc_, "ForOfPIC ArrayIterator.prototype.next builtin.");
   266     // Free all the stubs in the chain.
   267     while (stubs_)
   268         removeStub(stubs_, nullptr);
   269 }
   271 void
   272 js::ForOfPIC::Chain::sweep(FreeOp *fop)
   273 {
   274     // Free all the stubs in the chain.
   275     while (stubs_) {
   276         Stub *next = stubs_->next();
   277         fop->delete_(stubs_);
   278         stubs_ = next;
   279     }
   280     fop->delete_(this);
   281 }
   283 static void
   284 ForOfPIC_finalize(FreeOp *fop, JSObject *obj)
   285 {
   286     if (ForOfPIC::Chain *chain = ForOfPIC::fromJSObject(obj))
   287         chain->sweep(fop);
   288 }
   290 static void
   291 ForOfPIC_traceObject(JSTracer *trc, JSObject *obj)
   292 {
   293     if (ForOfPIC::Chain *chain = ForOfPIC::fromJSObject(obj))
   294         chain->mark(trc);
   295 }
   297 const Class ForOfPIC::jsclass = {
   298     "ForOfPIC", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
   299     JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   300     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, ForOfPIC_finalize,
   301     nullptr,              /* call        */
   302     nullptr,              /* hasInstance */
   303     nullptr,              /* construct   */
   304     ForOfPIC_traceObject
   305 };
   307 /* static */ JSObject *
   308 js::ForOfPIC::createForOfPICObject(JSContext *cx, Handle<GlobalObject*> global)
   309 {
   310     assertSameCompartment(cx, global);
   311     JSObject *obj = NewObjectWithGivenProto(cx, &ForOfPIC::jsclass, nullptr, global);
   312     if (!obj)
   313         return nullptr;
   314     ForOfPIC::Chain *chain = cx->new_<ForOfPIC::Chain>();
   315     if (!chain)
   316         return nullptr;
   317     obj->setPrivate(chain);
   318     return obj;
   319 }
   321 /* static */ js::ForOfPIC::Chain *
   322 js::ForOfPIC::create(JSContext *cx)
   323 {
   324     JS_ASSERT(!cx->global()->getForOfPICObject());
   325     Rooted<GlobalObject *> global(cx, cx->global());
   326     JSObject *obj = GlobalObject::getOrCreateForOfPICObject(cx, global);
   327     if (!obj)
   328         return nullptr;
   329     return fromJSObject(obj);
   330 }

mercurial