Commit 5f562c46 authored by Marius Wachtler's avatar Marius Wachtler Committed by GitHub

Merge pull request #1259 from undingen/rewriter_slots4

ICs: variable size IC slots
parents dc0a2f2b 258a2b0a
......@@ -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