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 #include "hphp/runtime/vm/hhbc-codec.h"
18 #include "hphp/runtime/vm/unit-emitter.h"
19 #include "hphp/runtime/vm/unit.h"
25 const StringData
* decode_string(PC
& pc
, StringDecoder u
) {
26 auto const id
= decode_raw
<Id
>(pc
);
27 if (u
.isNull()) return nullptr;
29 [id
](const Unit
* u
) { return u
->lookupLitstrId(id
); },
30 [id
](const UnitEmitter
* ue
) { return ue
->lookupLitstr(id
); }
36 NamedLocal
decode_named_local(PC
& pc
) {
37 LocalName lname
= decode_iva(pc
) - 1;
38 int32_t id
= decode_iva(pc
);
39 return NamedLocal
{lname
, id
};
42 ///////////////////////////////////////////////////////////////////////////////
44 MemberKey
decode_member_key(PC
& pc
, Either
<const Unit
*, const UnitEmitter
*> u
) {
45 auto const mcode
= static_cast<MemberCode
>(decode_byte(pc
));
49 return MemberKey
{mcode
, static_cast<int32_t>(decode_iva(pc
))};
52 return MemberKey
{mcode
, decode_named_local(pc
)};
55 return MemberKey
{mcode
, decode_raw
<int64_t>(pc
)};
57 case MET
: case MPT
: case MQT
: {
58 return MemberKey
{mcode
, decode_string(pc
, u
)};
67 void encode_member_key(MemberKey mk
, UnitEmitter
& ue
) {
68 ue
.emitByte(mk
.mcode
);
76 ue
.emitNamedLocal(mk
.local
);
80 ue
.emitInt64(mk
.int64
);
83 case MET
: case MPT
: case MQT
:
84 ue
.emitInt32(ue
.mergeLitstr(mk
.litstr
));
93 ///////////////////////////////////////////////////////////////////////////////
95 void encodeLocalRange(UnitEmitter
& ue
, const LocalRange
& range
) {
96 ue
.emitIVA(range
.first
);
97 ue
.emitIVA(range
.count
);
100 LocalRange
decodeLocalRange(const unsigned char*& pc
) {
101 auto const first
= decode_iva(pc
);
102 auto const restCount
= decode_iva(pc
);
103 return LocalRange
{uint32_t(first
), uint32_t(restCount
)};
106 ///////////////////////////////////////////////////////////////////////////////
108 void encodeIterArgs(UnitEmitter
& ue
, const IterArgs
& args
) {
109 ue
.emitByte(args
.flags
);
110 ue
.emitIVA(args
.iterId
);
111 ue
.emitIVA(args
.keyId
- IterArgs::kNoKey
);
112 ue
.emitIVA(args
.valId
);
115 IterArgs
decodeIterArgs(PC
& pc
) {
116 auto const flags
= static_cast<IterArgs::Flags
>(decode_byte(pc
));
117 auto const iterId
= int32_t(decode_iva(pc
));
118 auto const keyId
= int32_t(decode_iva(pc
)) + IterArgs::kNoKey
;
119 auto const valId
= int32_t(decode_iva(pc
));
120 return IterArgs(flags
, iterId
, keyId
, valId
);
123 ///////////////////////////////////////////////////////////////////////////////
125 void encodeFCallArgsBase(UnitEmitter
& ue
, const FCallArgsBase
& fca
,
126 bool hasInoutArgs
, bool hasAsyncEagerOffset
,
128 auto flags
= uint8_t{fca
.flags
};
129 assertx(!(flags
& ~FCallArgsBase::kInternalFlags
));
130 if (fca
.numRets
!= 1) flags
|= FCallArgsBase::HasInOut
;
131 if (hasInoutArgs
) flags
|= FCallArgsBase::EnforceInOut
;
132 if (hasAsyncEagerOffset
) flags
|= FCallArgsBase::HasAsyncEagerOffset
;
133 if (hasContext
) flags
|= FCallArgsBase::ExplicitContext
;
136 ue
.emitIVA(fca
.numArgs
);
137 if (fca
.numRets
!= 1) ue
.emitIVA(fca
.numRets
);
140 void encodeFCallArgsIO(UnitEmitter
& ue
, int numBytes
,
141 const uint8_t* inoutArgs
) {
142 for (auto i
= 0; i
< numBytes
; ++i
) ue
.emitByte(inoutArgs
[i
]);
145 FCallArgs
decodeFCallArgs(Op thisOpcode
, PC
& pc
, StringDecoder u
) {
146 assertx(isFCall(thisOpcode
));
147 bool skipContext
= true;
148 auto const flags
= [&]() {
149 auto rawFlags
= decode_byte(pc
);
150 skipContext
= !(rawFlags
& FCallArgs::ExplicitContext
);
151 if (u
.isNull()) rawFlags
&= ~FCallArgs::ExplicitContext
;
155 uint32_t numArgs
= decode_iva(pc
);
156 auto const numRets
= (flags
& FCallArgs::HasInOut
) ? decode_iva(pc
) : 1;
157 auto const inoutArgs
= (flags
& FCallArgs::EnforceInOut
) ? pc
: nullptr;
158 if (inoutArgs
!= nullptr) pc
+= (numArgs
+ 7) / 8;
159 auto const asyncEagerOffset
= (flags
& FCallArgs::HasAsyncEagerOffset
)
160 ? decode_ba(pc
) : kInvalidOffset
;
161 auto const context
= !skipContext
? decode_string(pc
, u
) : nullptr;
163 static_cast<FCallArgs::Flags
>(flags
& FCallArgs::kInternalFlags
),
164 numArgs
, numRets
, inoutArgs
, asyncEagerOffset
, context
168 ///////////////////////////////////////////////////////////////////////////////