/* main output routine... */ int dooutput(lpPointBlankRange pointblankrange, int error) { if (error) posterr_error(error, (error > 0) ? errors_pbr[error] : NULL); else { html_cgitext(); setup_openhead(); setup_body(); setup_info(PBR_VERSION); setup_header(2); html_horzrule(NULL, 0, 0, 0, 0); writedata(pointblankrange); html_horzrule(NULL, 0, 0, 0, 0); writetable(pointblankrange); html_closebody(); html_closehead(); } return 0; }
RuntimeIC::RuntimeIC(void* func_addr, int num_slots, int slot_size) : eh_frame(RUNTIMEICS_OMIT_FRAME_PTR) { static StatCounter sc("runtime_ics_num"); sc.log(); if (ENABLE_RUNTIME_ICS) { assert(SCRATCH_BYTES >= 0); assert(SCRATCH_BYTES < 0x80); // This would break both the instruction encoding and the dwarf encoding assert(SCRATCH_BYTES % 8 == 0); #if RUNTIMEICS_OMIT_FRAME_PTR /* * prologue: * sub $0x28, %rsp # 48 83 ec 28 * * epilogue: * add $0x28, %rsp # 48 83 c4 28 * retq # c3 * */ static const int PROLOGUE_SIZE = 4; static const int EPILOGUE_SIZE = 5; assert(SCRATCH_BYTES % 16 == 8); #else /* * The prologue looks like: * push %rbp # 55 * mov %rsp, %rbp # 48 89 e5 * sub $0x30, %rsp # 48 83 ec 30 * * The epilogue is: * add $0x30, %rsp # 48 83 c4 30 * pop %rbp # 5d * retq # c3 */ static const int PROLOGUE_SIZE = 8; static const int EPILOGUE_SIZE = 6; assert(SCRATCH_BYTES % 16 == 0); #endif static const int CALL_SIZE = 13; int patchable_size = num_slots * slot_size; #ifdef NVALGRIND int total_size = PROLOGUE_SIZE + patchable_size + CALL_SIZE + EPILOGUE_SIZE; addr = malloc(total_size); #else total_size = PROLOGUE_SIZE + patchable_size + CALL_SIZE + EPILOGUE_SIZE; addr = mmap(NULL, (total_size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); RELEASE_ASSERT(addr != MAP_FAILED, ""); #endif // printf("Allocated runtime IC at %p\n", addr); std::unique_ptr<ICSetupInfo> setup_info( ICSetupInfo::initialize(true, num_slots, slot_size, ICSetupInfo::Generic, NULL)); uint8_t* pp_start = (uint8_t*)addr + PROLOGUE_SIZE; uint8_t* pp_end = pp_start + patchable_size + CALL_SIZE; SpillMap _spill_map; PatchpointInitializationInfo initialization_info = initializePatchpoint3(func_addr, pp_start, pp_end, 0 /* scratch_offset */, 0 /* scratch_size */, std::unordered_set<int>(), _spill_map); assert(_spill_map.size() == 0); assert(initialization_info.slowpath_start == pp_start + patchable_size); assert(initialization_info.slowpath_rtn_addr == pp_end); assert(initialization_info.continue_addr == pp_end); StackInfo stack_info(SCRATCH_BYTES, 0); icinfo = registerCompiledPatchpoint(pp_start, pp_start + patchable_size, pp_end, pp_end, setup_info.get(), stack_info, std::unordered_set<int>()); assembler::Assembler prologue_assem((uint8_t*)addr, PROLOGUE_SIZE); #if RUNTIMEICS_OMIT_FRAME_PTR // If SCRATCH_BYTES is 8 or less, we could use more compact instruction encodings // (push instead of sub), but it doesn't seem worth it for now. prologue_assem.sub(assembler::Immediate(SCRATCH_BYTES), assembler::RSP); #else prologue_assem.push(assembler::RBP); prologue_assem.mov(assembler::RSP, assembler::RBP); prologue_assem.sub(assembler::Immediate(SCRATCH_BYTES), assembler::RSP); #endif assert(!prologue_assem.hasFailed()); assert(prologue_assem.isExactlyFull()); assembler::Assembler epilogue_assem(pp_end, EPILOGUE_SIZE); #if RUNTIMEICS_OMIT_FRAME_PTR epilogue_assem.add(assembler::Immediate(SCRATCH_BYTES), assembler::RSP); #else epilogue_assem.add(assembler::Immediate(SCRATCH_BYTES), assembler::RSP); epilogue_assem.pop(assembler::RBP); #endif epilogue_assem.retq(); assert(!epilogue_assem.hasFailed()); assert(epilogue_assem.isExactlyFull()); // TODO: ideally would be more intelligent about allocation strategies. // The code sections should be together and the eh sections together eh_frame.writeAndRegister(addr, total_size); } else { addr = func_addr; } }
RuntimeIC::RuntimeIC(void* func_addr, int total_size) { static StatCounter sc("num_runtime_ics"); sc.log(); if (ENABLE_RUNTIME_ICS) { assert(SCRATCH_BYTES >= 0); assert(SCRATCH_BYTES < 0x80); // This would break both the instruction encoding and the dwarf encoding assert(SCRATCH_BYTES % 8 == 0); #if RUNTIMEICS_OMIT_FRAME_PTR /* * prologue: * sub $0x28, %rsp # 48 83 ec 28 * * epilogue: * add $0x28, %rsp # 48 83 c4 28 * retq # c3 * */ static const int PROLOGUE_SIZE = 4; static const int EPILOGUE_SIZE = 5; assert(SCRATCH_BYTES % 16 == 8); #else /* * The prologue looks like: * push %rbp # 55 * mov %rsp, %rbp # 48 89 e5 * sub $0x30, %rsp # 48 83 ec 30 * * The epilogue is: * add $0x30, %rsp # 48 83 c4 30 * pop %rbp # 5d * retq # c3 */ static const int PROLOGUE_SIZE = 8; static const int EPILOGUE_SIZE = 6; assert(SCRATCH_BYTES % 16 == 0); #endif static const int CALL_SIZE = 13; int total_code_size = total_size - EH_FRAME_SIZE; int patchable_size = total_code_size - (PROLOGUE_SIZE + CALL_SIZE + EPILOGUE_SIZE); int total_size = total_code_size + EH_FRAME_SIZE; assert(total_size == 512 && "we currently only have a 512 byte block memory manager"); addr = memory_manager_512b.alloc(); // the memory block contains the EH frame directly followed by the generated machine code. void* eh_frame_addr = addr; addr = (char*)addr + EH_FRAME_SIZE; // printf("Allocated runtime IC at %p\n", addr); std::unique_ptr<ICSetupInfo> setup_info(ICSetupInfo::initialize(true, patchable_size, ICSetupInfo::Generic)); uint8_t* pp_start = (uint8_t*)addr + PROLOGUE_SIZE; uint8_t* pp_end = pp_start + patchable_size + CALL_SIZE; SpillMap _spill_map; PatchpointInitializationInfo initialization_info = initializePatchpoint3( func_addr, pp_start, pp_end, 0 /* scratch_offset */, 0 /* scratch_size */, LiveOutSet(), _spill_map); assert(_spill_map.size() == 0); assert(initialization_info.slowpath_start == pp_start + patchable_size); assert(initialization_info.slowpath_rtn_addr == pp_end); assert(initialization_info.continue_addr == pp_end); StackInfo stack_info(SCRATCH_BYTES, 0); icinfo = registerCompiledPatchpoint(pp_start, pp_start + patchable_size, pp_end, pp_end, setup_info.get(), stack_info, LiveOutSet()); assembler::Assembler prologue_assem((uint8_t*)addr, PROLOGUE_SIZE); #if RUNTIMEICS_OMIT_FRAME_PTR // If SCRATCH_BYTES is 8 or less, we could use more compact instruction encodings // (push instead of sub), but it doesn't seem worth it for now. prologue_assem.sub(assembler::Immediate(SCRATCH_BYTES), assembler::RSP); #else prologue_assem.push(assembler::RBP); prologue_assem.mov(assembler::RSP, assembler::RBP); prologue_assem.sub(assembler::Immediate(SCRATCH_BYTES), assembler::RSP); #endif assert(!prologue_assem.hasFailed()); assert(prologue_assem.isExactlyFull()); assembler::Assembler epilogue_assem(pp_end, EPILOGUE_SIZE); #if RUNTIMEICS_OMIT_FRAME_PTR epilogue_assem.add(assembler::Immediate(SCRATCH_BYTES), assembler::RSP); #else epilogue_assem.add(assembler::Immediate(SCRATCH_BYTES), assembler::RSP); epilogue_assem.pop(assembler::RBP); #endif epilogue_assem.retq(); assert(!epilogue_assem.hasFailed()); assert(epilogue_assem.isExactlyFull()); if (RUNTIMEICS_OMIT_FRAME_PTR) memcpy(eh_frame_addr, _eh_frame_template_ofp, _eh_frame_template_ofp_size); else memcpy(eh_frame_addr, _eh_frame_template_fp, _eh_frame_template_fp_size); register_eh_frame.updateAndRegisterFrameFromTemplate((uint64_t)addr, total_code_size, (uint64_t)eh_frame_addr, EH_FRAME_SIZE); } else { addr = func_addr; } }
void JitFragmentWriter::_emitPPCall(RewriterVar* result, void* func_addr, const RewriterVar::SmallVector& args, int num_slots, int slot_size) { assembler::Register r = allocReg(assembler::R11); if (args.size() > 6) { // only 6 args can get passed in registers. assert(args.size() <= 6 + JitCodeBlock::num_stack_args); for (int i = 6; i < args.size(); ++i) { assembler::Register reg = args[i]->getInReg(Location::any(), true); assembler->mov(reg, assembler::Indirect(assembler::RSP, sizeof(void*) * (i - 6))); } RewriterVar::SmallVector reg_args(args.begin(), args.begin() + 6); assert(reg_args.size() == 6); _setupCall(false, reg_args, RewriterVar::SmallVector()); } else _setupCall(false, args, RewriterVar::SmallVector()); if (failed) return; // make sure setupCall doesn't use R11 assert(vars_by_location.count(assembler::R11) == 0); int pp_size = slot_size * num_slots; // make space for patchpoint uint8_t* pp_start = rewrite->getSlotStart() + assembler->bytesWritten(); constexpr int call_size = 16; assembler->skipBytes(pp_size + call_size); uint8_t* pp_end = rewrite->getSlotStart() + assembler->bytesWritten(); assert(assembler->hasFailed() || (pp_start + pp_size + call_size == pp_end)); std::unique_ptr<ICSetupInfo> setup_info( ICSetupInfo::initialize(true, num_slots, slot_size, ICSetupInfo::Generic, NULL)); // calculate available scratch space int pp_scratch_size = 0; int pp_scratch_location = rewrite->getScratchRspOffset() + rewrite->getScratchSize(); for (int i = rewrite->getScratchSize() - 8; i >= 0; i -= 8) { Location l(Location::Scratch, i); if (vars_by_location.count(l)) break; pp_scratch_size += 8; pp_scratch_location -= 8; } for (RewriterVar* arg : args) { arg->bumpUse(); } assertConsistent(); StackInfo stack_info(pp_scratch_size, pp_scratch_location); pp_infos.emplace_back(PPInfo{ func_addr, pp_start, pp_end, std::move(setup_info), stack_info }); assert(vars_by_location.count(assembler::RAX) == 0); result->initializeInReg(assembler::RAX); assertConsistent(); result->releaseIfNoUses(); }