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 */