void emitColAddElemC(HTS& env) { if (!topC(env, 2)->isA(Type::Obj)) { return interpOne(env, Type::Obj, 3); } if (!topC(env, 1, DataTypeGeneric)->type(). subtypeOfAny(Type::Int, Type::Str)) { interpOne(env, Type::Obj, 3); return; } auto const val = popC(env); auto const key = popC(env); auto const coll = popC(env); push(env, gen(env, ColAddElemC, coll, key, val)); gen(env, DecRef, key); }
void emitPrint(HTS& env) { auto const type = topC(env)->type(); if (!type.subtypeOfAny(Type::Int, Type::Bool, Type::Null, Type::Str)) { interpOne(env, Type::Int, 1); return; } auto const cell = popC(env); Opcode op; if (type <= Type::Str) { op = PrintStr; } else if (type <= Type::Int) { op = PrintInt; } else if (type <= Type::Bool) { op = PrintBool; } else { assert(type <= Type::Null); op = Nop; } // the print helpers decref their arg, so don't decref pop'ed value if (op != Nop) { gen(env, op, cell); } push(env, cns(env, 1)); }
void emitParent(HTS& env) { auto const clss = curClass(env); if (clss == nullptr || clss->parent() == nullptr) { interpOne(env, Type::Cls, 0); } else { push(env, cns(env, clss->parent())); } }
void emitSelf(HTS& env) { auto const clss = curClass(env); if (clss == nullptr) { interpOne(env, Type::Cls, 0); } else { push(env, cns(env, clss)); } }
Block* makeExitSlow(IRGS& env) { auto const exit = env.unit.defBlock(Block::Hint::Unlikely); BlockPusher bp(*env.irb, makeMarker(env, bcOff(env)), exit); interpOne(env, *env.currentNormalizedInstruction); // If it changes the PC, InterpOneCF will get us to the new location. if (!opcodeChangesPC(env.currentNormalizedInstruction->op())) { gen(env, Jmp, makeExit(env, nextBcOff(env))); } return exit; }
void emitAGetC(HTS& env) { auto const name = topC(env); if (name->type().subtypeOfAny(Type::Obj, Type::Str)) { popC(env); implAGet(env, name); gen(env, DecRef, name); } else { interpOne(env, Type::Cls, 1); } }
void emitLateBoundCls(HTS& env) { auto const clss = curClass(env); if (!clss) { // no static context class, so this will raise an error interpOne(env, Type::Cls, 0); return; } auto const ctx = ldCtx(env); push(env, gen(env, LdClsCtx, ctx)); }
void emitColAddNewElemC(HTS& env) { if (!topC(env, 1)->isA(Type::Obj)) { return interpOne(env, Type::Obj, 2); } auto const val = popC(env); auto const coll = popC(env); // The AddNewElem helper decrefs its args, so don't decref pop'ed values. push(env, gen(env, ColAddNewElemC, coll, val)); }
void emitAddNewElemC(HTS& env) { if (!topC(env, 1)->isA(Type::Arr)) { return interpOne(env, Type::Arr, 2); } auto const val = popC(env); auto const arr = popC(env); // The AddNewElem helper decrefs its args, so don't decref pop'ed values. push(env, gen(env, AddNewElem, arr, val)); }
void emitBareThis(HTS& env, BareThisOp subop) { if (!curClass(env)) { interpOne(env, Type::InitNull, 0); // will raise notice and push null return; } auto const ctx = gen(env, LdCtx, fp(env)); if (subop == BareThisOp::NeverNull) { env.irb->setThisAvailable(); } else { gen(env, CheckCtxThis, makeExitSlow(env), ctx); } pushIncRef(env, gen(env, CastCtxThis, ctx)); }
void emitBindL(HTS& env, int32_t id) { if (curFunc(env)->isPseudoMain()) { interpOne(env, Type::BoxedInitCell, 1); return; } auto const ldPMExit = makePseudoMainExit(env); auto const newValue = popV(env); // Note that the IncRef must happen first, for correctness in a // pseudo-main: the destructor could decref the value again after // we've stored it into the local. pushIncRef(env, newValue); auto const oldValue = ldLoc(env, id, ldPMExit, DataTypeSpecific); stLocRaw(env, id, fp(env), newValue); gen(env, DecRef, oldValue); }
void emitAddElemC(HTS& env) { // This is just to peek at the type; it'll be consumed for real down below and // we don't want to constrain it if we're just going to InterpOne. auto const kt = topC(env, 1, DataTypeGeneric)->type(); Opcode op; if (kt <= Type::Int) { op = AddElemIntKey; } else if (kt <= Type::Str) { op = AddElemStrKey; } else { interpOne(env, Type::Arr, 3); return; } // val is teleported from the stack to the array, so we don't have to do any // refcounting. auto const val = popC(env, DataTypeGeneric); auto const key = popC(env); auto const arr = popC(env); // The AddElem* instructions decref their args, so don't decref pop'ed // values. push(env, gen(env, op, arr, key, val)); }
void interpOne(IRGS& env, Type outType, int popped) { InterpOneData idata { offsetFromIRSP(env, BCSPOffset{0}) }; interpOne(env, outType, popped, 1, idata); }
void interpOne(IRGS& env, Type outType, int popped) { InterpOneData idata { spOffBCFromIRSP(env) }; interpOne(env, outType, popped, 1, idata); }
void interpOne(IRGS& env, int popped) { InterpOneData idata { spOffBCFromIRSP(env) }; interpOne(env, folly::none, popped, 0, idata); }
void interpOne(IRGS& env, Type outType, int popped) { InterpOneData idata { bcSPOffset(env) }; interpOne(env, outType, popped, 1, idata); }