Commit 258a2b0a authored by Marius Wachtler's avatar Marius Wachtler

ICs: variable size IC slots

before this change we had a fixed number of equal size slots inside an IC.
Because of the large difference in rewrite sizes a fixed slot size is not ideal.
We often ended up with too large slots which prevented us from emitting more slots.
(or very large ICs in general which are bad for memory usage and the instruction cache)

With this commit we will start with a single slot with the size of the whole IC and then decreasing its size to the actual bytes emitted
and creating a new slot which starts directly at the end of the previous slot.
We will repeat to to this until the space left is smaller than the number of bytes the last slot required.
This makes it a little bit less likely that we will be successful in overwritting an existing slot
but our benchmarks show that it is still a large win on all our benchmarks.

Some notable changes are:
- we pick the slot to rewrite much earlier now and prevent it from getting rewritten while we rewrite using num_inside = 1
  the reason is that we would otherwise not know how big the slot is
- when we resize a slot we have to patch the failing guard jumps to the address of the next slot
parent a6b4559d
......@@ -206,6 +206,7 @@ public:
uint8_t* startAddr() const { return start_addr; }
int bytesLeft() const { return end_addr - addr; }
int bytesWritten() const { return addr - start_addr; }
int size() const { return end_addr - start_addr; }
uint8_t* curInstPointer() { return addr; }
void setCurInstPointer(uint8_t* ptr) { addr = ptr; }
bool isExactlyFull() const { return addr == end_addr; }
......
This diff is collapsed.
......@@ -15,10 +15,12 @@
#ifndef PYSTON_ASMWRITING_ICINFO_H
#define PYSTON_ASMWRITING_ICINFO_H
#include <deque>
#include <memory>
#include <unordered_set>
#include <vector>
#include "llvm/ADT/ArrayRef.h"
#include "llvm/IR/CallingConv.h"
#include "asm_writing/assembler.h"
......@@ -55,11 +57,15 @@ struct DecrefInfo {
struct ICSlotInfo {
public:
ICSlotInfo(ICInfo* ic, int idx) : ic(ic), idx(idx), num_inside(0) {}
ICSlotInfo(ICInfo* ic, uint8_t* addr, int size)
: ic(ic), start_addr(addr), num_inside(0), size(size), used(false) {}
ICInfo* ic;
int idx; // the index inside the ic
int num_inside; // the number of stack frames that are currently inside this slot
uint8_t* start_addr;
int num_inside; // the number of stack frames that are currently inside this slot will also get increased during a
// rewrite
int size;
bool used; // if this slot is empty or got invalidated
std::vector<void*> gc_references;
std::vector<DecrefInfo> decref_infos;
......@@ -68,59 +74,12 @@ public:
void clear();
};
class ICSlotRewrite {
public:
class CommitHook {
public:
virtual ~CommitHook() {}
virtual bool finishAssembly(int fastpath_offset) = 0;
};
private:
ICInfo* ic;
const char* debug_name;
uint8_t* buf;
assembler::Assembler assembler;
llvm::SmallVector<std::pair<ICInvalidator*, int64_t>, 4> dependencies;
ICSlotInfo* ic_entry;
public:
ICSlotRewrite(ICInfo* ic, const char* debug_name);
~ICSlotRewrite();
assembler::Assembler* getAssembler() { return &assembler; }
int getSlotSize();
int getScratchRspOffset();
int getScratchSize();
uint8_t* getSlotStart();
TypeRecorder* getTypeRecorder();
assembler::GenericRegister returnRegister();
ICSlotInfo* prepareEntry();
void addDependenceOn(ICInvalidator&);
void commit(CommitHook* hook, std::vector<void*> gc_references,
std::vector<std::pair<uint64_t, std::vector<Location>>> decref_infos);
void abort();
const ICInfo* getICInfo() { return ic; }
const char* debugName() { return debug_name; }
friend class ICInfo;
};
typedef BitSet<16> LiveOutSet;
class ICSlotRewrite;
class ICInfo {
private:
std::vector<ICSlotInfo> slots;
std::deque<ICSlotInfo> slots;
// For now, just use a round-robin eviction policy.
// This is probably a bunch worse than LRU, but it's also
// probably a bunch better than the "always evict slot #0" policy
......@@ -129,8 +88,6 @@ private:
int next_slot_to_try;
const StackInfo stack_info;
const int num_slots;
const int slot_size;
const llvm::CallingConv::ID calling_conv;
LiveOutSet live_outs;
const assembler::GenericRegister return_register;
......@@ -148,15 +105,15 @@ private:
ICSlotInfo* pickEntryForRewrite(const char* debug_name);
public:
ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int num_slots,
int slot_size, llvm::CallingConv::ID calling_conv, LiveOutSet live_outs,
assembler::GenericRegister return_register, TypeRecorder* type_recorder,
std::vector<Location> ic_global_decref_locations);
ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int size,
llvm::CallingConv::ID calling_conv, LiveOutSet live_outs, assembler::GenericRegister return_register,
TypeRecorder* type_recorder, std::vector<Location> ic_global_decref_locations);
~ICInfo();
void* const start_addr, *const slowpath_rtn_addr, *const continue_addr;
int getSlotSize() { return slot_size; }
int getNumSlots() { return num_slots; }
// returns a suggestion about how large this IC should be based on the number of used slots
int calculateSuggestedSize();
llvm::CallingConv::ID getCallingConvention() { return calling_conv; }
const LiveOutSet& getLiveOuts() { return live_outs; }
......@@ -184,6 +141,54 @@ public:
void appendDecrefInfosTo(std::vector<DecrefInfo>& dest_decref_infos);
};
typedef std::tuple<int /*offset of jmp instr*/, int /*end of jmp instr*/, assembler::ConditionCode> NextSlotJumpInfo;
class ICSlotRewrite {
public:
class CommitHook {
public:
virtual ~CommitHook() {}
virtual bool finishAssembly(int fastpath_offset, bool& should_fill_with_nops, bool& variable_size_slots) = 0;
};
private:
ICSlotInfo* ic_entry;
const char* debug_name;
uint8_t* buf;
assembler::Assembler assembler;
llvm::SmallVector<std::pair<ICInvalidator*, int64_t>, 4> dependencies;
ICSlotRewrite(ICSlotInfo* ic_entry, const char* debug_name);
public:
static std::unique_ptr<ICSlotRewrite> create(ICInfo* ic, const char* debug_name);
~ICSlotRewrite();
const char* debugName() { return debug_name; }
assembler::Assembler* getAssembler() { return &assembler; }
ICInfo* getICInfo() { return ic_entry->ic; }
int getSlotSize() { return ic_entry->size; }
uint8_t* getSlotStart() { return ic_entry->start_addr; }
TypeRecorder* getTypeRecorder() { return getICInfo()->type_recorder; }
assembler::GenericRegister returnRegister() { return getICInfo()->return_register; }
int getScratchSize() { return getICInfo()->stack_info.scratch_size; }
int getScratchRspOffset() {
assert(getICInfo()->stack_info.scratch_size);
return getICInfo()->stack_info.scratch_rsp_offset;
}
ICSlotInfo* prepareEntry() { return (ic_entry && ic_entry->num_inside == 1) ? ic_entry : NULL; }
void addDependenceOn(ICInvalidator&);
void commit(CommitHook* hook, std::vector<void*> gc_references,
std::vector<std::pair<uint64_t, std::vector<Location>>> decref_infos,
llvm::ArrayRef<NextSlotJumpInfo> next_slot_jumps);
void abort();
friend class ICInfo;
};
inline void registerGCTrackedICInfo(ICInfo* ic) {
}
inline void deregisterGCTrackedICInfo(ICInfo* ic) {
......
......@@ -287,20 +287,20 @@ void RewriterVar::addGuard(uint64_t val) {
rewriter->addAction([=]() { rewriter->_addGuard(this, val_var); }, { this, val_var }, ActionType::GUARD);
}
void Rewriter::_slowpathJump(bool condition_eq) {
void Rewriter::_nextSlotJump(bool condition_eq) {
// If a jump offset is larger then 0x80 the instruction encoding requires 6bytes instead of 2bytes.
// This adds up quickly, thats why we will try to find another jump to the slowpath with the same condition with a
// smaller offset and jump to it / use it as a trampoline.
// The benchmark show that this increases the performance slightly even though it introduces additional jumps.
int& last_jmp_offset = condition_eq ? offset_eq_jmp_slowpath : offset_ne_jmp_slowpath;
int& last_jmp_offset = condition_eq ? offset_eq_jmp_next_slot : offset_ne_jmp_next_slot;
auto condition = condition_eq ? assembler::COND_EQUAL : assembler::COND_NOT_EQUAL;
assert(assembler->bytesWritten() + assembler->bytesLeft() == rewrite->getSlotSize());
if (last_jmp_offset != -1 && assembler->bytesLeft() >= 0x80 && assembler->bytesWritten() - last_jmp_offset < 0x80) {
if (last_jmp_offset != -1 && assembler->bytesWritten() - last_jmp_offset < 0x80) {
assembler->jmp_cond(assembler::JumpDestination::fromStart(last_jmp_offset), condition);
} else {
last_jmp_offset = assembler->bytesWritten();
assembler->jmp_cond(assembler::JumpDestination::fromStart(rewrite->getSlotSize()), condition);
next_slot_jmps.emplace_back(last_jmp_offset, assembler->bytesWritten(), condition);
}
}
......@@ -321,7 +321,7 @@ void Rewriter::_addGuard(RewriterVar* var, RewriterVar* val_constant) {
restoreArgs(); // can only do movs, doesn't affect flags, so it's safe
assertArgsInPlace();
_slowpathJump(false /*= not equal jmp */);
_nextSlotJump(false /*= not equal jmp */);
var->bumpUse();
val_constant->bumpUse();
......@@ -353,7 +353,7 @@ void Rewriter::_addGuardNotEq(RewriterVar* var, RewriterVar* val_constant) {
restoreArgs(); // can only do movs, doesn't affect flags, so it's safe
assertArgsInPlace();
_slowpathJump(true /*= equal jmp */);
_nextSlotJump(true /*= equal jmp */);
var->bumpUse();
val_constant->bumpUse();
......@@ -405,7 +405,7 @@ void Rewriter::_addAttrGuard(RewriterVar* var, int offset, RewriterVar* val_cons
restoreArgs(); // can only do movs, doesn't affect flags, so it's safe
assertArgsInPlace();
_slowpathJump(negate);
_nextSlotJump(negate);
var->bumpUse();
val_constant->bumpUse();
......@@ -1683,7 +1683,7 @@ void Rewriter::commit() {
}
#endif
rewrite->commit(this, std::move(gc_references), std::move(decref_infos));
rewrite->commit(this, std::move(gc_references), std::move(decref_infos), next_slot_jmps);
assert(gc_references.empty());
if (assembler->hasFailed()) {
......@@ -1706,12 +1706,13 @@ void Rewriter::commit() {
ic_rewrites_total_bytes.log(asm_size_bytes);
}
bool Rewriter::finishAssembly(int continue_offset) {
bool Rewriter::finishAssembly(int continue_offset, bool& should_fill_with_nops, bool& variable_size_slots) {
assert(picked_slot);
assembler->jmp(assembler::JumpDestination::fromStart(continue_offset));
assembler->fillWithNops();
should_fill_with_nops = true;
variable_size_slots = true;
return !assembler->hasFailed();
}
......@@ -2217,8 +2218,8 @@ Rewriter::Rewriter(std::unique_ptr<ICSlotRewrite> rewrite, int num_args, const L
marked_inside_ic(false),
done_guarding(false),
last_guard_action(-1),
offset_eq_jmp_slowpath(-1),
offset_ne_jmp_slowpath(-1),
offset_eq_jmp_next_slot(-1),
offset_ne_jmp_next_slot(-1),
allocatable_regs(std_allocatable_regs) {
initPhaseCollecting();
......@@ -2369,7 +2370,10 @@ Rewriter* Rewriter::createRewriter(void* rtn_addr, int num_args, const char* deb
}
log_ic_attempts_started(debug_name);
return new Rewriter(ic->startRewrite(debug_name), num_args, ic->getLiveOuts());
std::unique_ptr<ICSlotRewrite> slots = ic->startRewrite(debug_name);
if (!slots)
return NULL;
return new Rewriter(std::move(slots), num_args, ic->getLiveOuts());
}
static const int INITIAL_CALL_SIZE = 13;
......
......@@ -502,8 +502,11 @@ protected:
}
int last_guard_action;
int offset_eq_jmp_slowpath;
int offset_ne_jmp_slowpath;
int offset_eq_jmp_next_slot;
int offset_ne_jmp_next_slot;
// keeps track of all jumps to the next slot so we can patch them if the size of the current slot changes
std::vector<NextSlotJumpInfo> next_slot_jmps;
// Move the original IC args back into their original registers:
void restoreArgs();
......@@ -535,9 +538,9 @@ protected:
// Do the bookkeeping to say that var is no longer in location l
void removeLocationFromVar(RewriterVar* var, Location l);
bool finishAssembly(int continue_offset) override;
bool finishAssembly(int continue_offset, bool& should_fill_with_nops, bool& variable_size_slots) override;
void _slowpathJump(bool condition_eq);
void _nextSlotJump(bool condition_eq);
void _trap();
void _loadConst(RewriterVar* result, int64_t val);
void _setupCall(bool has_side_effects, llvm::ArrayRef<RewriterVar*> args = {},
......
This diff is collapsed.
......@@ -302,7 +302,7 @@ public:
void abortCompilation();
int finishCompilation();
bool finishAssembly(int continue_offset) override;
bool finishAssembly(int continue_offset, bool& should_fill_with_nops, bool& variable_size_slots) override;
private:
RewriterVar* allocArgs(const llvm::ArrayRef<RewriterVar*> args, RewriterVar::SetattrType);
......@@ -319,8 +319,8 @@ private:
RewriterVar* emitCallWithAllocatedArgs(void* func_addr, const llvm::ArrayRef<RewriterVar*> args,
const llvm::ArrayRef<RewriterVar*> additional_uses);
std::pair<RewriterVar*, RewriterAction*> emitPPCall(void* func_addr, llvm::ArrayRef<RewriterVar*> args,
unsigned char num_slots, unsigned short slot_size,
AST* ast_node = NULL, TypeRecorder* type_recorder = NULL,
unsigned short pp_size, AST* ast_node = NULL,
TypeRecorder* type_recorder = NULL,
llvm::ArrayRef<RewriterVar*> additional_uses = {});
static void assertNameDefinedHelper(const char* id);
......@@ -340,8 +340,8 @@ private:
void _emitGetLocal(RewriterVar* val_var, const char* name);
void _emitJump(CFGBlock* b, RewriterVar* block_next, ExitInfo& exit_info);
void _emitOSRPoint();
void _emitPPCall(RewriterVar* result, void* func_addr, llvm::ArrayRef<RewriterVar*> args, int num_slots,
int slot_size, AST* ast_node, llvm::ArrayRef<RewriterVar*> vars_to_bump);
void _emitPPCall(RewriterVar* result, void* func_addr, llvm::ArrayRef<RewriterVar*> args, unsigned short pp_size,
AST* ast_node, llvm::ArrayRef<RewriterVar*> vars_to_bump);
void _emitRecordType(RewriterVar* type_recorder_var, RewriterVar* obj_cls_var);
void _emitReturn(RewriterVar* v);
void _emitSideExit(STOLEN(RewriterVar*) var, RewriterVar* val_constant, CFGBlock* next_block,
......
......@@ -43,14 +43,13 @@ int ICSetupInfo::totalSize() const {
// 14 bytes per reg that needs to be spilled
call_size += 14 * 4;
}
return num_slots * slot_size + call_size;
return size + call_size;
}
static std::vector<std::pair<PatchpointInfo*, void* /* addr of func to call */>> new_patchpoints;
ICSetupInfo* ICSetupInfo::initialize(bool has_return_value, int num_slots, int slot_size, ICType type,
TypeRecorder* type_recorder) {
ICSetupInfo* rtn = new ICSetupInfo(type, num_slots, slot_size, has_return_value, type_recorder);
ICSetupInfo* ICSetupInfo::initialize(bool has_return_value, int size, ICType type, TypeRecorder* type_recorder) {
ICSetupInfo* rtn = new ICSetupInfo(type, size, has_return_value, type_recorder);
// We use size == CALL_ONLY_SIZE to imply that the call isn't patchable
assert(rtn->totalSize() > CALL_ONLY_SIZE);
......@@ -303,7 +302,7 @@ void processStackmap(CompiledFunction* cf, StackMap* stackmap) {
auto initialization_info = initializePatchpoint3(slowpath_func, start_addr, end_addr, scratch_rbp_offset,
scratch_size, std::move(live_outs), frame_remapped);
ASSERT(initialization_info.slowpath_start - start_addr >= ic->num_slots * ic->slot_size,
ASSERT(initialization_info.slowpath_start - start_addr >= ic->size,
"Used more slowpath space than expected; change ICSetupInfo::totalSize()?");
assert(pp->numICStackmapArgs() == 0); // don't do anything with these for now
......@@ -360,72 +359,72 @@ void* PatchpointInfo::getSlowpathAddr(unsigned int pp_id) {
return new_patchpoints[pp_id].second;
}
int numSlots(ICInfo* bjit_ic_info, int default_num_slots) {
int slotSize(ICInfo* bjit_ic_info, int default_size) {
if (!bjit_ic_info)
return default_num_slots;
// this thresholds are chosen by running the benchmarks several times with different settings.
int num_slots = std::max(bjit_ic_info->getNumSlots(), default_num_slots);
if (bjit_ic_info->isMegamorphic())
num_slots *= 3;
else if (bjit_ic_info->timesRewritten() > IC_MEGAMORPHIC_THRESHOLD / 2)
num_slots += 2;
else
num_slots = std::min(std::max(bjit_ic_info->timesRewritten(), 1), default_num_slots);
return std::min(num_slots, 10);
return default_size;
int suggested_size = bjit_ic_info->calculateSuggestedSize();
if (suggested_size <= 0)
return default_size;
// round up to make it more likely that we will find a entry in the object cache
if (suggested_size & 31)
suggested_size += (suggested_size + 32) & 31;
return suggested_size;
}
ICSetupInfo* createGenericIC(TypeRecorder* type_recorder, bool has_return_value, int size) {
return ICSetupInfo::initialize(has_return_value, 1, size, ICSetupInfo::Generic, type_recorder);
return ICSetupInfo::initialize(has_return_value, size, ICSetupInfo::Generic, type_recorder);
}
ICSetupInfo* createGetattrIC(TypeRecorder* type_recorder, ICInfo* bjit_ic_info) {
return ICSetupInfo::initialize(true, numSlots(bjit_ic_info, 2), 512, ICSetupInfo::Getattr, type_recorder);
return ICSetupInfo::initialize(true, slotSize(bjit_ic_info, 1024), ICSetupInfo::Getattr, type_recorder);
}
ICSetupInfo* createGetitemIC(TypeRecorder* type_recorder, ICInfo* bjit_ic_info) {
return ICSetupInfo::initialize(true, numSlots(bjit_ic_info, 1), 512, ICSetupInfo::Getitem, type_recorder);
return ICSetupInfo::initialize(true, slotSize(bjit_ic_info, 512), ICSetupInfo::Getitem, type_recorder);
}
ICSetupInfo* createSetitemIC(TypeRecorder* type_recorder) {
return ICSetupInfo::initialize(true, 1, 512, ICSetupInfo::Setitem, type_recorder);
return ICSetupInfo::initialize(true, 512, ICSetupInfo::Setitem, type_recorder);
}
ICSetupInfo* createDelitemIC(TypeRecorder* type_recorder) {
return ICSetupInfo::initialize(false, 1, 512, ICSetupInfo::Delitem, type_recorder);
return ICSetupInfo::initialize(false, 512, ICSetupInfo::Delitem, type_recorder);
}
ICSetupInfo* createSetattrIC(TypeRecorder* type_recorder, ICInfo* bjit_ic_info) {
return ICSetupInfo::initialize(false, numSlots(bjit_ic_info, 2), 512, ICSetupInfo::Setattr, type_recorder);
return ICSetupInfo::initialize(false, slotSize(bjit_ic_info, 1024), ICSetupInfo::Setattr, type_recorder);
}
ICSetupInfo* createDelattrIC(TypeRecorder* type_recorder) {
return ICSetupInfo::initialize(false, 1, 144, ICSetupInfo::Delattr, type_recorder);
return ICSetupInfo::initialize(false, 144, ICSetupInfo::Delattr, type_recorder);
}
ICSetupInfo* createCallsiteIC(TypeRecorder* type_recorder, int num_args, ICInfo* bjit_ic_info) {
return ICSetupInfo::initialize(true, numSlots(bjit_ic_info, 4), 640 + 48 * num_args, ICSetupInfo::Callsite,
return ICSetupInfo::initialize(true, slotSize(bjit_ic_info, 4 * (640 + 48 * num_args)), ICSetupInfo::Callsite,
type_recorder);
}
ICSetupInfo* createGetGlobalIC(TypeRecorder* type_recorder) {
return ICSetupInfo::initialize(true, 1, 128, ICSetupInfo::GetGlobal, type_recorder);
return ICSetupInfo::initialize(true, 128, ICSetupInfo::GetGlobal, type_recorder);
}
ICSetupInfo* createBinexpIC(TypeRecorder* type_recorder, ICInfo* bjit_ic_info) {
return ICSetupInfo::initialize(true, numSlots(bjit_ic_info, 4), 512, ICSetupInfo::Binexp, type_recorder);
return ICSetupInfo::initialize(true, slotSize(bjit_ic_info, 2048), ICSetupInfo::Binexp, type_recorder);
}
ICSetupInfo* createNonzeroIC(TypeRecorder* type_recorder) {
return ICSetupInfo::initialize(true, 2, 512, ICSetupInfo::Nonzero, type_recorder);
return ICSetupInfo::initialize(true, 1024, ICSetupInfo::Nonzero, type_recorder);
}
ICSetupInfo* createHasnextIC(TypeRecorder* type_recorder) {
return ICSetupInfo::initialize(true, 2, 64, ICSetupInfo::Hasnext, type_recorder);
return ICSetupInfo::initialize(true, 128, ICSetupInfo::Hasnext, type_recorder);
}
ICSetupInfo* createDeoptIC() {
return ICSetupInfo::initialize(true, 1, 0, ICSetupInfo::Deopt, NULL);
return ICSetupInfo::initialize(true, 0, ICSetupInfo::Deopt, NULL);
}
} // namespace pyston
......@@ -64,17 +64,12 @@ public:
};
private:
ICSetupInfo(ICType type, int num_slots, int slot_size, bool has_return_value, TypeRecorder* type_recorder)
: type(type),
num_slots(num_slots),
slot_size(slot_size),
has_return_value(has_return_value),
type_recorder(type_recorder) {}
ICSetupInfo(ICType type, int size, bool has_return_value, TypeRecorder* type_recorder)
: type(type), size(size), has_return_value(has_return_value), type_recorder(type_recorder) {}
public:
const ICType type;
const int num_slots, slot_size;
const int size;
const bool has_return_value;
TypeRecorder* const type_recorder;
......@@ -95,8 +90,7 @@ public:
return llvm::CallingConv::C;
}
static ICSetupInfo* initialize(bool has_return_value, int num_slots, int slot_size, ICType type,
TypeRecorder* type_recorder);
static ICSetupInfo* initialize(bool has_return_value, int size, ICType type, TypeRecorder* type_recorder);
};
struct PatchpointInfo {
......
......@@ -188,7 +188,7 @@ static void writeTrivialEhFrame(void* eh_frame_addr, void* func_addr, uint64_t f
#define SCRATCH_BYTES 0x30
#endif
RuntimeIC::RuntimeIC(void* func_addr, int num_slots, int slot_size) {
RuntimeIC::RuntimeIC(void* func_addr, int patchable_size) {
static StatCounter sc("runtime_ics_num");
sc.log();
......@@ -228,8 +228,6 @@ RuntimeIC::RuntimeIC(void* func_addr, int num_slots, int slot_size) {
#endif
static const int CALL_SIZE = 13;
int patchable_size = num_slots * slot_size;
int total_code_size = PROLOGUE_SIZE + patchable_size + CALL_SIZE + EPILOGUE_SIZE;
#ifdef NVALGRIND
......@@ -248,7 +246,7 @@ RuntimeIC::RuntimeIC(void* func_addr, int num_slots, int slot_size) {
// printf("Allocated runtime IC at %p\n", addr);
std::unique_ptr<ICSetupInfo> setup_info(
ICSetupInfo::initialize(true, num_slots, slot_size, ICSetupInfo::Generic, NULL));
ICSetupInfo::initialize(true, patchable_size, ICSetupInfo::Generic, NULL));
uint8_t* pp_start = (uint8_t*)addr + PROLOGUE_SIZE;
uint8_t* pp_end = pp_start + patchable_size + CALL_SIZE;
......
......@@ -35,7 +35,7 @@ private:
void operator=(const RuntimeIC&) = delete;
protected:
RuntimeIC(void* addr, int num_slots, int slot_size);
RuntimeIC(void* addr, int patchable_size);
~RuntimeIC();
template <class... Args> uint64_t call_int(Args... args) {
......@@ -57,7 +57,7 @@ protected:
class CallattrIC : public RuntimeIC {
public:
CallattrIC() : RuntimeIC((void*)callattr, 1, 320) {}
CallattrIC() : RuntimeIC((void*)callattr, 320) {}
Box* call(Box* obj, BoxedString* attr, CallattrFlags flags, Box* arg0, Box* arg1, Box* arg2, Box** args,
const std::vector<BoxedString*>* keyword_names) {
......@@ -67,7 +67,7 @@ public:
class CallattrCapiIC : public RuntimeIC {
public:
CallattrCapiIC() : RuntimeIC((void*)callattrCapi, 1, 320) {}
CallattrCapiIC() : RuntimeIC((void*)callattrCapi, 320) {}
Box* call(Box* obj, BoxedString* attr, CallattrFlags flags, Box* arg0, Box* arg1, Box* arg2, Box** args,
const std::vector<BoxedString*>* keyword_names) {
......@@ -78,14 +78,14 @@ public:
class BinopIC : public RuntimeIC {
public:
BinopIC() : RuntimeIC((void*)binop, 2, 240) {}
BinopIC() : RuntimeIC((void*)binop, 2 * 240) {}
Box* call(Box* lhs, Box* rhs, int op_type) { return (Box*)call_ptr(lhs, rhs, op_type); }
};
class NonzeroIC : public RuntimeIC {
public:
NonzeroIC() : RuntimeIC((void*)nonzero, 1, 512) {}
NonzeroIC() : RuntimeIC((void*)nonzero, 512) {}
bool call(Box* obj) { return call_bool(obj); }
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment