js/public/Anchor.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/public/Anchor.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,174 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* JS::Anchor implementation. */
    1.11 +
    1.12 +#ifndef js_Anchor_h
    1.13 +#define js_Anchor_h
    1.14 +
    1.15 +#include "mozilla/Attributes.h"
    1.16 +
    1.17 +#include "js/TypeDecls.h"
    1.18 +
    1.19 +namespace JS {
    1.20 +
    1.21 +/*
    1.22 + * Protecting non-Value, non-JSObject *, non-JSString * values from collection
    1.23 + *
    1.24 + * Most of the time, the garbage collector's conservative stack scanner works
    1.25 + * behind the scenes, finding all live values and protecting them from being
    1.26 + * collected. However, when JSAPI client code obtains a pointer to data the
    1.27 + * scanner does not know about, owned by an object the scanner does know about,
    1.28 + * Care Must Be Taken.
    1.29 + *
    1.30 + * The scanner recognizes only a select set of types: pointers to JSObjects and
    1.31 + * similar things (JSFunctions, and so on), pointers to JSStrings, and Values.
    1.32 + * So while the scanner finds all live |JSString| pointers, it does not notice
    1.33 + * |jschar| pointers.
    1.34 + *
    1.35 + * So suppose we have:
    1.36 + *
    1.37 + *   void f(JSString *str) {
    1.38 + *     const jschar *ch = JS_GetStringCharsZ(str);
    1.39 + *     ... do stuff with ch, but no uses of str ...;
    1.40 + *   }
    1.41 + *
    1.42 + * After the call to |JS_GetStringCharsZ|, there are no further uses of
    1.43 + * |str|, which means that the compiler is within its rights to not store
    1.44 + * it anywhere. But because the stack scanner will not notice |ch|, there
    1.45 + * is no longer any live value in this frame that would keep the string
    1.46 + * alive. If |str| is the last reference to that |JSString|, and the
    1.47 + * collector runs while we are using |ch|, the string's array of |jschar|s
    1.48 + * may be freed out from under us.
    1.49 + *
    1.50 + * Note that there is only an issue when 1) we extract a thing X the scanner
    1.51 + * doesn't recognize from 2) a thing Y the scanner does recognize, and 3) if Y
    1.52 + * gets garbage-collected, then X gets freed. If we have code like this:
    1.53 + *
    1.54 + *   void g(JSObject *obj) {
    1.55 + *     JS::Value x;
    1.56 + *     JS_GetProperty(obj, "x", &x);
    1.57 + *     ... do stuff with x ...
    1.58 + *   }
    1.59 + *
    1.60 + * there's no problem, because the value we've extracted, x, is a Value, a
    1.61 + * type that the conservative scanner recognizes.
    1.62 + *
    1.63 + * Conservative GC frees us from the obligation to explicitly root the types it
    1.64 + * knows about, but when we work with derived values like |ch|, we must root
    1.65 + * their owners, as the derived value alone won't keep them alive.
    1.66 + *
    1.67 + * A JS::Anchor is a kind of GC root that allows us to keep the owners of
    1.68 + * derived values like |ch| alive throughout the Anchor's lifetime. We could
    1.69 + * fix the above code as follows:
    1.70 + *
    1.71 + *   void f(JSString *str) {
    1.72 + *     JS::Anchor<JSString *> a_str(str);
    1.73 + *     const jschar *ch = JS_GetStringCharsZ(str);
    1.74 + *     ... do stuff with ch, but no uses of str ...;
    1.75 + *   }
    1.76 + *
    1.77 + * This simply ensures that |str| will be live until |a_str| goes out of scope.
    1.78 + * As long as we don't retain a pointer to the string's characters for longer
    1.79 + * than that, we have avoided all garbage collection hazards.
    1.80 + */
    1.81 +template<typename T> class AnchorPermitted;
    1.82 +template<> class AnchorPermitted<JSObject *> { };
    1.83 +template<> class AnchorPermitted<const JSObject *> { };
    1.84 +template<> class AnchorPermitted<JSFunction *> { };
    1.85 +template<> class AnchorPermitted<const JSFunction *> { };
    1.86 +template<> class AnchorPermitted<JSString *> { };
    1.87 +template<> class AnchorPermitted<const JSString *> { };
    1.88 +template<> class AnchorPermitted<Value> { };
    1.89 +template<> class AnchorPermitted<const JSScript *> { };
    1.90 +template<> class AnchorPermitted<JSScript *> { };
    1.91 +
    1.92 +template<typename T>
    1.93 +class Anchor : AnchorPermitted<T>
    1.94 +{
    1.95 +  public:
    1.96 +    Anchor() { }
    1.97 +    explicit Anchor(T t) { hold = t; }
    1.98 +    inline ~Anchor();
    1.99 +
   1.100 +  private:
   1.101 +    T hold;
   1.102 +
   1.103 +    /*
   1.104 +     * Rooting analysis considers use of operator= to be a use of an anchor.
   1.105 +     * For simplicity, Anchor is treated as if it contained a GC thing, from
   1.106 +     * construction. Thus if we had
   1.107 +     *
   1.108 +     *   void operator=(const T &t) { hold = t; }
   1.109 +     *
   1.110 +     * and this code
   1.111 +     *
   1.112 +     *   JS::Anchor<JSString*> anchor;
   1.113 +     *   stuff that could GC, producing |str|;
   1.114 +     *   anchor = str;
   1.115 +     *
   1.116 +     * the last line would be seen as a hazard, because the final = would "use"
   1.117 +     * |anchor| that is a GC thing -- which could have been moved around by the
   1.118 +     * GC. The workaround is to structure your code so that JS::Anchor is
   1.119 +     * always constructed, living for however long the corresponding value must
   1.120 +     * live.
   1.121 +     */
   1.122 +    void operator=(const T &t) MOZ_DELETE;
   1.123 +
   1.124 +    Anchor(const Anchor &other) MOZ_DELETE;
   1.125 +    void operator=(const Anchor &other) MOZ_DELETE;
   1.126 +};
   1.127 +
   1.128 +template<typename T>
   1.129 +inline Anchor<T>::~Anchor()
   1.130 +{
   1.131 +#ifdef __GNUC__
   1.132 +    /*
   1.133 +     * No code is generated for this. But because this is marked 'volatile', G++ will
   1.134 +     * assume it has important side-effects, and won't delete it. (G++ never looks at
   1.135 +     * the actual text and notices it's empty.) And because we have passed |hold| to
   1.136 +     * it, GCC will keep |hold| alive until this point.
   1.137 +     *
   1.138 +     * The "memory" clobber operand ensures that G++ will not move prior memory
   1.139 +     * accesses after the asm --- it's a barrier. Unfortunately, it also means that
   1.140 +     * G++ will assume that all memory has changed after the asm, as it would for a
   1.141 +     * call to an unknown function. I don't know of a way to avoid that consequence.
   1.142 +     */
   1.143 +    asm volatile("":: "g" (hold) : "memory");
   1.144 +#else
   1.145 +    /*
   1.146 +     * An adequate portable substitute, for non-structure types.
   1.147 +     *
   1.148 +     * The compiler promises that, by the end of an expression statement, the
   1.149 +     * last-stored value to a volatile object is the same as it would be in an
   1.150 +     * unoptimized, direct implementation (the "abstract machine" whose behavior the
   1.151 +     * language spec describes). However, the compiler is still free to reorder
   1.152 +     * non-volatile accesses across this store --- which is what we must prevent. So
   1.153 +     * assigning the held value to a volatile variable, as we do here, is not enough.
   1.154 +     *
   1.155 +     * In our case, however, garbage collection only occurs at function calls, so it
   1.156 +     * is sufficient to ensure that the destructor's store isn't moved earlier across
   1.157 +     * any function calls that could collect. It is hard to imagine the compiler
   1.158 +     * analyzing the program so thoroughly that it could prove that such motion was
   1.159 +     * safe. In practice, compilers treat calls to the collector as opaque operations
   1.160 +     * --- in particular, as operations which could access volatile variables, across
   1.161 +     * which this destructor must not be moved.
   1.162 +     *
   1.163 +     * ("Objection, your honor!  *Alleged* killer whale!")
   1.164 +     *
   1.165 +     * The disadvantage of this approach is that it does generate code for the store.
   1.166 +     * We do need to use Anchors in some cases where cycles are tight.
   1.167 +     *
   1.168 +     * Note that there is a Anchor<Value>::~Anchor() specialization in Value.h.
   1.169 +     */
   1.170 +    volatile T sink;
   1.171 +    sink = hold;
   1.172 +#endif  /* defined(__GNUC__) */
   1.173 +}
   1.174 +
   1.175 +} // namespace JS
   1.176 +
   1.177 +#endif /* js_Anchor_h */

mercurial