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 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_VM_HHBC_CODEC_H_
18 #define incl_HPHP_VM_HHBC_CODEC_H_
20 #include "hphp/runtime/base/repo-auth-type-codec.h"
21 #include "hphp/runtime/vm/hhbc.h"
22 #include "hphp/util/either.h"
30 * This file contains various functions for reading and writing bytecode
31 * streams, both opcodes and immediates.
34 //////////////////////////////////////////////////////////////////////
37 * The functions in this section are responsible for encoding and decoding Ops
38 * to and from bytecode streams, and should be the only pieces of code that
41 * We currently use a variable-width encoding scheme that can store [0, 0xff)
42 * using one byte and [0xff, 0x1fe) using two bytes. If and when we hit 0x1fe
43 * bytecodes we can adjust the encoding.
47 * Read a T from in, advancing in past the read value.
50 T
decode_raw(PC
& in
) {
52 memcpy(&data
, in
, sizeof(data
));
57 inline uint8_t decode_byte(PC
& pc
) {
58 return decode_raw
<uint8_t>(pc
);
62 * Encode the given Op, using write_byte to write a byte at a time.
65 void encode_op(Op op
, F write_byte
) {
66 static_assert(Op_count
<= 0x1fe,
67 "Op encoding scheme doesn't support Ops >= 0x1fe");
68 auto rawVal
= static_cast<size_t>(op
);
70 // Write a 0xff signal byte
71 write_byte(static_cast<uint8_t>(0xff));
74 assertx(rawVal
< 0xff);
80 * Read on Op from pc, advancing pc past the Op. This version makes no
81 * assertions on the validity of the Op returned, and is useful for testing the
82 * decoding scheme with arbitrary values.
84 inline Op
decode_op_unchecked(PC
& pc
) {
85 uint32_t raw
= decode_byte(pc
);
86 return LIKELY(raw
!= 0xff) ? Op(raw
) : Op(decode_byte(pc
) + 0xff);
90 * Read an Op from pc, advancing pc past the Op.
92 inline Op
decode_op(PC
& pc
) {
93 auto const op
= decode_op_unchecked(pc
);
94 if (!isValidOpcode(op
)) not_reached();
99 * Read an Op from pc, without modifying pc.
101 inline Op
peek_op(PC pc
) {
102 return decode_op(pc
);
106 * Return the encoded size of the given Op, in bytes.
108 constexpr size_t encoded_op_size(Op op
) {
109 return static_cast<size_t>(op
) < 0xff ? 1 : 2;
112 //////////////////////////////////////////////////////////////////////
115 * Read various immediate types from a pc, optionally advancing pc past the
119 template<class T
> T
decode_oa(PC
& pc
) {
120 return decode_raw
<T
>(pc
);
123 ALWAYS_INLINE Offset
decode_ba(PC
& pc
) {
124 return decode_raw
<Offset
>(pc
);
127 ALWAYS_INLINE
uint32_t decode_iva(PC
& pc
) {
128 auto const small
= *pc
;
129 if (UNLIKELY(int8_t(small
) < 0)) {
130 auto const large
= decode_raw
<uint32_t>(pc
);
131 return (large
& 0xffffff00) >> 1 | (small
& 0x7f);
137 using StringDecoder
= Either
<const Unit
*, const UnitEmitter
*>;
140 * decode a namedlocal, advancing pc past it.
142 NamedLocal
decode_named_local(PC
& pc
);
145 * Decode a MemberKey, advancing pc past it.
147 MemberKey
decode_member_key(PC
& pc
, StringDecoder u
);
149 void encode_member_key(MemberKey mk
, UnitEmitter
& ue
);
151 //////////////////////////////////////////////////////////////////////
154 void foreachSwitchTarget(PC pc
, L func
) {
155 auto const op
= decode_op(pc
);
156 assertx(isSwitch(op
));
157 if (op
== Op::Switch
) {
158 (void)decode_oa
<SwitchKind
>(pc
); // skip bounded kind
159 (void)decode_raw
<int64_t>(pc
); // skip base
161 int32_t size
= decode_iva(pc
);
162 for (int i
= 0; i
< size
; ++i
) {
163 if (op
== Op::SSwitch
) decode_raw
<Id
>(pc
);
164 func(decode_raw
<Offset
>(pc
));
169 void foreachSSwitchString(PC pc
, L func
) {
170 auto const UNUSED op
= decode_op(pc
);
171 assertx(op
== Op::SSwitch
);
172 int32_t size
= decode_iva(pc
) - 1; // the last item is the default
173 for (int i
= 0; i
< size
; ++i
) {
174 func(decode_raw
<Id
>(pc
));
175 decode_raw
<Offset
>(pc
);
179 //////////////////////////////////////////////////////////////////////
181 void encodeLocalRange(UnitEmitter
&, const LocalRange
&);
182 LocalRange
decodeLocalRange(const unsigned char*&);
184 //////////////////////////////////////////////////////////////////////
186 void encodeIterArgs(UnitEmitter
&, const IterArgs
&);
187 IterArgs
decodeIterArgs(const unsigned char*&);
189 //////////////////////////////////////////////////////////////////////
191 void encodeFCallArgsBase(UnitEmitter
&, const FCallArgsBase
&,
192 bool hasInoutArgs
, bool hasAsyncEagerOffset
,
194 void encodeFCallArgsIO(UnitEmitter
&, int numBytes
, const uint8_t* inoutArgs
);
196 FCallArgs
decodeFCallArgs(Op
, PC
&, StringDecoder
);
198 template<typename T
, typename IO
, typename CTX
>
199 void encodeFCallArgs(UnitEmitter
& ue
, const FCallArgsBase
& fca
,
200 bool hasInoutArgs
, IO emitInoutArgs
,
201 bool hasAsyncEagerOffset
, T emitAsyncEagerOffset
,
202 bool hasContext
, CTX emitContext
) {
203 encodeFCallArgsBase(ue
, fca
, hasInoutArgs
, hasAsyncEagerOffset
, hasContext
);
204 if (hasInoutArgs
) emitInoutArgs();
205 if (hasAsyncEagerOffset
) emitAsyncEagerOffset();
206 if (hasContext
) emitContext();
209 //////////////////////////////////////////////////////////////////////