Remove SpillFrame, merge its memory effects into CallEffects and InlineEnterEffects
[hiphop-php.git] / hphp / runtime / vm / jit / code-gen-tls-x64.h
blob7bc57c4d01f4011305d901ba0d87de521756b950
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_VM_CODE_GEN_TLS_X64_H_
18 #define incl_HPHP_VM_CODE_GEN_TLS_X64_H_
20 #include "hphp/runtime/vm/jit/vasm-gen.h"
21 #include "hphp/runtime/vm/jit/vasm-instr.h"
22 #include "hphp/runtime/vm/jit/vasm-reg.h"
24 #include "hphp/util/asm-x64.h"
25 #include "hphp/util/thread-local.h"
27 namespace HPHP { namespace jit { namespace x64 { namespace detail {
29 ///////////////////////////////////////////////////////////////////////////////
32 * We support x64 linux (linked off FS), and x64 MacOS using some reverse
33 * engineering of their generated code.
36 #ifndef __APPLE__
38 * x86 terminology review: "Virtual addresses" are subject to both segmented
39 * translation and paged translation. "Linear addresses" are post-segmentation
40 * address, subject only to paging. C and C++ generally only have access to
41 * bitwise linear addresses.
43 * On Linux, TLS data live at negative virtual addresses off FS: the first
44 * datum is typically at VA(FS:-sizeof(datum)). Linux's x64 ABI stores the
45 * linear address of the base of TLS at VA(FS:0). While this is just a
46 * convention, it is firm: gcc builds binaries that assume it when, e.g.,
47 * evaluating "&myTlsDatum".
49 * The virtual addresses of TLS data are not exposed to C/C++. To figure it
50 * out, we take a datum's linear address, and subtract it from the linear
51 * address where TLS starts.
53 template <typename T>
54 Vptr emitTLSAddr(Vout& /*v*/, TLSDatum<T> datum) {
55 uintptr_t vaddr = uintptr_t(datum.tls) - tlsBase();
56 return Vptr{baseless(vaddr), Segment::FS};
59 template<typename T>
60 Vreg emitTLSLea(Vout& v, TLSDatum<T> datum) {
61 auto const vaddr = v.cns(uintptr_t(datum.tls) - tlsBase());
62 auto const addr = v.makeReg();
63 v << addqmr{Vptr{baseless(0), Segment::FS}, vaddr, addr, v.makeReg()};
64 return addr;
67 #else // __APPLE__
69 * In MacOS an __thread variable has a "key" allocated in global memory, under
70 * the name of the object. The key consists of three longs. The first holds
71 * the address of a function, which if called with $rdi pointing at the key
72 * (i.e., $rdi = &key; call 0x0($rdi)) will return the address of the thread
73 * local (possibly allocating it, if this is the first time its been accessed
74 * in the current thread).
76 * The function is very short (in the case that the thread local has already
77 * been allocated), and preserves all the registers except for $rax (which gets
78 * the address of the thread local)---so we could just use it to access the
79 * thread locals. But we can do better.
81 * The second long contains a gs-relative index to a pointer to the block of
82 * memory containing the thread-local, and the third long contains the offset
83 * to it within that block. So if $rdi points at the key,
85 * movq 8($rdi), $rax
86 * movq gs:(,$rax,8), $rax
87 * addq 16($rdi), $rax
89 * will get us the address of the thread local.
91 * But we can still do better. key[1] and key[2] are constants for the
92 * duration of the program; so we can burn their values into the tc:
94 * movq gs:{key[1]*8}, $rax
95 * addq {key[2]}, $rax
97 * But note that the add will often fold into a following load or store.
99 * So the only remaining problem is to get the address of the key:
101 * __asm__("lea %1, %0" : "=r"(ret) : "m"(tlvar));
103 * Unfortunately, clang is too smart here, and converts the lea into:
105 * lea _tlvar, $rdi
106 * call ($rdi)
107 * move $rax, ret
109 * Fortunately, the helper preserves all regs (except $rax), and so $rdi now
110 * has the address of the key. We use that trick in the OSX version of
111 * tls_datum().
113 * Finally note that all of this is only valid if the thread local has already
114 * been accessed in the current thread---but we can easily ensure that (it's
115 * already true for any ThreadLocalNoCheck variable).
117 template<typename T>
118 Vptr emitTLSAddr(Vout& v, TLSDatum<T> datum) {
119 auto const scratch = v.makeReg();
121 v << load{Vptr{baseless(datum.raw[1] * 8), Segment::GS}, scratch};
122 return scratch[datum.raw[2]];
125 template<typename T>
126 Vreg emitTLSLea(Vout& v, TLSDatum<T> datum) {
127 auto const b = v.makeReg();
128 v << lea{detail::emitTLSAddr(v, datum), b};
129 return b;
132 #endif
134 ///////////////////////////////////////////////////////////////////////////////
136 }}}}
138 #endif