void StubQueue::commit(int committed_code_size, CodeStrings& strings) { assert(committed_code_size > 0, "committed_code_size must be > 0"); int committed_size = round_to(stub_code_size_to_size(committed_code_size), CodeEntryAlignment); Stub* s = current_stub(); assert(committed_size <= stub_size(s), "committed size must not exceed requested size"); stub_initialize(s, committed_size, strings); _queue_end += committed_size; _number_of_stubs++; if (_mutex != NULL) _mutex->unlock(); debug_only(stub_verify(s);) }
/* * Service request stub emitter. * * Emit a service request stub of type `sr' at `start' in `cb'. */ void emit_svcreq(CodeBlock& cb, TCA start, bool persist, folly::Optional<FPInvOffset> spOff, ServiceRequest sr, const ArgVec& argv) { FTRACE(2, "svcreq @{} {}(", start, to_name(sr)); auto const is_reused = start != cb.frontier(); CodeBlock stub; stub.init(start, stub_size(), "svcreq_stub"); { Vauto vasm{stub}; auto& v = vasm.main(); // If we have an spOff, materialize rvmsp() so that handleSRHelper() can do // a VM reg sync. (When we don't have an spOff, the caller of the service // request was responsible for making sure rvmsp already contained the top // of the stack.) if (spOff) { v << lea{rvmfp()[-cellsToBytes(spOff->offset)], rvmsp()}; } auto live_out = leave_trace_regs(); assert(argv.size() <= kMaxArgs); // Pick up CondCode arguments first---vasm may optimize immediate loads // into operations which clobber status flags. for (auto i = 0; i < argv.size(); ++i) { auto const& arg = argv[i]; if (arg.kind != Arg::Kind::CondCode) continue; FTRACE(2, "c({}), ", cc_names[arg.cc]); v << setcc{arg.cc, r_svcreq_sf(), rbyte(r_svcreq_arg(i))}; } for (auto i = 0; i < argv.size(); ++i) { auto const& arg = argv[i]; auto const r = r_svcreq_arg(i); switch (arg.kind) { case Arg::Kind::Immed: FTRACE(2, "{}, ", arg.imm); v << copy{v.cns(arg.imm), r}; break; case Arg::Kind::Address: FTRACE(2, "{}(%rip), ", arg.imm); v << leap{reg::rip[arg.imm], r}; break; case Arg::Kind::CondCode: break; } live_out |= r; } FTRACE(2, ") : stub@"); if (persist) { FTRACE(2, "<none>"); v << copy{v.cns(0), r_svcreq_stub()}; } else { FTRACE(2, "{}", stub.base()); v << leap{reg::rip[int64_t(stub.base())], r_svcreq_stub()}; } v << copy{v.cns(sr), r_svcreq_req()}; live_out |= r_svcreq_stub(); live_out |= r_svcreq_req(); v << jmpi{TCA(handleSRHelper), live_out}; // We pad ephemeral stubs unconditionally. This is required for // correctness by the x64 code relocator. vasm.unit().padding = !persist; } if (!is_reused) cb.skip(stub.used()); }