Improve refineLocation a little
[hiphop-php.git] / hphp / hhbbc / bc.h
blob710fef2fc672ef40b8464778e26bb75be4a787ff
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 +----------------------------------------------------------------------+
16 #ifndef incl_HHBBC_BC_H_
17 #define incl_HHBBC_BC_H_
19 #include <vector>
20 #include <utility>
21 #include <type_traits>
23 #include <boost/mpl/has_xxx.hpp>
24 #include <algorithm>
26 #include <folly/Hash.h>
28 #include "hphp/util/compact-vector.h"
29 #include "hphp/runtime/vm/hhbc.h"
31 #include "hphp/hhbbc/src-loc.h"
32 #include "hphp/hhbbc/misc.h"
33 #include "hphp/hhbbc/type-system.h"
35 namespace HPHP { namespace HHBBC {
37 struct Bytecode;
39 namespace php {
41 struct Func;
45 //////////////////////////////////////////////////////////////////////
48 * The following creates a struct for each bytecode using the opcode
49 * table. Each opcode will be named bc::opcode, and has a single
50 * constructor that takes its immediate types in order.
52 * E.g.
54 * auto fpass = bc::FPassC { 2 }; // FPassC for arg 2
57 //////////////////////////////////////////////////////////////////////
59 struct MKey {
60 MKey()
61 : mcode{MW}
62 , int64{0}
65 MKey(MemberCode mcode, LocalId local)
66 : mcode{mcode}
67 , local{local}
70 MKey(MemberCode mcode, int32_t idx)
71 : mcode{mcode}
72 , idx{idx}
75 MKey(MemberCode mcode, int64_t int64)
76 : mcode{mcode}
77 , int64{int64}
80 MKey(MemberCode mcode, SString litstr)
81 : mcode{mcode}
82 , litstr{litstr}
85 MemberCode mcode;
86 union {
87 SString litstr;
88 int64_t int64;
89 int64_t idx;
90 LocalId local;
94 inline bool operator==(MKey a, MKey b) {
95 return a.mcode == b.mcode && a.int64 == b.int64;
98 inline bool operator!=(MKey a, MKey b) {
99 return !(a == b);
102 // Represents a non-empty range of locals. There's always a first local,
103 // followed by a count of additional ones.
104 struct LocalRange {
105 LocalId first;
106 uint32_t restCount;
109 inline bool operator==(const LocalRange& a, const LocalRange& b) {
110 return a.first == b.first && a.restCount == b.restCount;
113 inline bool operator!=(const LocalRange& a, const LocalRange& b) {
114 return !(a == b);
117 struct IterTabEnt {
118 IterKind kind;
119 IterId id;
120 LocalId local;
123 inline bool operator==(const IterTabEnt& a, const IterTabEnt& b) {
124 return std::tie(a.kind, a.id, a.local) == std::tie(b.kind, b.id, b.local);
127 inline bool operator!=(const IterTabEnt& a, const IterTabEnt& b) {
128 return !(a == b);
131 using IterTab = CompactVector<IterTabEnt>;
133 using SwitchTab = CompactVector<BlockId>;
135 // The final entry in the SSwitchTab is the default case, it will
136 // always have a nullptr for the string.
137 using SSwitchTabEnt = std::pair<LSString,BlockId>;
138 using SSwitchTab = CompactVector<SSwitchTabEnt>;
140 //////////////////////////////////////////////////////////////////////
142 namespace bc {
144 //////////////////////////////////////////////////////////////////////
146 namespace detail {
149 * Trivial hasher overrides, which will cause bytecodes to hash according to
150 * the hashes defined by hasher_impl.
152 struct hasher_default {};
155 * Default bytecode immediate hashers.
157 struct hasher_impl {
158 static size_t hash(SString s) { return s->hash(); }
159 static size_t hash(LSString s) { return s->hash(); }
160 static size_t hash(RepoAuthType rat) { return rat.hash(); }
162 static size_t hash(const IterTabEnt& iterTab) {
163 auto const partial = folly::hash::hash_128_to_64(
164 iterTab.kind, iterTab.id
166 return static_cast<size_t>(
167 folly::hash::hash_128_to_64(iterTab.local, partial)
171 static size_t hash(MKey mkey) {
172 return HPHP::hash_int64_pair(mkey.mcode, mkey.int64);
175 template<class T>
176 static size_t hash(const CompactVector<T>& v) {
177 return v.empty() ? 0 : v.size() ^ hash(v.front());
180 static size_t hash(std::pair<LSString,BlockId> kv) {
181 return HPHP::hash_int64_pair(kv.first->hash(), kv.second);
184 static size_t hash(LocalRange range) {
185 return HPHP::hash_int64_pair(range.first, range.restCount);
188 template<class T>
189 static typename std::enable_if<
190 std::is_enum<T>::value,
191 size_t
192 >::type hash(T t) {
193 using U = typename std::underlying_type<T>::type;
194 return std::hash<U>()(static_cast<U>(t));
197 template<class T>
198 static typename std::enable_if<
199 !std::is_enum<T>::value,
200 size_t
201 >::type hash(const T& t) { return std::hash<T>()(t); }
205 * Hash operand wrapper.
207 template<typename T, typename S>
208 struct hash_operand { const T& val; S type; };
211 * Hash T using H::operator() if it is compatible, else fall back to
212 * hasher_impl (e.g., if H := hasher_default).
214 template<typename T, typename S, class H>
215 auto hash(const hash_operand<T,S>& t, H h) -> decltype(h(t.val)) {
216 return h(t.val);
218 template<typename T, typename S, class H>
219 auto hash(const hash_operand<T,S>& t, H h) -> decltype(h(t.val, t.type)) {
220 return h(t.val, t.type);
222 template<typename T, typename S, typename... Unused>
223 typename std::enable_if<sizeof...(Unused) == 1, size_t>::type
224 hash(const hash_operand<T,S>& t, Unused...) {
225 return hasher_impl::hash(t.val);
229 * Clone of folly::hash::hash_combine_generic(), but with a hasher argument
230 * instead of a hasher template parameter.
232 template <class H>
233 size_t hash_combine(H /*h*/) {
234 return 0;
237 template<class H, typename T, typename... Ts>
238 size_t hash_combine(H h, const T& t, const Ts&... ts) {
239 auto const seed = size_t{hash(t, h)};
240 if (sizeof...(ts) == 0) return seed;
242 auto const remainder = hash_combine(h, ts...);
243 return static_cast<size_t>(folly::hash::hash_128_to_64(seed, remainder));
247 * Trivial equality overrides, which will cause bytecodes to compare via
248 * operator==() on the various immediate types.
250 struct eq_default {};
253 * Equality operand wrapper.
255 template<typename T, typename S>
256 struct eq_operand { const T& l; const T& r; S type; };
259 * Compare two values, using E::operator() if it exists, else the default
260 * operator==.
262 template<typename T, typename S, class E>
263 auto equals(const eq_operand<T,S>& t, E e) -> decltype(e(t.l, t.r)) {
264 return e(t.l, t.r);
266 template<typename T, typename S, class E>
267 auto equals(const eq_operand<T,S>& t, E e) -> decltype(e(t.l, t.r, t.type)) {
268 return e(t.l, t.r, t.type);
270 template<typename T, typename S, typename... Unused>
271 typename std::enable_if<sizeof...(Unused) == 1, bool>::type
272 equals(const eq_operand<T,S>& t, Unused...) {
273 return t.l == t.r;
277 * Check if a list of eq_operands are pairwise-equal.
279 template <class E>
280 bool eq_pairs(E /*e*/) {
281 return true;
284 template<class E, typename T, typename... Ts>
285 bool eq_pairs(E e, const T& t, const Ts&... ts) {
286 return equals(t, e) && (sizeof...(ts) == 0 || eq_pairs(e, ts...));
291 //////////////////////////////////////////////////////////////////////
294 * Bytecode immediate type tags.
296 namespace imm {
297 #define ARGTYPE(name, type) enum class name : uint8_t {};
298 #define ARGTYPEVEC(name, type) enum class name : uint8_t {};
299 ARGTYPES
300 #undef ARGTYPE
301 #undef ARGTYPEVEC
304 #define IMM_ID_BLA BLA
305 #define IMM_ID_SLA SLA
306 #define IMM_ID_ILA ILA
307 #define IMM_ID_I32LA I32LA
308 #define IMM_ID_IVA IVA
309 #define IMM_ID_I64A I64A
310 #define IMM_ID_LA LA
311 #define IMM_ID_IA IA
312 #define IMM_ID_CAR CAR
313 #define IMM_ID_CAW CAW
314 #define IMM_ID_DA DA
315 #define IMM_ID_SA SA
316 #define IMM_ID_RATA RATA
317 #define IMM_ID_AA AA
318 #define IMM_ID_BA BA
319 #define IMM_ID_OA(type) OA
320 #define IMM_ID_VSA VSA
321 #define IMM_ID_KA KA
322 #define IMM_ID_LAR LAR
324 #define IMM_TY_BLA SwitchTab
325 #define IMM_TY_SLA SSwitchTab
326 #define IMM_TY_ILA IterTab
327 #define IMM_TY_I32LA CompactVector<uint32_t>
328 #define IMM_TY_IVA uint32_t
329 #define IMM_TY_I64A int64_t
330 #define IMM_TY_LA LocalId
331 #define IMM_TY_IA IterId
332 #define IMM_TY_CAR ClsRefSlotId
333 #define IMM_TY_CAW ClsRefSlotId
334 #define IMM_TY_DA double
335 #define IMM_TY_SA SString
336 #define IMM_TY_RATA RepoAuthType
337 #define IMM_TY_AA SArray
338 #define IMM_TY_BA BlockId
339 #define IMM_TY_OA(type) type
340 #define IMM_TY_VSA CompactVector<LSString>
341 #define IMM_TY_KA MKey
342 #define IMM_TY_LAR LocalRange
344 #define IMM_NAME_BLA(n) targets
345 #define IMM_NAME_SLA(n) targets
346 #define IMM_NAME_ILA(n) iterTab
347 #define IMM_NAME_I32LA(n) argv
348 #define IMM_NAME_IVA(n) arg##n
349 #define IMM_NAME_I64A(n) arg##n
350 #define IMM_NAME_LA(n) loc##n
351 #define IMM_NAME_IA(n) iter##n
352 #define IMM_NAME_CAR(n) slot
353 #define IMM_NAME_CAW(n) slot
354 #define IMM_NAME_DA(n) dbl##n
355 #define IMM_NAME_SA(n) str##n
356 #define IMM_NAME_RATA(n) rat
357 #define IMM_NAME_AA(n) arr##n
358 #define IMM_NAME_BA(n) target
359 #define IMM_NAME_OA_IMPL(n) subop##n
360 #define IMM_NAME_OA(type) IMM_NAME_OA_IMPL
361 #define IMM_NAME_VSA(n) keys
362 #define IMM_NAME_KA(n) mkey
363 #define IMM_NAME_LAR(n) locrange
365 #define IMM_EXTRA_BLA
366 #define IMM_EXTRA_SLA
367 #define IMM_EXTRA_ILA
368 #define IMM_EXTRA_I32LA
369 #define IMM_EXTRA_IVA
370 #define IMM_EXTRA_I64A
371 #define IMM_EXTRA_LA
372 #define IMM_EXTRA_IA
373 #define IMM_EXTRA_CAR using has_car_flag = std::true_type;
374 #define IMM_EXTRA_CAW using has_caw_flag = std::true_type;
375 #define IMM_EXTRA_DA
376 #define IMM_EXTRA_SA
377 #define IMM_EXTRA_RATA
378 #define IMM_EXTRA_AA
379 #define IMM_EXTRA_BA using has_target_flag = std::true_type;
380 #define IMM_EXTRA_OA(x)
381 #define IMM_EXTRA_VSA
382 #define IMM_EXTRA_KA
383 #define IMM_EXTRA_LAR
385 #define IMM_MEM(which, n) IMM_TY_##which IMM_NAME_##which(n)
386 #define IMM_MEM_NA
387 #define IMM_MEM_ONE(x) IMM_MEM(x, 1);
388 #define IMM_MEM_TWO(x, y) IMM_MEM(x, 1); IMM_MEM(y, 2);
389 #define IMM_MEM_THREE(x, y, z) IMM_MEM(x, 1); IMM_MEM(y, 2); \
390 IMM_MEM(z, 3);
391 #define IMM_MEM_FOUR(x, y, z, l) IMM_MEM(x, 1); IMM_MEM(y, 2); \
392 IMM_MEM(z, 3); IMM_MEM(l, 4);
393 #define IMM_MEM_FIVE(x, y, z, l, m) IMM_MEM(x, 1); IMM_MEM(y, 2); \
394 IMM_MEM(z, 3); IMM_MEM(l, 4); \
395 IMM_MEM(m, 5);
397 #define IMM_EQ_WRAP(e, ...) detail::eq_pairs(e, __VA_ARGS__)
398 #define IMM_EQ(which, n) detail::eq_operand< \
399 IMM_TY_##which, \
400 imm::IMM_ID_##which \
401 > { \
402 IMM_NAME_##which(n), \
403 o.IMM_NAME_##which(n) \
405 #define IMM_EQ_NA detail::eq_operand<void*,imm::NA> { 0, 0 }
406 #define IMM_EQ_ONE(x) IMM_EQ(x, 1)
407 #define IMM_EQ_TWO(x, y) IMM_EQ_ONE(x), IMM_EQ(y, 2)
408 #define IMM_EQ_THREE(x, y, z) IMM_EQ_TWO(x, y), IMM_EQ(z, 3)
409 #define IMM_EQ_FOUR(x, y, z, l) IMM_EQ_THREE(x, y, z), IMM_EQ(l, 4)
410 #define IMM_EQ_FIVE(x, y, z, l, m) IMM_EQ_FOUR(x, y, z, l), IMM_EQ(m, 5)
412 #define IMM_HASH_WRAP(h, ...) detail::hash_combine(h, __VA_ARGS__)
413 #define IMM_HASH(which, n) detail::hash_operand< \
414 IMM_TY_##which, \
415 imm::IMM_ID_##which \
416 > { IMM_NAME_##which(n) }
417 #define IMM_HASH_NA detail::hash_operand<void*,imm::NA> { 0 }
418 #define IMM_HASH_ONE(x) IMM_HASH(x, 1)
419 #define IMM_HASH_TWO(x, y) IMM_HASH_ONE(x), IMM_HASH(y, 2)
420 #define IMM_HASH_THREE(x, y, z) IMM_HASH_TWO(x, y), IMM_HASH(z, 3)
421 #define IMM_HASH_FOUR(x, y, z, l) IMM_HASH_THREE(x, y, z), IMM_HASH(l, 4)
422 #define IMM_HASH_FIVE(x, y, z, l, m) IMM_HASH_FOUR(x, y, z, l), IMM_HASH(m, 5)
424 #define IMM_EXTRA_NA
425 #define IMM_EXTRA_ONE(x) IMM_EXTRA_##x
426 #define IMM_EXTRA_TWO(x,y) IMM_EXTRA_ONE(x) IMM_EXTRA_ONE(y)
427 #define IMM_EXTRA_THREE(x,y,z) IMM_EXTRA_TWO(x,y) IMM_EXTRA_ONE(z)
428 #define IMM_EXTRA_FOUR(x,y,z,l) IMM_EXTRA_THREE(x,y,z) IMM_EXTRA_ONE(l)
429 #define IMM_EXTRA_FIVE(x,y,z,l,m) IMM_EXTRA_FOUR(x,y,z,l) IMM_EXTRA_ONE(m)
431 #define IMM_CTOR(which, n) IMM_TY_##which IMM_NAME_##which(n)
432 #define IMM_CTOR_NA
433 #define IMM_CTOR_ONE(x) IMM_CTOR(x, 1)
434 #define IMM_CTOR_TWO(x, y) IMM_CTOR(x, 1), IMM_CTOR(y, 2)
435 #define IMM_CTOR_THREE(x, y, z) IMM_CTOR(x, 1), IMM_CTOR(y, 2), \
436 IMM_CTOR(z, 3)
437 #define IMM_CTOR_FOUR(x, y, z, l) IMM_CTOR(x, 1), IMM_CTOR(y, 2), \
438 IMM_CTOR(z, 3), IMM_CTOR(l, 4)
439 #define IMM_CTOR_FIVE(x, y, z, l, m) IMM_CTOR(x, 1), IMM_CTOR(y, 2), \
440 IMM_CTOR(z, 3), IMM_CTOR(l, 4), \
441 IMM_CTOR(m, 5)
443 #define IMM_INIT(which, n) IMM_NAME_##which(n) \
444 ( std::move(IMM_NAME_##which(n)) )
445 #define IMM_INIT_NA
446 #define IMM_INIT_ONE(x) : IMM_INIT(x, 1)
447 #define IMM_INIT_TWO(x, y) : IMM_INIT(x, 1), IMM_INIT(y, 2)
448 #define IMM_INIT_THREE(x, y, z) : IMM_INIT(x, 1), IMM_INIT(y, 2), \
449 IMM_INIT(z, 3)
450 #define IMM_INIT_FOUR(x, y, z, l) : IMM_INIT(x, 1), IMM_INIT(y, 2), \
451 IMM_INIT(z, 3), IMM_INIT(l, 4)
452 #define IMM_INIT_FIVE(x, y, z, l, m) : IMM_INIT(x, 1), IMM_INIT(y, 2), \
453 IMM_INIT(z, 3), IMM_INIT(l, 4), \
454 IMM_INIT(m, 5)
456 #define POP_UV if (i == 0) return Flavor::U
457 #define POP_CV if (i == 0) return Flavor::C
458 #define POP_VV if (i == 0) return Flavor::V
459 #define POP_FV if (i == 0) return Flavor::F
460 #define POP_RV if (i == 0) return Flavor::R
461 #define POP_CUV if (i == 0) return Flavor::CU
463 #define POP_NOV uint32_t numPop() const { return 0; } \
464 Flavor popFlavor(uint32_t) const { not_reached(); }
466 #define POP_ONE(x) uint32_t numPop() const { return 1; } \
467 Flavor popFlavor(uint32_t i) const { \
468 POP_##x; not_reached(); \
471 #define POP_TWO(x, y) uint32_t numPop() const { return 2; } \
472 Flavor popFlavor(uint32_t i) const { \
473 POP_##x; --i; POP_##y; not_reached(); \
476 #define POP_THREE(x, y, z) uint32_t numPop() const { return 3; } \
477 Flavor popFlavor(uint32_t i) const { \
478 POP_##x; --i; POP_##y; --i; POP_##z; \
479 not_reached(); \
482 #define POP_MFINAL uint32_t numPop() const { return arg1; } \
483 Flavor popFlavor(uint32_t) const { not_reached(); }
485 #define POP_F_MFINAL uint32_t numPop() const { return arg2; } \
486 Flavor popFlavor(uint32_t) const { not_reached(); }
488 #define POP_C_MFINAL uint32_t numPop() const { return arg1 + 1; } \
489 Flavor popFlavor(uint32_t) const { not_reached(); }
491 #define POP_V_MFINAL POP_C_MFINAL
493 #define POP_CMANY uint32_t numPop() const { return arg1; } \
494 Flavor popFlavor(uint32_t i) const { \
495 assert(i < numPop()); \
496 return Flavor::C; \
499 #define POP_SMANY uint32_t numPop() const { return keys.size(); } \
500 Flavor popFlavor(uint32_t i) const { \
501 assert(i < numPop()); \
502 return Flavor::C; \
505 #define POP_FMANY uint32_t numPop() const { return arg1; } \
506 Flavor popFlavor(uint32_t i) const { \
507 assert(i < numPop()); \
508 return Flavor::F; \
511 #define POP_C_FMANY uint32_t numPop() const { return arg1; } \
512 Flavor popFlavor(uint32_t i) const { \
513 assert(i < numPop()); \
514 return i == 0 ? Flavor::C : Flavor::F; \
517 #define POP_UFMANY uint32_t numPop() const { return arg1 + arg2 - 1; } \
518 Flavor popFlavor(uint32_t i) const { \
519 assert(i < numPop()); \
520 return i < arg1 ? Flavor::F : Flavor::U; \
523 #define POP_C_UFMANY uint32_t numPop() const { return arg1 + arg2 - 1; } \
524 Flavor popFlavor(uint32_t i) const { \
525 assert(i < numPop()); \
526 if (i == 0) return Flavor::C; \
527 return i < arg1 ? Flavor::F : Flavor::U; \
530 #define POP_CVUMANY uint32_t numPop() const { return arg1; } \
531 Flavor popFlavor(uint32_t i) const { \
532 return Flavor::CVU; \
535 #define PUSH_NOV uint32_t numPush() const { return 0; }
537 #define PUSH_ONE(x) uint32_t numPush() const { return 1; }
539 #define PUSH_TWO(x, y) uint32_t numPush() const { return 2; }
541 #define PUSH_INS_1(...) uint32_t numPush() const { return 1; }
543 #define PUSH_CMANY uint32_t numPush() const { return arg2; }
545 #define FLAGS_NF
546 #define FLAGS_TF
547 #define FLAGS_CF
548 #define FLAGS_FF
549 #define FLAGS_PF bool has_unpack;
550 #define FLAGS_CF_TF
551 #define FLAGS_CF_FF
553 #define FLAGS_CTOR_NF
554 #define FLAGS_CTOR_TF
555 #define FLAGS_CTOR_CF
556 #define FLAGS_CTOR_FF
557 #define FLAGS_CTOR_PF ,bool hu
558 #define FLAGS_CTOR_CF_TF
559 #define FLAGS_CTOR_CF_FF
561 #define FLAGS_INIT_NF
562 #define FLAGS_INIT_TF
563 #define FLAGS_INIT_CF
564 #define FLAGS_INIT_FF
565 #define FLAGS_INIT_PF ,has_unpack(hu)
566 #define FLAGS_INIT_CF_TF
567 #define FLAGS_INIT_CF_FF
569 #define O(opcode, imms, inputs, outputs, flags) \
570 struct opcode { \
571 static constexpr Op op = Op::opcode; \
572 explicit opcode ( IMM_CTOR_##imms \
573 FLAGS_CTOR_##flags) \
574 IMM_INIT_##imms \
575 FLAGS_INIT_##flags \
576 {} \
578 IMM_MEM_##imms \
579 FLAGS_##flags \
580 IMM_EXTRA_##imms \
581 POP_##inputs \
582 PUSH_##outputs \
584 bool operator==(const opcode& o) const { \
585 return equals(o, detail::eq_default{}); \
588 bool operator!=(const opcode& o) const { \
589 return !(*this == o); \
592 template<class E> \
593 bool equals(const opcode& o, E e) const { \
594 return IMM_EQ_WRAP(e, IMM_EQ_##imms); \
597 size_t hash() const { \
598 return IMM_HASH_WRAP( \
599 detail::hasher_default{}, \
600 IMM_HASH_##imms); \
603 template<class H> \
604 size_t hash(H h) const { \
605 return IMM_HASH_WRAP(h, IMM_HASH_##imms); \
608 OPCODES
609 #undef O
611 #undef FLAGS_NA
612 #undef FLAGS_TF
613 #undef FLAGS_CF
614 #undef FLAGS_FF
615 #undef FLAGS_PF
616 #undef FLAGS_CF_TF
617 #undef FLAGS_CF_FF
619 #undef FLAGS_CTOR_NA
620 #undef FLAGS_CTOR_TF
621 #undef FLAGS_CTOR_CF
622 #undef FLAGS_CTOR_FF
623 #undef FLAGS_CTOR_PF
624 #undef FLAGS_CTOR_CF_TF
625 #undef FLAGS_CTOR_CF_FF
627 #undef FLAGS_INIT_NA
628 #undef FLAGS_INIT_TF
629 #undef FLAGS_INIT_CF
630 #undef FLAGS_INIT_FF
631 #undef FLAGS_INIT_PF
632 #undef FLAGS_INIT_CF_TF
633 #undef FLAGS_INIT_CF_FF
635 #undef PUSH_NOV
636 #undef PUSH_ONE
637 #undef PUSH_TWO
638 #undef PUSH_INS_1
639 #undef PUSH_CMANY
641 #undef POP_UV
642 #undef POP_CV
643 #undef POP_VV
644 #undef POP_FV
645 #undef POP_RV
647 #undef POP_NOV
648 #undef POP_ONE
649 #undef POP_TWO
650 #undef POP_THREE
651 #undef POP_MFINAL
652 #undef POP_F_MFINAL
653 #undef POP_C_MFINAL
654 #undef POP_V_MFINAL
655 #undef POP_CMANY
656 #undef POP_SMANY
657 #undef POP_FMANY
658 #undef POP_C_FMANY
659 #undef POP_UFMANY
660 #undef POP_C_UFMANY
661 #undef POP_CVUMANY
663 #undef IMM_TY_MA
664 #undef IMM_TY_BLA
665 #undef IMM_TY_SLA
666 #undef IMM_TY_ILA
667 #undef IMM_TY_I32LA
668 #undef IMM_TY_IVA
669 #undef IMM_TY_I64A
670 #undef IMM_TY_LA
671 #undef IMM_TY_IA
672 #undef IMM_TY_CAR
673 #undef IMM_TY_CAW
674 #undef IMM_TY_DA
675 #undef IMM_TY_SA
676 #undef IMM_TY_RATA
677 #undef IMM_TY_AA
678 #undef IMM_TY_BA
679 #undef IMM_TY_OA
680 #undef IMM_TY_VSA
681 #undef IMM_TY_KA
682 #undef IMM_TY_LAR
684 // These are deliberately not undefined, so they can be used in other
685 // places.
686 // #undef IMM_NAME_BLA
687 // #undef IMM_NAME_SLA
688 // #undef IMM_NAME_ILA
689 // #undef IMM_NAME_I32LA
690 // #undef IMM_NAME_IVA
691 // #undef IMM_NAME_I64A
692 // #undef IMM_NAME_LA
693 // #undef IMM_NAME_IA
694 // #undef IMM_NAME_CAR
695 // #undef IMM_NAME_CAW
696 // #undef IMM_NAME_DA
697 // #undef IMM_NAME_SA
698 // #undef IMM_NAME_RATA
699 // #undef IMM_NAME_AA
700 // #undef IMM_NAME_BA
701 // #undef IMM_NAME_OA
702 // #undef IMM_NAME_OA_IMPL
703 // #undef IMM_NAME_LAR
705 #undef IMM_EXTRA_BLA
706 #undef IMM_EXTRA_SLA
707 #undef IMM_EXTRA_ILA
708 #undef IMM_EXTRA_I32LA
709 #undef IMM_EXTRA_IVA
710 #undef IMM_EXTRA_I64A
711 #undef IMM_EXTRA_LA
712 #undef IMM_EXTRA_IA
713 #undef IMM_EXTRA_CAR
714 #undef IMM_EXTRA_CAW
715 #undef IMM_EXTRA_DA
716 #undef IMM_EXTRA_SA
717 #undef IMM_EXTRA_RATA
718 #undef IMM_EXTRA_AA
719 #undef IMM_EXTRA_BA
720 #undef IMM_EXTRA_OA
721 #undef IMM_EXTRA_KA
722 #undef IMM_EXTRA_LAR
724 #undef IMM_MEM
725 #undef IMM_MEM_NA
726 #undef IMM_MEM_ONE
727 #undef IMM_MEM_TWO
728 #undef IMM_MEM_THREE
729 #undef IMM_MEM_FOUR
730 #undef IMM_MEM_FIVE
732 #undef IMM_EQ
733 #undef IMM_EQ_NA
734 #undef IMM_EQ_ONE
735 #undef IMM_EQ_TWO
736 #undef IMM_EQ_THREE
737 #undef IMM_EQ_FOUR
738 #undef IMM_EQ_FIVE
740 #undef IMM_HASH
741 #undef IMM_HASH_DO
742 #undef IMM_HASH_NA
743 #undef IMM_HASH_ONE
744 #undef IMM_HASH_TWO
745 #undef IMM_HASH_THREE
746 #undef IMM_HASH_FOUR
747 #undef IMM_HASH_FIVE
749 #undef IMM_CTOR
750 #undef IMM_CTOR_NA
751 #undef IMM_CTOR_ONE
752 #undef IMM_CTOR_TWO
753 #undef IMM_CTOR_THREE
754 #undef IMM_CTOR_FOUR
755 #undef IMM_CTOR_FIVE
757 #undef IMM_INIT
758 #undef IMM_INIT_NA
759 #undef IMM_INIT_ONE
760 #undef IMM_INIT_TWO
761 #undef IMM_INIT_THREE
762 #undef IMM_INIT_FOUR
766 //////////////////////////////////////////////////////////////////////
769 * Bytecode is a tagged-union that can hold any HHBC opcode struct
770 * defined above. You can visit a bytecode with a static_visitor
771 * using visit(), defined below.
773 * Each Bytecode also carries a corresponding SrcLoc that indicates
774 * which line of PHP code the bytecode was generated for.
776 struct Bytecode {
777 // Default construction creates a Nop.
778 Bytecode()
779 : op(Op::Nop)
780 , Nop(bc::Nop{})
783 #define O(opcode, ...) \
784 /* implicit */ Bytecode(bc::opcode data) \
785 : op(Op::opcode) \
787 new (&opcode) bc::opcode(std::move(data)); \
790 OPCODES
792 #undef O
794 // Note: assuming bc::Nop is empty and has trivial dtor/ctor.
796 Bytecode(const Bytecode& o) : op(Op::Nop) { *this = o; }
797 Bytecode(Bytecode&& o) noexcept : op(Op::Nop) { *this = std::move(o); }
799 Bytecode& operator=(const Bytecode& o) {
800 destruct();
801 op = Op::Nop;
802 srcLoc = o.srcLoc;
803 #define O(opcode, ...) \
804 case Op::opcode: new (&opcode) bc::opcode(o.opcode); break;
805 switch (o.op) { OPCODES }
806 #undef O
807 op = o.op;
808 return *this;
811 Bytecode& operator=(Bytecode&& o) {
812 destruct();
813 srcLoc = o.srcLoc;
814 #define O(opcode, ...) \
815 case Op::opcode: new (&opcode) bc::opcode(std::move(o.opcode)); break;
816 switch (o.op) { OPCODES }
817 #undef O
818 op = o.op;
819 return *this;
822 ~Bytecode() { destruct(); }
824 uint32_t numPop() const {
825 #define O(opcode, ...) \
826 case Op::opcode: return opcode.numPop();
827 switch (op) { OPCODES }
828 #undef O
829 not_reached();
832 Flavor popFlavor(uint32_t i) const {
833 #define O(opcode, ...) \
834 case Op::opcode: return opcode.popFlavor(i);
835 switch (op) { OPCODES }
836 #undef O
837 not_reached();
840 uint32_t numPush() const {
841 #define O(opcode, ...) \
842 case Op::opcode: return opcode.numPush();
843 switch (op) { OPCODES }
844 #undef O
845 not_reached();
848 Op op;
849 int32_t srcLoc{-1};
851 #define O(opcode, ...) bc::opcode opcode;
852 union { OPCODES };
853 #undef O
855 private:
856 void destruct() {
857 switch (op) {
858 #define O(opcode, ...) \
859 case Op::opcode: \
860 { typedef bc::opcode X; \
861 this->opcode.~X(); } \
862 break;
863 OPCODES
864 #undef O
869 //////////////////////////////////////////////////////////////////////
871 inline bool operator==(const Bytecode& a, const Bytecode& b) {
872 if (a.op != b.op) return false;
873 #define O(opcode, ...) case Op::opcode: return a.opcode == b.opcode;
874 switch (a.op) { OPCODES }
875 #undef O
876 not_reached();
879 inline bool operator!=(const Bytecode& a, const Bytecode& b) {
880 return !(a == b);
883 template<class E>
884 inline bool equals(const Bytecode& a, const Bytecode& b, E equals) {
885 if (a.op != b.op) return false;
886 #define O(opcode, ...) \
887 case Op::opcode: return a.opcode.equals(b.opcode, equals);
888 switch (a.op) { OPCODES }
889 #undef O
890 not_reached();
893 template<class H>
894 inline size_t hash(const Bytecode& b, H hasher) {
895 auto hash = 14695981039346656037ULL;
896 auto o = static_cast<size_t>(b.op);
897 hash ^= o;
898 #define O(opcode, ...) \
899 case Op::opcode: \
900 return folly::hash::hash_combine(b.opcode.hash(hasher), hash);
901 switch (b.op) { OPCODES }
902 #undef O
903 not_reached();
906 inline size_t hash(const Bytecode& b) {
907 return hash(b, bc::detail::hasher_default{});
910 //////////////////////////////////////////////////////////////////////
913 * Helper for making a Bytecode with a given srcLoc.
915 * Ex:
916 * auto b = bc_with_loc(something.srcLoc, bc::Nop {});
918 template<class T> Bytecode bc_with_loc(int32_t loc, const T& t) {
919 Bytecode b = t;
920 b.srcLoc = loc;
921 return b;
924 //////////////////////////////////////////////////////////////////////
927 * Visit a bytecode using a StaticVisitor, similar to
928 * boost::apply_visitor or match().
930 * The `v' argument should be a function object that accepts a call
931 * operator for all the bc::Foo types, with a nested member typedef
932 * called result_type that indicates the return type of the call.
934 template<class Visit>
935 typename Visit::result_type visit(Bytecode& b, Visit v) {
936 #define O(opcode, ...) case Op::opcode: return v(b.opcode);
937 switch (b.op) { OPCODES }
938 #undef O
939 not_reached();
942 template<class Visit>
943 typename Visit::result_type visit(const Bytecode& b, Visit v) {
944 #define O(opcode, ...) case Op::opcode: return v(b.opcode);
945 switch (b.op) { OPCODES }
946 #undef O
947 not_reached();
950 //////////////////////////////////////////////////////////////////////
952 BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_target, has_target_flag, false);
953 BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_car, has_car_flag, false);
954 BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_caw, has_caw_flag, false);
956 //////////////////////////////////////////////////////////////////////
958 struct ReadClsRefSlotVisitor : boost::static_visitor<ClsRefSlotId> {
959 template <class T>
960 typename std::enable_if<!has_car<T>::value, ClsRefSlotId>::type
961 operator()(T const& /*t*/) const {
962 return NoClsRefSlotId;
965 template<class T>
966 typename std::enable_if<has_car<T>::value,ClsRefSlotId>::type
967 operator()(T const& t) const { return t.slot; }
970 struct WriteClsRefSlotVisitor : boost::static_visitor<ClsRefSlotId> {
971 template <class T>
972 typename std::enable_if<!has_caw<T>::value, ClsRefSlotId>::type
973 operator()(T const& /*t*/) const {
974 return NoClsRefSlotId;
977 template<class T>
978 typename std::enable_if<has_caw<T>::value,ClsRefSlotId>::type
979 operator()(T const& t) const { return t.slot; }
982 //////////////////////////////////////////////////////////////////////
984 std::string show(const php::Func&, const Bytecode& bc);
985 inline std::string show(borrowed_ptr<const php::Func> func,
986 const Bytecode& bc) {
987 return show(*func, bc);
990 //////////////////////////////////////////////////////////////////////
996 #endif