2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #ifndef INCL_TARGETCACHE_H_
17 #define INCL_TARGETCACHE_H_
19 #include "hphp/runtime/vm/func.h"
20 #include "hphp/util/util.h"
21 #include "hphp/runtime/vm/jit/types.h"
22 #include "hphp/runtime/vm/jit/unwind-x64.h"
23 #include "hphp/util/asm-x64.h"
24 #include <boost/static_assert.hpp>
28 namespace TargetCache
{
37 * The targetCaches are physically thread-private, but they share their
38 * layout. So the memory is in tl_targetCaches, but we allocate it via the
39 * global s_frontier. This is protected by the translator's write-lease.
41 extern __thread
void* tl_targetCaches
;
42 extern size_t s_frontier
;
43 extern size_t s_persistent_frontier
;
44 extern size_t s_persistent_start
;
47 * Array of dynamically defined constants
49 extern __thread HphpArray
* s_constants
;
52 * The fields in TargetCacheHeader are pre-allocated at process
53 * startup and live at the beginning of the targetCache.
55 struct TargetCacheHeader
{
56 ssize_t conditionFlags
;
58 // Used to pass values between unwinder code and catch traces:
59 int64_t unwinderScratch
;
60 TypedValue unwinderTv
;
64 inline TargetCacheHeader
* header() {
65 return (TargetCacheHeader
*)tl_targetCaches
;
68 constexpr int kConditionFlagsOff
=
69 offsetof(TargetCacheHeader
, conditionFlags
);
70 constexpr int kUnwinderScratchOff
=
71 offsetof(TargetCacheHeader
, unwinderScratch
);
72 constexpr int kUnwinderSideExitOff
=
73 offsetof(TargetCacheHeader
, doSideExit
);
74 constexpr int kUnwinderTvOff
=
75 offsetof(TargetCacheHeader
, unwinderTv
);
78 * Some caches have different numbers of lines. This is our default.
80 static const int kDefaultNumLines
= 4;
83 * The lookup functions are called into from generated assembly and passed an
84 * opaque handle into the request-private targetcache.
86 typedef ptrdiff_t CacheHandle
;
98 NumInsensitive
, _NS_placeholder
= NumInsensitive
-1,
108 NumCaseSensitive
= NumNameSpaces
- NumInsensitive
,
109 FirstCaseSensitive
= NumInsensitive
,
115 template <bool sensitive
>
116 CacheHandle
namedAlloc(PHPNameSpace where
, const StringData
* name
,
117 int numBytes
, int align
);
119 template<PHPNameSpace where
>
120 CacheHandle
namedAlloc(const StringData
* name
, int numBytes
, int align
) {
121 return namedAlloc
<(where
>= FirstCaseSensitive
)>(where
, name
,
126 CacheHandle
bitOffToHandleAndMask(size_t bit
, uint8_t &mask
);
127 bool testBit(CacheHandle handle
, uint32_t mask
);
128 bool testBit(size_t bit
);
129 bool testAndSetBit(CacheHandle handle
, uint32_t mask
);
130 bool testAndSetBit(size_t bit
);
131 bool isPersistentHandle(CacheHandle handle
);
132 bool classIsPersistent(const Class
* cls
);
134 CacheHandle
ptrToHandle(const void*);
136 TCA
fcallHelper(ActRec
* ar
);
138 template<typename T
= void>
140 handleToPtr(CacheHandle h
) {
141 assert(h
< RuntimeOption::EvalJitTargetCacheSize
);
142 return (T
*)((char*)tl_targetCaches
+ h
);
146 T
& handleToRef(CacheHandle h
) {
147 return *static_cast<T
*>(handleToPtr(h
));
150 inline ssize_t
* conditionFlagsPtr() {
151 return &header()->conditionFlags
;
154 inline ssize_t
loadConditionFlags() {
155 return atomic_acquire_load(conditionFlagsPtr());
158 void invalidateForRename(const StringData
* name
);
161 * Some caches have a Lookup != k, because the TC passes a container
162 * with other necessary info to Cache::lookup. E.g., when looking up
163 * function preludes, we also need the number of arguments. Since
164 * the current ActRec encapsulates both, we pass in an ActRec to
165 * Cache::lookup even though CallCache maps Funcs to TCAs.
167 * KNLines must be a power of two.
169 template<typename Key
, typename Value
, class LookupKey
,
170 PHPNameSpace NameSpace
= NSInvalid
,
171 int KNLines
= kDefaultNumLines
,
172 typename ReturnValue
= Value
>
175 typedef Cache
<Key
, Value
, LookupKey
, NameSpace
, KNLines
, ReturnValue
> Self
;
176 static const int kNumLines
= KNLines
;
181 } m_pairs
[kNumLines
];
183 static inline Self
* cacheAtHandle(CacheHandle handle
) {
184 return (Self
*)handleToPtr(handle
);
187 inline Pair
* keyToPair(Key k
) {
188 if (kNumLines
== 1) {
191 assert(HPHP::Util::isPowerOfTwo(kNumLines
));
192 return m_pairs
+ (hashKey(k
) & (kNumLines
- 1));
196 // Each instance needs to implement this
197 static int hashKey(Key k
);
200 typedef Key CacheKey
;
201 typedef LookupKey CacheLookupKey
;
202 typedef Value CacheValue
;
204 static CacheHandle
alloc(const StringData
* name
= nullptr) {
205 // Each lookup should access exactly one Pair so there's no point
206 // in making sure the entire cache fits on one cache line.
207 return namedAlloc
<NameSpace
>(name
, sizeof(Self
), sizeof(Pair
));
209 inline CacheHandle
cacheHandle() const {
210 return ptrToHandle(this);
212 static void invalidate(CacheHandle chand
, Key lookup
) {
213 Pair
* pair
= cacheAtHandle(chand
)->keyToPair(lookup
);
214 memset(pair
, 0, sizeof(Pair
));
216 static void invalidate(CacheHandle chand
) {
217 Self
*thiz
= cacheAtHandle(chand
);
218 memset(thiz
, 0, sizeof(*thiz
));
220 static ReturnValue
lookup(CacheHandle chand
, LookupKey lookup
,
221 const void* extraKey
= nullptr);
224 struct FixedFuncCache
{
227 static inline FixedFuncCache
* cacheAtHandle(CacheHandle handle
) {
228 return (FixedFuncCache
*)handleToPtr(handle
);
231 static void invalidate(CacheHandle handle
) {
232 FixedFuncCache
* thiz
= cacheAtHandle(handle
);
233 thiz
->m_func
= nullptr;
236 static const Func
* lookupUnknownFunc(StringData
* name
);
239 struct StaticMethodCache
{
242 static CacheHandle
alloc(const StringData
* cls
, const StringData
* meth
,
243 const char* ctxName
);
244 static const Func
* lookupIR(CacheHandle chand
,
245 const NamedEntity
* ne
, const StringData
* cls
,
246 const StringData
* meth
, TypedValue
* vmfp
,
248 static const Func
* lookup(CacheHandle chand
,
249 const NamedEntity
* ne
, const StringData
* cls
,
250 const StringData
* meth
);
253 struct StaticMethodFCache
{
257 static CacheHandle
alloc(const StringData
* cls
, const StringData
* meth
,
258 const char* ctxName
);
259 static const Func
* lookupIR(CacheHandle chand
, const Class
* cls
,
260 const StringData
* meth
, TypedValue
* vmfp
);
263 typedef Cache
<const StringData
*, const Func
*, StringData
*, NSDynFunction
>
265 typedef Cache
<uintptr_t, const Func
*, ActRec
*, NSInvalid
, 1, void>
267 typedef Cache
<StringData
*, const Class
*, StringData
*, NSClass
> ClassCache
;
272 * Records offsets into the current global array.
274 * For both GlobalCache and BoxedGlobalCache, the lookup routine may
275 * return NULL, but lookupCreate will create new entries with
276 * KindOfNull if the global didn't exist.
278 * Both routines will decRef the name on behalf of the caller, but
279 * only if the lookup was successful (or a global was created).
285 static inline GlobalCache
* cacheAtHandle(CacheHandle handle
) {
286 return (GlobalCache
*)(uintptr_t(tl_targetCaches
) + handle
);
289 template<bool isBoxed
>
290 TypedValue
* lookupImpl(StringData
*name
, bool allowCreate
);
293 inline CacheHandle
cacheHandle() const {
294 return ptrToHandle(this);
297 static CacheHandle
alloc(const StringData
* sd
) {
299 return namedAlloc
<NSGlobal
>(sd
, sizeof(GlobalCache
), sizeof(GlobalCache
));
302 static TypedValue
* lookup(CacheHandle handle
, StringData
* nm
);
303 static TypedValue
* lookupCreate(CacheHandle handle
, StringData
* nm
);
304 static TypedValue
* lookupCreateAddr(void* cacheAddr
, StringData
* nm
);
307 class BoxedGlobalCache
: public GlobalCache
{
310 * Note: the returned pointer is a pointer to the outer variant.
311 * You'll need to incref (or whatever) it yourself (if desired) and
312 * emitDeref if you are going to put it in a register associated
313 * with some vm location. (Note that KindOfRef in-register
314 * values are the pointers to inner items.)
316 static TypedValue
* lookup(CacheHandle handle
, StringData
* nm
);
317 static TypedValue
* lookupCreate(CacheHandle handle
, StringData
* nm
);
323 * The request-private Class* for a given class name. This is used when
324 * the class name is known at translation time.
326 CacheHandle
allocKnownClass(const Class
* name
);
327 CacheHandle
allocKnownClass(const NamedEntity
* name
, bool persistent
);
328 CacheHandle
allocKnownClass(const StringData
* name
);
329 typedef Class
* (*lookupKnownClass_func_t
)(Class
** cache
,
330 const StringData
* clsName
,
332 template<bool checkOnly
>
333 Class
* lookupKnownClass(Class
** cache
, const StringData
* clsName
,
335 CacheHandle
allocClassInitProp(const StringData
* name
);
336 CacheHandle
allocClassInitSProp(const StringData
* name
);
341 CacheHandle
allocFixedFunction(const NamedEntity
* ne
, bool persistent
);
342 CacheHandle
allocFixedFunction(const StringData
* name
);
347 * Request-private values for type aliases (typedefs). When a typedef
348 * is defined, the entry for it is cached. This reserves enough space
349 * for a TypedefReq struct.
351 CacheHandle
allocTypedef(const NamedEntity
* name
);
356 * The request-private value of a constant.
358 CacheHandle
allocConstant(uint32_t* handlep
, bool persistent
);
360 CacheHandle
allocClassConstant(StringData
* name
);
361 TypedValue
* lookupClassConstant(TypedValue
* cache
,
362 const NamedEntity
* ne
,
363 const StringData
* cls
,
364 const StringData
* cns
);
365 TypedValue
lookupClassConstantTv(TypedValue
* cache
,
366 const NamedEntity
* ne
,
367 const StringData
* cls
,
368 const StringData
* cns
);
371 * Static locals. Each StaticLocInit we translate gets its own soft
372 * reference to the variant where it resides.
374 CacheHandle
allocStatic();
377 * Static properties. We only cache statically known property name
378 * references from within the class. Current statistics shows in
379 * class references dominating by 91.5% of all static property access.
384 static inline SPropCache
* cacheAtHandle(CacheHandle handle
) {
385 return (SPropCache
*)(uintptr_t(tl_targetCaches
) + handle
);
388 TypedValue
* m_tv
; // public; it is used from TC and we assert the offset
389 static CacheHandle
alloc(const StringData
* sd
= nullptr) {
390 return namedAlloc
<NSSProp
>(sd
, sizeof(SPropCache
), sizeof(SPropCache
));
392 static TypedValue
* lookup(CacheHandle handle
, const Class
* cls
,
393 const StringData
* nm
);
395 template<bool raiseOnError
>
396 static TypedValue
* lookupIR(CacheHandle handle
, const Class
* cls
,
397 const StringData
* nm
, Class
* ctx
);
399 template<bool raiseOnError
>
400 static TypedValue
* lookupSProp(const Class
*cls
, const StringData
*name
,
404 void methodCacheSlowPath(MethodCache::Pair
* mce
,