2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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.h"
18 #include "hphp/runtime/ext/ext_variable.h"
19 #include "hphp/runtime/vm/unit.h"
20 #include "hphp/runtime/base/stats.h"
24 ///////////////////////////////////////////////////////////////////////////////
26 int numImmediates(Op opcode
) {
27 assert(isValidOpcode(opcode
));
28 static const int8_t values
[] = {
34 #define O(name, imm, unusedPop, unusedPush, unusedFlags) imm,
43 return values
[uint8_t(opcode
)];
46 ArgType
immType(const Op opcode
, int idx
) {
47 assert(isValidOpcode(opcode
));
48 assert(idx
>= 0 && idx
< numImmediates(opcode
));
49 always_assert(idx
< 4); // No opcodes have more than four immediates
50 static const int8_t arg0Types
[] = {
54 #define THREE(a, b, c) a,
55 #define FOUR(a, b, c, d) a,
56 #define O(name, imm, unusedPop, unusedPush, unusedFlags) imm
58 // re-using definition of O below.
65 static const int8_t arg1Types
[] = {
69 #define THREE(a, b, c) b,
70 #define FOUR(a, b, c, d) b,
72 // re-using definition of O below.
79 static const int8_t arg2Types
[] = {
83 #define THREE(a, b, c) c,
84 #define FOUR(a, b, c, d) c,
92 static const int8_t arg3Types
[] = {
96 #define THREE(a, b, c) -1,
97 #define FOUR(a, b, c, d) d,
106 auto opInt
= uint8_t(opcode
);
108 case 0: return (ArgType
)arg0Types
[opInt
];
109 case 1: return (ArgType
)arg1Types
[opInt
];
110 case 2: return (ArgType
)arg2Types
[opInt
];
111 case 3: return (ArgType
)arg3Types
[opInt
];
112 default: assert(false); return (ArgType
)-1;
116 int immSize(const Op
* opcode
, int idx
) {
117 assert(idx
>= 0 && idx
< numImmediates(*opcode
));
118 always_assert(idx
< 4); // No opcodes have more than four immediates
119 static const int8_t argTypeToSizes
[] = {
120 #define ARGTYPE(nm, type) sizeof(type),
121 #define ARGTYPEVEC(nm, type) 0,
126 if (immType(*opcode
, idx
) == IVA
|| immType(*opcode
, idx
) == HA
||
127 immType(*opcode
, idx
) == IA
) {
129 if (idx
>= 1) offset
+= immSize(opcode
, 0);
130 if (idx
>= 2) offset
+= immSize(opcode
, 1);
131 if (idx
>= 3) offset
+= immSize(opcode
, 2);
133 unsigned char imm
= *(unsigned char*)(opcode
+ offset
);
134 // Low order bit set => 4-byte.
135 return (imm
& 0x1 ? sizeof(int32_t) : sizeof(unsigned char));
136 } else if (immIsVector(*opcode
, idx
)) {
138 if (idx
>= 1) offset
+= immSize(opcode
, 0);
139 if (idx
>= 2) offset
+= immSize(opcode
, 1);
140 if (idx
>= 3) offset
+= immSize(opcode
, 2);
141 int prefixes
, vecElemSz
;
142 auto itype
= immType(*opcode
, idx
);
145 vecElemSz
= sizeof(uint8_t);
146 } else if (itype
== BLA
) {
148 vecElemSz
= sizeof(Offset
);
149 } else if (itype
== ILA
) {
151 vecElemSz
= 2 * sizeof(uint32_t);
153 assert(itype
== SLA
);
155 vecElemSz
= sizeof(StrVecItem
);
157 return prefixes
* sizeof(int32_t) +
158 vecElemSz
* *(int32_t*)((int8_t*)opcode
+ offset
);
160 ArgType type
= immType(*opcode
, idx
);
161 return (type
>= 0) ? argTypeToSizes
[type
] : 0;
165 bool immIsVector(Op opcode
, int idx
) {
166 ArgType type
= immType(opcode
, idx
);
167 return (type
== MA
|| type
== BLA
|| type
== SLA
|| type
== ILA
);
170 bool hasImmVector(Op opcode
) {
171 const int num
= numImmediates(opcode
);
172 for (int i
= 0; i
< num
; ++i
) {
173 if (immIsVector(opcode
, i
)) return true;
178 ArgUnion
getImm(const Op
* opcode
, int idx
) {
179 const Op
* p
= opcode
+ 1;
180 assert(idx
>= 0 && idx
< numImmediates(*opcode
));
184 for (cursor
= 0; cursor
< idx
; cursor
++) {
185 // Advance over this immediate.
186 p
+= immSize(opcode
, cursor
);
188 always_assert(cursor
== idx
);
189 ArgType type
= immType(*opcode
, idx
);
190 if (type
== IVA
|| type
== HA
|| type
== IA
) {
191 retval
.u_IVA
= decodeVariableSizeImm((const uint8_t**)&p
);
192 } else if (!immIsVector(*opcode
, cursor
)) {
193 memcpy(&retval
.bytes
, p
, immSize(opcode
, idx
));
195 always_assert(numImmediates(*opcode
) > idx
);
199 ArgUnion
* getImmPtr(const Op
* opcode
, int idx
) {
200 assert(immType(*opcode
, idx
) != IVA
);
201 assert(immType(*opcode
, idx
) != HA
);
202 assert(immType(*opcode
, idx
) != IA
);
203 const Op
* ptr
= opcode
+ 1;
204 for (int i
= 0; i
< idx
; i
++) {
205 ptr
+= immSize(opcode
, i
);
207 return (ArgUnion
*)ptr
;
211 T
decodeImm(const unsigned char** immPtr
) {
212 T val
= *(T
*)*immPtr
;
213 *immPtr
+= sizeof(T
);
217 int64_t decodeMemberCodeImm(const unsigned char** immPtr
, MemberCode mcode
) {
221 return decodeVariableSizeImm(immPtr
);
225 return decodeImm
<int32_t>(immPtr
);
228 return decodeImm
<int64_t>(immPtr
);
235 // TODO: merge with emitIVA in unit.h
236 size_t encodeVariableSizeImm(int32_t n
, unsigned char* buf
) {
237 if (LIKELY((n
& 0x7f) == n
)) {
238 *buf
= static_cast<unsigned char>(n
) << 1;
241 assert((n
& 0x7fffffff) == n
);
242 *reinterpret_cast<uint32_t*>(buf
) = (uint32_t(n
) << 1) | 0x1;
246 void encodeIvaToVector(std::vector
<uchar
>& out
, int32_t val
) {
247 size_t currentLen
= out
.size();
248 out
.resize(currentLen
+ 4);
249 out
.resize(currentLen
+ encodeVariableSizeImm(val
, &out
[currentLen
]));
252 int instrLen(const Op
* opcode
) {
255 int nImm
= numImmediates(op
);
256 for (int i
= 0; i
< nImm
; i
++) {
257 len
+= immSize(opcode
, i
);
262 InstrFlags
instrFlags(Op opcode
) {
263 static const InstrFlags instrFlagsData
[] = {
264 #define O(unusedName, unusedImm, unusedPop, unusedPush, flags) flags,
268 return instrFlagsData
[uint8_t(opcode
)];
271 Offset
* instrJumpOffset(Op
* instr
) {
272 static const int8_t jumpMask
[] = {
285 #define TWO(a, b) (a + 2 * b)
286 #define THREE(a, b, c) (a + 2 * b + 4 * c)
287 #define FOUR(a, b, c, d) (a + 2 * b + 4 * c + 8 * d)
288 #define O(name, imm, pop, push, flags) imm,
308 assert(!isSwitch(*instr
));
310 if (Op(*instr
) == OpIterBreak
) {
311 uint32_t veclen
= *(uint32_t *)(instr
+ 1);
313 Offset
* target
= (Offset
*)((uint32_t *)(instr
+ 1) + 2 * veclen
+ 1);
317 int mask
= jumpMask
[uint8_t(*instr
)];
323 case 0: return nullptr;
324 case 1: immNum
= 0; break;
325 case 2: immNum
= 1; break;
326 case 4: immNum
= 2; break;
327 case 8: immNum
= 3; break;
328 default: assert(false); return nullptr;
331 return &getImmPtr(instr
, immNum
)->u_BA
;
334 Offset
instrJumpTarget(const Op
* instrs
, Offset pos
) {
335 Offset
* offset
= instrJumpOffset(const_cast<Op
*>(instrs
+ pos
));
338 return InvalidAbsoluteOffset
;
340 return *offset
+ pos
;
345 * Return the number of successor-edges including fall-through paths but not
346 * implicit exception paths.
348 int numSuccs(const Op
* instr
) {
349 if (!instrIsControlFlow(*instr
)) return 1;
350 if ((instrFlags(*instr
) & TF
) != 0) {
351 if (isSwitch(*instr
)) {
352 return *(int*)(instr
+ 1);
354 if (*instr
== OpJmp
|| *instr
== OpIterBreak
) return 1;
357 if (instrJumpOffset(const_cast<Op
*>(instr
))) return 2;
362 * instrNumPops() returns the number of values consumed from the stack
363 * for a given push/pop instruction. For peek/poke instructions, this
364 * function returns 0.
366 int instrNumPops(const Op
* opcode
) {
367 static const int8_t numberOfPops
[] = {
373 #define LMANY(...) -1
374 #define C_LMANY(...) -2
375 #define V_LMANY(...) -2
376 #define R_LMANY(...) -2
380 #define O(name, imm, pop, push, flags) pop,
396 int n
= numberOfPops
[uint8_t(*opcode
)];
397 // For most instructions, we know how many values are popped based
398 // solely on the opcode
399 if (n
>= 0) return n
;
400 // FCall and NewTuple specify how many values are popped in their
402 if (n
== -3) return getImm(opcode
, 0).u_IVA
;
403 // For instructions with vector immediates, we have to scan the
404 // contents of the vector immediate to determine how many values
406 assert(n
== -1 || n
== -2);
407 ImmVector iv
= getImmVector(opcode
);
408 // Count the number of values on the stack accounted for by the
409 // ImmVector's location and members
410 int k
= iv
.numStackValues();
411 // If this instruction also takes a RHS, count that too
417 * instrNumPushes() returns the number of values pushed onto the stack
418 * for a given push/pop instruction. For peek/poke instructions or
419 * InsertMid instructions, this function returns 0.
421 int instrNumPushes(const Op
* opcode
) {
422 static const int8_t numberOfPushes
[] = {
430 #define O(name, imm, pop, push, flags) push,
441 return numberOfPushes
[uint8_t(*opcode
)];
444 StackTransInfo
instrStackTransInfo(const Op
* opcode
) {
445 static const StackTransInfo::Kind transKind
[] = {
446 #define NOV StackTransInfo::Kind::PushPop
447 #define ONE(...) StackTransInfo::Kind::PushPop
448 #define TWO(...) StackTransInfo::Kind::PushPop
449 #define THREE(...) StackTransInfo::Kind::PushPop
450 #define FOUR(...) StackTransInfo::Kind::PushPop
451 #define INS_1(...) StackTransInfo::Kind::InsertMid
452 #define INS_2(...) StackTransInfo::Kind::InsertMid
453 #define O(name, imm, pop, push, flags) push,
464 static const int8_t peekPokeType
[] = {
468 #define THREE(...) -1
472 #define O(name, imm, pop, push, flags) push,
484 ret
.kind
= transKind
[uint8_t(*opcode
)];
486 case StackTransInfo::Kind::PushPop
:
488 ret
.numPushes
= instrNumPushes(opcode
);
489 ret
.numPops
= instrNumPops(opcode
);
491 case StackTransInfo::Kind::InsertMid
:
494 ret
.pos
= peekPokeType
[uint8_t(*opcode
)];
501 bool pushesActRec(Op opcode
) {
506 case OpFPushObjMethod
:
507 case OpFPushObjMethodD
:
508 case OpFPushClsMethod
:
509 case OpFPushClsMethodF
:
510 case OpFPushClsMethodD
:
523 static void staticArrayStreamer(ArrayData
* ad
, std::stringstream
& out
) {
527 for (ArrayIter
it(ad
); !it
.end(); it
.next()) {
533 Variant key
= it
.first();
535 switch (key
.getType()) {
537 out
<< *key
.getInt64Data();
540 case KindOfStaticString
:
543 << Util::escapeStringForCPP(key
.getStringData()->data(),
544 key
.getStringData()->size())
548 default: assert(false);
552 Variant val
= it
.second();
553 switch (val
.getType()) {
559 case KindOfBoolean
: {
560 out
<< (val
.toBoolean() ? "true" : "false");
563 case KindOfStaticString
:
566 << Util::escapeStringForCPP(val
.getStringData()->data(),
567 val
.getStringData()->size())
572 out
<< *val
.getInt64Data();
576 out
<< *val
.getDoubleData();
580 staticArrayStreamer(val
.getArrayData(), out
);
583 default: assert(false);
590 void staticStreamer(const TypedValue
* tv
, std::stringstream
& out
) {
591 switch (tv
->m_type
) {
597 case KindOfBoolean
: {
598 out
<< (tv
->m_data
.num
? "true" : "false");
601 case KindOfStaticString
:
603 out
<< "\"" << tv
->m_data
.pstr
->data() << "\"";
607 out
<< tv
->m_data
.num
;
611 out
<< tv
->m_data
.dbl
;
615 staticArrayStreamer(tv
->m_data
.parr
, out
);
618 default: assert(false);
622 const char* const locationNames
[] = { "L", "C", "H",
627 const size_t locationNamesCount
= sizeof(locationNames
) /
628 sizeof(*locationNames
);
629 static_assert(locationNamesCount
== NumLocationCodes
,
630 "Location code missing for locationCodeString");
632 const char* locationCodeString(LocationCode lcode
) {
633 assert(lcode
>= 0 && lcode
< NumLocationCodes
);
634 return locationNames
[lcode
];
637 LocationCode
parseLocationCode(const char* s
) {
638 if (!*s
) return InvalidLocationCode
;
646 int incr
= (s
[1] == 'C');
648 case 'G': return LocationCode(LGL
+ incr
);
649 case 'N': return LocationCode(LNL
+ incr
);
650 case 'S': return LocationCode(LSL
+ incr
);
652 return InvalidLocationCode
;
656 const char* const memberNames
[] =
657 { "EC", "PC", "EL", "PL", "ET", "PT", "EI", "W" };
658 const size_t memberNamesCount
= sizeof(memberNames
) /
659 sizeof(*memberNames
);
661 static_assert(memberNamesCount
== NumMemberCodes
,
662 "Member code missing for memberCodeString");
664 const char* memberCodeString(MemberCode mcode
) {
665 assert(mcode
>= 0 && mcode
< NumMemberCodes
);
666 return memberNames
[mcode
];
669 MemberCode
parseMemberCode(const char* s
) {
673 case 'E': incr
= 0; break;
674 case 'P': incr
= 1; break;
675 default: return InvalidMemberCode
;
678 case 'C': return MemberCode(MEC
+ incr
);
679 case 'L': return MemberCode(MEL
+ incr
);
680 case 'T': return MemberCode(MET
+ incr
);
681 case 'I': return incr
? InvalidMemberCode
: MEI
;
682 default: return InvalidMemberCode
;
686 std::string
instrToString(const Op
* it
, const Unit
* u
/* = NULL */) {
688 static const char* incdecNames
[] = {
689 "PreInc", "PostInc", "PreDec", "PostDec"
691 static const int incdecNamesCount
=
692 (int)(sizeof(incdecNames
)/sizeof(const char*));
694 static const char* setopNames
[] = {
695 #define SETOP_OP(setOpOp, bcOp) #bcOp,
699 static const int setopNamesCount
=
700 (int)(sizeof(setopNames
)/sizeof(const char*));
702 std::stringstream out
;
703 const Op
* iStart
= it
;
708 #define READ(t) out << " " << *((t*)&*it); it += sizeof(t)
710 #define READOFF() do { \
711 Offset _value = *(Offset*)it; \
712 out << " " << _value; \
713 if (u != nullptr && _value >= 0) { \
714 out << " (" << u->offsetOf(iStart + _value) << ")"; \
716 it += sizeof(Offset); \
719 #define READV() out << " " << decodeVariableSizeImm((const uint8_t**)&it);
721 #define READIVA() do { \
723 auto imm = decodeVariableSizeImm((const uint8_t**)&it); \
724 if (op == OpIncStat && immIdx == 0) { \
725 out << Stats::g_counterNames[imm]; \
732 #define READOA() do { \
733 int immVal = (int)*((uchar*)&*it); \
734 it += sizeof(uchar); \
737 case OpIncDecL: case OpIncDecN: case OpIncDecG: case OpIncDecS: \
739 out << ((immVal >= 0 && immVal < incdecNamesCount) ? \
740 incdecNames[immVal] : "?"); \
742 case OpSetOpL: case OpSetOpN: case OpSetOpG: case OpSetOpS: \
744 out << ((immVal >=0 && immVal < setopNamesCount) ? \
745 setopNames[immVal] : "?"); \
753 #define READVEC() do { \
754 int sz = *((int*)&*it); \
755 it += sizeof(int) * 2; \
756 const uint8_t* const start = (uint8_t*)it; \
759 int immVal = (int)*((uchar*)&*it); \
760 out << ((immVal >= 0 && size_t(immVal) < locationNamesCount) ? \
761 locationCodeString(LocationCode(immVal)) : "?"); \
762 it += sizeof(uchar); \
763 int numLocImms = numLocationCodeImms(LocationCode(immVal)); \
764 for (int i = 0; i < numLocImms; ++i) { \
765 out << ':' << decodeVariableSizeImm((const uint8_t**)&it); \
767 while (reinterpret_cast<const uint8_t*>(it) - start < sz) { \
768 immVal = (int)*((uchar*)&*it); \
769 out << " " << ((immVal >=0 && size_t(immVal) < memberNamesCount) ? \
770 memberCodeString(MemberCode(immVal)) : "?"); \
771 it += sizeof(uchar); \
772 if (memberCodeHasImm(MemberCode(immVal))) { \
773 int64_t imm = decodeMemberCodeImm((const uint8_t**)&it, \
774 MemberCode(immVal)); \
776 if (memberCodeImmIsString(MemberCode(immVal)) && u) { \
777 const StringData* str = u->lookupLitstrId(imm); \
778 int len = str->size(); \
779 char* escaped = string_addslashes(str->data(), len); \
780 out << '"' << escaped << '"'; \
787 assert(reinterpret_cast<const uint8_t*>(it) - start == sz); \
792 #define READLITSTR(sep) do { \
793 Id id = readData<Id>(it); \
795 assert(op == OpSSwitch); \
798 const StringData* sd = u->lookupLitstrId(id); \
799 out << sep << "\"" << \
800 Util::escapeStringForCPP(sd->data(), sd->size()) << "\""; \
806 #define READSVEC() do { \
807 int sz = readData<int>(it); \
809 const char* sep = ""; \
810 for (int i = 0; i < sz; ++i) { \
812 if (op == OpSSwitch) { \
816 Offset o = readData<Offset>(it); \
817 if (u != nullptr) { \
818 if (iStart + o == (Op*)u->entry() - 1) { \
821 out << u->offsetOf(iStart + o); \
831 #define READIVEC() do { \
832 int sz = readData<int>(it); \
834 const char* sep = ""; \
835 for (int i = 0; i < sz; ++i) { \
837 IterKind k = (IterKind)readData<Id>(it); \
839 case KindOfIter: out << "(Iter) "; break; \
840 case KindOfMIter: out << "(MIter) "; break; \
841 case KindOfCIter: out << "(CIter) "; break; \
843 out << readData<Id>(it); \
850 #define TWO(a, b) H_##a; H_##b
851 #define THREE(a, b, c) H_##a; H_##b; H_##c;
852 #define FOUR(a, b, c, d) H_##a; H_##b; H_##c; H_##d;
854 #define H_MA READVEC()
855 #define H_BLA READSVEC()
856 #define H_SLA READSVEC()
857 #define H_ILA READIVEC()
858 #define H_IVA READIVA()
859 #define H_I64A READ(int64_t)
862 #define H_DA READ(double)
863 #define H_BA READOFF()
864 #define H_OA READOA()
865 #define H_SA READLITSTR(" ")
869 staticArrayStreamer(u->lookupArrayId(*((Id*)it)), out); \
871 out << " " << *((Id*)it); \
874 #define O(name, imm, push, pop, flags) \
877 UNUSED unsigned immIdx = 0; \
902 default: assert(false);
907 const char* opcodeToName(Op op
) {
908 const char* namesArr
[] = {
909 #define O(name, imm, inputs, outputs, flags) \
914 if (op
>= Op::LowInvalid
&& op
<= Op::HighInvalid
) {
915 return namesArr
[uint8_t(op
)];
920 bool instrIsControlFlow(Op opcode
) {
921 InstrFlags opFlags
= instrFlags(opcode
);
922 return (opFlags
& CF
) != 0;
925 bool instrIsNonCallControlFlow(Op opcode
) {
926 if (!instrIsControlFlow(opcode
) || isFCallStar(opcode
)) return false;
942 bool instrAllowsFallThru(Op opcode
) {
943 InstrFlags opFlags
= instrFlags(opcode
);
944 return (opFlags
& TF
) == 0;
947 bool instrReadsCurrentFpi(Op opcode
) {
948 InstrFlags opFlags
= instrFlags(opcode
);
949 return (opFlags
& FF
) != 0;
952 ImmVector
getImmVector(const Op
* opcode
) {
953 int numImm
= numImmediates(*opcode
);
954 for (int k
= 0; k
< numImm
; ++k
) {
955 ArgType t
= immType(*opcode
, k
);
957 void* vp
= getImmPtr(opcode
, k
);
958 return ImmVector::createFromStream(
959 static_cast<const uint8_t*>(vp
));
960 } else if (t
== BLA
|| t
== SLA
|| t
== ILA
) {
961 void* vp
= getImmPtr(opcode
, k
);
962 return ImmVector::createFromStream(
963 static_cast<const int32_t*>(vp
));
970 MInstrLocation
getMLocation(const Op
* opcode
) {
971 auto immVec
= getImmVector(opcode
);
972 auto vec
= immVec
.vec();
973 auto const lcode
= LocationCode(*vec
++);
974 auto const imm
= numLocationCodeImms(lcode
) ? decodeVariableSizeImm(&vec
)
979 std::vector
<MVectorItem
> getMVector(const Op
* opcode
) {
980 auto immVec
= getImmVector(opcode
);
981 std::vector
<MVectorItem
> result
;
982 auto it
= immVec
.vec();
983 auto end
= it
+ immVec
.size();
985 // Skip the LocationCode and its immediate
986 auto const lcode
= LocationCode(*it
++);
987 if (numLocationCodeImms(lcode
)) decodeVariableSizeImm(&it
);
990 auto const mcode
= MemberCode(*it
++);
991 auto const imm
= memberCodeHasImm(mcode
) ? decodeMemberCodeImm(&it
, mcode
)
993 result
.push_back({mcode
, imm
});
999 const uint8_t* ImmVector::findLastMember() const {
1000 assert(m_length
> 0);
1002 // Loop that does basically the same as numStackValues(), except
1003 // stop at the last.
1004 const uint8_t* vec
= m_start
;
1005 const LocationCode locCode
= LocationCode(*vec
++);
1006 const int numLocImms
= numLocationCodeImms(locCode
);
1007 for (int i
= 0; i
< numLocImms
; ++i
) {
1008 decodeVariableSizeImm(&vec
);
1012 const uint8_t* ret
= vec
;
1013 MemberCode code
= MemberCode(*vec
++);
1014 if (memberCodeHasImm(code
)) {
1015 decodeMemberCodeImm(&vec
, code
);
1017 if (vec
- m_start
== m_length
) {
1020 assert(vec
- m_start
< m_length
);
1026 bool ImmVector::decodeLastMember(const Unit
* u
,
1028 MemberCode
& membOut
,
1029 int64_t* strIdOut
/*=NULL*/) const {
1030 const uint8_t* vec
= findLastMember();
1031 membOut
= MemberCode(*vec
++);
1032 if (memberCodeImmIsString(membOut
)) {
1033 int64_t strId
= decodeMemberCodeImm(&vec
, membOut
);
1034 if (strIdOut
) *strIdOut
= strId
;
1035 sdOut
= u
->lookupLitstrId(strId
);
1042 int instrSpToArDelta(const Op
* opcode
) {
1043 // This function should only be called for instructions that read
1045 assert(instrReadsCurrentFpi(*opcode
));
1046 // The delta from sp to ar is equal to the number of values on the stack
1047 // that will be consumed by this instruction (numPops) plus the number of
1048 // parameters pushed onto the stack so far that are not being consumed by
1049 // this instruction (numExtra). For the FPass* instructions, numExtra will
1050 // be equal to the first immediate argument (param id). For the FCall
1051 // instructions, numExtra will be 0 because all of the parameters on the
1052 // stack are already accounted for by numPops.
1053 int numPops
= instrNumPops(opcode
);
1054 int numExtra
= isFCallStar(*opcode
) ? 0 : getImm(opcode
, 0).u_IVA
;
1055 return numPops
+ numExtra
;
1058 const MInstrInfo
& getMInstrInfo(Op op
) {
1059 static const MInstrInfo mInstrInfo
[] = {
1060 #define MII(instr, attrs, bS, iS, vC, fN) \
1062 {MInstrAttr((attrs) & MIA_base), /* LL */ \
1063 MIA_none, /* LC */ \
1064 MIA_none, /* LH */ \
1065 MInstrAttr((attrs) & MIA_base), /* LGL */ \
1066 MInstrAttr((attrs) & MIA_base), /* LGC */ \
1067 MInstrAttr((attrs) & MIA_base), /* LNL */ \
1068 MInstrAttr((attrs) & MIA_base), /* LNC */ \
1069 MIA_none, /* LSL */ \
1070 MIA_none, /* LSC */ \
1071 MIA_none}, /* LR */ \
1072 {MInstrAttr((attrs) & MIA_intermediate), /* MEC */ \
1073 MInstrAttr((attrs) & MIA_intermediate), /* MPC */ \
1074 MInstrAttr((attrs) & MIA_intermediate), /* MEL */ \
1075 MInstrAttr((attrs) & MIA_intermediate), /* MPL */ \
1076 MInstrAttr((attrs) & MIA_intermediate), /* MET */ \
1077 MInstrAttr((attrs) & MIA_intermediate), /* MPT */ \
1078 MInstrAttr((attrs) & MIA_intermediate), /* MEI */ \
1079 MInstrAttr((attrs) & MIA_final)}, /* MW */ \
1080 unsigned(vC), bool((attrs) & MIA_new), bool((attrs) & MIA_final_get), \
1087 #define MII(instr_, attrs, bS, iS, vC, fN) \
1088 case Op##instr_##M: { \
1089 const MInstrInfo& mii = mInstrInfo[MI_##instr_##M]; \
1090 assert(mii.instr() == MI_##instr_##M); \
1095 default: not_reached();
1099 ///////////////////////////////////////////////////////////////////////////////