Commit fc111bc5 authored by Travis Hance's avatar Travis Hance

ported objmodel.cpp to use rewriter2 exclusively, deprecates rewriter1

parent a5258c49
......@@ -477,7 +477,6 @@ void Assembler::cmp(Register reg1, Register reg2) {
reg1_idx -= 8;
}
if (reg2_idx >= 8) {
trap();
rex |= REX_B;
reg2_idx -= 8;
}
......
......@@ -51,9 +51,8 @@ Location Location::forArg(int argnum) {
default:
break;
}
RELEASE_ASSERT(0, "the following is untested");
// int offset = (argnum - 6) * 8;
// return Location(Stack, offset);
int offset = (argnum - 6) * 8;
return Location(Stack, offset);
}
assembler::Register Location::asRegister() const {
......@@ -80,6 +79,9 @@ bool Location::isClobberedByCall() const {
if (type == Constant)
return false;
if (type == Stack)
return false;
RELEASE_ASSERT(0, "%d", type);
}
......@@ -95,7 +97,7 @@ void Location::dump() const {
}
if (type == Scratch) {
printf("scratch(%d)\n", stack_offset);
printf("scratch(%d)\n", scratch_offset);
return;
}
......@@ -104,25 +106,69 @@ void Location::dump() const {
return;
}
if (type == Stack) {
printf("stack(%d)\n", stack_offset);
return;
}
RELEASE_ASSERT(0, "%d", type);
}
RewriterVarUsage2::RewriterVarUsage2(RewriterVar2* var) : var(var), done_using(false) {
var->incUse();
assert(var->rewriter);
}
void RewriterVarUsage2::addAttrGuard(int offset, uint64_t val) {
void RewriterVarUsage2::addGuard(uint64_t val) {
assertValid();
Rewriter2* rewriter = var->rewriter;
assembler::Assembler* assembler = rewriter->assembler;
assert(!rewriter->done_guarding && "too late to add a guard!");
assembler::Register this_reg = var->getInReg();
if (val < (-1L << 31) || val >= (1L << 31) - 1) {
assembler::Register reg = rewriter->allocReg(Location::any());
assembler->mov(assembler::Immediate(val), reg);
assembler->cmp(this_reg, reg);
} else {
assembler->cmp(this_reg, assembler::Immediate(val));
}
assembler->jne(assembler::JumpDestination::fromStart(rewriter->rewrite->getSlotSize()));
}
void RewriterVarUsage2::addGuardNotEq(uint64_t val) {
assertValid();
Rewriter2* rewriter = var->rewriter;
assembler::Assembler* assembler = rewriter->assembler;
assert(!rewriter->done_guarding && "too late to add a guard!");
assembler::Register this_reg = var->getInReg();
if (val < (-1L << 31) || val >= (1L << 31) - 1) {
assembler::Register reg = rewriter->allocReg(Location::any());
assembler->mov(assembler::Immediate(val), reg);
assembler->cmp(this_reg, reg);
} else {
assembler->cmp(this_reg, assembler::Immediate(val));
}
assembler->je(assembler::JumpDestination::fromStart(rewriter->rewrite->getSlotSize()));
}
void RewriterVarUsage2::addAttrGuard(int offset, uint64_t val) {
assertValid();
Rewriter2* rewriter = var->rewriter;
assembler::Assembler* assembler = rewriter->assembler;
assert(!rewriter->done_guarding && "too late to add a guard!");
assembler::Register this_reg = var->getInReg();
if (val < (-1L << 31) || val >= (1L << 31) - 1) {
assembler::Register reg = rewriter->allocReg(Location::any());
assert(reg != this_reg);
assembler->mov(assembler::Immediate(val), reg);
assembler->cmp(assembler::Indirect(this_reg, offset), reg);
} else {
......@@ -148,6 +194,51 @@ RewriterVarUsage2 RewriterVarUsage2::getAttr(int offset, KillFlag kill, Location
return std::move(newvar);
}
RewriterVarUsage2 RewriterVarUsage2::cmp(AST_TYPE::AST_TYPE cmp_type, RewriterVarUsage2 other, Location dest) {
assertValid();
assembler::Register this_reg = var->getInReg();
assembler::Register other_reg = other.var->getInReg();
assert(this_reg != other_reg); // TODO how do we ensure this?
Rewriter2* rewriter = var->rewriter;
assembler::Register newvar_reg = rewriter->allocReg(dest);
RewriterVarUsage2 newvar = rewriter->createNewVar(newvar_reg);
rewriter->assembler->cmp(this_reg, newvar_reg);
switch (cmp_type) {
case AST_TYPE::Eq:
rewriter->assembler->sete(newvar_reg);
break;
case AST_TYPE::NotEq:
rewriter->assembler->setne(newvar_reg);
break;
default:
RELEASE_ASSERT(0, "%d", cmp_type);
}
other.setDoneUsing();
return std::move(newvar);
}
RewriterVarUsage2 RewriterVarUsage2::toBool(KillFlag kill, Location dest) {
assertValid();
assembler::Register this_reg = var->getInReg();
Rewriter2* rewriter = var->rewriter;
if (kill == Kill) {
setDoneUsing();
}
rewriter->assembler->test(this_reg, this_reg);
assembler::Register result_reg = rewriter->allocReg(dest);
rewriter->assembler->setnz(result_reg);
RewriterVarUsage2 result = rewriter->createNewVar(result_reg);
return result;
}
void RewriterVarUsage2::setAttr(int offset, RewriterVarUsage2 val) {
assertValid();
var->rewriter->assertChangesOk();
......@@ -179,6 +270,15 @@ void RewriterVarUsage2::setDoneUsing() {
var = NULL;
}
bool RewriterVarUsage2::isDoneUsing() {
return done_using;
}
void RewriterVarUsage2::ensureDoneUsing() {
if (!done_using)
setDoneUsing();
}
RewriterVarUsage2::RewriterVarUsage2(RewriterVarUsage2&& usage) {
assert(!usage.done_using);
assert(usage.var != NULL);
......@@ -260,7 +360,7 @@ assembler::Register RewriterVar2::getInReg(Location dest) {
assert(locations.size() == 1);
Location l(*locations.begin());
assert(l.type == Location::Scratch);
assert(l.type == Location::Scratch || l.type == Location::Stack);
assembler::Register reg = rewriter->allocReg(dest);
......@@ -362,7 +462,6 @@ RewriterVarUsage2 Rewriter2::getArg(int argnum) {
assert(argnum >= 0 && argnum < args.size());
RewriterVar2* var = args[argnum];
var->incUse();
return RewriterVarUsage2(var);
}
......@@ -377,7 +476,11 @@ void Rewriter2::trap() {
RewriterVarUsage2 Rewriter2::loadConst(int64_t val, Location dest) {
if (val >= (-1L << 31) && val < (1L << 31) - 1) {
Location l(Location::Constant, val);
return createNewVar(l);
RewriterVar2*& var = vars_by_location[l];
if (!var) {
var = new RewriterVar2(this, l);
}
return RewriterVarUsage2(var);
}
assembler::Register reg = allocReg(dest);
......@@ -410,7 +513,9 @@ static const Location caller_save_registers[]{
};
RewriterVarUsage2 Rewriter2::call(bool can_call_into_python, void* func_addr, std::vector<RewriterVarUsage2> args) {
assert(!can_call_into_python);
// TODO figure out why this is here -- what needs to be done differently
// if can_call_into_python is true?
// assert(!can_call_into_python);
assertChangesOk();
......@@ -461,16 +566,6 @@ RewriterVarUsage2 Rewriter2::call(bool can_call_into_python, void* func_addr, st
}
#endif
// This is kind of hacky: we release the use of these right now,
// and then expect that everything else will not clobber any of the arguments.
// Naively moving this below the reg spilling will always spill the arguments;
// but sometimes you need to do that if the argument lives past the call.
// Hacky, but the right way to do it requires a bit of reworking so that it can
// spill but keep its current use.
for (int i = 0; i < args.size(); i++) {
args[i].setDoneUsing();
}
// Spill caller-saved registers:
for (auto check_reg : caller_save_registers) {
// check_reg.dump();
......@@ -488,6 +583,17 @@ RewriterVarUsage2 Rewriter2::call(bool can_call_into_python, void* func_addr, st
break;
}
}
for (int i = 0; i < args.size(); i++) {
if (args[i].var == var) {
if (var->num_uses == 1) {
// If we hold the only usage of this arg var, we are
// going to kill all of its usages soon anyway,
// so we have no need to spill it.
need_to_spill = false;
}
break;
}
}
if (need_to_spill) {
if (check_reg.type == Location::Register) {
......@@ -502,6 +608,15 @@ RewriterVarUsage2 Rewriter2::call(bool can_call_into_python, void* func_addr, st
}
}
// We call setDoneUsing after spilling because when we release these,
// we might release a pointer to an array in the scratch space allocated
// with _allocate. If we do that before spilling, we might spill into that
// scratch space.
for (int i = 0; i < args.size(); i++) {
args[i].setDoneUsing();
}
#ifndef NDEBUG
for (const auto& p : vars_by_location) {
Location l = p.first;
......@@ -558,7 +673,7 @@ void Rewriter2::commit() {
assert(vars_by_location.size() == 0);
rewrite->commit(0, this);
rewrite->commit(decision_path, this);
}
void Rewriter2::finishAssembly(int continue_offset) {
......@@ -568,29 +683,32 @@ void Rewriter2::finishAssembly(int continue_offset) {
}
void Rewriter2::commitReturning(RewriterVarUsage2 usage) {
assert(usage.var->isInLocation(getReturnDestination()));
/*
Location l = usage.var->location;
Location expected = getReturnDestination();
if (l != expected) {
assert(l.type == Location::Register);
assert(expected.type == Location::Register);
assembler->mov(l.asRegister(), expected.asRegister());
}
*/
// assert(usage.var->isInLocation(getReturnDestination()));
usage.var->getInReg(getReturnDestination());
usage.setDoneUsing();
commit();
}
void Rewriter2::addDecision(int way) {
assert(ndecisions < 60);
ndecisions++;
decision_path = (decision_path << 1) | way;
}
void Rewriter2::addDependenceOn(ICInvalidator& invalidator) {
rewrite->addDependenceOn(invalidator);
}
void Rewriter2::kill(RewriterVar2* var) {
for (RewriterVarUsage2& scratch_range_usage : var->scratch_range) {
// Should be the only usage for this particular var (we
// hold the only usage) so it should cause the array to
// be deallocated.
scratch_range_usage.setDoneUsing();
}
var->scratch_range.clear();
for (Location l : var->locations) {
assert(vars_by_location[l] == var);
vars_by_location.erase(l);
......@@ -601,22 +719,121 @@ Location Rewriter2::allocScratch() {
int scratch_bytes = rewrite->getScratchBytes();
for (int i = 0; i < scratch_bytes; i += 8) {
Location l(Location::Scratch, i);
if (vars_by_location.count(l) == 0)
if (vars_by_location.count(l) == 0) {
return l;
}
}
RELEASE_ASSERT(0, "Using all %d bytes of scratch!", scratch_bytes);
}
std::pair<RewriterVarUsage2, int> Rewriter2::_allocate(int n) {
assert(n >= 1);
int scratch_bytes = rewrite->getScratchBytes();
int consec = 0;
for (int i = 0; i < scratch_bytes; i += 8) {
Location l(Location::Scratch, i);
if (vars_by_location.count(l) == 0) {
consec++;
if (consec == n) {
int a = i / 8 - n + 1;
int b = i / 8;
assembler::Register r = allocReg(Location::any());
// TODO should be a LEA instruction
// In fact, we could do something like we do for constants and only load
// this when necessary, so it won't spill. Is that worth?
assembler->mov(assembler::RBP, r);
assembler->add(assembler::Immediate(8 * a + rewrite->getScratchRbpOffset()), r);
RewriterVarUsage2 usage = createNewVar(r);
for (int j = a; j <= b; j++) {
Location m(Location::Scratch, j * 8);
RewriterVarUsage2 placeholder = createNewVar(m);
usage.var->scratch_range.push_back(std::move(placeholder));
}
return std::make_pair(std::move(usage), a);
}
} else {
consec = 0;
}
}
RELEASE_ASSERT(0, "Using all %d bytes of scratch!", scratch_bytes);
}
RewriterVarUsage2 Rewriter2::allocate(int n) {
return _allocate(n).first;
}
RewriterVarUsage2 Rewriter2::allocateAndCopy(RewriterVarUsage2 array_ptr, int n) {
// TODO smart register allocation
array_ptr.assertValid();
std::pair<RewriterVarUsage2, int> allocation = _allocate(n);
int offset = allocation.second;
assembler::Register tmp = allocReg(Location::any());
assembler::Register src_ptr = array_ptr.var->getInReg();
assert(tmp != src_ptr); // TODO how to ensure this?
for (int i = 0; i < n; i++) {
assembler->mov(assembler::Indirect(src_ptr, 8 * i), tmp);
assembler->mov(tmp, assembler::Indirect(assembler::RBP, 8 * (offset + i) + rewrite->getScratchRbpOffset()));
}
array_ptr.setDoneUsing();
return std::move(allocation.first);
}
RewriterVarUsage2 Rewriter2::allocateAndCopyPlus1(RewriterVarUsage2 first_elem, RewriterVarUsage2 rest_ptr,
int n_rest) {
first_elem.assertValid();
if (n_rest > 0)
rest_ptr.assertValid();
else
assert(rest_ptr.isDoneUsing());
std::pair<RewriterVarUsage2, int> allocation = _allocate(n_rest + 1);
int offset = allocation.second;
assembler::Register tmp = first_elem.var->getInReg();
assembler->mov(tmp, assembler::Indirect(assembler::RBP, 8 * offset + rewrite->getScratchRbpOffset()));
if (n_rest > 0) {
assembler::Register src_ptr = rest_ptr.var->getInReg();
// TODO if this triggers we'll need a way to allocate two distinct registers
assert(tmp != src_ptr);
for (int i = 0; i < n_rest; i++) {
assembler->mov(assembler::Indirect(src_ptr, 8 * i), tmp);
assembler->mov(tmp,
assembler::Indirect(assembler::RBP, 8 * (offset + i + 1) + rewrite->getScratchRbpOffset()));
}
rest_ptr.setDoneUsing();
}
first_elem.setDoneUsing();
return std::move(allocation.first);
}
assembler::Indirect Rewriter2::indirectFor(Location l) {
assert(l.type == Location::Scratch);
assert(l.type == Location::Scratch || l.type == Location::Stack);
// TODO it can sometimes be more efficient to do RSP-relative addressing?
int rbp_offset = rewrite->getScratchRbpOffset() + l.scratch_offset;
return assembler::Indirect(assembler::RBP, rbp_offset);
if (l.type == Location::Scratch)
// TODO it can sometimes be more efficient to do RSP-relative addressing?
return assembler::Indirect(assembler::RBP, rewrite->getScratchRbpOffset() + l.scratch_offset);
else
return assembler::Indirect(assembler::RSP, l.stack_offset);
}
void Rewriter2::spillRegister(assembler::Register reg) {
assert(done_guarding);
// Don't spill a register than an input argument is in, unless
// we are done guarding (in which case `args` will be empty)
for (int i = 0; i < args.size(); i++) {
assert(!args[i]->isInLocation(Location(reg)));
}
RewriterVar2* var = vars_by_location[reg];
assert(var);
......@@ -662,7 +879,7 @@ assembler::Register Rewriter2::allocReg(Location dest) {
if (vars_by_location.count(reg) == 0)
return reg;
}
RELEASE_ASSERT(0, "couldn't find a reg to allocate and haven't added spilling");
return allocReg(assembler::R15); // seem as fine as any
} else if (dest.type == Location::Register) {
assembler::Register reg(dest.regnum);
......@@ -690,7 +907,7 @@ void Rewriter2::addLocationToVar(RewriterVar2* var, Location l) {
void Rewriter2::removeLocationFromVar(RewriterVar2* var, Location l) {
assert(var->isInLocation(l));
assert(vars_by_location[l] = var);
assert(vars_by_location[l] == var);
vars_by_location.erase(l);
var->locations.erase(l);
......@@ -710,7 +927,7 @@ TypeRecorder* Rewriter2::getTypeRecorder() {
Rewriter2::Rewriter2(ICSlotRewrite* rewrite, int num_args, const std::vector<int>& live_outs)
: rewrite(rewrite), assembler(rewrite->getAssembler()), return_location(rewrite->returnRegister()),
done_guarding(false) {
done_guarding(false), ndecisions(0), decision_path(1) {
// assembler->trap();
for (int i = 0; i < num_args; i++) {
......@@ -718,6 +935,7 @@ Rewriter2::Rewriter2(ICSlotRewrite* rewrite, int num_args, const std::vector<int
RewriterVar2* var = new RewriterVar2(this, l);
vars_by_location[l] = var;
var->incUse();
args.push_back(var);
}
......@@ -747,11 +965,10 @@ Rewriter2::Rewriter2(ICSlotRewrite* rewrite, int num_args, const std::vector<int
}
RewriterVar2*& var = vars_by_location[l];
if (var) {
var->incUse();
} else {
if (!var) {
var = new RewriterVar2(this, l);
}
var->incUse();
this->live_outs.push_back(var);
this->live_out_regs.push_back(dwarf_regnum);
......@@ -770,4 +987,8 @@ Rewriter2* Rewriter2::createRewriter(void* rtn_addr, int num_args, const char* d
return new Rewriter2(ic->startRewrite(debug_name), num_args, ic->getLiveOuts());
}
RewriterVarUsage2 RewriterVarUsage2::addUse() {
return RewriterVarUsage2(var);
}
}
......@@ -36,7 +36,7 @@ public:
enum LocationType : uint8_t {
Register,
XMMRegister,
// Stack,
Stack,
Scratch, // stack location, relative to the scratch start
// For representing constants that fit in 32-bits, that can be encoded as immediates
......@@ -152,13 +152,18 @@ public:
#endif
void setDoneUsing();
bool isDoneUsing();
void ensureDoneUsing();
// RewriterVarUsage2 addUse() { return var->addUse(); }
RewriterVarUsage2 addUse();
void addGuard(uint64_t val);
void addGuardNotEq(uint64_t val);
void addAttrGuard(int offset, uint64_t val);
RewriterVarUsage2 getAttr(int offset, KillFlag kill, Location loc = Location::any());
void setAttr(int offset, RewriterVarUsage2 other);
RewriterVarUsage2 cmp(AST_TYPE::AST_TYPE cmp_type, RewriterVarUsage2 other, Location loc = Location::any());
RewriterVarUsage2 toBool(KillFlag kill, Location loc = Location::any());
friend class Rewriter2;
};
......@@ -174,6 +179,10 @@ private:
std::unordered_set<Location> locations;
bool isInLocation(Location l);
// Indicates that this value is a pointer to a fixed-size range in the scratch space.
// This is a vector of variable usages that keep the range allocated.
std::vector<RewriterVarUsage2> scratch_range;
// Gets a copy of this variable in a register, spilling/reloading if necessary.
// TODO have to be careful with the result since the interface doesn't guarantee
// that the register will still contain your value when you go to use it
......@@ -189,7 +198,7 @@ public:
void incUse();
void decUse();
RewriterVar2(Rewriter2* rewriter, Location location) : rewriter(rewriter), num_uses(1) {
RewriterVar2(Rewriter2* rewriter, Location location) : rewriter(rewriter), num_uses(0) {
assert(rewriter);
locations.insert(location);
}
......@@ -239,6 +248,11 @@ private:
void finishAssembly(int continue_offset) override;
std::pair<RewriterVarUsage2, int> _allocate(int n);
int ndecisions;
uint64_t decision_path;
public:
// This should be called exactly once for each argument
RewriterVarUsage2 getArg(int argnum);
......@@ -255,6 +269,10 @@ public:
RewriterVarUsage2 call(bool can_call_into_python, void* func_addr, std::vector<RewriterVarUsage2> args);
RewriterVarUsage2 call(bool can_call_into_python, void* func_addr, RewriterVarUsage2 arg0);
RewriterVarUsage2 call(bool can_call_into_python, void* func_addr, RewriterVarUsage2 arg0, RewriterVarUsage2 arg1);
RewriterVarUsage2 allocate(int n);
RewriterVarUsage2 allocateAndCopy(RewriterVarUsage2 array, int n);
RewriterVarUsage2 allocateAndCopyPlus1(RewriterVarUsage2 first_elem, RewriterVarUsage2 rest, int n_rest);
void deallocateStack(int nbytes);
void commit();
void commitReturning(RewriterVarUsage2 rtn);
......@@ -263,6 +281,8 @@ public:
static Rewriter2* createRewriter(void* rtn_addr, int num_args, const char* debug_name);
void addDecision(int way);
friend class RewriterVar2;
friend class RewriterVarUsage2;
};
......
......@@ -1812,7 +1812,7 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
if (source->ast->type == AST_TYPE::ClassDef) {
// A classdef always starts with "__module__ = __name__"
Box* module_name = source->parent_module->getattr("__name__", NULL, NULL);
Box* module_name = source->parent_module->getattr("__name__", NULL);
assert(module_name->cls == str_cls);
AST_Assign* module_assign = new AST_Assign();
module_assign->targets.push_back(makeName("__module__", AST_TYPE::Store));
......
......@@ -54,6 +54,11 @@ struct ArgPassSpec {
int totalPassed() { return num_args + num_keywords + (has_starargs ? 1 : 0) + (has_kwargs ? 1 : 0); }
uintptr_t asInt() const { return *reinterpret_cast<const uintptr_t*>(this); }
void dump() {
printf("(has_starargs=%s, has_kwargs=%s, num_keywords=%d, num_args=%d)\n", has_starargs ? "true" : "false",
has_kwargs ? "true" : "false", num_keywords, num_args);
}
};
static_assert(sizeof(ArgPassSpec) <= sizeof(void*), "ArgPassSpec doesn't fit in register!");
......@@ -233,7 +238,7 @@ public:
};
typedef std::vector<CompiledFunction*> FunctionList;
class CallRewriteArgs;
class CallRewriteArgs2;
class CLFunction {
public:
int num_args;
......@@ -249,7 +254,7 @@ public:
// of the normal dispatch through the functionlist.
// This can be used to implement functions which know how to rewrite themselves,
// such as typeCall.
typedef Box* (*InternalCallable)(BoxedFunction*, CallRewriteArgs*, ArgPassSpec, Box*, Box*, Box*, Box**,
typedef Box* (*InternalCallable)(BoxedFunction*, CallRewriteArgs2*, ArgPassSpec, Box*, Box*, Box*, Box**,
const std::vector<const std::string*>*);
InternalCallable internal_callable = NULL;
......@@ -372,7 +377,6 @@ private:
class SetattrRewriteArgs2;
class GetattrRewriteArgs;
class GetattrRewriteArgs2;
class DelattrRewriteArgs2;
......@@ -404,8 +408,8 @@ public:
this->setattr(attr, val, NULL);
}
Box* getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2);
Box* getattr(const std::string& attr) { return getattr(attr, NULL, NULL); }
Box* getattr(const std::string& attr, GetattrRewriteArgs2* rewrite_args2);
Box* getattr(const std::string& attr) { return getattr(attr, NULL); }
void delattr(const std::string& attr, DelattrRewriteArgs2* rewrite_args);
};
......
......@@ -56,7 +56,7 @@ extern "C" Box* dir(Box* obj) {
}
// If __dict__ is present use its keys and add the reset below
Box* obj_dict = getattr_internal(obj, "__dict__", false, true, nullptr, nullptr);
Box* obj_dict = getattr_internal(obj, "__dict__", false, true, nullptr);
if (obj_dict && obj_dict->cls == dict_cls) {
result = new BoxedList();
for (auto& kv : static_cast<BoxedDict*>(obj_dict)->d) {
......@@ -326,7 +326,7 @@ Box* getattrFunc(Box* obj, Box* _str, Box* default_value) {
}
BoxedString* str = static_cast<BoxedString*>(_str);
Box* rtn = getattr_internal(obj, str->s, true, true, NULL, NULL);
Box* rtn = getattr_internal(obj, str->s, true, true, NULL);
if (!rtn) {
if (default_value)
......@@ -345,7 +345,7 @@ Box* hasattr(Box* obj, Box* _str) {
}
BoxedString* str = static_cast<BoxedString*>(_str);
Box* attr = getattr_internal(obj, str->s, true, true, NULL, NULL);
Box* attr = getattr_internal(obj, str->s, true, true, NULL);
Box* rtn = attr ? True : False;
return rtn;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -81,30 +81,29 @@ extern "C" void assertFail(BoxedModule* inModule, Box* msg);
extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent);
extern "C" BoxedClosure* createClosure(BoxedClosure* parent_closure);
class BinopRewriteArgs;
extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, BinopRewriteArgs* rewrite_args);
class BinopRewriteArgs2;
extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, BinopRewriteArgs2* rewrite_args);
Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
class CallRewriteArgs2;
Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs2* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names);
class CallRewriteArgs;
enum LookupScope {
CLASS_ONLY = 1,
INST_ONLY = 2,
CLASS_OR_INST = 3,
};
extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope, CallRewriteArgs* rewrite_args,
extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope, CallRewriteArgs2* rewrite_args,
ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<const std::string*>* keyword_names);
extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_custom,
DelattrRewriteArgs2* rewrite_args);
struct CompareRewriteArgs;
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args);
struct CompareRewriteArgs2;
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs2* rewrite_args);
Box* getattr_internal(Box* obj, const std::string& attr, bool check_cls, bool allow_custom,
GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2);
GetattrRewriteArgs2* rewrite_args2);
Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* rewrite_args,
GetattrRewriteArgs2* rewrite_args2);
Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs2* rewrite_args2);
extern "C" void raiseAttributeErrorStr(const char* typeName, const char* attr) __attribute__((__noreturn__));
extern "C" void raiseAttributeError(Box* obj, const char* attr) __attribute__((__noreturn__));
......@@ -114,7 +113,7 @@ Box* typeCall(Box*, BoxedList*);
Box* typeNew(Box*, Box*);
bool isUserDefined(BoxedClass* cls);
Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_args, BoxedClosure* closure,
Box* callCLFunc(CLFunction* f, CallRewriteArgs2* rewrite_args, int num_output_args, BoxedClosure* closure,
BoxedGenerator* generator, Box* oarg1, Box* oarg2, Box* oarg3, Box** oargs);
}
#endif
......@@ -84,7 +84,7 @@ extern "C" BoxedFunction::BoxedFunction(CLFunction* f)
// this->giveAttr("__name__", boxString(&f->source->ast->name));
this->giveAttr("__name__", boxString(f->source->getName()));
Box* modname = f->source->parent_module->getattr("__name__", NULL, NULL);
Box* modname = f->source->parent_module->getattr("__name__", NULL);
this->giveAttr("__module__", modname);
}
......@@ -110,7 +110,7 @@ extern "C" BoxedFunction::BoxedFunction(CLFunction* f, std::initializer_list<Box
// this->giveAttr("__name__", boxString(&f->source->ast->name));
this->giveAttr("__name__", boxString(f->source->getName()));
Box* modname = f->source->parent_module->getattr("__name__", NULL, NULL);
Box* modname = f->source->parent_module->getattr("__name__", NULL);
this->giveAttr("__module__", modname);
}
......@@ -513,7 +513,7 @@ Box* objectNew(BoxedClass* cls, BoxedTuple* args) {
if (args->elts.size() != 0) {
// TODO slow
if (typeLookup(cls, "__init__", NULL, NULL) == typeLookup(object_cls, "__init__", NULL, NULL))
if (typeLookup(cls, "__init__", NULL) == typeLookup(object_cls, "__init__", NULL))
raiseExcHelper(TypeError, "object.__new__() takes no parameters");
}
......
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