2 +----------------------------------------------------------------------+
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_
21 #include <type_traits>
23 #include <boost/mpl/has_xxx.hpp>
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
{
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.
54 * auto fpass = bc::FPassC { 2 }; // FPassC for arg 2
57 //////////////////////////////////////////////////////////////////////
65 MKey(MemberCode mcode
, LocalId local
)
70 MKey(MemberCode mcode
, int32_t idx
)
75 MKey(MemberCode mcode
, int64_t int64
)
80 MKey(MemberCode mcode
, SString litstr
)
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
) {
102 // Represents a non-empty range of locals. There's always a first local,
103 // followed by a count of additional ones.
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
) {
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
) {
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 //////////////////////////////////////////////////////////////////////
144 //////////////////////////////////////////////////////////////////////
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.
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
);
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
);
189 static typename
std::enable_if
<
190 std::is_enum
<T
>::value
,
193 using U
= typename
std::underlying_type
<T
>::type
;
194 return std::hash
<U
>()(static_cast<U
>(t
));
198 static typename
std::enable_if
<
199 !std::is_enum
<T
>::value
,
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
)) {
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.
233 size_t hash_combine(H
/*h*/) {
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
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
)) {
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
...) {
277 * Check if a list of eq_operands are pairwise-equal.
280 bool eq_pairs(E
/*e*/) {
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.
297 #define ARGTYPE(name, type) enum class name : uint8_t {};
298 #define ARGTYPEVEC(name, type) enum class name : uint8_t {};
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
312 #define IMM_ID_CAR CAR
313 #define IMM_ID_CAW CAW
316 #define IMM_ID_RATA RATA
319 #define IMM_ID_OA(type) OA
320 #define IMM_ID_VSA VSA
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
373 #define IMM_EXTRA_CAR using has_car_flag = std::true_type;
374 #define IMM_EXTRA_CAW using has_caw_flag = std::true_type;
377 #define IMM_EXTRA_RATA
379 #define IMM_EXTRA_BA using has_target_flag = std::true_type;
380 #define IMM_EXTRA_OA(x)
381 #define IMM_EXTRA_VSA
383 #define IMM_EXTRA_LAR
385 #define IMM_MEM(which, n) IMM_TY_##which IMM_NAME_##which(n)
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); \
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); \
397 #define IMM_EQ_WRAP(e, ...) detail::eq_pairs(e, __VA_ARGS__)
398 #define IMM_EQ(which, n) detail::eq_operand< \
400 imm::IMM_ID_##which \
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< \
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)
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)
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), \
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), \
443 #define IMM_INIT(which, n) IMM_NAME_##which(n) \
444 ( std::move(IMM_NAME_##which(n)) )
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), \
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), \
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; \
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()); \
499 #define POP_SMANY uint32_t numPop() const { return keys.size(); } \
500 Flavor popFlavor(uint32_t i) const { \
501 assert(i < numPop()); \
505 #define POP_FMANY uint32_t numPop() const { return arg1; } \
506 Flavor popFlavor(uint32_t i) const { \
507 assert(i < numPop()); \
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; }
549 #define FLAGS_PF bool has_unpack;
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) \
571 static constexpr Op op = Op::opcode; \
572 explicit opcode ( IMM_CTOR_##imms \
573 FLAGS_CTOR_##flags) \
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); \
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{}, \
604 size_t hash(H h) const { \
605 return IMM_HASH_WRAP(h, IMM_HASH_##imms); \
624 #undef FLAGS_CTOR_CF_TF
625 #undef FLAGS_CTOR_CF_FF
632 #undef FLAGS_INIT_CF_TF
633 #undef FLAGS_INIT_CF_FF
684 // These are deliberately not undefined, so they can be used in other
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
708 #undef IMM_EXTRA_I32LA
710 #undef IMM_EXTRA_I64A
717 #undef IMM_EXTRA_RATA
745 #undef IMM_HASH_THREE
753 #undef IMM_CTOR_THREE
761 #undef IMM_INIT_THREE
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.
777 // Default construction creates a Nop.
783 #define O(opcode, ...) \
784 /* implicit */ Bytecode(bc::opcode data) \
787 new (&opcode) bc::opcode(std::move(data)); \
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
) {
803 #define O(opcode, ...) \
804 case Op::opcode: new (&opcode) bc::opcode(o.opcode); break;
805 switch (o
.op
) { OPCODES
}
811 Bytecode
& operator=(Bytecode
&& o
) {
814 #define O(opcode, ...) \
815 case Op::opcode: new (&opcode) bc::opcode(std::move(o.opcode)); break;
816 switch (o
.op
) { OPCODES
}
822 ~Bytecode() { destruct(); }
824 uint32_t numPop() const {
825 #define O(opcode, ...) \
826 case Op::opcode: return opcode.numPop();
827 switch (op
) { OPCODES
}
832 Flavor
popFlavor(uint32_t i
) const {
833 #define O(opcode, ...) \
834 case Op::opcode: return opcode.popFlavor(i);
835 switch (op
) { OPCODES
}
840 uint32_t numPush() const {
841 #define O(opcode, ...) \
842 case Op::opcode: return opcode.numPush();
843 switch (op
) { OPCODES
}
851 #define O(opcode, ...) bc::opcode opcode;
858 #define O(opcode, ...) \
860 { typedef bc::opcode X; \
861 this->opcode.~X(); } \
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
}
879 inline bool operator!=(const Bytecode
& a
, const Bytecode
& b
) {
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
}
894 inline size_t hash(const Bytecode
& b
, H hasher
) {
895 auto hash
= 14695981039346656037ULL;
896 auto o
= static_cast<size_t>(b
.op
);
898 #define O(opcode, ...) \
900 return folly::hash::hash_combine(b.opcode.hash(hasher), hash);
901 switch (b
.op
) { OPCODES
}
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.
916 * auto b = bc_with_loc(something.srcLoc, bc::Nop {});
918 template<class T
> Bytecode
bc_with_loc(int32_t loc
, const T
& t
) {
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
}
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
}
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
> {
960 typename
std::enable_if
<!has_car
<T
>::value
, ClsRefSlotId
>::type
961 operator()(T
const& /*t*/) const {
962 return NoClsRefSlotId
;
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
> {
972 typename
std::enable_if
<!has_caw
<T
>::value
, ClsRefSlotId
>::type
973 operator()(T
const& /*t*/) const {
974 return NoClsRefSlotId
;
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 //////////////////////////////////////////////////////////////////////