Allow using ExtraData-supplied immediates in native-calls.cpp
Ports CreateCont* opcodes to use extra data for their compile-time constants as a test case.
Esse commit está contido em:
@@ -1518,20 +1518,14 @@ D:Obj = CreateCl S0:ConstCls S1:ConstInt S2:FramePtr S3:StkPtr
|
||||
object. Saves the $this and Func* from ActRec S2 into the object,
|
||||
and returns the object.
|
||||
|
||||
D:Obj = CreateContFunc S0:ConstFunc S1:ConstFunc
|
||||
D:Obj = CreateContFunc<origFunc,generatorFunc>
|
||||
|
||||
Create a continuation object from function. Arguments:
|
||||
Create a continuation object for a generator function.
|
||||
|
||||
S0 - the "original" function
|
||||
S1 - the generator function
|
||||
D:Obj = CreateContMeth<origFunc,generatorFunc> S0:Ctx
|
||||
|
||||
D:Obj = CreateContMeth S0:ConstFunc S1:ConstFunc S2:Ctx
|
||||
|
||||
Create a continuation object from method. Arguments:
|
||||
|
||||
S0 - the "original" method
|
||||
S1 - the generator function
|
||||
S2 - the m_this/m_cls field of the current frame pointer
|
||||
Create a continuation object for a generator method. S0 is the
|
||||
m_this/m_cls field of the current frame pointer.
|
||||
|
||||
ContEnter S0:FramePtr S1:TCA S2:ConstInt S3:FramePtr
|
||||
|
||||
|
||||
@@ -340,7 +340,7 @@ Address CodeGenerator::cgInst(IRInstruction* inst) {
|
||||
void CodeGenerator::cg##opcode(IRInstruction*) {}
|
||||
|
||||
#define CALL_OPCODE(opcode) \
|
||||
void CodeGenerator::cg##opcode(IRInstruction* i) { cgCallNative(i); }
|
||||
void CodeGenerator::cg##opcode(IRInstruction* i) { cgCallNative(m_as, i); }
|
||||
|
||||
#define CALL_STK_OPCODE(opcode) \
|
||||
CALL_OPCODE(opcode) \
|
||||
@@ -1046,6 +1046,9 @@ void CodeGenerator::cgCallNative(Asm& a, IRInstruction* inst) {
|
||||
case VecKeyIS:
|
||||
argGroup.vectorKeyIS(src);
|
||||
break;
|
||||
case ExtraImm:
|
||||
argGroup.imm(arg.extraFunc(inst));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5768,7 +5771,7 @@ void CodeGenerator::cgVerifyParamCls(IRInstruction* inst) {
|
||||
// The native call for this instruction is the slow path that does
|
||||
// proper subtype checking. The comparison above is just to
|
||||
// short-circuit the overhead when the Classes are an exact match.
|
||||
ifThen(m_as, CC_NE, [&]{ cgCallNative(inst); });
|
||||
ifThen(m_as, CC_NE, [&]{ cgCallNative(m_as, inst); });
|
||||
}
|
||||
|
||||
static void emitTraceCall(CodeGenerator::Asm& as,
|
||||
|
||||
@@ -140,9 +140,6 @@ private:
|
||||
#undef O
|
||||
|
||||
// helper functions for code generation
|
||||
void cgCallNative(IRInstruction* inst) {
|
||||
cgCallNative(m_as, inst);
|
||||
}
|
||||
void cgCallNative(Asm& a, IRInstruction* inst);
|
||||
void doStackArgs(Asm&, ArgGroup&);
|
||||
void cgCallHelper(Asm&,
|
||||
|
||||
@@ -154,30 +154,8 @@ struct FPushCufData : IRExtraData {
|
||||
struct ConstData : IRExtraData {
|
||||
template<class T>
|
||||
explicit ConstData(T data)
|
||||
: m_dataBits(0)
|
||||
{
|
||||
static_assert(sizeof(T) <= sizeof m_dataBits,
|
||||
"Constant data was larger than supported");
|
||||
static_assert(std::is_pod<T>::value,
|
||||
"Constant data wasn't a pod?");
|
||||
const auto toCopy = promoteIfNeeded(data);
|
||||
std::memcpy(&m_dataBits, &toCopy, sizeof(toCopy));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct needsPromotion {
|
||||
static constexpr bool value = std::is_integral<T>::value ||
|
||||
std::is_same<T,bool>::value ||
|
||||
std::is_enum<T>::value;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<needsPromotion<T>::value, int64_t>::type
|
||||
promoteIfNeeded(T t) { return t; }
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<!needsPromotion<T>::value, T>::type
|
||||
promoteIfNeeded(T t) { return t; }
|
||||
: m_dataBits(constToBits(data))
|
||||
{}
|
||||
|
||||
template<class T>
|
||||
T as() const {
|
||||
@@ -324,9 +302,6 @@ struct CheckDefinedClsData : IRExtraData {
|
||||
* Offset and stack deltas for InterpOne.
|
||||
*/
|
||||
struct InterpOneData : IRExtraData {
|
||||
InterpOneData(Offset o, int64_t pop, int64_t push, Op op)
|
||||
: bcOff(o), cellsPopped(pop), cellsPushed(push), opcode(op) {}
|
||||
|
||||
// Offset of the instruction to interpret, in the Unit indicated by
|
||||
// the current Marker.
|
||||
Offset bcOff;
|
||||
@@ -341,6 +316,24 @@ struct InterpOneData : IRExtraData {
|
||||
Op opcode;
|
||||
};
|
||||
|
||||
/*
|
||||
* Information for creating continuation objects.
|
||||
* CreateCont{Func,Meth}.
|
||||
*/
|
||||
struct CreateContData : IRExtraData {
|
||||
CreateContData(const Func* origFunc, const Func* genFunc)
|
||||
: origFunc(origFunc)
|
||||
, genFunc(genFunc)
|
||||
{}
|
||||
|
||||
std::string show() const {
|
||||
return folly::to<std::string>(origFunc->fullName()->data(), "()");
|
||||
}
|
||||
|
||||
const Func* origFunc;
|
||||
const Func* genFunc;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define X(op, data) \
|
||||
@@ -405,6 +398,8 @@ X(SideExitGuardLoc, SideExitGuardData);
|
||||
X(SideExitGuardStk, SideExitGuardData);
|
||||
X(CheckDefinedClsEq, CheckDefinedClsData);
|
||||
X(InterpOne, InterpOneData);
|
||||
X(CreateContFunc, CreateContData);
|
||||
X(CreateContMeth, CreateContData);
|
||||
|
||||
#undef X
|
||||
|
||||
|
||||
@@ -1152,14 +1152,12 @@ void HhbcTranslator::emitCreateCont(Id funNameStrId) {
|
||||
auto const cont = origFunc->isMethod()
|
||||
? gen(
|
||||
CreateContMeth,
|
||||
cns(origFunc),
|
||||
cns(genFunc),
|
||||
CreateContData { origFunc, genFunc },
|
||||
gen(LdCtx, m_tb->fp(), cns(curFunc()))
|
||||
)
|
||||
: gen(
|
||||
CreateContFunc,
|
||||
cns(origFunc),
|
||||
cns(genFunc)
|
||||
CreateContData { origFunc, genFunc }
|
||||
);
|
||||
|
||||
ContParamMap params;
|
||||
@@ -3805,9 +3803,14 @@ void HhbcTranslator::emitInterpOne(Type outType, int popped) {
|
||||
void HhbcTranslator::emitInterpOne(Type outType, int popped, int pushed) {
|
||||
auto sp = spillStack();
|
||||
Unit *u = curFunc()->unit();
|
||||
gen(InterpOne, outType, InterpOneData(bcOff(), popped, pushed,
|
||||
u->getOpcode(bcOff())),
|
||||
m_tb->fp(), sp);
|
||||
|
||||
InterpOneData idata;
|
||||
idata.bcOff = bcOff();
|
||||
idata.cellsPopped = popped;
|
||||
idata.cellsPushed = pushed;
|
||||
idata.opcode = u->getOpcode(bcOff());
|
||||
|
||||
gen(InterpOne, outType, idata, m_tb->fp(), sp);
|
||||
assert(m_stackDeficit == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -475,8 +475,8 @@ O(InterpOneCF, ND, S(FramePtr) S(StkPtr) \
|
||||
C(Int), T|E|N|Mem|Refs|Er) \
|
||||
O(Spill, DofS(0), SUnk, Mem) \
|
||||
O(Reload, DofS(0), SUnk, Mem) \
|
||||
O(CreateContFunc, D(Obj), C(Func) C(Func), E|N|PRc) \
|
||||
O(CreateContMeth, D(Obj), C(Func) C(Func) S(Ctx), E|N|PRc) \
|
||||
O(CreateContFunc, D(Obj), NA, E|N|PRc) \
|
||||
O(CreateContMeth, D(Obj), S(Ctx), E|N|PRc) \
|
||||
O(ContEnter, ND, S(FramePtr) \
|
||||
S(TCA) C(Int) S(FramePtr), E|Mem) \
|
||||
O(ContPreNext, ND, S(Obj), E|Mem) \
|
||||
@@ -840,6 +840,46 @@ inline Type typeForConst(const ArrayData* ad) {
|
||||
return Type::Arr;
|
||||
}
|
||||
|
||||
/*
|
||||
* constToBits(T)
|
||||
*
|
||||
* Returns a constant value as a 8-byte word (in the shape it would
|
||||
* need to be to go into a register). Takes care to ensure that
|
||||
* various types are safely copied.
|
||||
*/
|
||||
|
||||
namespace constToBits_detail {
|
||||
template<class T>
|
||||
struct needs_promotion
|
||||
: std::integral_constant<
|
||||
bool,
|
||||
std::is_integral<T>::value ||
|
||||
std::is_same<T,bool>::value ||
|
||||
std::is_enum<T>::value
|
||||
>
|
||||
{};
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<needs_promotion<T>::value,uint64_t>::type
|
||||
promoteIfNeeded(T t) { return t; }
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<!needs_promotion<T>::value,T>::type
|
||||
promoteIfNeeded(T t) { return t; }
|
||||
}
|
||||
|
||||
template<class T>
|
||||
uintptr_t constToBits(T input) {
|
||||
uintptr_t ret;
|
||||
static_assert(sizeof(T) <= sizeof ret,
|
||||
"Constant data was larger than supported");
|
||||
static_assert(std::is_pod<T>::value,
|
||||
"Constant data wasn't a pod?");
|
||||
const auto toCopy = constToBits_detail::promoteIfNeeded(input);
|
||||
std::memcpy(&ret, &toCopy, sizeof toCopy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool cmpOpTypesMayReenter(Opcode, Type t0, Type t1);
|
||||
|
||||
class RawMemSlot {
|
||||
|
||||
@@ -780,6 +780,8 @@ void LinearScan::computePreColoringHint() {
|
||||
m_preColoringHint.add(inst->src(arg.srcIdx), 0, reg++);
|
||||
m_preColoringHint.add(inst->src(arg.srcIdx), 1, reg++);
|
||||
break;
|
||||
case ExtraImm:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -27,13 +27,28 @@ namespace HPHP { namespace JIT { namespace NativeCalls {
|
||||
using namespace HPHP::Transl;
|
||||
using namespace HPHP::Transl::TargetCache;
|
||||
|
||||
const SyncOptions SNone = SyncOptions::kNoSyncPoint;
|
||||
const SyncOptions SSync = SyncOptions::kSyncPoint;
|
||||
const SyncOptions SSyncAdj1 = SyncOptions::kSyncPointAdjustOne;
|
||||
namespace {
|
||||
|
||||
const DestType DSSA = DestType::SSA;
|
||||
const DestType DTV = DestType::TV;
|
||||
const DestType DNone = DestType::None;
|
||||
constexpr SyncOptions SNone = SyncOptions::kNoSyncPoint;
|
||||
constexpr SyncOptions SSync = SyncOptions::kSyncPoint;
|
||||
constexpr SyncOptions SSyncAdj1 = SyncOptions::kSyncPointAdjustOne;
|
||||
|
||||
constexpr DestType DSSA = DestType::SSA;
|
||||
constexpr DestType DTV = DestType::TV;
|
||||
constexpr DestType DNone = DestType::None;
|
||||
|
||||
template<class EDType, class MemberType>
|
||||
Arg extra(MemberType EDType::*ptr) {
|
||||
auto fun = [ptr] (IRInstruction* inst) {
|
||||
auto const extra = inst->extra<EDType>();
|
||||
return constToBits(extra->*ptr);
|
||||
};
|
||||
return Arg(fun);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* The table passed to s_callMap's constructor describes helpers calls
|
||||
@@ -65,8 +80,9 @@ const DestType DNone = DestType::None;
|
||||
* {VecKeyS, idx} - Like TV, but Str values are passed as a raw
|
||||
* StringData*, in a single register
|
||||
* {VecKeyIS, idx} - Like VecKeyS, including Int
|
||||
* extra(&EDStruct::member) -- extract an immediate from extra data
|
||||
*/
|
||||
static CallMap s_callMap({
|
||||
static CallMap s_callMap {
|
||||
/* Opcode, Func, Dest, SyncPoint, Args */
|
||||
{ConvBoolToArr, (TCA)convCellToArrHelper, DSSA, SNone,
|
||||
{{TV, 0}}},
|
||||
@@ -175,9 +191,12 @@ static CallMap s_callMap({
|
||||
|
||||
/* Continuation support helpers */
|
||||
{CreateContFunc, (TCA)&VMExecutionContext::createContFunc, DSSA, SNone,
|
||||
{{SSA, 0}, {SSA, 1}}},
|
||||
{ extra(&CreateContData::origFunc),
|
||||
extra(&CreateContData::genFunc) }},
|
||||
{CreateContMeth, (TCA)&VMExecutionContext::createContMeth, DSSA, SNone,
|
||||
{{SSA, 0}, {SSA, 1}, {SSA, 2}}},
|
||||
{ extra(&CreateContData::origFunc),
|
||||
extra(&CreateContData::genFunc),
|
||||
{SSA, 0} }},
|
||||
|
||||
/* VectorTranslator helpers */
|
||||
{BaseG, {FSSA, 0}, DSSA, SSync, {{TV, 1}, {SSA, 2}}},
|
||||
@@ -267,7 +286,7 @@ static CallMap s_callMap({
|
||||
|
||||
/* debug assert helpers */
|
||||
{DbgAssertPtr, (TCA)assertTv, DNone, SNone, {{SSA, 0}}},
|
||||
});
|
||||
};
|
||||
|
||||
CallMap::CallMap(CallInfoList infos) {
|
||||
for (auto const& info : infos) {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define incl_HPHP_VM_TRANSL_HOPT_NATIVECALLS_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include "hphp/runtime/vm/jit/types.h"
|
||||
@@ -51,19 +52,33 @@ enum ArgType : unsigned {
|
||||
TV,
|
||||
VecKeyS,
|
||||
VecKeyIS,
|
||||
ExtraImm,
|
||||
};
|
||||
|
||||
// Function that extracts the bits for an immediate value from extra
|
||||
// data.
|
||||
typedef std::function<uintptr_t (IRInstruction*)> ExtraDataBits;
|
||||
|
||||
struct Arg {
|
||||
Arg(ArgType type, unsigned srcIdx) : type(type), srcIdx(srcIdx) {}
|
||||
|
||||
explicit Arg(ExtraDataBits&& func)
|
||||
: type(ExtraImm)
|
||||
, srcIdx(-1u)
|
||||
, extraFunc(std::move(func))
|
||||
{}
|
||||
|
||||
ArgType type;
|
||||
unsigned srcIdx;
|
||||
ExtraDataBits extraFunc;
|
||||
};
|
||||
typedef std::vector<Arg> ArgVec;
|
||||
|
||||
struct CallInfo {
|
||||
Opcode op;
|
||||
FuncPtr func;
|
||||
DestType dest;
|
||||
SyncOptions sync;
|
||||
ArgVec args;
|
||||
std::vector<Arg> args;
|
||||
};
|
||||
|
||||
typedef std::initializer_list<CallInfo> CallInfoList;
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário