Reland D23318594 and D23318592 add recordbasenativesp instr
[hiphop-php.git] / hphp / runtime / vm / hhbc-codec.cpp
blob8ddeab6381ce87e9451a35d06982c40d1ddfe2f1
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 #include "hphp/runtime/vm/hhbc-codec.h"
18 #include "hphp/runtime/vm/unit-emitter.h"
19 #include "hphp/runtime/vm/unit.h"
21 namespace HPHP {
23 namespace {
25 const StringData* decode_string(PC& pc, StringDecoder u) {
26 auto const id = decode_raw<Id>(pc);
27 if (u.isNull()) return nullptr;
28 return u.match(
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));
47 switch (mcode) {
48 case MEC: case MPC:
49 return MemberKey{mcode, static_cast<int32_t>(decode_iva(pc))};
51 case MEL: case MPL:
52 return MemberKey{mcode, decode_named_local(pc)};
54 case MEI:
55 return MemberKey{mcode, decode_raw<int64_t>(pc)};
57 case MET: case MPT: case MQT: {
58 return MemberKey{mcode, decode_string(pc, u)};
61 case MW:
62 return MemberKey{};
64 not_reached();
67 void encode_member_key(MemberKey mk, UnitEmitter& ue) {
68 ue.emitByte(mk.mcode);
70 switch (mk.mcode) {
71 case MEC: case MPC:
72 ue.emitIVA(mk.iva);
73 break;
75 case MEL: case MPL:
76 ue.emitNamedLocal(mk.local);
77 break;
79 case MEI:
80 ue.emitInt64(mk.int64);
81 break;
83 case MET: case MPT: case MQT:
84 ue.emitInt32(ue.mergeLitstr(mk.litstr));
85 break;
87 case MW:
88 // No immediate
89 break;
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,
127 bool hasContext) {
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;
135 ue.emitByte(flags);
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;
152 return rawFlags;
153 }();
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;
162 return FCallArgs(
163 static_cast<FCallArgs::Flags>(flags & FCallArgs::kInternalFlags),
164 numArgs, numRets, inoutArgs, asyncEagerOffset, context
168 ///////////////////////////////////////////////////////////////////////////////