Reland D23318594 and D23318592 add recordbasenativesp instr
[hiphop-php.git] / hphp / runtime / vm / hhbc-codec.h
blobb0337144e171ece7510c5598346989e21ebe4df6
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_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"
24 namespace HPHP {
26 struct Unit;
27 struct UnitEmitter;
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
39 * know how to do so.
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.
49 template<typename T>
50 T decode_raw(PC& in) {
51 T data;
52 memcpy(&data, in, sizeof(data));
53 in += sizeof(data);
54 return 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.
64 template<typename F>
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);
69 if (rawVal >= 0xff) {
70 // Write a 0xff signal byte
71 write_byte(static_cast<uint8_t>(0xff));
72 rawVal -= 0xff;
74 assertx(rawVal < 0xff);
76 write_byte(rawVal);
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();
95 return op;
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
116 * read data.
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);
133 pc++;
134 return small;
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 //////////////////////////////////////////////////////////////////////
153 template<typename L>
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));
168 template<typename L>
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,
193 bool hasContext);
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 //////////////////////////////////////////////////////////////////////
213 #endif