Fix spilling bug
[hiphop-php.git] / hphp / runtime / vm / jit / targetcache.h
blob1c99a75857b38c0eba21a31c81241d6820f592c6
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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>
26 namespace HPHP {
27 namespace Transl {
28 namespace TargetCache {
30 void requestInit();
31 void requestExit();
32 void threadInit();
33 void threadExit();
34 void flush();
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;
61 bool doSideExit;
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;
88 enum PHPNameSpace {
89 NSCtor,
90 NSFixedCall,
91 NSDynFunction,
92 NSStaticMethod,
93 NSStaticMethodF,
94 NSClass,
95 NSClsInitProp,
96 NSClsInitSProp,
98 NumInsensitive, _NS_placeholder = NumInsensitive-1,
100 NSConstant,
101 NSClassConstant,
102 NSGlobal,
103 NSSProp,
104 NSProperty,
105 NSCnsBits,
107 NumNameSpaces,
108 NumCaseSensitive = NumNameSpaces - NumInsensitive,
109 FirstCaseSensitive = NumInsensitive,
111 NSInvalid = -1,
112 NSPersistent = -2
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,
122 numBytes, align);
125 size_t allocBit();
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>
139 static inline T*
140 handleToPtr(CacheHandle h) {
141 assert(h < RuntimeOption::EvalJitTargetCacheSize);
142 return (T*)((char*)tl_targetCaches + h);
145 template<class T>
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>
173 class Cache {
174 public:
175 typedef Cache<Key, Value, LookupKey, NameSpace, KNLines, ReturnValue> Self;
176 static const int kNumLines = KNLines;
178 struct Pair {
179 Key m_key;
180 Value m_value;
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) {
189 return &m_pairs[0];
191 assert(HPHP::Util::isPowerOfTwo(kNumLines));
192 return m_pairs + (hashKey(k) & (kNumLines - 1));
195 protected:
196 // Each instance needs to implement this
197 static int hashKey(Key k);
199 public:
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 {
225 const Func* m_func;
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 {
240 const Func* m_func;
241 const Class* m_cls;
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,
247 TypedValue* vmsp);
248 static const Func* lookup(CacheHandle chand,
249 const NamedEntity* ne, const StringData* cls,
250 const StringData* meth);
253 struct StaticMethodFCache {
254 const Func* m_func;
255 int m_static;
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>
264 FuncCache;
265 typedef Cache<uintptr_t, const Func*, ActRec*, NSInvalid, 1, void>
266 MethodCache;
267 typedef Cache<StringData*, const Class*, StringData*, NSClass> ClassCache;
270 * GlobalCache --
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).
281 class GlobalCache {
282 TypedValue* m_tv;
284 protected:
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);
292 public:
293 inline CacheHandle cacheHandle() const {
294 return ptrToHandle(this);
297 static CacheHandle alloc(const StringData* sd) {
298 assert(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 {
308 public:
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);
321 * Classes.
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,
331 bool isClass);
332 template<bool checkOnly>
333 Class* lookupKnownClass(Class** cache, const StringData* clsName,
334 bool isClass);
335 CacheHandle allocClassInitProp(const StringData* name);
336 CacheHandle allocClassInitSProp(const StringData* name);
339 * Functions.
341 CacheHandle allocFixedFunction(const NamedEntity* ne, bool persistent);
342 CacheHandle allocFixedFunction(const StringData* name);
345 * Type aliases.
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);
354 * Constants.
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.
382 class SPropCache {
383 private:
384 static inline SPropCache* cacheAtHandle(CacheHandle handle) {
385 return (SPropCache*)(uintptr_t(tl_targetCaches) + handle);
387 public:
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,
401 Class* ctx);
404 void methodCacheSlowPath(MethodCache::Pair* mce,
405 ActRec* ar,
406 StringData* name,
407 Class* cls);
409 } } }
411 #endif