PhysRegSaver::PhysRegSaver(Vout& v, RegSet regs) : m_v(v) , m_regs(regs) { auto gpr = m_regs & abi().gp(); auto xmm = m_regs & abi().simd(); auto const sp = rsp(); m_adjust = gpr.size() & 0x1 ? 8 : 0; if (!xmm.empty()) { v << lea{sp[-16 * xmm.size()], sp}; int offset = 0; xmm.forEach([&] (PhysReg r) { v << storeups{r, sp[offset]}; offset += 16; }); } gpr.forEach([&] (PhysReg r) { v << push{r}; }); if (m_adjust) { v << lea{sp[-m_adjust], sp}; } }
std::string ChallengeResponse( opendnp3::IINField iin, uint8_t seq, uint32_t csq, uint16_t user, HMACType hmacType, ChallengeReason reason, std::string challengeDataHex ) { Buffer buffer(DEFAULT_MAX_APDU_SIZE); APDUResponse apdu(buffer.GetWSlice()); apdu.SetControl(AppControlField(true, true, false, false, seq)); apdu.SetFunction(FunctionCode::AUTH_RESPONSE); apdu.SetIIN(iin); HexSequence challengeBuff(challengeDataHex); Group120Var1 rsp( csq, user, hmacType, reason, challengeBuff.ToRSlice() ); apdu.GetWriter().WriteFreeFormat(rsp); return ToHex(apdu.ToRSlice()); }
TCA emitCallToExit(CodeBlock& cb, DataBlock& data, const UniqueStubs& us) { ppc64_asm::Assembler a { cb }; auto const start = a.frontier(); if (RuntimeOption::EvalHHIRGenerateAsserts) { vwrap(cb, data, [&] (Vout& v) { // Not doing it directly as rret(0) == rarg(0) on ppc64 Vreg ret_addr = v.makeReg(); // exittc address pushed on calltc/resumetc. v << copy{rsp(), ret_addr}; // We need to spill the return registers around the assert call. v << push{rret(0)}; v << push{rret(1)}; v << copy{ret_addr, rarg(0)}; v << call{TCA(assert_tc_saved_rip), RegSet(rarg(0))}; v << pop{rret(1)}; v << pop{rret(0)}; }); } // Discard the exittc address pushed on calltc/resumetc for balancing the // stack next. a.addi(rsp(), rsp(), 8); // Reinitialize r1 for the external code found after enterTCExit's stubret a.addi(rsfp(), rsp(), 8); // r31 should have the same value as caller's r1. Loading it soon on stubret. // (this corrupts the backchain, but it's not relevant as this frame will be // destroyed soon) a.std(rsfp(), rsp()[8]); // Emulate a ret to enterTCExit without actually doing one to avoid // unbalancing the return stack buffer. a.branchAuto(TCA(mcg->ustubs().enterTCExit)); return start; }
MANGO_NS_BEGIN std::string WireHandler::handle(const std::string& msg) const { try { std::unique_ptr<WireRequest> req(ROLE(WireCodec).decode(msg)); std::unique_ptr<WireResponse> rsp(req->run(ROLE(Runner))); return ROLE(WireCodec).encode(*rsp); } catch (...) { return "[\"fail\"]"; } }
TCA emitCallToExit(CodeBlock& cb) { X64Assembler a { cb }; // Emit a byte of padding. This is a kind of hacky way to avoid // hitting an assert in recordGdbStub when we call it with stub - 1 // as the start address. a.emitNop(1); auto const start = a.frontier(); if (RuntimeOption::EvalHHIRGenerateAsserts) { Label ok; a.emitImmReg(uintptr_t(enterTCExit), reg::rax); a.cmpq(reg::rax, *rsp()); a.je8 (ok); a.ud2(); asm_label(a, ok); } // Emulate a ret to enterTCExit without actually doing one to avoid // unbalancing the return stack buffer. The call from enterTCHelper() that // got us into the TC was popped off the RSB by the ret that got us to this // stub. a.addq(8, rsp()); if (a.jmpDeltaFits(TCA(enterTCExit))) { a.jmp(TCA(enterTCExit)); } else { // can't do a near jmp and a rip-relative load/jmp would require threading // through extra state to allocate a literal. use an indirect jump through // a register a.emitImmReg(uintptr_t(enterTCExit), reg::rax); a.jmp(reg::rax); } // On a backtrace, gdb tries to locate the calling frame at address // returnRIP-1. However, for the first VM frame, there is no code at // returnRIP-1, since the AR was set up manually. For this frame, // record the tracelet address as starting from this callToExit-1, // so gdb does not barf. return start; }
TCA emitCallToExit(CodeBlock& cb, DataBlock& data, const UniqueStubs& /*us*/) { ppc64_asm::Assembler a { cb }; auto const start = a.frontier(); if (RuntimeOption::EvalHHIRGenerateAsserts) { vwrap(cb, data, [&] (Vout& v) { // Not doing it directly as rret(0) == rarg(0) on ppc64 Vreg ret_addr = v.makeReg(); // exittc address pushed on calltc/resumetc. v << copy{rsp(), ret_addr}; // We need to spill the return registers around the assert call. v << push{rret(0)}; v << push{rret(1)}; v << copy{ret_addr, rarg(0)}; v << call{TCA(assert_tc_saved_rip), RegSet(rarg(0))}; v << pop{rret(1)}; v << pop{rret(0)}; }); } // Discard the exittc address pushed on calltc/resumetc for balancing the // stack next. a.addi(rsp(), rsp(), 8); // Reinitialize r1 for the external code found after enterTCExit's stubret a.addi(rsfp(), rsp(), 8); // Restore the rvmfp when leaving the VM, which must be the same of rsfp. a.mr(rvmfp(), rsfp()); // Emulate a ret to enterTCExit without actually doing one to avoid // unbalancing the return stack buffer. a.branchAuto(TCA(tc::ustubs().enterTCExit)); return start; }
/* * Helper for the freeLocalsHelpers which does the actual work of decrementing * a value's refcount or releasing it. * * This helper is reached via call from the various freeLocalHelpers. It * expects `tv' to be the address of a TypedValue with refcounted type `type' * (though it may be static, and we will do nothing in that case). * * The `live' registers must be preserved across any native calls (and * generally left untouched). */ static TCA emitDecRefHelper(CodeBlock& cb, DataBlock& data, CGMeta& fixups, PhysReg tv, PhysReg type, RegSet live) { return vwrap(cb, data, fixups, [&] (Vout& v) { // We use the first argument register for the TV data because we might pass // it to the native release call. It's not live when we enter the helper. auto const data = rarg(0); v << load{tv[TVOFF(m_data)], data}; auto destroy = [&](Vout& v) { PhysRegSaver prs{v, live}; auto const dword_size = sizeof(int64_t); // saving return value on the stack, but keeping it 16-byte aligned v << mflr{rfuncln()}; v << lea {rsp()[-2 * dword_size], rsp()}; v << store{rfuncln(), rsp()[0]}; // The refcount is exactly 1; release the value. // Avoid 'this' pointer overwriting by reserving it as an argument. v << callm{lookupDestructor(v, type), arg_regs(1)}; // Between where r1 is now and the saved RIP of the call into the // freeLocalsHelpers stub, we have all the live regs we pushed, plus the // stack size reserved for the LR saved right above and the LR offset in // the frame. v << syncpoint{makeIndirectFixup(prs.dwordsPushed())}; // fallthru // restore the return value from the stack v << load{rsp()[0], rfuncln()}; v << lea {rsp()[2 * dword_size], rsp()}; v << mtlr{rfuncln()}; }; auto const sf = emitCmpRefCount(v, OneReference, data); if (one_bit_refcount) { ifThen(v, CC_E, sf, destroy); } else { ifThen(v, CC_NL, sf, [&] (Vout& v) { // The refcount is positive, so the value is refcounted. We need to // either decref or release. ifThen(v, CC_NE, sf, [&] (Vout& v) { // The refcount is greater than 1; decref it. emitDecRefCount(v, data); v << ret{live}; }); destroy(v); }); } // Either we did a decref, or the value was static. v << ret{live}; }); }
/* * Helper for the freeLocalsHelpers which does the actual work of decrementing * a value's refcount or releasing it. * * This helper is reached via call from the various freeLocalHelpers. It * expects `tv' to be the address of a TypedValue with refcounted type `type' * (though it may be static, and we will do nothing in that case). * * The `live' registers must be preserved across any native calls (and * generally left untouched). */ static TCA emitDecRefHelper(CodeBlock& cb, DataBlock& data, CGMeta& fixups, PhysReg tv, PhysReg type, RegSet live) { return vwrap(cb, data, fixups, [&] (Vout& v) { // Set up frame linkage to avoid an indirect fixup. v << pushp{rlr(), rfp()}; v << copy{rsp(), rfp()}; // We use the first argument register for the TV data because we might pass // it to the native release call. It's not live when we enter the helper. auto const data = rarg(0); v << load{tv[TVOFF(m_data)], data}; auto const sf = v.makeReg(); v << cmplim{1, data[FAST_REFCOUNT_OFFSET], sf}; ifThen(v, CC_NL, sf, [&] (Vout& v) { // The refcount is positive, so the value is refcounted. We need to // either decref or release. ifThen(v, CC_NE, sf, [&] (Vout& v) { // The refcount is greater than 1; decref it. v << declm{data[FAST_REFCOUNT_OFFSET], v.makeReg()}; // Pop FP/LR and return v << popp{rfp(), rlr()}; v << ret{live}; }); // Note that the stack is aligned since we called to this helper from an // stack-unaligned stub. PhysRegSaver prs{v, live}; // The refcount is exactly 1; release the value. // Avoid 'this' pointer overwriting by reserving it as an argument. v << callm{lookupDestructor(v, type), arg_regs(1)}; // Between where %rsp is now and the saved RIP of the call into the // freeLocalsHelpers stub, we have all the live regs we pushed, plus the // saved RIP of the call from the stub to this helper. v << syncpoint{makeIndirectFixup(prs.dwordsPushed())}; // fallthru }); // Either we did a decref, or the value was static. // Pop FP/LR and return v << popp{rfp(), rlr()}; v << ret{live}; }); }
/* * Helper for the freeLocalsHelpers which does the actual work of decrementing * a value's refcount or releasing it. * * This helper is reached via call from the various freeLocalHelpers. It * expects `tv' to be the address of a TypedValue with refcounted type `type' * (though it may be static, and we will do nothing in that case). * * The `live' registers must be preserved across any native calls (and * generally left untouched). */ static TCA emitDecRefHelper(CodeBlock& cb, DataBlock& data, CGMeta& fixups, PhysReg tv, PhysReg type, RegSet live) { return vwrap(cb, data, fixups, [&] (Vout& v) { // Set up frame linkage to avoid an indirect fixup. v << stublogue{true}; v << copy{rsp(), rfp()}; // We use the first argument register for the TV data because we might pass // it to the native release call. It's not live when we enter the helper. auto const data = rarg(0); v << load{tv[TVOFF(m_data)], data}; auto destroy = [&](Vout& v) { // Note that the stack is aligned since we called to this helper from an // stack-unaligned stub. PhysRegSaver prs{v, live}; // The refcount is exactly 1; release the value. // Avoid 'this' pointer overwriting by reserving it as an argument. // There's no need for a fixup, because we setup a frame on the c++ // stack. v << callm{lookupDestructor(v, type), arg_regs(1)}; // fallthru }; auto const sf = emitCmpRefCount(v, OneReference, data); if (one_bit_refcount) { ifThen(v, CC_E, sf, destroy); } else { ifThen(v, CC_NL, sf, [&] (Vout& v) { // The refcount is positive, so the value is refcounted. We need to // either decref or release. ifThen(v, CC_NE, sf, [&] (Vout& v) { // The refcount is greater than 1; decref it. emitDecRefCount(v, data); v << stubret{live, true}; }); destroy(v); }); } // Either we did a decref, or the value was static. v << stubret{live, true}; }); }
/****************************************************************** Function: ProcessDList Purpose: This function is called when there is a Dlist to be processed. (High level GFX list) input: none output: none *******************************************************************/ EXPORT void CALL ProcessDList(void) { // GX_SetCopyClear ((GXColor){0,0,0,255}, 0x000000); // GX_SetCopyClear ((GXColor){0,0,0,255}, 0xFFFFFF); // GX_CopyDisp (vi->getScreenPointer(), GX_TRUE); //clear the EFB before executing new Dlist // GX_DrawDone (); RSP rsp(gfxInfo); // vi->updateDEBUG(); /*static int firstTime=0; if(firstTime< 1) { firstTime++; bool found = true; int level = 1; OSTask_t *task = (OSTask_t*)(gfxInfo.DMEM+0xFC0); char *udata = (char*)gfxInfo.RDRAM + task->ucode_data; int length = task->ucode_data_size; while (found) { printf("searching strings... (level %d)\n", level); found = false; for (int i=level; i<length; i++) { if(udata[i^3] >= 32 && udata[i^3] <=126) { bool isString = true; for (int j=1; j<=level; j++) if (udata[(i-j)^3] < 32 || udata[(i-j)^3] > 126) isString = false; if (isString) { found = true; for (int j=level; j>=0; j--) printf("%c", udata[(i-j)^3]); printf("\n"); getchar(); } } } level++; } }*/ }
TEST(ResponseTest, test_gen_response) { CodeMsg cm = {0, "OK"}; Response rsp(cm); rsp.set_head("Allow", "GET"); Json::Value root; root["code"] = 0; rsp.set_body(root); int ret = rsp.gen_response("HTTP/1.0", false); ASSERT_EQ(0, ret); char buf[1024]; int read_size; ret = rsp.readsome(buf, sizeof(buf), read_size); ASSERT_EQ(0, ret); // read eof ret = rsp.rollback(10); // rollback a little ASSERT_EQ(0, ret); int except_size = 5; ret = rsp.readsome(buf, except_size, read_size); // read a little which not reach eof ASSERT_EQ(NEED_MORE_STATUS, ret); ASSERT_EQ(except_size, read_size); }
/****************************************************************** Function: ProcessDList Purpose: This function is called when there is a Dlist to be processed. (High level GFX list) input: none output: none *******************************************************************/ EXPORT void CALL ProcessDList(void) { RSP rsp(gfxInfo); /*static int firstTime=0; if(firstTime< 1) { firstTime++; bool found = true; int level = 1; OSTask_t *task = (OSTask_t*)(gfxInfo.DMEM+0xFC0); char *udata = (char*)gfxInfo.RDRAM + task->ucode_data; int length = task->ucode_data_size; while (found) { printf("searching strings... (level %d)\n", level); found = false; for (int i=level; i<length; i++) { if(udata[i^3] >= 32 && udata[i^3] <=126) { bool isString = true; for (int j=1; j<=level; j++) if (udata[(i-j)^3] < 32 || udata[(i-j)^3] > 126) isString = false; if (isString) { found = true; for (int j=level; j>=0; j--) printf("%c", udata[(i-j)^3]); printf("\n"); getchar(); } } } level++; } }*/ }
std::string ChallengeReply( uint8_t appSeq, uint32_t challengeSeqNum, uint16_t userNum, std::string hmacHex ) { Buffer buffer(DEFAULT_MAX_APDU_SIZE); APDURequest apdu(buffer.GetWSlice()); apdu.SetControl(AppControlField(true, true, false, false, appSeq)); apdu.SetFunction(FunctionCode::AUTH_REQUEST); HexSequence hmacBuff(hmacHex); Group120Var2 rsp(challengeSeqNum, userNum, hmacBuff.ToRSlice()); apdu.GetWriter().WriteFreeFormat(rsp); return ToHex(apdu.ToRSlice()); }
void MmspSession::on_play( boost::system::error_code const & ec) { LOG_INFO("[on_play] session_id:" << session_id_ << " ec:" << ec.message()); --play_count_; if (!post_resp_.empty() && play_count_ == 0) { boost::system::error_code ec1; response_type resp; resp.swap(post_resp_); resp(ec1); } else if (!ec) { MmspMessage msg; MmspDataReportEndOfStream & rsp(msg.get<MmspDataReportEndOfStream>()); rsp.playIncarnation = play_incarnation_; boost::system::error_code ec1; write(msg, ec1); } else if (ec != boost::asio::error::operation_aborted) { boost::system::error_code ec1; cancel(ec1); } }
PhysRegSaver::~PhysRegSaver() { auto& v = m_v; auto const sp = rsp(); if (m_adjust) { v << lea{sp[m_adjust], sp}; } auto gpr = m_regs & abi().gp(); auto xmm = m_regs & abi().simd(); gpr.forEachR([&] (PhysReg r) { v << pop{r}; }); if (!xmm.empty()) { int offset = 0; xmm.forEach([&] (PhysReg r) { v << loadups{sp[offset], r}; offset += 16; }); v << lea{sp[offset], sp}; } }
int main(int argc, const char * argv[]) { const double pi = std::abs(std::atan2(0,-1)); Floorplan flp; double wall_loss = 2.0; // layered drywall double angle_loss = 5.0 / (pi/2); // 5.0dB for 90 degrees double exterior_wall_loss = 15.0; // thick concrete int size_x = 15; int size_y = 15; unsigned seed = 0; unsigned st_seed = 0; int office = 0; double office_x = 3.0; double office_y = 4.0; double hall_width = 2.0; const char *save = 0; const char *load = 0; const char *saveimage = 0; std::vector<int> pathset; bool display_paths = 1; bool label_floorplan = 1; double grid_measurements = 5.0; double step = 0.5; bool truncate_dijkstra = true; // quick hack for various computations // mode 0 == s-t breakpoint path computation // mode 1 == all destinations // mode 2 == approx all dest // mode 3 == heatmap // mode 4 == random s-t pair breakpoint evaluation // mode 5 == coverage // mode 6 == ratio_all_measurement int mode = 0; int num_experiments = 100; double p = 20.0/std::log(10.0); // This program finds the paths from pts[0] to pts[1] Point pts[3]; pts[0].x = 2.5; pts[0].y = 1.5; pts[1].x = 9.3; pts[1].y = 12.3; pts[2].x = 7.9; pts[2].y = 11.1; int limit = 50; int argi = 1; while (argi < argc - 1) { if (strcmp(argv[argi], "-sx") == 0) size_x = atoi(argv[++argi]); else if (strcmp(argv[argi], "-sy") == 0) size_y = atoi(argv[++argi]); else if (strcmp(argv[argi], "-wl") == 0) wall_loss = atof(argv[++argi]); else if (strcmp(argv[argi], "-al") == 0) angle_loss = atof(argv[++argi]); else if (strcmp(argv[argi], "-el") == 0) exterior_wall_loss = atof(argv[++argi]); else if (strcmp(argv[argi], "-sd") == 0) seed = atoi(argv[++argi]); else if (strcmp(argv[argi], "-st") == 0) st_seed = atoi(argv[++argi]); else if (strcmp(argv[argi], "-s") == 0) save = argv[++argi]; else if (strcmp(argv[argi], "-l") == 0) load = argv[++argi]; else if (strcmp(argv[argi], "-w") == 0) saveimage = argv[++argi]; else if (strcmp(argv[argi], "-p0x") == 0) pts[0].x = atof(argv[++argi]); else if (strcmp(argv[argi], "-p0y") == 0) pts[0].y = atof(argv[++argi]); else if (strcmp(argv[argi], "-p1x") == 0) pts[1].x = atof(argv[++argi]); else if (strcmp(argv[argi], "-p1y") == 0) pts[1].y = atof(argv[++argi]); else if (strcmp(argv[argi], "-dp") == 0) display_paths = atoi(argv[++argi]); else if (strcmp(argv[argi], "-gm") == 0) grid_measurements = atof(argv[++argi]); else if (strcmp(argv[argi], "-step") == 0) step = atof(argv[++argi]); else if (strcmp(argv[argi], "-mode") == 0) mode = atoi(argv[++argi]); else if (strcmp(argv[argi], "-p") == 0) p = atof(argv[++argi]); else if (strcmp(argv[argi], "-office") == 0) office = atoi(argv[++argi]); else if (strcmp(argv[argi], "-office_x") == 0) office_x = atof(argv[++argi]); else if (strcmp(argv[argi], "-office_y") == 0) office_y = atof(argv[++argi]); else if (strcmp(argv[argi], "-hall_width") == 0) hall_width = atof(argv[++argi]); else if (strcmp(argv[argi], "-n") == 0) num_experiments = atoi(argv[++argi]); else if (strcmp(argv[argi], "-path") == 0) pathset.push_back(atoi(argv[++argi])); else if (strcmp(argv[argi], "-truncate") == 0) truncate_dijkstra = atoi(argv[++argi]); else if (strcmp(argv[argi], "-label") == 0) label_floorplan = atoi(argv[++argi]); argi++; } if (load) { double start_time = util::cpu_timer(); flp.load(load); std::cerr << "Floorplan loaded in " << (util::cpu_timer() - start_time) << " cpu seconds." << std::endl; } else { double start_time = util::cpu_timer(); if (office == 1) { flp.genOffice1(size_x, size_y, office_x, office_y, hall_width, wall_loss, angle_loss, exterior_wall_loss); } else if (office == 2) { flp.genOffice2(size_x, size_y, office_x, office_y, hall_width, wall_loss, angle_loss, exterior_wall_loss); } else if (office == 3) { flp.genOffice3(size_x, size_y, office_x, office_y, hall_width, wall_loss, angle_loss, exterior_wall_loss); } else if (office == 4) { flp.genOffice4(size_x, size_y, office_x, office_y, hall_width, wall_loss, angle_loss, exterior_wall_loss); } else { flp.genRandomFloorplan(size_x, size_y, wall_loss, angle_loss, exterior_wall_loss, seed); } std::cerr << "Floorplan generated in " << (util::cpu_timer() - start_time) << " cpu seconds." << std::endl; } std::cerr << "Floorplan contains " << flp.getNumCorners() << " corners and " << flp.getNumWalls() << " walls." << std::endl; if (save) { double start_time = util::cpu_timer(); flp.save(save); std::cerr << "Floorplan saved in " << (util::cpu_timer() - start_time) << " cpu seconds." << std::endl; } int npts = 2; if (mode == 1 || mode == 2) npts = 3; if (mode == 3) label_floorplan = false; DominantPath dmp(&flp, npts, pts, label_floorplan); if (mode != 3 && mode != 4 && mode != 6) { double geng2_start = util::cpu_timer(); dmp.generateG2(); std::cerr << "G2 generated " << dmp.numG2Points() << " points, " << dmp.numG2Links() << " links in " << (util::cpu_timer() - geng2_start) << " cpu seconds." << std::endl; } Path *paths = new Path[limit]; int npaths = 2; if (mode == 0) { double break_start = util::cpu_timer(); int count = dmp.BreakPoints(0, 1, limit, paths, npaths); std::cerr << count << " relaxations performed in " << (util::cpu_timer() - break_start) << " cpu seconds." << std::endl; if (display_paths) { dmp.printPaths(npaths, paths, p, saveimage, pathset); } for (int i = 0; i < npaths; i++) { printf("%f\n", (paths[i].L+p*std::log(paths[i].D))); } } else if (mode == 1) { double break_start = util::cpu_timer(); dmp.Dijkstra_all_dest(100, paths); std::cerr << "Dijkstra_all_dest finished in " << (util::cpu_timer() - break_start) << " cpu seconds." << std::endl; } else if (mode == 2) { double break_start = util::cpu_timer(); dmp.Approx_all_dest(p, step, paths, truncate_dijkstra); std::cerr << "Approx_all_dest finished in " << (util::cpu_timer() - break_start) << " cpu seconds." << std::endl; } else if (mode == 3) { dmp.heatmap(p, step, pts[0].x, pts[0].y, flp.getWidth(), flp.getHeight(), grid_measurements, saveimage, truncate_dijkstra); } else if (mode == 4) { // for testing Random_st_pairs rsp(&flp, p); rsp.size_x = flp.getWidth(); rsp.size_y = flp.getHeight(); rsp.test(num_experiments, st_seed); } else if (mode == 5) { double break_start = util::cpu_timer(); coverage(dmp); std::cerr << "coverage finished in " << (util::cpu_timer() - break_start) << " cpu seconds." << std::endl; } else if (mode == 6) { dmp.ratio_all_measurement(step, pts[0].x, pts[0].y, flp.getWidth(), flp.getHeight(), grid_measurements, false, false, true); } delete [] paths; return 0; }
void lower_vcall(Vunit& unit, Inst& inst, Vlabel b, size_t i) { auto& blocks = unit.blocks; auto const& vinstr = blocks[b].code[i]; auto const is_vcall = vinstr.op == Vinstr::vcall; auto const vcall = vinstr.vcall_; auto const vinvoke = vinstr.vinvoke_; // We lower vinvoke in two phases, and `inst' is overwritten after the first // phase. We need to save any of its parameters that we care about in the // second phase ahead of time. auto const& vargs = unit.vcallArgs[inst.args]; auto const dests = unit.tuples[inst.d]; auto const destType = inst.destType; auto const scratch = unit.makeScratchBlock(); SCOPE_EXIT { unit.freeScratchBlock(scratch); }; Vout v(unit, scratch, vinstr.irctx()); // Push stack arguments, in reverse order. Push in pairs without padding // except for the last argument (pushed first) which should be padded if // there are an odd number of arguments. auto numArgs = vargs.stkArgs.size(); int32_t const adjust = (numArgs & 0x1) ? sizeof(uintptr_t) : 0; if (adjust) { // Using InvalidReg below fails SSA checks and simplify pass, so just // push the arg twice. It's on the same cacheline and will actually // perform faster than an explicit lea. v << pushp{vargs.stkArgs[numArgs - 1], vargs.stkArgs[numArgs - 1]}; --numArgs; } for (auto i2 = numArgs; i2 >= 2; i2 -= 2) { v << pushp{vargs.stkArgs[i2 - 1], vargs.stkArgs[i2 - 2]}; } // Get the arguments in the proper registers. RegSet argRegs; auto doArgs = [&] (const VregList& srcs, PhysReg (*r)(size_t)) { VregList argDests; for (size_t i2 = 0, n = srcs.size(); i2 < n; ++i2) { auto const reg = r(i2); argDests.push_back(reg); argRegs |= reg; } if (argDests.size()) { v << copyargs{v.makeTuple(srcs), v.makeTuple(std::move(argDests))}; } }; doArgs(vargs.indRetArgs, rarg_ind_ret); doArgs(vargs.args, rarg); doArgs(vargs.simdArgs, rarg_simd); // Emit the appropriate call instruction sequence. emitCall(v, inst.call, argRegs); // Handle fixup and unwind information. if (inst.fixup.isValid()) { v << syncpoint{inst.fixup}; } if (!is_vcall) { auto& targets = vinvoke.targets; v << unwind{{targets[0], targets[1]}}; // Insert an lea fixup for any stack args at the beginning of the catch // block. if (auto rspOffset = ((vargs.stkArgs.size() + 1) & ~1) * sizeof(uintptr_t)) { auto& taken = unit.blocks[targets[1]].code; assertx(taken.front().op == Vinstr::landingpad || taken.front().op == Vinstr::jmp); Vinstr vi { lea{rsp()[rspOffset], rsp()}, taken.front().irctx() }; if (taken.front().op == Vinstr::jmp) { taken.insert(taken.begin(), vi); } else { taken.insert(taken.begin() + 1, vi); } } // Write out the code so far to the end of b. Remaining code will be // emitted to the next block. vector_splice(blocks[b].code, i, 1, blocks[scratch].code); } else if (vcall.nothrow) { v << nothrow{}; } // For vinvoke, `inst' is no longer valid after this point. // Copy the call result to the destination register(s). switch (destType) { case DestType::TV: static_assert(offsetof(TypedValue, m_data) == 0, ""); static_assert(offsetof(TypedValue, m_type) == 8, ""); if (dests.size() == 2) { switch (arch()) { case Arch::X64: // fall through case Arch::PPC64: v << copy2{rret(0), rret(1), dests[0], dests[1]}; break; case Arch::ARM: // For ARM64 we need to clear the bits 8..31 from the type value. // That allows us to use the resulting register values in // type comparisons without the need for truncation there. // We must not touch bits 63..32 as they contain the AUX data. v << copy{rret(0), dests[0]}; v << andq{v.cns(0xffffffff000000ff), rret(1), dests[1], v.makeReg()}; break; } } else { // We have cases where we statically know the type but need the value // from native call. Even if the type does not really need a register // (e.g., InitNull), a Vreg is still allocated in assignRegs(), so the // following assertion holds. assertx(dests.size() == 1); v << copy{rret(0), dests[0]}; } break; case DestType::SIMD: static_assert(offsetof(TypedValue, m_data) == 0, ""); static_assert(offsetof(TypedValue, m_type) == 8, ""); assertx(dests.size() == 1); pack2(v, rret(0), rret(1), dests[0]); break; case DestType::SSA: case DestType::Byte: assertx(dests.size() == 1); assertx(dests[0].isValid()); // Copy the single-register result to dests[0]. v << copy{rret(0), dests[0]}; break; case DestType::SSAPair: assertx(dests.size() == 2); assertx(dests[0].isValid()); assertx(dests[1].isValid()); // Copy the result pair to dests. v << copy2{rret(0), rret(1), dests[0], dests[1]}; break; case DestType::Dbl: // Copy the single-register result to dests[0]. assertx(dests.size() == 1); assertx(dests[0].isValid()); v << copy{rret_simd(0), dests[0]}; break; case DestType::Indirect: // Already asserted above break; case DestType::None: assertx(dests.empty()); break; } if (vargs.stkArgs.size() > 0) { auto const delta = safe_cast<int32_t>( vargs.stkArgs.size() * sizeof(uintptr_t) + adjust ); v << lea{rsp()[delta], rsp()}; } // Insert new instructions to the appropriate block. if (is_vcall) { vector_splice(blocks[b].code, i, 1, blocks[scratch].code); } else { vector_splice(blocks[vinvoke.targets[0]].code, 0, 0, blocks[scratch].code); } }
TCA emitFreeLocalsHelpers(CodeBlock& cb, DataBlock& data, UniqueStubs& us) { // The address of the first local is passed in the second argument register. // We use the third and fourth as scratch registers. auto const local = rarg(1); auto const last = rarg(2); auto const type = rarg(3); CGMeta fixups; TCA freeLocalsHelpers[kNumFreeLocalsHelpers]; TCA freeManyLocalsHelper; // This stub is very hot; keep it cache-aligned. align(cb, &fixups, Alignment::CacheLine, AlignContext::Dead); auto const release = emitDecRefHelper(cb, data, fixups, local, type, local | last); auto const decref_local = [&] (Vout& v) { auto const sf = v.makeReg(); // We can't use emitLoadTVType() here because it does a byte load, and we // need to sign-extend since we use `type' as a 32-bit array index to the // destructor table. v << loadzbl{local[TVOFF(m_type)], type}; emitCmpTVType(v, sf, KindOfRefCountThreshold, type); ifThen(v, CC_G, sf, [&] (Vout& v) { v << call{release, arg_regs(3)}; }); }; auto const next_local = [&] (Vout& v) { v << addqi{static_cast<int>(sizeof(TypedValue)), local, local, v.makeReg()}; }; alignJmpTarget(cb); freeManyLocalsHelper = vwrap(cb, data, [&] (Vout& v) { // We always unroll the final `kNumFreeLocalsHelpers' decrefs, so only loop // until we hit that point. v << lea{rvmfp()[localOffset(kNumFreeLocalsHelpers - 1)], last}; // Set up frame linkage to avoid an indirect fixup. v << copy{rsp(), rfp()}; doWhile(v, CC_NZ, {}, [&] (const VregList& in, const VregList& out) { auto const sf = v.makeReg(); decref_local(v); next_local(v); v << cmpq{local, last, sf}; return sf; } ); }); for (auto i = kNumFreeLocalsHelpers - 1; i >= 0; --i) { freeLocalsHelpers[i] = vwrap(cb, data, [&] (Vout& v) { decref_local(v); if (i != 0) next_local(v); }); } // All the stub entrypoints share the same ret. vwrap(cb, data, fixups, [] (Vout& v) { v << popp{rfp(), rlr()}; v << ret{}; }); // Create a table of branches us.freeManyLocalsHelper = vwrap(cb, data, [&] (Vout& v) { v << pushp{rlr(), rfp()}; // rvmfp() is needed by the freeManyLocalsHelper stub above, so frame // linkage setup is deferred until after its use in freeManyLocalsHelper. v << jmpi{freeManyLocalsHelper}; }); for (auto i = kNumFreeLocalsHelpers - 1; i >= 0; --i) { us.freeLocalsHelpers[i] = vwrap(cb, data, [&] (Vout& v) { // We set up frame linkage to avoid an indirect fixup. v << pushp{rlr(), rfp()}; v << copy{rsp(), rfp()}; v << jmpi{freeLocalsHelpers[i]}; }); } // FIXME: This stub is hot, so make sure to keep it small. #if 0 always_assert(Stats::enabled() || (cb.frontier() - release <= 4 * x64::cache_line_size())); #endif fixups.process(nullptr); return release; }
void buildFakeAngTree(const Char_t* outtag, const Float_t timereso, // ns const UInt_t simevts=1, const Float_t thetaOpt=400, // deg const Float_t phiOpt=400, // deg const Float_t coneOpt=400, // deg const UInt_t rseed=23192, const Float_t norm=100.0, // mV const Float_t noise=20.0, // mV const Char_t* outdir="/data/users/cjreed/work/simEvts", const Char_t* infn="/w2/arianna/jtatar/nt.sigtemps.root", const Char_t* geofn="/data/users/cjreed/work/" "BounceStudy/Stn10/" "CampSiteGeometry.root") { // if any of the angles (thetaOpt, phiOpt, coneOpt) > 360, a random // value will be used instead // // expect angles in the Templates tree to be in degrees // // expect the waveforms in the Templates tree to have amplitude 1 TRandom3 rnd(rseed); geof = TFile::Open(geofn); gg = dynamic_cast<TGeoManager*>(geof->Get("CampSite2013")); site = dynamic_cast<const TSnGeoStnSite*>(gg->GetTopVolume()); TVector3 pos[NSnConstants::kNchans], nvec[NSnConstants::kNchans]; for (UChar_t ch=0; ch<NSnConstants::kNchans; ++ch) { site->SetLPDAPosition(ch, pos[ch]); site->SetLPDANormalVec(ch, nvec[ch]); Printf("pos ch%d:",ch); pos[ch].Print(); Printf("normal ch%d:",ch); nvec[ch].Print(); } TArrayD zeros(6); inf = TFile::Open(infn); nnt = dynamic_cast<TTree*>(inf->Get("Templates")); TString infns(infn); TString indir; Int_t fl(0); if (infns.Contains('/')) { fl = infns.Last('/') + 1; indir = infns(0, fl-1); } TString plaininfn = infns(fl, infns.Length()-fl); TString outfn = Form("%s/FakeEvts.%s.%s", outdir, outtag, plaininfn.Data()); outf = TFile::Open(outfn.Data(),"recreate"); outf->cd(); TParameter<Float_t> trp("TimeResolution", timereso); trp.Write(); TParameter<Float_t> nmp("Normalization", norm); nmp.Write(); TParameter<Float_t> nop("NoiseRMS", noise); nop.Write(); TParameter<UInt_t> rsp("RandomSeed", rseed); rsp.Write(); TSnCalWvData* wave = new TSnCalWvData; Float_t eang(0), hang(0), hpf(0), limiter(0), coneang(0); Bool_t bice(kFALSE); nnt->SetBranchAddress("wave.",&wave); nnt->SetBranchAddress("EAng",&eang); nnt->SetBranchAddress("HAng",&hang); nnt->SetBranchAddress("hpf",&hpf); nnt->SetBranchAddress("limiter",&limiter); nnt->SetBranchAddress("coneAng",&coneang); nnt->SetBranchAddress("bIce",&bice); // to look up waveform for EAng, HAng nnt->BuildIndex("EAng + (1000*HAng)","coneAng"); // find the max angles Printf("finding allowed angles..."); std::set<Float_t> Eangs, Hangs, Cangs; const Long64_t nnents = nnt->GetEntries(); for (Long64_t i=0; i<nnents; ++i) { nnt->GetEntry(i); Eangs.insert(eang); Hangs.insert(hang); Cangs.insert(coneang); } #ifdef DEBUG std::set<Float_t>::const_iterator ang, end = Eangs.end(); Printf("EAngs:"); for (ang=Eangs.begin(); ang!=end; ++ang) { Printf("%g",*ang); } Printf("HAngs:"); for (ang=Hangs.begin(), end=Hangs.end(); ang!=end; ++ang) { Printf("%g",*ang); } Printf("ConeAngs:"); for (ang=Cangs.begin(), end=Cangs.end(); ang!=end; ++ang) { Printf("%g",*ang); } #endif Float_t theta(0), phi(0), cone(0); Float_t EAng[NSnConstants::kNchans], HAng[NSnConstants::kNchans]; Float_t CAng(0); TSnCalWvData* evdat = new TSnCalWvData; TSnEventMetadata* meta = new TSnEventMetadata; TSnEventHeader* hdr = new TSnEventHeader; //ot = nnt->CloneTree(0); //ot->SetName("SimTemplEvts"); ot = new TTree("SimTemplEvts","simulated events from templates",1); ot->SetDirectory(outf); ot->Branch("EventMetadata.",&meta); ot->Branch("EventHeader.",&hdr); ot->Branch("EAng",&(EAng[0]),Form("EAng[%hhu]/F",NSnConstants::kNchans)); ot->Branch("HAng",&(HAng[0]),Form("HAng[%hhu]/F",NSnConstants::kNchans)); ot->Branch("CAng",&CAng,"CAng/F"); ot->Branch("theta",&theta,"theta/F"); ot->Branch("phi",&phi,"phi/F"); ot->Branch("NuData.",&evdat); // some useful aliases TString an; for (UChar_t ch=0; ch<NSnConstants::kNchans; ++ch) { // to use as a cut for a particular channel: an = Form("Ch%d",ch); ot->SetAlias(an.Data(), Form("(Iteration$>=(%hhu*%hhu)) && (Iteration$<(%hhu*%hhu))", NSnConstants::kNsamps, ch, NSnConstants::kNsamps, static_cast<UChar_t>(ch+1))); // to use as a variable showing the sample number [0,127] for any chan an = Form("SmpCh%d",ch); ot->SetAlias(an.Data(), Form("Iteration$-%u", static_cast<UInt_t>(ch) *static_cast<UInt_t>(NSnConstants::kNsamps))); // e.g. Draw("RawData.fData:SmpCh2","EventHeader.fNum==21 && Ch2","l") } Printf("generating events..."); TStopwatch timer; timer.Start(); for (UInt_t i=0; i<simevts; ++i) { if ( (i%1000)==0 ) { fprintf(stderr,"Processing %u/%u ... \r",i,simevts); } // choose angles theta = (thetaOpt>360.) ? TMath::ACos( rnd.Uniform(-1.0, 0.0) ) : thetaOpt * TMath::DegToRad(); phi = (phiOpt>360.) ? rnd.Uniform(0.0, TMath::TwoPi()) : phiOpt * TMath::DegToRad(); cone = (coneOpt>360.) ? rnd.Uniform(*(Cangs.begin()), *(Cangs.rbegin())) : coneOpt; // leave this one in degrees (as in the tree) CAng = findNearestAllowedAngle(Cangs, cone); #ifdef DEBUG Printf("--- theta=%g, phi=%g, cone=%g", theta*TMath::RadToDeg(), phi*TMath::RadToDeg(), cone); #endif // calculate channel shifts TArrayD pwdt = NSnChanCorl::GetPlaneWaveOffsets(theta, phi, zeros, pos, kNgTopFirn); TVector3 dir; dir.SetMagThetaPhi(1.0, theta, phi); #ifdef DEBUG TObjArray graphs; graphs.SetOwner(kTRUE); TCanvas* c1 = new TCanvas("c1","c1",800,700); c1->Divide(2,2); #endif for (UChar_t ch=0; ch<NSnConstants::kNchans; ++ch) { // look up the EAng, fhang for this antenna Float_t feang(0), fhang(0); findEangHang(nvec[ch], dir, feang, fhang); feang = TMath::Abs(TVector2::Phi_mpi_pi(feang)); fhang = TMath::Abs(TVector2::Phi_mpi_pi(fhang)); feang *= TMath::RadToDeg(); fhang *= TMath::RadToDeg(); // find closest allowed angle EAng[ch] = findNearestAllowedAngle(Eangs, feang); HAng[ch] = findNearestAllowedAngle(Hangs, fhang); const Long64_t ni = nnt->GetEntryNumberWithIndex(EAng[ch] + (1000*HAng[ch]), CAng); #ifdef DEBUG Printf("EAng=%g (%g), HAng=%g (%g), CAng=%g, ni=%lld", EAng[ch],feang,HAng[ch],fhang,CAng,ni); #endif if (ni>-1) { nnt->GetEntry(ni); #ifdef DEBUG c1->cd(ch+1); TGraph* och = wave->NewGraphForChan(0, kTRUE); const Int_t ochnp = och->GetN(); Double_t* ochy = och->GetY(); for (Int_t k=0; k<ochnp; ++k, ++ochy) { *ochy *= norm; } graphs.Add(och); och->SetLineColor(kBlack); och->SetMarkerColor(kBlack); och->SetMarkerStyle(7); och->Draw("apl"); #endif // first calculate the shift between chans due to the angle // ch0 is always unshifted; other chans shifted w.r.t. ch0 // jitter the shift by the specified timing resolution const Double_t shift = rnd.Gaus( (ch==0) ? 0.0 : -pwdt.At( TSnRecoChanOffsets::IndexFor(ch, 0) ), timereso); // get a graph of the waveform // data only in channel 0 of the template TGraph* gch = wave->NewGraphForChan(0, kTRUE); // "fit" the graph with an spline interpolation TSpline3* gsp = new TSpline3("stmp", gch); // evaluate the spline at the new sample positions // (shifted, but NOT wrapped) // and save that into the event data waveform Float_t* d = evdat->GetData(ch); const Float_t tstep = 1.0 / NSnConstants::kSampRate; const Float_t tlast = static_cast<Float_t>(NSnConstants::kNsamps-1) / NSnConstants::kSampRate; Float_t xloc = shift; for (UChar_t s=0; s<NSnConstants::kNsamps; ++s, ++d, xloc+=tstep) { if ( (xloc<0.0) || (xloc>=tlast) ) { *d = 0.0; } else { *d = gsp->Eval( xloc ); } } #ifdef DEBUG Printf("ch%hhu: shift=%g, dt=%g", ch, shift, (ch==0) ? 0.0 : pwdt.At( TSnRecoChanOffsets::IndexFor(ch, 0) )); TGraph* fch = evdat->NewGraphForChan(ch, kTRUE); Double_t* y = gch->GetY(); Double_t* fy = fch->GetY(); for (UChar_t s=0; s<NSnConstants::kNsamps; ++s, ++y, ++fy) { *y *= norm; *fy *= norm; } gch->SetLineColor(kRed+1); gch->SetMarkerColor(kRed+1); gch->SetMarkerStyle(7); gch->Draw("pl"); delete gsp; gsp = new TSpline3("stmp",gch); gsp->SetLineColor(kAzure-6); gsp->SetMarkerColor(kAzure-6); gsp->SetMarkerStyle(7); gsp->Draw("pl same"); graphs.Add(fch); fch->SetLineColor(kOrange+7); fch->SetMarkerColor(kOrange+7); fch->SetMarkerStyle(7); fch->Draw("pl"); #endif d = evdat->GetData(ch); // finally add noise to the waveform for (UChar_t s=0; s<NSnConstants::kNsamps; ++s, ++d) { *d = rnd.Gaus( (*d) * norm, noise ); } #ifdef DEBUG TGraph* nch = evdat->NewGraphForChan(ch, kTRUE); graphs.Add(nch); nch->SetLineColor(kGreen+2); nch->SetMarkerColor(kGreen+2); nch->SetMarkerStyle(7); nch->Draw("pl"); #endif // cleanup #ifdef DEBUG graphs.Add(gch); graphs.Add(gsp); #else delete gch; delete gsp; #endif } } // end channel loop #ifdef DEBUG TObject* o(0); while ( (o=c1->WaitPrimitive())!=0 ) { gSystem->ProcessEvents(); } delete c1; #endif // save this event ot->Fill(); } // end event loop fprintf(stderr,"\n"); timer.Stop(); Printf("Finished generating events in:"); timer.Print(); outf->Write(); Printf("Wrote [%s]",outf->GetName()); delete outf; outf=0; // close file }
/* Generate interrupts */ static void Interrupt(void) { /* the 6805 latches interrupt requests internally, so we don't clear */ /* pending_interrupts until the interrupt is taken, no matter what the */ /* external IRQ pin does. */ #if (1) //HAS_HD63705) if( (m6805.pending_interrupts & (1<<HD63705_INT_NMI)) != 0) { PUSHWORD(m6805.pc); PUSHBYTE(m6805.x); PUSHBYTE(m6805.a); PUSHBYTE(m6805.cc); SEI; /* no vectors supported, just do the callback to clear irq_state if needed */ if (m6805.irq_callback) (*m6805.irq_callback)(0); RM16( 0x1ffc, &pPC); change_pc(PC); m6805.pending_interrupts &= ~(1<<HD63705_INT_NMI); m6805_ICount -= 11; } else if( (m6805.pending_interrupts & ((1<<M6805_IRQ_LINE)|HD63705_INT_MASK)) != 0 ) { if ( (CC & IFLAG) == 0 ) { #else if( (m6805.pending_interrupts & (1<<M6805_IRQ_LINE)) != 0 ) { if ( (CC & IFLAG) == 0 ) { #endif { /* standard IRQ */ //#if (HAS_HD63705) // if(SUBTYPE!=SUBTYPE_HD63705) //#endif // PC |= ~AMASK; PUSHWORD(m6805.pc); PUSHBYTE(m6805.x); PUSHBYTE(m6805.a); PUSHBYTE(m6805.cc); SEI; /* no vectors supported, just do the callback to clear irq_state if needed */ if (m6805.irq_callback) (*m6805.irq_callback)(0); //#if (HAS_HD63705) if(SUBTYPE==SUBTYPE_HD63705) { /* Need to add emulation of other interrupt sources here KW-2/4/99 */ /* This is just a quick patch for Namco System 2 operation */ if((m6805.pending_interrupts&(1<<HD63705_INT_IRQ1))!=0) { m6805.pending_interrupts &= ~(1<<HD63705_INT_IRQ1); RM16( 0x1ff8, &pPC); change_pc(PC); } else if((m6805.pending_interrupts&(1<<HD63705_INT_IRQ2))!=0) { m6805.pending_interrupts &= ~(1<<HD63705_INT_IRQ2); RM16( 0x1fec, &pPC); change_pc(PC); } else if((m6805.pending_interrupts&(1<<HD63705_INT_ADCONV))!=0) { m6805.pending_interrupts &= ~(1<<HD63705_INT_ADCONV); RM16( 0x1fea, &pPC); change_pc(PC); } else if((m6805.pending_interrupts&(1<<HD63705_INT_TIMER1))!=0) { m6805.pending_interrupts &= ~(1<<HD63705_INT_TIMER1); RM16( 0x1ff6, &pPC); change_pc(PC); } else if((m6805.pending_interrupts&(1<<HD63705_INT_TIMER2))!=0) { m6805.pending_interrupts &= ~(1<<HD63705_INT_TIMER2); RM16( 0x1ff4, &pPC); change_pc(PC); } else if((m6805.pending_interrupts&(1<<HD63705_INT_TIMER3))!=0) { m6805.pending_interrupts &= ~(1<<HD63705_INT_TIMER3); RM16( 0x1ff2, &pPC); change_pc(PC); } else if((m6805.pending_interrupts&(1<<HD63705_INT_PCI))!=0) { m6805.pending_interrupts &= ~(1<<HD63705_INT_PCI); RM16( 0x1ff0, &pPC); change_pc(PC); } else if((m6805.pending_interrupts&(1<<HD63705_INT_SCI))!=0) { m6805.pending_interrupts &= ~(1<<HD63705_INT_SCI); RM16( 0x1fee, &pPC); change_pc(PC); } } else //#endif { RM16( 0xffff - 5, &pPC ); change_pc(PC); } } // CC & IFLAG m6805.pending_interrupts &= ~(1<<M6805_IRQ_LINE); } m6805_ICount -= 11; } } static void m6805_reset() { int (*save_irqcallback)(int) = m6805.irq_callback; memset(&m6805, 0, sizeof(m6805)); m6805.irq_callback = save_irqcallback; /* Force CPU sub-type and relevant masks */ m6805.subtype = SUBTYPE_M6805; SP_MASK = 0x07f; SP_LOW = 0x060; /* Initial stack pointer */ S = SP_MASK; /* IRQ disabled */ SEI; RM16( 0xfffe , &pPC ); change_pc(PC); } void m6805Reset() { m6805_reset(); } //static void m6805_init(int ) //int (*irqcallback)(int)) //{ // m6805.irq_callback = irqcallback; //} //static void m6805_exit(void) //{ // /* nothing to do */ //} void m6805SetIrqLine(int , int state) { /* Basic 6805 only has one IRQ line */ /* See HD63705 specific version */ if (m6805.irq_state[0] == state) return; m6805.irq_state[0] = state; if (state != CLEAR_LINE) m6805.pending_interrupts |= 1<<M6805_IRQ_LINE; } #include "6805ops.c" /* execute instructions on this CPU until icount expires */ int m6805Run(int cycles) { UINT8 ireg; m6805_ICount = cycles; do { if (m6805.pending_interrupts != 0) { if (SUBTYPE==SUBTYPE_M68705) { m68705_Interrupt(); } else { Interrupt(); } } ireg=M_RDOP(PC++); switch( ireg ) { case 0x00: brset(0x01); break; case 0x01: brclr(0x01); break; case 0x02: brset(0x02); break; case 0x03: brclr(0x02); break; case 0x04: brset(0x04); break; case 0x05: brclr(0x04); break; case 0x06: brset(0x08); break; case 0x07: brclr(0x08); break; case 0x08: brset(0x10); break; case 0x09: brclr(0x10); break; case 0x0A: brset(0x20); break; case 0x0B: brclr(0x20); break; case 0x0C: brset(0x40); break; case 0x0D: brclr(0x40); break; case 0x0E: brset(0x80); break; case 0x0F: brclr(0x80); break; case 0x10: bset(0x01); break; case 0x11: bclr(0x01); break; case 0x12: bset(0x02); break; case 0x13: bclr(0x02); break; case 0x14: bset(0x04); break; case 0x15: bclr(0x04); break; case 0x16: bset(0x08); break; case 0x17: bclr(0x08); break; case 0x18: bset(0x10); break; case 0x19: bclr(0x10); break; case 0x1a: bset(0x20); break; case 0x1b: bclr(0x20); break; case 0x1c: bset(0x40); break; case 0x1d: bclr(0x40); break; case 0x1e: bset(0x80); break; case 0x1f: bclr(0x80); break; case 0x20: bra(); break; case 0x21: brn(); break; case 0x22: bhi(); break; case 0x23: bls(); break; case 0x24: bcc(); break; case 0x25: bcs(); break; case 0x26: bne(); break; case 0x27: beq(); break; case 0x28: bhcc(); break; case 0x29: bhcs(); break; case 0x2a: bpl(); break; case 0x2b: bmi(); break; case 0x2c: bmc(); break; case 0x2d: bms(); break; case 0x2e: bil(); break; case 0x2f: bih(); break; case 0x30: neg_di(); break; case 0x31: illegal(); break; case 0x32: illegal(); break; case 0x33: com_di(); break; case 0x34: lsr_di(); break; case 0x35: illegal(); break; case 0x36: ror_di(); break; case 0x37: asr_di(); break; case 0x38: lsl_di(); break; case 0x39: rol_di(); break; case 0x3a: dec_di(); break; case 0x3b: illegal(); break; case 0x3c: inc_di(); break; case 0x3d: tst_di(); break; case 0x3e: illegal(); break; case 0x3f: clr_di(); break; case 0x40: nega(); break; case 0x41: illegal(); break; case 0x42: illegal(); break; case 0x43: coma(); break; case 0x44: lsra(); break; case 0x45: illegal(); break; case 0x46: rora(); break; case 0x47: asra(); break; case 0x48: lsla(); break; case 0x49: rola(); break; case 0x4a: deca(); break; case 0x4b: illegal(); break; case 0x4c: inca(); break; case 0x4d: tsta(); break; case 0x4e: illegal(); break; case 0x4f: clra(); break; case 0x50: negx(); break; case 0x51: illegal(); break; case 0x52: illegal(); break; case 0x53: comx(); break; case 0x54: lsrx(); break; case 0x55: illegal(); break; case 0x56: rorx(); break; case 0x57: asrx(); break; case 0x58: aslx(); break; case 0x59: rolx(); break; case 0x5a: decx(); break; case 0x5b: illegal(); break; case 0x5c: incx(); break; case 0x5d: tstx(); break; case 0x5e: illegal(); break; case 0x5f: clrx(); break; case 0x60: neg_ix1(); break; case 0x61: illegal(); break; case 0x62: illegal(); break; case 0x63: com_ix1(); break; case 0x64: lsr_ix1(); break; case 0x65: illegal(); break; case 0x66: ror_ix1(); break; case 0x67: asr_ix1(); break; case 0x68: lsl_ix1(); break; case 0x69: rol_ix1(); break; case 0x6a: dec_ix1(); break; case 0x6b: illegal(); break; case 0x6c: inc_ix1(); break; case 0x6d: tst_ix1(); break; case 0x6e: illegal(); break; case 0x6f: clr_ix1(); break; case 0x70: neg_ix(); break; case 0x71: illegal(); break; case 0x72: illegal(); break; case 0x73: com_ix(); break; case 0x74: lsr_ix(); break; case 0x75: illegal(); break; case 0x76: ror_ix(); break; case 0x77: asr_ix(); break; case 0x78: lsl_ix(); break; case 0x79: rol_ix(); break; case 0x7a: dec_ix(); break; case 0x7b: illegal(); break; case 0x7c: inc_ix(); break; case 0x7d: tst_ix(); break; case 0x7e: illegal(); break; case 0x7f: clr_ix(); break; case 0x80: rti(); break; case 0x81: rts(); break; case 0x82: illegal(); break; case 0x83: swi(); break; case 0x84: illegal(); break; case 0x85: illegal(); break; case 0x86: illegal(); break; case 0x87: illegal(); break; case 0x88: illegal(); break; case 0x89: illegal(); break; case 0x8a: illegal(); break; case 0x8b: illegal(); break; case 0x8c: illegal(); break; case 0x8d: illegal(); break; case 0x8e: illegal(); break; case 0x8f: illegal(); break; case 0x90: illegal(); break; case 0x91: illegal(); break; case 0x92: illegal(); break; case 0x93: illegal(); break; case 0x94: illegal(); break; case 0x95: illegal(); break; case 0x96: illegal(); break; case 0x97: tax(); break; case 0x98: CLC; break; case 0x99: SEC; break; #if IRQ_LEVEL_DETECT case 0x9a: CLI; if (m6805.irq_state != CLEAR_LINE) m6805.pending_interrupts |= 1<<M6805_IRQ_LINE; break; #else case 0x9a: CLI; break; #endif case 0x9b: SEI; break; case 0x9c: rsp(); break; case 0x9d: nop(); break; case 0x9e: illegal(); break; case 0x9f: txa(); break; case 0xa0: suba_im(); break; case 0xa1: cmpa_im(); break; case 0xa2: sbca_im(); break; case 0xa3: cpx_im(); break; case 0xa4: anda_im(); break; case 0xa5: bita_im(); break; case 0xa6: lda_im(); break; case 0xa7: illegal(); break; case 0xa8: eora_im(); break; case 0xa9: adca_im(); break; case 0xaa: ora_im(); break; case 0xab: adda_im(); break; case 0xac: illegal(); break; case 0xad: bsr(); break; case 0xae: ldx_im(); break; case 0xaf: illegal(); break; case 0xb0: suba_di(); break; case 0xb1: cmpa_di(); break; case 0xb2: sbca_di(); break; case 0xb3: cpx_di(); break; case 0xb4: anda_di(); break; case 0xb5: bita_di(); break; case 0xb6: lda_di(); break; case 0xb7: sta_di(); break; case 0xb8: eora_di(); break; case 0xb9: adca_di(); break; case 0xba: ora_di(); break; case 0xbb: adda_di(); break; case 0xbc: jmp_di(); break; case 0xbd: jsr_di(); break; case 0xbe: ldx_di(); break; case 0xbf: stx_di(); break; case 0xc0: suba_ex(); break; case 0xc1: cmpa_ex(); break; case 0xc2: sbca_ex(); break; case 0xc3: cpx_ex(); break; case 0xc4: anda_ex(); break; case 0xc5: bita_ex(); break; case 0xc6: lda_ex(); break; case 0xc7: sta_ex(); break; case 0xc8: eora_ex(); break; case 0xc9: adca_ex(); break; case 0xca: ora_ex(); break; case 0xcb: adda_ex(); break; case 0xcc: jmp_ex(); break; case 0xcd: jsr_ex(); break; case 0xce: ldx_ex(); break; case 0xcf: stx_ex(); break; case 0xd0: suba_ix2(); break; case 0xd1: cmpa_ix2(); break; case 0xd2: sbca_ix2(); break; case 0xd3: cpx_ix2(); break; case 0xd4: anda_ix2(); break; case 0xd5: bita_ix2(); break; case 0xd6: lda_ix2(); break; case 0xd7: sta_ix2(); break; case 0xd8: eora_ix2(); break; case 0xd9: adca_ix2(); break; case 0xda: ora_ix2(); break; case 0xdb: adda_ix2(); break; case 0xdc: jmp_ix2(); break; case 0xdd: jsr_ix2(); break; case 0xde: ldx_ix2(); break; case 0xdf: stx_ix2(); break; case 0xe0: suba_ix1(); break; case 0xe1: cmpa_ix1(); break; case 0xe2: sbca_ix1(); break; case 0xe3: cpx_ix1(); break; case 0xe4: anda_ix1(); break; case 0xe5: bita_ix1(); break; case 0xe6: lda_ix1(); break; case 0xe7: sta_ix1(); break; case 0xe8: eora_ix1(); break; case 0xe9: adca_ix1(); break; case 0xea: ora_ix1(); break; case 0xeb: adda_ix1(); break; case 0xec: jmp_ix1(); break; case 0xed: jsr_ix1(); break; case 0xee: ldx_ix1(); break; case 0xef: stx_ix1(); break; case 0xf0: suba_ix(); break; case 0xf1: cmpa_ix(); break; case 0xf2: sbca_ix(); break; case 0xf3: cpx_ix(); break; case 0xf4: anda_ix(); break; case 0xf5: bita_ix(); break; case 0xf6: lda_ix(); break; case 0xf7: sta_ix(); break; case 0xf8: eora_ix(); break; case 0xf9: adca_ix(); break; case 0xfa: ora_ix(); break; case 0xfb: adda_ix(); break; case 0xfc: jmp_ix(); break; case 0xfd: jsr_ix(); break; case 0xfe: ldx_ix(); break; case 0xff: stx_ix(); break; } m6805_ICount -= cycles1[ireg]; m6805.nTotalCycles += cycles1[ireg]; } while( m6805_ICount > 0 ); return cycles - m6805_ICount; }
// // case 0: depart-level // dep-id => [pid,...] => [{pid,*,*}, ...] // host=[auto] // case 1: pid-level // pid, *, * // host=[auto] // case 2: mid-level // pid, mid, * // host=[auto] // case 3: host-level // pid, mid, * // host=ip // case 4: expand-to-individual-hosts // pid,mid,iid as in [0-2] (no case #3) // host=[auto] // static void handleRequest(QueryParameters& parameters) { // step 1: context const char *strContext = parameters.getString("context", "resource"); int context; if (!strcmp(strContext, "business")) { context = CT_BUSINESS; } else if (!strcmp(strContext, "resource")) { context = CT_RESOURCE; } else { outputError(501, "Invalid context parameter"); return; } // step 2: group - how to combine stats together int totalView = 0; const char *strGroup = parameters.getString("group", "total"); if (!strcmp(strGroup, "total")) { totalView = 1; } else if (!strcmp(strGroup, "list")) { totalView = 0; } else { outputError(501, "invalid group parameter, which should be total|list."); return; } // step 3: time period, span, align int64_t startDtime, endDtime; int spanUnit, spanCount; if (parseDtimeSpan(parameters, startDtime, endDtime, spanUnit, spanCount) < 0) return; // move ahead one span for some calculation need its previous stats startDtime -= spanLength(spanUnit, spanCount); int mergeCount = (endDtime - startDtime) / spanLength(spanUnit, spanCount); // char buf1[128], buf2[128]; // APPLOG_DEBUG("parsed start=%s, end=%s, mergeCount=%d", // formatDtime(buf1, sizeof buf1, startDtime), // formatDtime(buf2, sizeof buf2, endDtime), mergeCount); StatMerger merger(NULL, NULL, NULL, NULL, spanUnit, spanCount, mergeCount); merger.periodStartTime = startDtime; // step 4: ids // TODO: group by department... // uint16_t did = parameters.getInt("did", 0); uint16_t pid = parameters.getInt("pid", 0); uint16_t mid = parameters.getInt("mid", 0); if (pid == 0) { outputError(501, "pid can not be 0(ANY) now"); return; } int cpuTotal = 0, cpuCores = 0; std::tr1::unordered_set<int> cpuIds; int memory = 0; int loadAvg = 0; int netAll = 0; std::tr1::unordered_set<int> netIds; int diskAll = 0; std::tr1::unordered_set<int> diskIds; // step 4.1: parse iids const char *strIid = parameters.getString("iid", "all"); if (strcmp(strIid, "all") == 0) { cpuTotal = 1; // no cpu-cores memory = 1; loadAvg = 1; netAll = 1; diskAll = 1; } else { char ss[1024]; strncpy(ss, strIid, sizeof ss); ss[sizeof(ss) - 1] = 0; char *endptr, *nptr = strtok_r(ss, MULTIVAL_SEPARATORS, &endptr); while (nptr != NULL) { if (!strcmp(nptr, "cpu-total")) cpuTotal = 1; else if (!strcmp(nptr, "cpu-cores")) cpuCores = 1; else if (!strncmp(nptr, "cpu-", 4)) cpuIds.insert(strtol(nptr + 4, NULL, 0)); else if (!strcmp(nptr, "mem")) memory = 1; else if (!strcmp(nptr, "load-avg")) loadAvg = 1; else if (!strcmp(nptr, "net-all")) netAll = 1; // TODO: mapping net-name to its id else if (!strncmp(nptr, "net-", 4)) netIds.insert(strtol(nptr + 4, NULL, 0)); else if (!strcmp(nptr, "disk-all")) diskAll = 1; // TODO: mapping disk-name to its id else if (!strncmp(nptr, "disk-", 5)) diskIds.insert(strtol(nptr + 5, NULL, 0)); else { outputError(501, "invalid iid parameter"); return; } nptr = strtok_r(NULL, MULTIVAL_SEPARATORS, &endptr); } } // step 4.2: get all possible iids first local_key_set_t ids; host_set_t hosts; // step 4.3: get hosts and mapping iids with hosts const char *strHost = parameters.getString("host", "auto"); if (strcmp(strHost, "auto")) { // individual host(s) char ss[1024]; strncpy(ss, strHost, sizeof ss); ss[sizeof(ss) - 1] = 0; char *endptr, *nptr = strtok_r(ss, MULTIVAL_SEPARATORS, &endptr); while (nptr != NULL) { stat_ip_t hip; if (inet_pton(AF_INET, nptr, &hip.ip.ip4) == 1) { hip.ver = 4; } else if (inet_pton(AF_INET6, nptr, &hip.ip.ip6[0]) == 1) { hip.ver = 6; } else { outputError(501, "invalid host parameter"); return; } hosts.insert(hip); nptr = strtok_r(NULL, MULTIVAL_SEPARATORS, &endptr); } } unsigned char buf[8192], rspBuf[8192]; Memorybuffer msg(buf, sizeof buf, false); MemoryBuffer rsp(rspBuf, sizeof rspBuf, false); struct proto_h16_head *h = (struct proto_h16_head *)msg.data(); memset(h, sizeof(*h), 0); msg.setWptr(sizeof(*h)); h->cmd = CMD_STAT_GET_SYSTEM_STATS_REQ; h->syn = nextSyn++; h->ack = 0; h->ver = 1; msg.writeUint8(context); msg.writeUint8(totalView); msg.writeInt64(startDtime); msg.writeInt64(endDtime); msg.writeUint8(spanUnit); msg.writeUint8(spanCount); msg.writeUint16(pid); msg.writeUint16(mid); msg.writeUint16(hosts.size()); for (hosts::iterator iter = hosts.begin(); iter != hosts.end(); ++iter) { if (encodeTo(msg, *iter) < 0) break; } beyondy::TimedoutCountdown timer(10*1000); ClientConnection client(storageAddress, 10*1000, 3); if (client.request(&msg, &rsp) < 0) { APPLOG_ERROR("request to %s failed: %m", storageAddress); return -1; } struct proto_h16_res *h2 = (struct proto_h16_res *)rsp.data(); rsp.setRptr(sizeof(*h2)); if (combiner.parseFrom(&rsp) < 0) { APPLOG_ERROR("parse combiner from rsp-msg failed"); return -1; } // further merge StatCombiner combiner(spanUnit, spanCount, startDtime, mergeCount); int gtype = combiner.groupType(); // output printf("Status: 200 OK\r\n"); printf("Content-Type: application/json\r\n"); printf("\r\n"); int64_t spanInterval = spanLength(spanUnit, spanCount); int64_t ts = startDtime + spanInterval; char buf[128]; printf("{\"start\":\"%s\"", formatDtime(buf, sizeof buf, ts)); printf(",\"end\":\"%s\"", formatDtime(buf, sizeof buf, endDtime)); printf(",\"span\":\"%s\"", formatSpan(buf, sizeof buf, spanUnit, spanCount)); printf(",\"stats\":["); for (int i = 1; i < mergeCount; ++i) { printf("%s{\"dtime\":\"%s\"", i == 1 ? "" : ",", formatDtime(buf, sizeof buf, ts)); printf(",\"data\":["); bool first = true; if (!cpuIds.empty()) { outputCpuCombinedGauges(gtype, combiner.mergedGauges[i-1], combiner.mergedGauges[i], first, cpuIds); } if (memory) { outputMemCombinedGauges(gtype, combiner.mergedGauges[i-1], combiner.mergedGauges[i], first); } if (loadAvg) { outputLoadavgCombinedGauges(gtype, combiner.mergedGauges[i-1], combiner.mergedGauges[i], first); } if (!netIds.empty()) { outputNetCombinedGauges(gtype, combiner.mergedGauges[i-1], combiner.mergedGauges[i], first, netIds); } if (!diskIds.empty()) { outputDiskCombinedGauges(gtype, combiner.mergedGauges[i-1], combiner.mergedGauges[i], first, diskIds); } printf("]}"); ts += spanInterval; } printf("]}"); return; }
QTSS_Error EasyCMSSession::processMessage() { if (NULL == fRequest) return QTSS_BadArgument; QTSS_Error theErr = fRequest->Parse(); if (theErr != QTSS_NoErr) return QTSS_BadArgument; //获取具体Content json数据部分 StrPtrLen* lengthPtr = fRequest->GetHeaderValue(httpContentLengthHeader); StringParser theContentLenParser(lengthPtr); theContentLenParser.ConsumeWhitespace(); UInt32 content_length = theContentLenParser.ConsumeInteger(NULL); if (content_length) { qtss_printf("EasyCMSSession::ProcessMessage read content-length:%lu \n", content_length); // 检查content的fContentBuffer和fContentBufferOffset是否有值存在,如果存在,说明我们已经开始 // 进行content请求处理,如果不存在,我们需要创建并初始化fContentBuffer和fContentBufferOffset if (fContentBuffer == NULL) { fContentBuffer = NEW char[content_length + 1]; memset(fContentBuffer, 0, content_length + 1); fContentBufferOffset = 0; } UInt32 theLen = 0; // 读取HTTP Content报文数据 theErr = fInputStream.Read(fContentBuffer + fContentBufferOffset, content_length - fContentBufferOffset, &theLen); Assert(theErr != QTSS_BadArgument); if (theErr == QTSS_RequestFailed) { OSCharArrayDeleter charArrayPathDeleter(fContentBuffer); fContentBufferOffset = 0; fContentBuffer = NULL; return QTSS_RequestFailed; } qtss_printf("EasyCMSSession::ProcessMessage() Add Len:%lu \n", theLen); if ((theErr == QTSS_WouldBlock) || (theLen < (content_length - fContentBufferOffset))) { // // Update our offset in the buffer fContentBufferOffset += theLen; Assert(theErr == QTSS_NoErr); return QTSS_WouldBlock; } Assert(theErr == QTSS_NoErr); // 处理完成报文后会自动进行Delete处理 OSCharArrayDeleter charArrayPathDeleter(fContentBuffer); qtss_printf("EasyCMSSession::ProcessMessage() Get Complete Msg:\n%s", fContentBuffer); fNoneACKMsgCount = 0; EasyProtocol protocol(fContentBuffer); int nNetMsg = protocol.GetMessageType(); switch (nNetMsg) { case MSG_SD_REGISTER_ACK: { EasyMsgSDRegisterACK ack(fContentBuffer); qtss_printf("session id = %s\n", ack.GetBodyValue(EASY_TAG_SESSION_ID).c_str()); qtss_printf("device serial = %s\n", ack.GetBodyValue(EASY_TAG_SERIAL).c_str()); } break; case MSG_SD_POST_SNAP_ACK: { ; } break; case MSG_SD_PUSH_STREAM_REQ: { EasyMsgSDPushStreamREQ startStreamReq(fContentBuffer); string serial = startStreamReq.GetBodyValue(EASY_TAG_SERIAL); string ip = startStreamReq.GetBodyValue(EASY_TAG_SERVER_IP); string port = startStreamReq.GetBodyValue(EASY_TAG_SERVER_PORT); string protocol = startStreamReq.GetBodyValue(EASY_TAG_PROTOCOL); string channel = startStreamReq.GetBodyValue(EASY_TAG_CHANNEL); string streamID = startStreamReq.GetBodyValue(EASY_TAG_STREAM_ID); string reserve = startStreamReq.GetBodyValue(EASY_TAG_RESERVE); qtss_printf("Serial = %s\n", serial.c_str()); qtss_printf("Server_IP = %s\n", ip.c_str()); qtss_printf("Server_Port = %s\n", port.c_str()); //TODO::这里需要对传入的Serial/StreamID/Channel做一下容错处理 if (serial.empty() || ip.empty() || port.empty()) { return QTSS_ValueNotFound; } QTSS_RoleParams params; params.startStreaParams.inIP = ip.c_str(); params.startStreaParams.inPort = atoi(port.c_str()); params.startStreaParams.inSerial = serial.c_str(); params.startStreaParams.inProtocol = protocol.c_str(); params.startStreaParams.inChannel = channel.c_str(); params.startStreaParams.inStreamID = streamID.c_str(); QTSS_Error errCode = QTSS_NoErr; UInt32 fCurrentModule = 0; UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kStartStreamRole); for (; fCurrentModule < numModules; ++fCurrentModule) { QTSSModule* theModule = QTSServerInterface::GetModule(QTSSModule::kStartStreamRole, fCurrentModule); errCode = theModule->CallDispatch(Easy_StartStream_Role, ¶ms); } fCurrentModule = 0; EasyJsonValue body; body[EASY_TAG_SERIAL] = params.startStreaParams.inSerial; body[EASY_TAG_CHANNEL] = params.startStreaParams.inChannel; body[EASY_TAG_PROTOCOL] = params.startStreaParams.inProtocol; body[EASY_TAG_SERVER_IP] = params.startStreaParams.inIP; body[EASY_TAG_SERVER_PORT] = params.startStreaParams.inPort; body[EASY_TAG_RESERVE] = reserve; EasyMsgDSPushSteamACK rsp(body, startStreamReq.GetMsgCSeq(), getStatusNo(errCode)); string msg = rsp.GetMsg(); StrPtrLen jsonContent((char*)msg.data()); HTTPRequest httpAck(&QTSServerInterface::GetServerHeader(), httpResponseType); if (httpAck.CreateResponseHeader()) { if (jsonContent.Len) httpAck.AppendContentLengthHeader(jsonContent.Len); //Push msg to OutputBuffer char respHeader[2048] = { 0 }; StrPtrLen* ackPtr = httpAck.GetCompleteHTTPHeader(); strncpy(respHeader, ackPtr->Ptr, ackPtr->Len); fOutputStream.Put(respHeader); if (jsonContent.Len > 0) fOutputStream.Put(jsonContent.Ptr, jsonContent.Len); } } break; case MSG_SD_STREAM_STOP_REQ: { EasyMsgSDStopStreamREQ stopStreamReq(fContentBuffer); QTSS_RoleParams params; string serial = stopStreamReq.GetBodyValue(EASY_TAG_SERIAL); params.stopStreamParams.inSerial = serial.c_str(); string protocol = stopStreamReq.GetBodyValue(EASY_TAG_PROTOCOL); params.stopStreamParams.inProtocol = protocol.c_str(); string channel = stopStreamReq.GetBodyValue(EASY_TAG_CHANNEL); params.stopStreamParams.inChannel = channel.c_str(); QTSS_Error errCode = QTSS_NoErr; UInt32 fCurrentModule = 0; UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kStopStreamRole); for (; fCurrentModule < numModules; ++fCurrentModule) { QTSSModule* theModule = QTSServerInterface::GetModule(QTSSModule::kStopStreamRole, fCurrentModule); errCode = theModule->CallDispatch(Easy_StopStream_Role, ¶ms); } fCurrentModule = 0; EasyJsonValue body; body[EASY_TAG_SERIAL] = params.stopStreamParams.inSerial; body[EASY_TAG_CHANNEL] = params.stopStreamParams.inChannel; body[EASY_TAG_PROTOCOL] = params.stopStreamParams.inProtocol; EasyMsgDSStopStreamACK rsp(body, stopStreamReq.GetMsgCSeq(), getStatusNo(errCode)); string msg = rsp.GetMsg(); //回应 StrPtrLen jsonContent((char*)msg.data()); HTTPRequest httpAck(&QTSServerInterface::GetServerHeader(), httpResponseType); if (httpAck.CreateResponseHeader()) { if (jsonContent.Len) httpAck.AppendContentLengthHeader(jsonContent.Len); //Push msg to OutputBuffer char respHeader[2048] = { 0 }; StrPtrLen* ackPtr = httpAck.GetCompleteHTTPHeader(); strncpy(respHeader, ackPtr->Ptr, ackPtr->Len); fOutputStream.Put(respHeader); if (jsonContent.Len > 0) fOutputStream.Put(jsonContent.Ptr, jsonContent.Len); } } break; default: break; } }
TCA emitFunctionEnterHelper(CodeBlock& cb, UniqueStubs& us) { alignJmpTarget(cb); auto const start = vwrap(cb, [&] (Vout& v) { auto const ar = v.makeReg(); v << copy{rvmfp(), ar}; // Fully set up the call frame for the stub. We can't skip this like we do // in other stubs because we need the return IP for this frame in the %rbp // chain, in order to find the proper fixup for the VMRegAnchor in the // intercept handler. v << stublogue{true}; v << copy{rsp(), rvmfp()}; // When we call the event hook, it might tell us to skip the callee // (because of fb_intercept). If that happens, we need to return to the // caller, but the handler will have already popped the callee's frame. // So, we need to save these values for later. v << pushm{ar[AROFF(m_savedRip)]}; v << pushm{ar[AROFF(m_sfp)]}; v << copy2{ar, v.cns(EventHook::NormalFunc), rarg(0), rarg(1)}; bool (*hook)(const ActRec*, int) = &EventHook::onFunctionCall; v << call{TCA(hook)}; }); us.functionEnterHelperReturn = vwrap2(cb, [&] (Vout& v, Vout& vcold) { auto const sf = v.makeReg(); v << testb{rret(), rret(), sf}; unlikelyIfThen(v, vcold, CC_Z, sf, [&] (Vout& v) { auto const saved_rip = v.makeReg(); // The event hook has already cleaned up the stack and popped the // callee's frame, so we're ready to continue from the original call // site. We just need to grab the fp/rip of the original frame that we // saved earlier, and sync rvmsp(). v << pop{rvmfp()}; v << pop{saved_rip}; // Drop our call frame; the stublogue{} instruction guarantees that this // is exactly 16 bytes. v << lea{rsp()[16], rsp()}; // Sync vmsp and return to the caller. This unbalances the return stack // buffer, but if we're intercepting, we probably don't care. v << load{rvmtl()[rds::kVmspOff], rvmsp()}; v << jmpr{saved_rip}; }); // Skip past the stuff we saved for the intercept case. v << lea{rsp()[16], rsp()}; // Restore rvmfp() and return to the callee's func prologue. v << stubret{RegSet(), true}; }); return start; }
void lower_vcall(Vunit& unit, Inst& inst, Vlabel b, size_t i) { auto& blocks = unit.blocks; auto const& vinstr = blocks[b].code[i]; auto const is_vcall = vinstr.op == Vinstr::vcall; auto const vcall = vinstr.vcall_; auto const vinvoke = vinstr.vinvoke_; // We lower vinvoke in two phases, and `inst' is overwritten after the first // phase. We need to save any of its parameters that we care about in the // second phase ahead of time. auto const& vargs = unit.vcallArgs[inst.args]; auto const dests = unit.tuples[inst.d]; auto const destType = inst.destType; auto const scratch = unit.makeScratchBlock(); SCOPE_EXIT { unit.freeScratchBlock(scratch); }; Vout v(unit, scratch, vinstr.origin); int32_t const adjust = (vargs.stkArgs.size() & 0x1) ? sizeof(uintptr_t) : 0; if (adjust) v << lea{rsp()[-adjust], rsp()}; // Push stack arguments, in reverse order. for (int i = vargs.stkArgs.size() - 1; i >= 0; --i) { v << push{vargs.stkArgs[i]}; } // Get the arguments in the proper registers. RegSet argRegs; bool needsCopy = false; auto doArgs = [&] (const VregList& srcs, PhysReg (*r)(size_t)) { VregList argDests; for (size_t i = 0, n = srcs.size(); i < n; ++i) { auto const reg = r(i); argDests.push_back(reg); argRegs |= reg; } if (argDests.size()) { v << copyargs{v.makeTuple(srcs), v.makeTuple(std::move(argDests))}; } }; switch (arch()) { case Arch::X64: case Arch::PPC64: doArgs(vargs.args, rarg); break; case Arch::ARM: if (vargs.indirect) { if (vargs.args.size() > 0) { // First arg is a pointer to storage for the return value. v << copy{vargs.args[0], rret_indirect()}; VregList rem(vargs.args.begin() + 1, vargs.args.end()); doArgs(rem, rarg); needsCopy = true; } } else { doArgs(vargs.args, rarg); } } doArgs(vargs.simdArgs, rarg_simd); // Emit the appropriate call instruction sequence. emitCall(v, inst.call, argRegs); // Handle fixup and unwind information. if (inst.fixup.isValid()) { v << syncpoint{inst.fixup}; } if (!is_vcall) { auto& targets = vinvoke.targets; v << unwind{{targets[0], targets[1]}}; // Insert an lea fixup for any stack args at the beginning of the catch // block. if (auto rspOffset = ((vargs.stkArgs.size() + 1) & ~1) * sizeof(uintptr_t)) { auto& taken = unit.blocks[targets[1]].code; assertx(taken.front().op == Vinstr::landingpad || taken.front().op == Vinstr::jmp); Vinstr vi { lea{rsp()[rspOffset], rsp()} }; vi.origin = taken.front().origin; if (taken.front().op == Vinstr::jmp) { taken.insert(taken.begin(), vi); } else { taken.insert(taken.begin() + 1, vi); } } // Write out the code so far to the end of b. Remaining code will be // emitted to the next block. vector_splice(blocks[b].code, i, 1, blocks[scratch].code); } else if (vcall.nothrow) { v << nothrow{}; } // Copy back the indirect result pointer into the return register. if (needsCopy) { v << copy{rret_indirect(), rret(0)}; } // For vinvoke, `inst' is no longer valid after this point. // Copy the call result to the destination register(s). switch (destType) { case DestType::TV: static_assert(offsetof(TypedValue, m_data) == 0, ""); static_assert(offsetof(TypedValue, m_type) == 8, ""); if (dests.size() == 2) { v << copy2{rret(0), rret(1), dests[0], dests[1]}; } else { // We have cases where we statically know the type but need the value // from native call. Even if the type does not really need a register // (e.g., InitNull), a Vreg is still allocated in assignRegs(), so the // following assertion holds. assertx(dests.size() == 1); v << copy{rret(0), dests[0]}; } break; case DestType::SIMD: static_assert(offsetof(TypedValue, m_data) == 0, ""); static_assert(offsetof(TypedValue, m_type) == 8, ""); assertx(dests.size() == 1); pack2(v, rret(0), rret(1), dests[0]); break; case DestType::SSA: case DestType::Byte: assertx(dests.size() == 1); assertx(dests[0].isValid()); // Copy the single-register result to dests[0]. v << copy{rret(0), dests[0]}; break; case DestType::Dbl: // Copy the single-register result to dests[0]. assertx(dests.size() == 1); assertx(dests[0].isValid()); v << copy{rret_simd(0), dests[0]}; break; case DestType::None: assertx(dests.empty()); break; } if (vargs.stkArgs.size() > 0) { auto const delta = safe_cast<int32_t>( vargs.stkArgs.size() * sizeof(uintptr_t) + adjust ); v << lea{rsp()[delta], rsp()}; } // Insert new instructions to the appropriate block. if (is_vcall) { vector_splice(blocks[b].code, i, 1, blocks[scratch].code); } else { vector_splice(blocks[vinvoke.targets[0]].code, 0, 0, blocks[scratch].code); } }
/* execute instructions on this CPU until icount expires */ void m6805_base_device::execute_run() { UINT8 ireg; S = SP_ADJUST( S ); /* Taken from CPU_SET_CONTEXT when pointer'afying */ do { if (m_pending_interrupts != 0) { interrupt(); } debugger_instruction_hook(this, PC); ireg=M_RDOP(PC++); switch( ireg ) { case 0x00: brset(0x01); break; case 0x01: brclr(0x01); break; case 0x02: brset(0x02); break; case 0x03: brclr(0x02); break; case 0x04: brset(0x04); break; case 0x05: brclr(0x04); break; case 0x06: brset(0x08); break; case 0x07: brclr(0x08); break; case 0x08: brset(0x10); break; case 0x09: brclr(0x10); break; case 0x0A: brset(0x20); break; case 0x0B: brclr(0x20); break; case 0x0C: brset(0x40); break; case 0x0D: brclr(0x40); break; case 0x0E: brset(0x80); break; case 0x0F: brclr(0x80); break; case 0x10: bset(0x01); break; case 0x11: bclr(0x01); break; case 0x12: bset(0x02); break; case 0x13: bclr(0x02); break; case 0x14: bset(0x04); break; case 0x15: bclr(0x04); break; case 0x16: bset(0x08); break; case 0x17: bclr(0x08); break; case 0x18: bset(0x10); break; case 0x19: bclr(0x10); break; case 0x1a: bset(0x20); break; case 0x1b: bclr(0x20); break; case 0x1c: bset(0x40); break; case 0x1d: bclr(0x40); break; case 0x1e: bset(0x80); break; case 0x1f: bclr(0x80); break; case 0x20: bra(); break; case 0x21: brn(); break; case 0x22: bhi(); break; case 0x23: bls(); break; case 0x24: bcc(); break; case 0x25: bcs(); break; case 0x26: bne(); break; case 0x27: beq(); break; case 0x28: bhcc(); break; case 0x29: bhcs(); break; case 0x2a: bpl(); break; case 0x2b: bmi(); break; case 0x2c: bmc(); break; case 0x2d: bms(); break; case 0x2e: bil(); break; case 0x2f: bih(); break; case 0x30: neg_di(); break; case 0x31: illegal(); break; case 0x32: illegal(); break; case 0x33: com_di(); break; case 0x34: lsr_di(); break; case 0x35: illegal(); break; case 0x36: ror_di(); break; case 0x37: asr_di(); break; case 0x38: lsl_di(); break; case 0x39: rol_di(); break; case 0x3a: dec_di(); break; case 0x3b: illegal(); break; case 0x3c: inc_di(); break; case 0x3d: tst_di(); break; case 0x3e: illegal(); break; case 0x3f: clr_di(); break; case 0x40: nega(); break; case 0x41: illegal(); break; case 0x42: illegal(); break; case 0x43: coma(); break; case 0x44: lsra(); break; case 0x45: illegal(); break; case 0x46: rora(); break; case 0x47: asra(); break; case 0x48: lsla(); break; case 0x49: rola(); break; case 0x4a: deca(); break; case 0x4b: illegal(); break; case 0x4c: inca(); break; case 0x4d: tsta(); break; case 0x4e: illegal(); break; case 0x4f: clra(); break; case 0x50: negx(); break; case 0x51: illegal(); break; case 0x52: illegal(); break; case 0x53: comx(); break; case 0x54: lsrx(); break; case 0x55: illegal(); break; case 0x56: rorx(); break; case 0x57: asrx(); break; case 0x58: aslx(); break; case 0x59: rolx(); break; case 0x5a: decx(); break; case 0x5b: illegal(); break; case 0x5c: incx(); break; case 0x5d: tstx(); break; case 0x5e: illegal(); break; case 0x5f: clrx(); break; case 0x60: neg_ix1(); break; case 0x61: illegal(); break; case 0x62: illegal(); break; case 0x63: com_ix1(); break; case 0x64: lsr_ix1(); break; case 0x65: illegal(); break; case 0x66: ror_ix1(); break; case 0x67: asr_ix1(); break; case 0x68: lsl_ix1(); break; case 0x69: rol_ix1(); break; case 0x6a: dec_ix1(); break; case 0x6b: illegal(); break; case 0x6c: inc_ix1(); break; case 0x6d: tst_ix1(); break; case 0x6e: illegal(); break; case 0x6f: clr_ix1(); break; case 0x70: neg_ix(); break; case 0x71: illegal(); break; case 0x72: illegal(); break; case 0x73: com_ix(); break; case 0x74: lsr_ix(); break; case 0x75: illegal(); break; case 0x76: ror_ix(); break; case 0x77: asr_ix(); break; case 0x78: lsl_ix(); break; case 0x79: rol_ix(); break; case 0x7a: dec_ix(); break; case 0x7b: illegal(); break; case 0x7c: inc_ix(); break; case 0x7d: tst_ix(); break; case 0x7e: illegal(); break; case 0x7f: clr_ix(); break; case 0x80: rti(); break; case 0x81: rts(); break; case 0x82: illegal(); break; case 0x83: swi(); break; case 0x84: illegal(); break; case 0x85: illegal(); break; case 0x86: illegal(); break; case 0x87: illegal(); break; case 0x88: illegal(); break; case 0x89: illegal(); break; case 0x8a: illegal(); break; case 0x8b: illegal(); break; case 0x8c: illegal(); break; case 0x8d: illegal(); break; case 0x8e: illegal(); break; case 0x8f: illegal(); break; case 0x90: illegal(); break; case 0x91: illegal(); break; case 0x92: illegal(); break; case 0x93: illegal(); break; case 0x94: illegal(); break; case 0x95: illegal(); break; case 0x96: illegal(); break; case 0x97: tax(); break; case 0x98: CLC; break; case 0x99: SEC; break; #if IRQ_LEVEL_DETECT case 0x9a: CLI; if (m_irq_state != CLEAR_LINE) m_pending_interrupts |= 1 << M6805_IRQ_LINE; break; #else case 0x9a: CLI; break; #endif case 0x9b: SEI; break; case 0x9c: rsp(); break; case 0x9d: nop(); break; case 0x9e: illegal(); break; case 0x9f: txa(); break; case 0xa0: suba_im(); break; case 0xa1: cmpa_im(); break; case 0xa2: sbca_im(); break; case 0xa3: cpx_im(); break; case 0xa4: anda_im(); break; case 0xa5: bita_im(); break; case 0xa6: lda_im(); break; case 0xa7: illegal(); break; case 0xa8: eora_im(); break; case 0xa9: adca_im(); break; case 0xaa: ora_im(); break; case 0xab: adda_im(); break; case 0xac: illegal(); break; case 0xad: bsr(); break; case 0xae: ldx_im(); break; case 0xaf: illegal(); break; case 0xb0: suba_di(); break; case 0xb1: cmpa_di(); break; case 0xb2: sbca_di(); break; case 0xb3: cpx_di(); break; case 0xb4: anda_di(); break; case 0xb5: bita_di(); break; case 0xb6: lda_di(); break; case 0xb7: sta_di(); break; case 0xb8: eora_di(); break; case 0xb9: adca_di(); break; case 0xba: ora_di(); break; case 0xbb: adda_di(); break; case 0xbc: jmp_di(); break; case 0xbd: jsr_di(); break; case 0xbe: ldx_di(); break; case 0xbf: stx_di(); break; case 0xc0: suba_ex(); break; case 0xc1: cmpa_ex(); break; case 0xc2: sbca_ex(); break; case 0xc3: cpx_ex(); break; case 0xc4: anda_ex(); break; case 0xc5: bita_ex(); break; case 0xc6: lda_ex(); break; case 0xc7: sta_ex(); break; case 0xc8: eora_ex(); break; case 0xc9: adca_ex(); break; case 0xca: ora_ex(); break; case 0xcb: adda_ex(); break; case 0xcc: jmp_ex(); break; case 0xcd: jsr_ex(); break; case 0xce: ldx_ex(); break; case 0xcf: stx_ex(); break; case 0xd0: suba_ix2(); break; case 0xd1: cmpa_ix2(); break; case 0xd2: sbca_ix2(); break; case 0xd3: cpx_ix2(); break; case 0xd4: anda_ix2(); break; case 0xd5: bita_ix2(); break; case 0xd6: lda_ix2(); break; case 0xd7: sta_ix2(); break; case 0xd8: eora_ix2(); break; case 0xd9: adca_ix2(); break; case 0xda: ora_ix2(); break; case 0xdb: adda_ix2(); break; case 0xdc: jmp_ix2(); break; case 0xdd: jsr_ix2(); break; case 0xde: ldx_ix2(); break; case 0xdf: stx_ix2(); break; case 0xe0: suba_ix1(); break; case 0xe1: cmpa_ix1(); break; case 0xe2: sbca_ix1(); break; case 0xe3: cpx_ix1(); break; case 0xe4: anda_ix1(); break; case 0xe5: bita_ix1(); break; case 0xe6: lda_ix1(); break; case 0xe7: sta_ix1(); break; case 0xe8: eora_ix1(); break; case 0xe9: adca_ix1(); break; case 0xea: ora_ix1(); break; case 0xeb: adda_ix1(); break; case 0xec: jmp_ix1(); break; case 0xed: jsr_ix1(); break; case 0xee: ldx_ix1(); break; case 0xef: stx_ix1(); break; case 0xf0: suba_ix(); break; case 0xf1: cmpa_ix(); break; case 0xf2: sbca_ix(); break; case 0xf3: cpx_ix(); break; case 0xf4: anda_ix(); break; case 0xf5: bita_ix(); break; case 0xf6: lda_ix(); break; case 0xf7: sta_ix(); break; case 0xf8: eora_ix(); break; case 0xf9: adca_ix(); break; case 0xfa: ora_ix(); break; case 0xfb: adda_ix(); break; case 0xfc: jmp_ix(); break; case 0xfd: jsr_ix(); break; case 0xfe: ldx_ix(); break; case 0xff: stx_ix(); break; } m_icount -= m_cycles1[ireg]; } while( m_icount > 0 ); }
// returns true if the import can continue, false otherwise bool ABI_Collab_Import::_handleCollision(UT_sint32 iIncomingRev, UT_sint32 iLocalRev, BuddyPtr pCollaborator) { UT_DEBUGMSG(("_handleCollision() - incoming rev %d collides against local rev %d!!!\n", iIncomingRev, iLocalRev)); UT_return_val_if_fail(pCollaborator, false); if (m_pAbiCollab->isLocallyControlled()) { UT_DEBUGMSG(("We're controlling this session, refusing this changerecord from %s!\n", pCollaborator->getDescription().utf8_str())); // add this collaborator to our revert ack list, so we can ignore his packets // until we get an acknoledgement that he has reverted his local, colliding changes m_revertSet.push_back(std::make_pair(pCollaborator, iIncomingRev)); // send the revert command to the collaborator RevertSessionPacket rsp(m_pAbiCollab->getSessionId(), m_pDoc->getOrigDocUUIDString(), iIncomingRev); m_pAbiCollab->push(&rsp, pCollaborator); return false; } else { UT_DEBUGMSG(("We're NOT controlling this session, reverting local changes and accepting changerecord!\n")); ABI_Collab_Export* pExport = m_pAbiCollab->getExport(); UT_return_val_if_fail(pExport, false); UT_GenericVector<ChangeAdjust *>* pAdjusts = pExport->getAdjusts(); UT_return_val_if_fail(pAdjusts, false); m_pAbiCollab->setIsReverting(true); // mask all changes in the exporter // undo our cool local changes, and nuke our exported packet list as well up to (and including) iLocalRev for (UT_sint32 i = pAdjusts->getItemCount() - 1; i >= 0; i--) { ChangeAdjust* pChange = pAdjusts->getNthItem(i); if (pChange) { if (pChange->getLocalRev() >= iLocalRev) { if (strcmp(m_pDoc->getOrigDocUUIDString(), pChange->getRemoteDocUUID().utf8_str()) == 0) { UT_DEBUGMSG(("UNDO-ING AND NUKING LOCAL CHANGE: EXPORT POSITION %d, pChange->m_iCRNumber: %d!\n", i, pChange->getLocalRev())); // undo the change locally m_pDoc->undoCmd(1); // fix up the positions on the change stack for (UT_sint32 j = i+1; j < pAdjusts->getItemCount(); j++) { ChangeAdjust* pC = pAdjusts->getNthItem(j); if (pC) { UT_DEBUGMSG(("Looking at fixing up the position of change pos %d\n", j)); if (pChange->getLocalPos() < pC->getLocalPos()) { UT_DEBUGMSG(("Adjusting change pos %d from m_iDocPos: %d to m_iDocPos: %d\n", j, pC->getLocalPos(), pC->getLocalPos() - pChange->getLocalAdjust())); pC->setLocalPos(pC->getLocalPos() - pChange->getLocalAdjust()); } else { UT_DEBUGMSG(("No need to adjust change pos %d\n", j)); } } else { UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); } } // kill off the item pAdjusts->deleteNthItem(i); delete pChange; } else { UT_DEBUGMSG(("Skipping undo of remote change\n")); } } else break; } else { UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); } } m_pAbiCollab->setIsReverting(false); // unmask all changes in the exporter UT_DEBUGMSG(("Pre-Acknowledging revert of revision %d\n", iLocalRev)); // send the revert acknowledgement command to the session owner RevertAckSessionPacket rasp(m_pAbiCollab->getSessionId(), m_pDoc->getOrigDocUUIDString(), iLocalRev); m_pAbiCollab->push(&rasp, pCollaborator); m_iAlreadyRevertedRevs.push_back(iLocalRev); return true; } }
void MmspSession::local_process( response_type const & resp) { boost::system::error_code ec; LOG_DEBUG("[local_process] session_id:" << session_id_ << " request:" << request().id()); switch (request().id()) { case MmspViewerToMacMessage::CONNECT: { //MmspDataConnect & req(request().as<MmspDataConnect>()); MmspDataReportConnectedEx & rsp(response().get<MmspDataReportConnectedEx>()); rsp.playIncarnation = 0xf0f0f0ef; // MMS_DISABLE_PACKET_PAIR rsp.cbServerVersionInfo = SERVER_VERSION_LENGTH; rsp.cbAuthenPackage = AUTH_TYPE_LENGTH; rsp.ServerVersionInfo = SERVER_VERSION; rsp.AuthenPackage = AUTH_TYPE; } break; case MmspViewerToMacMessage::CONNECT_FUNNEL: { MmspDataConnectFunnel & req(request().as<MmspDataConnectFunnel>()); MmspDataReportConnectedFunnel & rsp(response().get<MmspDataReportConnectedFunnel>()); transport_ = req.funnelName.to_string(); rsp.funnelName = FUNNEL_NAME; } break; case MmspViewerToMacMessage::OPEN_FILE: { MmspDataOpenFile & req(request().as<MmspDataOpenFile>()); MmspDataReportOpenFile & rsp(response().get<MmspDataReportOpenFile>()); rsp.playIncarnation = req.playIncarnation; rsp.openFileId = ++file_id_; framework::string::Url url("mms://host/" + req.fileName.to_string()); dispatcher_ = mgr_.alloc_dispatcher(url, ec); dispatcher_->async_open(url, rsp, resp); } return; case MmspViewerToMacMessage::READ_BLOCK: { MmspDataReadBlock & req(request().as<MmspDataReadBlock>()); MmspDataReportReadBlock & rsp(response().get<MmspDataReportReadBlock>()); rsp.playIncarnation = req.playIncarnation; dispatcher_->setup(*this, transport_, ec); } break; case MmspViewerToMacMessage::STREAM_SWITCH: { //MmspDataStreamSwitch & req(request().as<MmspDataStreamSwitch>()); //MmspDataReportStreamSwitch & rsp(response().get<MmspDataReportStreamSwitch>()); } break; case MmspViewerToMacMessage::START_PLAYING: { MmspDataStartPlaying & req(request().as<MmspDataStartPlaying>()); MmspDataReportStartPlaying & rsp(response().get<MmspDataReportStartPlaying>()); rsp.playIncarnation = req.playIncarnation; rsp.tigerFileId = file_id_; ++play_count_; play_incarnation_ = req.playIncarnation; dispatcher_->async_play(req, resp, boost::bind(&MmspSession::on_play, this, _1)); } return; case MmspViewerToMacMessage::STOP_PLAYING: { MmspDataStopPlaying & req(request().as<MmspDataStopPlaying>()); MmspDataReportEndOfStream & rsp(response().get<MmspDataReportEndOfStream>()); rsp.playIncarnation = req.playIncarnation; if (play_count_) dispatcher_->cancel(ec); } break; case MmspViewerToMacMessage::CLOSE_FILE: { //MmspDataCloseFile & req(request().as<MmspDataCloseFile>()); if (dispatcher_) { dispatcher_->close(ec); dispatcher_ = NULL; } } break; default: ec = mmsp_error::unkown_command; } resp(ec); }
TCA emitFreeLocalsHelpers(CodeBlock& cb, DataBlock& data, UniqueStubs& us) { // The address of the first local is passed in the second argument register. // We use the third and fourth as scratch registers. auto const local = rarg(1); auto const last = rarg(2); auto const type = rarg(3); CGMeta fixups; // This stub is very hot; keep it cache-aligned. align(cb, &fixups, Alignment::CacheLine, AlignContext::Dead); auto const release = emitDecRefHelper(cb, data, fixups, local, type, local | last); auto const decref_local = [&] (Vout& v) { auto const sf = v.makeReg(); // We can't do a byte load here---we have to sign-extend since we use // `type' as a 32-bit array index to the destructor table. v << loadzbl{local[TVOFF(m_type)], type}; emitCmpTVType(v, sf, KindOfRefCountThreshold, type); ifThen(v, CC_G, sf, [&] (Vout& v) { auto const dword_size = sizeof(int64_t); // saving return value on the stack, but keeping it 16-byte aligned v << mflr{rfuncln()}; v << lea {rsp()[-2 * dword_size], rsp()}; v << store{rfuncln(), rsp()[0]}; v << call{release, arg_regs(3)}; // restore the return value from the stack v << load{rsp()[0], rfuncln()}; v << lea {rsp()[2 * dword_size], rsp()}; v << mtlr{rfuncln()}; }); }; auto const next_local = [&] (Vout& v) { v << addqi{static_cast<int>(sizeof(TypedValue)), local, local, v.makeReg()}; }; alignJmpTarget(cb); us.freeManyLocalsHelper = vwrap(cb, data, fixups, [&] (Vout& v) { // We always unroll the final `kNumFreeLocalsHelpers' decrefs, so only loop // until we hit that point. v << lea{rvmfp()[localOffset(kNumFreeLocalsHelpers - 1)], last}; doWhile(v, CC_NZ, {}, [&] (const VregList& in, const VregList& out) { auto const sf = v.makeReg(); decref_local(v); next_local(v); v << cmpq{local, last, sf}; return sf; } ); }); for (auto i = kNumFreeLocalsHelpers - 1; i >= 0; --i) { us.freeLocalsHelpers[i] = vwrap(cb, data, [&] (Vout& v) { decref_local(v); if (i != 0) next_local(v); }); } // All the stub entrypoints share the same ret. vwrap(cb, data, fixups, [] (Vout& v) { v << ret{}; }); // This stub is hot, so make sure to keep it small. #if 0 // TODO(gut): Currently this assert fails. // Take a closer look when looking at performance always_assert(Stats::enabled() || (cb.frontier() - release <= 4 * cache_line_size())); #endif fixups.process(nullptr); return release; }