Commit 45fc5847 authored by Marius Wachtler's avatar Marius Wachtler

Merge branch 'master' of https://github.com/dropbox/pyston into generators

Conflicts:
	src/codegen/irgen/irgenerator.cpp
	src/codegen/runtime_hooks.h
parents bc512baf 07af2757
......@@ -59,7 +59,7 @@ typename BBAnalyzer<T>::AllMap computeFixedPoint(CFG* cfg, const BBAnalyzer<T>&
CFGBlock* block = q.top();
q.pop();
Map initial = states[block];
Map& initial = states[block];
if (VERBOSITY("analysis") >= 2)
printf("fpc on block %d - %ld entries\n", block->idx, initial.size());
......
......@@ -95,6 +95,9 @@ public:
};
bool LivenessAnalysis::isLiveAtEnd(const std::string& name, CFGBlock* block) {
if (name[0] != '#')
return true;
if (block->successors.size() == 0)
return false;
......@@ -292,19 +295,19 @@ DefinednessAnalysis::DefinednessAnalysis(const SourceInfo::ArgNames& arg_names,
// printf("%d %s %d\n", p.first->idx, p2.first.c_str(), p2.second);
required.insert(p2.first);
}
defined.insert(make_pair(p.first, required));
defined_at_end.insert(make_pair(p.first, required));
}
}
DefinednessAnalysis::DefinitionLevel DefinednessAnalysis::isDefinedAt(const std::string& name, CFGBlock* block) {
DefinednessAnalysis::DefinitionLevel DefinednessAnalysis::isDefinedAtEnd(const std::string& name, CFGBlock* block) {
std::unordered_map<std::string, DefinitionLevel>& map = results[block];
if (map.count(name) == 0)
return Undefined;
return map[name];
}
const DefinednessAnalysis::RequiredSet& DefinednessAnalysis::getDefinedNamesAt(CFGBlock* block) {
return defined[block];
const DefinednessAnalysis::RequiredSet& DefinednessAnalysis::getDefinedNamesAtEnd(CFGBlock* block) {
return defined_at_end[block];
}
PhiAnalysis::PhiAnalysis(const SourceInfo::ArgNames& arg_names, CFG* cfg, LivenessAnalysis* liveness,
......@@ -313,19 +316,21 @@ PhiAnalysis::PhiAnalysis(const SourceInfo::ArgNames& arg_names, CFG* cfg, Livene
for (CFGBlock* block : cfg->blocks) {
RequiredSet required;
if (block->predecessors.size() < 2)
continue;
const RequiredSet& defined = definedness.getDefinedNamesAt(block);
if (defined.size())
assert(block->predecessors.size());
for (const auto& s : defined) {
if (liveness->isLiveAtEnd(s, block->predecessors[0])) {
required.insert(s);
if (block->predecessors.size() > 1) {
for (CFGBlock* pred : block->predecessors) {
const RequiredSet& defined = definedness.getDefinedNamesAtEnd(pred);
for (const auto& s : defined) {
if (required.count(s) == 0 && liveness->isLiveAtEnd(s, pred)) {
// printf("%d-%d %s\n", pred->idx, block->idx, s.c_str());
required.insert(s);
}
}
}
}
required_phis.insert(make_pair(block, required));
required_phis.insert(make_pair(block, std::move(required)));
}
}
......@@ -336,8 +341,8 @@ const PhiAnalysis::RequiredSet& PhiAnalysis::getAllRequiredAfter(CFGBlock* block
return required_phis[block->successors[0]];
}
const PhiAnalysis::RequiredSet& PhiAnalysis::getAllDefinedAt(CFGBlock* block) {
return definedness.getDefinedNamesAt(block);
const PhiAnalysis::RequiredSet& PhiAnalysis::getAllRequiredFor(CFGBlock* block) {
return required_phis[block];
}
bool PhiAnalysis::isRequired(const std::string& name, CFGBlock* block) {
......@@ -358,11 +363,16 @@ bool PhiAnalysis::isRequiredAfter(const std::string& name, CFGBlock* block) {
bool PhiAnalysis::isPotentiallyUndefinedAfter(const std::string& name, CFGBlock* block) {
assert(!startswith(name, "!"));
assert(block->successors.size() > 0);
DefinednessAnalysis::DefinitionLevel dlevel = definedness.isDefinedAt(name, block->successors[0]);
ASSERT(dlevel != DefinednessAnalysis::Undefined, "%s %d", name.c_str(), block->idx);
return dlevel == DefinednessAnalysis::PotentiallyDefined;
if (block->successors.size() != 1)
return false;
for (CFGBlock* pred : block->successors[0]->predecessors) {
DefinednessAnalysis::DefinitionLevel dlevel = definedness.isDefinedAtEnd(name, pred);
if (dlevel != DefinednessAnalysis::Defined)
return true;
}
return false;
}
LivenessAnalysis* computeLivenessInfo(CFG*) {
......
......@@ -49,14 +49,14 @@ public:
private:
std::unordered_map<CFGBlock*, std::unordered_map<std::string, DefinitionLevel> > results;
std::unordered_map<CFGBlock*, const RequiredSet> defined;
std::unordered_map<CFGBlock*, const RequiredSet> defined_at_end;
ScopeInfo* scope_info;
public:
DefinednessAnalysis(const SourceInfo::ArgNames& args, CFG* cfg, ScopeInfo* scope_info);
DefinitionLevel isDefinedAt(const std::string& name, CFGBlock* block);
const RequiredSet& getDefinedNamesAt(CFGBlock* block);
DefinitionLevel isDefinedAtEnd(const std::string& name, CFGBlock* block);
const RequiredSet& getDefinedNamesAtEnd(CFGBlock* block);
};
class PhiAnalysis {
public:
......@@ -73,7 +73,7 @@ public:
bool isRequired(const std::string& name, CFGBlock* block);
bool isRequiredAfter(const std::string& name, CFGBlock* block);
const RequiredSet& getAllRequiredAfter(CFGBlock* block);
const RequiredSet& getAllDefinedAt(CFGBlock* block);
const RequiredSet& getAllRequiredFor(CFGBlock* block);
bool isPotentiallyUndefinedAfter(const std::string& name, CFGBlock* block);
};
......
......@@ -61,6 +61,8 @@ public:
virtual bool takesClosure() { return false; }
bool passesThroughClosure() override { return false; }
virtual bool refersToGlobal(const std::string& name) {
if (isCompilerCreatedName(name))
return false;
......@@ -88,6 +90,7 @@ struct ScopingAnalysis::ScopeNameUsage {
// Properties determined by looking at other scopes as well:
StrSet referenced_from_nested;
StrSet got_from_closure;
StrSet passthrough_accesses; // what names a child scope accesses a name from a parent scope
ScopeNameUsage(AST* node, ScopeNameUsage* parent) : node(node), parent(parent) {
if (node->type == AST_TYPE::ClassDef) {
......@@ -123,7 +126,9 @@ public:
virtual bool createsClosure() { return usage->referenced_from_nested.size() > 0; }
virtual bool takesClosure() { return usage->got_from_closure.size() > 0; }
virtual bool takesClosure() { return usage->got_from_closure.size() > 0 || usage->passthrough_accesses.size() > 0; }
bool passesThroughClosure() override { return usage->passthrough_accesses.size() > 0 && !createsClosure(); }
virtual bool refersToGlobal(const std::string& name) {
// HAX
......@@ -235,6 +240,13 @@ public:
virtual bool visit_jump(AST_Jump* node) { return false; }
virtual bool visit_delete(AST_Delete* node) {
for (auto t : node->targets) {
RELEASE_ASSERT(t->type != AST_TYPE::Name, "");
}
return false;
}
virtual bool visit_global(AST_Global* node) {
for (int i = 0; i < node->names.size(); i++) {
const std::string& name = node->names[i];
......@@ -364,6 +376,7 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
ScopeNameUsage* parent = usage->parent;
while (parent) {
if (parent->node->type == AST_TYPE::ClassDef) {
intermediate_parents.push_back(parent);
parent = parent->parent;
} else if (parent->forced_globals.count(name)) {
break;
......@@ -372,8 +385,7 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
parent->referenced_from_nested.insert(name);
for (ScopeNameUsage* iparent : intermediate_parents) {
iparent->referenced_from_nested.insert(name);
iparent->got_from_closure.insert(name);
iparent->passthrough_accesses.insert(name);
}
break;
......
......@@ -30,6 +30,7 @@ public:
virtual bool createsClosure() = 0;
virtual bool takesClosure() = 0;
virtual bool passesThroughClosure() = 0;
virtual bool takesGenerator() { return isGeneratorValue; }
virtual void setTakesGenerator(bool b = true) { isGeneratorValue = b; }
......
......@@ -359,6 +359,8 @@ private:
return BOOL;
case AST_LangPrimitive::LANDINGPAD:
return UNKNOWN;
case AST_LangPrimitive::LOCALS:
return DICT;
default:
RELEASE_ASSERT(0, "%d", node->opcode);
}
......@@ -384,6 +386,10 @@ private:
return UNKNOWN;
}
if (scope_info->refersToClosure(node->id)) {
return UNKNOWN;
}
CompilerType*& t = sym_table[node->id];
if (t == NULL) {
// if (VERBOSITY() >= 2) {
......
......@@ -288,6 +288,55 @@ public:
converted_slice->decvref(emitter);
return new ConcreteCompilerVariable(UNKNOWN, rtn, true);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted_rhs = rhs->makeConverted(emitter, rhs->getBoxType());
llvm::Value* rtn;
bool do_patchpoint = ENABLE_ICBINEXPS && !info.isInterpreted();
llvm::Value* rt_func;
void* rt_func_addr;
if (exp_type == BinOp) {
rt_func = g.funcs.binop;
rt_func_addr = (void*)binop;
} else if (exp_type == AugBinOp) {
rt_func = g.funcs.augbinop;
rt_func_addr = (void*)augbinop;
} else {
rt_func = g.funcs.compare;
rt_func_addr = (void*)compare;
}
if (do_patchpoint) {
PatchpointSetupInfo* pp
= patchpoints::createBinexpPatchpoint(emitter.currentFunction(), info.getTypeRecorder());
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(var->getValue());
llvm_args.push_back(converted_rhs->getValue());
llvm_args.push_back(getConstantInt(op_type, g.i32));
llvm::Value* uncasted
= emitter.createPatchpoint(pp, rt_func_addr, llvm_args, info.exc_info).getInstruction();
rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
} else {
rtn = emitter.createCall3(info.exc_info, rt_func, var->getValue(), converted_rhs->getValue(),
getConstantInt(op_type, g.i32)).getInstruction();
}
converted_rhs->decvref(emitter);
if (op_type == AST_TYPE::In || op_type == AST_TYPE::NotIn || op_type == AST_TYPE::Is
|| op_type == AST_TYPE::IsNot) {
llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxBool, rtn);
ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(BOOL, unboxed, true);
return rtn;
}
return new ConcreteCompilerVariable(UNKNOWN, rtn, true);
}
};
ConcreteCompilerType* UNKNOWN = new UnknownType();
......@@ -564,6 +613,7 @@ public:
struct Sig {
std::vector<ConcreteCompilerType*> arg_types;
CompilerType* rtn_type;
int ndefaults;
};
private:
......@@ -589,11 +639,11 @@ public:
for (int i = 0; i < sigs.size(); i++) {
Sig* sig = sigs[i];
if (sig->arg_types.size() != arg_types.size())
if (arg_types.size() < sig->arg_types.size() - sig->ndefaults || arg_types.size() > sig->arg_types.size())
continue;
bool works = true;
for (int j = 0; j < sig->arg_types.size(); j++) {
for (int j = 0; j < arg_types.size(); j++) {
if (!arg_types[j]->canConvertTo(sig->arg_types[j])) {
works = false;
break;
......@@ -621,6 +671,7 @@ public:
Sig* type_sig = new Sig();
type_sig->rtn_type = fspec->rtn_type;
type_sig->ndefaults = clf->num_defaults;
if (stripfirst) {
assert(fspec->arg_types.size() >= 1);
......@@ -637,14 +688,6 @@ public:
static CompilerType* get(const std::vector<Sig*>& sigs) { return new AbstractFunctionType(sigs); }
};
CompilerType* makeFuncType(ConcreteCompilerType* rtn_type, const std::vector<ConcreteCompilerType*>& arg_types) {
std::vector<AbstractFunctionType::Sig*> sigs;
AbstractFunctionType::Sig* sig = new AbstractFunctionType::Sig();
sig->rtn_type = rtn_type;
sig->arg_types = arg_types;
return AbstractFunctionType::get(sigs);
}
class IntType : public ConcreteCompilerType {
public:
IntType() {}
......@@ -755,6 +798,95 @@ public:
return new ConcreteCompilerVariable(BOOL, cmp, true);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
if (rhs->getType() != INT) {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_INT);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
ConcreteCompilerVariable* converted_right = rhs->makeConverted(emitter, INT);
llvm::Value* v;
if (op_type == AST_TYPE::Mod) {
v = emitter.createCall2(info.exc_info, g.funcs.mod_i64_i64, var->getValue(), converted_right->getValue())
.getInstruction();
} else if (op_type == AST_TYPE::Div || op_type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(info.exc_info, g.funcs.div_i64_i64, var->getValue(), converted_right->getValue())
.getInstruction();
} else if (op_type == AST_TYPE::Pow) {
v = emitter.createCall2(info.exc_info, g.funcs.pow_i64_i64, var->getValue(), converted_right->getValue())
.getInstruction();
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (op_type) {
case AST_TYPE::Add:
binopcode = llvm::Instruction::Add;
break;
case AST_TYPE::BitAnd:
binopcode = llvm::Instruction::And;
break;
case AST_TYPE::BitOr:
binopcode = llvm::Instruction::Or;
break;
case AST_TYPE::BitXor:
binopcode = llvm::Instruction::Xor;
break;
case AST_TYPE::LShift:
binopcode = llvm::Instruction::Shl;
break;
case AST_TYPE::RShift:
binopcode = llvm::Instruction::AShr;
break;
case AST_TYPE::Mult:
binopcode = llvm::Instruction::Mul;
break;
case AST_TYPE::Sub:
binopcode = llvm::Instruction::Sub;
break;
default:
ASSERT(0, "%s", getOpName(op_type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateBinOp(binopcode, var->getValue(), converted_right->getValue());
} else {
assert(exp_type == Compare);
llvm::CmpInst::Predicate cmp_pred;
switch (op_type) {
case AST_TYPE::Eq:
case AST_TYPE::Is:
cmp_pred = llvm::CmpInst::ICMP_EQ;
break;
case AST_TYPE::Lt:
cmp_pred = llvm::CmpInst::ICMP_SLT;
break;
case AST_TYPE::LtE:
cmp_pred = llvm::CmpInst::ICMP_SLE;
break;
case AST_TYPE::Gt:
cmp_pred = llvm::CmpInst::ICMP_SGT;
break;
case AST_TYPE::GtE:
cmp_pred = llvm::CmpInst::ICMP_SGE;
break;
case AST_TYPE::NotEq:
case AST_TYPE::IsNot:
cmp_pred = llvm::CmpInst::ICMP_NE;
break;
default:
ASSERT(0, "%s", getOpName(op_type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateICmp(cmp_pred, var->getValue(), converted_right->getValue());
}
converted_right->decvref(emitter);
assert(v->getType() == g.i64 || v->getType() == g.i1);
return new ConcreteCompilerVariable(v->getType() == g.i64 ? INT : BOOL, v, true);
}
virtual ConcreteCompilerType* getBoxType() { return BOXED_INT; }
} _INT;
ConcreteCompilerType* INT = &_INT;
......@@ -849,6 +981,110 @@ public:
llvm::Value* cmp = emitter.getBuilder()->CreateFCmpUNE(var->getValue(), llvm::ConstantFP::get(g.double_, 0));
return new ConcreteCompilerVariable(BOOL, cmp, true);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
if (rhs->getType() != INT && rhs->getType() != FLOAT) {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_FLOAT);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
ConcreteCompilerVariable* converted_right;
if (rhs->getType() == FLOAT) {
converted_right = rhs->makeConverted(emitter, FLOAT);
} else {
converted_right = rhs->makeConverted(emitter, INT);
llvm::Value* conv = emitter.getBuilder()->CreateSIToFP(converted_right->getValue(), g.double_);
converted_right->decvref(emitter);
converted_right = new ConcreteCompilerVariable(FLOAT, conv, true);
}
llvm::Value* v;
bool succeeded = true;
if (op_type == AST_TYPE::Mod) {
v = emitter.createCall2(info.exc_info, g.funcs.mod_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
} else if (op_type == AST_TYPE::Div || op_type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(info.exc_info, g.funcs.div_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
} else if (op_type == AST_TYPE::Pow) {
v = emitter.createCall2(info.exc_info, g.funcs.pow_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (op_type) {
case AST_TYPE::Add:
binopcode = llvm::Instruction::FAdd;
break;
case AST_TYPE::Mult:
binopcode = llvm::Instruction::FMul;
break;
case AST_TYPE::Sub:
binopcode = llvm::Instruction::FSub;
break;
case AST_TYPE::BitAnd:
case AST_TYPE::BitOr:
case AST_TYPE::BitXor:
case AST_TYPE::LShift:
case AST_TYPE::RShift:
succeeded = false;
break;
default:
ASSERT(0, "%s", getOpName(op_type).c_str());
abort();
break;
}
if (succeeded) {
v = emitter.getBuilder()->CreateBinOp(binopcode, var->getValue(), converted_right->getValue());
}
} else {
assert(exp_type == Compare);
llvm::CmpInst::Predicate cmp_pred;
switch (op_type) {
case AST_TYPE::Eq:
case AST_TYPE::Is:
cmp_pred = llvm::CmpInst::FCMP_OEQ;
break;
case AST_TYPE::Lt:
cmp_pred = llvm::CmpInst::FCMP_OLT;
break;
case AST_TYPE::LtE:
cmp_pred = llvm::CmpInst::FCMP_OLE;
break;
case AST_TYPE::Gt:
cmp_pred = llvm::CmpInst::FCMP_OGT;
break;
case AST_TYPE::GtE:
cmp_pred = llvm::CmpInst::FCMP_OGE;
break;
case AST_TYPE::NotEq:
case AST_TYPE::IsNot:
cmp_pred = llvm::CmpInst::FCMP_UNE;
break;
default:
ASSERT(0, "%s", getOpName(op_type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateFCmp(cmp_pred, var->getValue(), converted_right->getValue());
}
converted_right->decvref(emitter);
if (succeeded) {
assert(v->getType() == g.double_ || v->getType() == g.i1);
return new ConcreteCompilerVariable(v->getType() == g.double_ ? FLOAT : BOOL, v, true);
}
// TODO duplication with top of function, other functions, etc
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_FLOAT);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
virtual ConcreteCompilerType* getBoxType() { return BOXED_FLOAT; }
} _FLOAT;
ConcreteCompilerType* FLOAT = &_FLOAT;
......@@ -1022,19 +1258,20 @@ public:
if (rtattr->cls != function_cls)
return NULL;
BoxedFunction* rtattr_func = static_cast<BoxedFunction*>(rtattr);
RELEASE_ASSERT(!argspec.has_starargs, "");
RELEASE_ASSERT(!argspec.has_kwargs, "");
RELEASE_ASSERT(argspec.num_keywords == 0, "");
CLFunction* cl = unboxRTFunction(rtattr);
CLFunction* cl = rtattr_func->f;
assert(cl);
if (cl->num_defaults || cl->takes_varargs || cl->takes_kwargs)
if (cl->takes_varargs || cl->takes_kwargs)
return NULL;
RELEASE_ASSERT(cl->num_args == cl->numReceivedArgs(), "");
RELEASE_ASSERT(cl->num_args == args.size() + 1, "");
RELEASE_ASSERT(args.size() + 1 >= cl->num_args - cl->num_defaults && args.size() + 1 <= cl->num_args, "");
CompiledFunction* cf = NULL;
bool found = false;
......@@ -1044,13 +1281,8 @@ public:
assert(cf->spec->arg_types.size() == cl->numReceivedArgs());
bool fits = true;
for (int j = 1; j < cl->num_args; j++) {
// if (cf->sig->arg_types[j] != UNKNOWN) {
// if (cf->sig->arg_types[j]->isFitBy(args[j-1]->guaranteedClass())) {
if (!args[j - 1]->canConvertTo(cf->spec->arg_types[j])) {
// printf("Can't use version %d since arg %d (%s) doesn't fit into spec arg of %s\n", i, j,
// args[j - 1]->getType()->debugName().c_str(),
// cf->spec->arg_types[j]->debugName().c_str());
for (int j = 0; j < args.size(); j++) {
if (!args[j]->canConvertTo(cf->spec->arg_types[j + 1])) {
fits = false;
break;
}
......@@ -1086,6 +1318,13 @@ public:
new_args.push_back(var);
new_args.insert(new_args.end(), args.begin(), args.end());
for (int i = args.size() + 1; i < cl->num_args; i++) {
// TODO should _call() be able to take llvm::Value's directly?
new_args.push_back(new ConcreteCompilerVariable(
UNKNOWN, embedConstantPtr(rtattr_func->defaults->elts[i - args.size() - 1], g.llvm_value_type_ptr),
true));
}
std::vector<llvm::Value*> other_args;
ConcreteCompilerVariable* rtn = _call(emitter, info, linked_function, cf->code, other_args, argspec, new_args,
......@@ -1128,6 +1367,31 @@ public:
return rtn;
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted_rhs = rhs->makeConverted(emitter, rhs->getBoxType());
BoxedClass* rhs_cls = converted_rhs->guaranteedClass();
if (rhs_cls && rhs_cls->is_constant && !rhs_cls->is_user_defined) {
// Ugly, but for now special-case the set of type-pairs that we know will always work
if (exp_type == BinOp
&& ((cls == int_cls && rhs_cls == int_cls) || (cls == float_cls && rhs_cls == float_cls)
|| (cls == list_cls && rhs_cls == int_cls))) {
const std::string& left_side_name = getOpName(op_type);
ConcreteCompilerVariable* called_constant = tryCallattrConstant(
emitter, info, var, &left_side_name, true, ArgPassSpec(1, 0, 0, 0), { converted_rhs }, NULL, false);
if (called_constant)
return called_constant;
}
}
auto rtn = UNKNOWN->binexp(emitter, info, var, converted_rhs, op_type, exp_type);
converted_rhs->decvref(emitter);
return rtn;
}
virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* slice) {
static const std::string attr("__getitem__");
ConcreteCompilerVariable* called_constant
......@@ -1201,6 +1465,10 @@ public:
virtual ConcreteCompilerType* getConcreteType() { return this; }
// Shouldn't call this:
virtual ConcreteCompilerType* getBoxType() { RELEASE_ASSERT(0, ""); }
void drop(IREmitter& emitter, VAR* var) override {}
void grab(IREmitter& emitter, VAR* var) override {}
} _CLOSURE;
ConcreteCompilerType* CLOSURE = &_CLOSURE;
......@@ -1277,6 +1545,14 @@ public:
return rtn;
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, VAR* var) override {
return makeBool(var->getValue()->size() != 0);
}
......@@ -1286,6 +1562,8 @@ public:
if (rtn == NULL) {
rtn = new VAR(this, var->getValue(), var->isGrabbed());
while (rtn->getVrefs() < var->getVrefs())
rtn->incvref();
}
return rtn;
}
......@@ -1357,6 +1635,14 @@ public:
return rtn;
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
virtual ConcreteCompilerType* getBoxType() { return BOXED_BOOL; }
};
ConcreteCompilerType* BOOL = new BoolType();
......@@ -1499,6 +1785,14 @@ public:
return BOXED_TUPLE->getattrType(attr, cls_only);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool clsonly, ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
......@@ -1575,6 +1869,11 @@ public:
return new ConcreteCompilerVariable(BOOL, llvm::UndefValue::get(g.i1), true);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
return undefVariable();
}
virtual ConcreteCompilerType* getBoxType() { return UNKNOWN; }
virtual ConcreteCompilerType* getConcreteType() { return this; }
......
......@@ -19,6 +19,7 @@
#include <vector>
#include "codegen/codegen.h"
#include "core/ast.h"
#include "core/types.h"
namespace pyston {
......@@ -47,6 +48,12 @@ public:
typedef std::unordered_map<CompilerVariable*, CompilerVariable*> DupCache;
enum BinExpType {
AugBinOp,
BinOp,
Compare,
};
template <class V> class _ValuedCompilerType : public CompilerType {
public:
typedef ValuedCompilerVariable<V> VAR;
......@@ -63,11 +70,11 @@ public:
printf("getBoxType not defined for %s\n", debugName().c_str());
abort();
}
virtual void drop(IREmitter& emmitter, VAR* value) {
virtual void drop(IREmitter& emmitter, VAR* var) {
printf("drop not defined for %s\n", debugName().c_str());
abort();
}
virtual void grab(IREmitter& emmitter, VAR* value) {
virtual void grab(IREmitter& emmitter, VAR* var) {
printf("grab not defined for %s\n", debugName().c_str());
abort();
}
......@@ -75,53 +82,58 @@ public:
printf("canConvertTo not defined for %s\n", debugName().c_str());
abort();
}
virtual ConcreteCompilerVariable* makeConverted(IREmitter& emitter, VAR* value, ConcreteCompilerType* other_type) {
virtual ConcreteCompilerVariable* makeConverted(IREmitter& emitter, VAR* var, ConcreteCompilerType* other_type) {
printf("makeConverted not defined for %s\n", debugName().c_str());
abort();
}
virtual ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, VAR* value) {
virtual ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, VAR* var) {
printf("nonzero not defined for %s\n", debugName().c_str());
abort();
}
virtual CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr,
virtual CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool cls_only) {
printf("getattr not defined for %s\n", debugName().c_str());
abort();
}
virtual void setattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr,
virtual void setattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
CompilerVariable* v) {
printf("setattr not defined for %s\n", debugName().c_str());
abort();
}
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr,
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool clsonly, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
printf("callattr not defined for %s\n", debugName().c_str());
abort();
}
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, VAR* value, struct ArgPassSpec argspec,
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, VAR* var, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
printf("call not defined for %s\n", debugName().c_str());
abort();
}
virtual void print(IREmitter& emitter, const OpInfo& info, VAR* value) {
virtual void print(IREmitter& emitter, const OpInfo& info, VAR* var) {
printf("print not defined for %s\n", debugName().c_str());
abort();
}
virtual ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info, VAR* value) {
virtual ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info, VAR* var) {
printf("len not defined for %s\n", debugName().c_str());
abort();
}
virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, VAR* value, CompilerVariable* v) {
virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* v) {
// Can almost do this, except for error messages + types:
// static const std::string attr("__getitem__");
// return callattr(emitter, info, value, &attr, true, ArgPassSpec(1, 0, 0, 0), {v}, NULL);
// return callattr(emitter, info, var, &attr, true, ArgPassSpec(1, 0, 0, 0), {v}, NULL);
printf("getitem not defined for %s\n", debugName().c_str());
abort();
}
virtual llvm::Value* makeClassCheck(IREmitter& emitter, VAR* value, BoxedClass* c) {
virtual CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) {
printf("binexp not defined for %s\n", debugName().c_str());
abort();
}
virtual llvm::Value* makeClassCheck(IREmitter& emitter, VAR* var, BoxedClass* c) {
printf("makeClassCheck not defined for %s\n", debugName().c_str());
abort();
}
......@@ -189,7 +201,7 @@ public:
}
}
void decvref(IREmitter& emitter) {
assert(vrefs > 0 && vrefs < (1 << 20));
ASSERT(vrefs > 0 && vrefs < (1 << 20), "%d", vrefs);
// ASSERT(vrefs, "%s", getType()->debugName().c_str());
vrefs--;
if (vrefs == 0) {
......@@ -229,6 +241,8 @@ public:
virtual void print(IREmitter& emitter, const OpInfo& info) = 0;
virtual ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info) = 0;
virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, CompilerVariable*) = 0;
virtual CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) = 0;
};
template <class V> class ValuedCompilerVariable : public CompilerVariable {
......@@ -299,6 +313,12 @@ public:
CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, CompilerVariable* slice) override {
return type->getitem(emitter, info, this, slice);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, CompilerVariable* rhs, AST_TYPE::AST_TYPE op_type,
BinExpType exp_type) override {
return type->binexp(emitter, info, this, rhs, op_type, exp_type);
}
llvm::Value* makeClassCheck(IREmitter& emitter, BoxedClass* cls) override {
return type->makeClassCheck(emitter, this, cls);
}
......
......@@ -337,13 +337,18 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
arg_num++;
if (arg_num < 3) {
from_arg = func_args[arg_num];
assert(from_arg->getType() == p.second->llvmType());
} else {
ASSERT(func_args.size() == 4, "%ld", func_args.size());
llvm::Value* ptr = entry_emitter->getBuilder()->CreateConstGEP1_32(func_args[3], arg_num - 3);
if (p.second == INT) {
ptr = entry_emitter->getBuilder()->CreateBitCast(ptr, g.i64->getPointerTo());
} else if (p.second == BOOL) {
ptr = entry_emitter->getBuilder()->CreateBitCast(ptr, g.i1->getPointerTo());
} else if (p.second == FLOAT) {
ptr = entry_emitter->getBuilder()->CreateBitCast(ptr, g.double_->getPointerTo());
} else {
assert(p.second->llvmType() == g.llvm_value_type_ptr);
}
from_arg = entry_emitter->getBuilder()->CreateLoad(ptr);
assert(from_arg->getType() == p.second->llvmType());
......@@ -599,12 +604,8 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
into_hax.insert(b2);
}
const PhiAnalysis::RequiredSet& names = source->phis->getAllDefinedAt(block);
const PhiAnalysis::RequiredSet& names = source->phis->getAllRequiredFor(block);
for (const auto& s : names) {
// TODO the list from getAllDefinedAt should come filtered:
if (!source->liveness->isLiveAtEnd(s, block->predecessors[0]))
continue;
// printf("adding guessed phi for %s\n", s.c_str());
ConcreteCompilerType* type = types->getTypeAtBlockStart(s, block);
llvm::PHINode* phi = emitter->getBuilder()->CreatePHI(type->llvmType(), block->predecessors.size(), s);
......
......@@ -33,13 +33,6 @@
#include "runtime/objmodel.h"
#include "runtime/types.h"
extern "C" {
// Hack: we only need RTTI for a single type (Box*), which we know will get emmitted,
// so just use the mangled name directly instead of using typeid() since that requires
// turning on RTTI for *everything* (including llvm)
extern void* _ZTIPN6pyston3BoxE;
}
namespace pyston {
llvm::Value* IRGenState::getScratchSpace(int min_bytes) {
......@@ -353,244 +346,66 @@ private:
}
return new ConcreteCompilerVariable(UNKNOWN, exc_obj, true);
}
default:
RELEASE_ASSERT(0, "%d", node->opcode);
}
}
case AST_LangPrimitive::LOCALS: {
assert(node->args.size() == 0);
enum BinExpType {
AugBinOp,
BinOp,
Compare,
};
CompilerVariable* _evalBinExp(AST* node, CompilerVariable* left, CompilerVariable* right, AST_TYPE::AST_TYPE type,
BinExpType exp_type, ExcInfo exc_info) {
assert(state != PARTIAL);
assert(left);
assert(right);
llvm::Value* v = emitter.getBuilder()->CreateCall(g.funcs.createDict);
ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(DICT, v, true);
if (left->getType() == INT && right->getType() == INT) {
ConcreteCompilerVariable* converted_left = left->makeConverted(emitter, INT);
ConcreteCompilerVariable* converted_right = right->makeConverted(emitter, INT);
llvm::Value* v;
if (type == AST_TYPE::Mod) {
v = emitter.createCall2(exc_info, g.funcs.mod_i64_i64, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (type == AST_TYPE::Div || type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(exc_info, g.funcs.div_i64_i64, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (type == AST_TYPE::Pow) {
v = emitter.createCall2(exc_info, g.funcs.pow_i64_i64, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (type) {
case AST_TYPE::Add:
binopcode = llvm::Instruction::Add;
break;
case AST_TYPE::BitAnd:
binopcode = llvm::Instruction::And;
break;
case AST_TYPE::BitOr:
binopcode = llvm::Instruction::Or;
break;
case AST_TYPE::BitXor:
binopcode = llvm::Instruction::Xor;
break;
case AST_TYPE::LShift:
binopcode = llvm::Instruction::Shl;
break;
case AST_TYPE::RShift:
binopcode = llvm::Instruction::AShr;
break;
case AST_TYPE::Mult:
binopcode = llvm::Instruction::Mul;
break;
case AST_TYPE::Sub:
binopcode = llvm::Instruction::Sub;
break;
default:
ASSERT(0, "%s", getOpName(type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateBinOp(binopcode, converted_left->getValue(),
converted_right->getValue());
} else {
assert(exp_type == Compare);
llvm::CmpInst::Predicate cmp_pred;
switch (type) {
case AST_TYPE::Eq:
case AST_TYPE::Is:
cmp_pred = llvm::CmpInst::ICMP_EQ;
break;
case AST_TYPE::Lt:
cmp_pred = llvm::CmpInst::ICMP_SLT;
break;
case AST_TYPE::LtE:
cmp_pred = llvm::CmpInst::ICMP_SLE;
break;
case AST_TYPE::Gt:
cmp_pred = llvm::CmpInst::ICMP_SGT;
break;
case AST_TYPE::GtE:
cmp_pred = llvm::CmpInst::ICMP_SGE;
break;
case AST_TYPE::NotEq:
case AST_TYPE::IsNot:
cmp_pred = llvm::CmpInst::ICMP_NE;
break;
default:
ASSERT(0, "%s", getOpName(type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateICmp(cmp_pred, converted_left->getValue(), converted_right->getValue());
}
converted_left->decvref(emitter);
converted_right->decvref(emitter);
assert(v->getType() == g.i64 || v->getType() == g.i1);
return new ConcreteCompilerVariable(v->getType() == g.i64 ? INT : BOOL, v, true);
}
for (auto& p : symbol_table) {
if (p.first[0] == '!')
continue;
if (left->getType() == FLOAT && (right->getType() == FLOAT || right->getType() == INT)) {
ConcreteCompilerVariable* converted_left = left->makeConverted(emitter, FLOAT);
ConcreteCompilerVariable* is_defined_var = static_cast<ConcreteCompilerVariable*>(
_getFake(_getFakeName("is_defined", p.first.c_str()), true));
ConcreteCompilerVariable* converted_right;
if (right->getType() == FLOAT) {
converted_right = right->makeConverted(emitter, FLOAT);
} else {
converted_right = right->makeConverted(emitter, INT);
llvm::Value* conv = emitter.getBuilder()->CreateSIToFP(converted_right->getValue(), g.double_);
converted_right->decvref(emitter);
converted_right = new ConcreteCompilerVariable(FLOAT, conv, true);
}
llvm::Value* v;
bool succeeded = true;
if (type == AST_TYPE::Mod) {
v = emitter.createCall2(exc_info, g.funcs.mod_float_float, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (type == AST_TYPE::Div || type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(exc_info, g.funcs.div_float_float, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (type == AST_TYPE::Pow) {
v = emitter.createCall2(exc_info, g.funcs.pow_float_float, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (type) {
case AST_TYPE::Add:
binopcode = llvm::Instruction::FAdd;
break;
case AST_TYPE::Mult:
binopcode = llvm::Instruction::FMul;
break;
case AST_TYPE::Sub:
binopcode = llvm::Instruction::FSub;
break;
case AST_TYPE::BitAnd:
case AST_TYPE::BitOr:
case AST_TYPE::BitXor:
case AST_TYPE::LShift:
case AST_TYPE::RShift:
succeeded = false;
break;
default:
ASSERT(0, "%s", getOpName(type).c_str());
abort();
break;
}
static const std::string setitem_str("__setitem__");
if (!is_defined_var) {
ConcreteCompilerVariable* converted = p.second->makeConverted(emitter, p.second->getBoxType());
if (succeeded) {
v = emitter.getBuilder()->CreateBinOp(binopcode, converted_left->getValue(),
converted_right->getValue());
}
} else {
assert(exp_type == Compare);
llvm::CmpInst::Predicate cmp_pred;
switch (type) {
case AST_TYPE::Eq:
case AST_TYPE::Is:
cmp_pred = llvm::CmpInst::FCMP_OEQ;
break;
case AST_TYPE::Lt:
cmp_pred = llvm::CmpInst::FCMP_OLT;
break;
case AST_TYPE::LtE:
cmp_pred = llvm::CmpInst::FCMP_OLE;
break;
case AST_TYPE::Gt:
cmp_pred = llvm::CmpInst::FCMP_OGT;
break;
case AST_TYPE::GtE:
cmp_pred = llvm::CmpInst::FCMP_OGE;
break;
case AST_TYPE::NotEq:
case AST_TYPE::IsNot:
cmp_pred = llvm::CmpInst::FCMP_UNE;
break;
default:
ASSERT(0, "%s", getOpName(type).c_str());
abort();
break;
// TODO super dumb that it reallocates the name again
CompilerVariable* _r
= rtn->callattr(emitter, getEmptyOpInfo(exc_info), &setitem_str, true, ArgPassSpec(2),
{ makeStr(new std::string(p.first)), converted }, NULL);
converted->decvref(emitter);
_r->decvref(emitter);
} else {
assert(is_defined_var->getType() == BOOL);
llvm::BasicBlock* was_defined
= llvm::BasicBlock::Create(g.context, "was_defined", irstate->getLLVMFunction());
llvm::BasicBlock* join
= llvm::BasicBlock::Create(g.context, "join", irstate->getLLVMFunction());
emitter.getBuilder()->CreateCondBr(is_defined_var->getValue(), was_defined, join);
emitter.getBuilder()->SetInsertPoint(was_defined);
ConcreteCompilerVariable* converted = p.second->makeConverted(emitter, p.second->getBoxType());
// TODO super dumb that it reallocates the name again
CompilerVariable* _r
= rtn->callattr(emitter, getEmptyOpInfo(exc_info), &setitem_str, true, ArgPassSpec(2),
{ makeStr(new std::string(p.first)), converted }, NULL);
converted->decvref(emitter);
_r->decvref(emitter);
emitter.getBuilder()->CreateBr(join);
emitter.getBuilder()->SetInsertPoint(join);
}
}
v = emitter.getBuilder()->CreateFCmp(cmp_pred, converted_left->getValue(), converted_right->getValue());
}
converted_left->decvref(emitter);
converted_right->decvref(emitter);
if (succeeded) {
assert(v->getType() == g.double_ || v->getType() == g.i1);
return new ConcreteCompilerVariable(v->getType() == g.double_ ? FLOAT : BOOL, v, true);
return rtn;
}
default:
RELEASE_ASSERT(0, "%d", node->opcode);
}
// ASSERT(left->getType() == left->getBoxType() || right->getType() == right->getBoxType(), "%s %s",
// left->getType()->debugName().c_str(), right->getType()->debugName().c_str());
ConcreteCompilerVariable* boxed_left = left->makeConverted(emitter, left->getBoxType());
ConcreteCompilerVariable* boxed_right = right->makeConverted(emitter, right->getBoxType());
llvm::Value* rtn;
bool do_patchpoint = ENABLE_ICBINEXPS && (irstate->getEffortLevel() != EffortLevel::INTERPRETED);
llvm::Value* rt_func;
void* rt_func_addr;
if (exp_type == BinOp) {
rt_func = g.funcs.binop;
rt_func_addr = (void*)binop;
} else if (exp_type == AugBinOp) {
rt_func = g.funcs.augbinop;
rt_func_addr = (void*)augbinop;
} else {
rt_func = g.funcs.compare;
rt_func_addr = (void*)compare;
}
if (do_patchpoint) {
PatchpointSetupInfo* pp = patchpoints::createBinexpPatchpoint(
emitter.currentFunction(), getOpInfoForNode(node, exc_info).getTypeRecorder());
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(boxed_left->getValue());
llvm_args.push_back(boxed_right->getValue());
llvm_args.push_back(getConstantInt(type, g.i32));
llvm::Value* uncasted = emitter.createPatchpoint(pp, rt_func_addr, llvm_args, exc_info).getInstruction();
rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
} else {
rtn = emitter.createCall3(exc_info, rt_func, boxed_left->getValue(), boxed_right->getValue(),
getConstantInt(type, g.i32)).getInstruction();
}
}
boxed_left->decvref(emitter);
boxed_right->decvref(emitter);
CompilerVariable* _evalBinExp(AST* node, CompilerVariable* left, CompilerVariable* right, AST_TYPE::AST_TYPE type,
BinExpType exp_type, ExcInfo exc_info) {
assert(state != PARTIAL);
if (type == AST_TYPE::In || type == AST_TYPE::NotIn || type == AST_TYPE::Is || type == AST_TYPE::IsNot) {
return unboxVar(BOXED_BOOL, rtn, true);
}
assert(left);
assert(right);
return new ConcreteCompilerVariable(UNKNOWN, rtn, true);
return left->binexp(emitter, getOpInfoForNode(node, exc_info), right, type, exp_type);
}
CompilerVariable* evalBinOp(AST_BinOp* node, ExcInfo exc_info) {
......@@ -734,7 +549,7 @@ private:
std::vector<CompilerVariable*> args;
args.push_back(key);
args.push_back(value);
// TODO could use the internal _listAppend function to avoid incref/decref'ing None
// TODO should use callattr
CompilerVariable* rtn = setitem->call(emitter, getEmptyOpInfo(exc_info), ArgPassSpec(2), args, NULL);
rtn->decvref(emitter);
......@@ -862,9 +677,10 @@ private:
}
std::string defined_name = _getFakeName("is_defined", node->id.c_str());
ConcreteCompilerVariable* is_defined = static_cast<ConcreteCompilerVariable*>(_popFake(defined_name, true));
ConcreteCompilerVariable* is_defined_var
= static_cast<ConcreteCompilerVariable*>(_getFake(defined_name, true));
if (is_defined) {
if (is_defined_var) {
// classdefs have different scoping rules than functions:
if (irstate->getSourceInfo()->ast->type == AST_TYPE::ClassDef) {
llvm::BasicBlock* from_local
......@@ -873,7 +689,7 @@ private:
= llvm::BasicBlock::Create(g.context, "from_global", irstate->getLLVMFunction());
llvm::BasicBlock* join = llvm::BasicBlock::Create(g.context, "join", irstate->getLLVMFunction());
emitter.getBuilder()->CreateCondBr(is_defined->getValue(), from_local, from_global);
emitter.getBuilder()->CreateCondBr(is_defined_var->getValue(), from_local, from_global);
emitter.getBuilder()->SetInsertPoint(from_local);
CompilerVariable* local = symbol_table[node->id];
......@@ -893,8 +709,11 @@ private:
return new ConcreteCompilerVariable(UNKNOWN, phi, true);
}
emitter.createCall2(exc_info, g.funcs.assertNameDefined, is_defined->getValue(),
emitter.createCall2(exc_info, g.funcs.assertNameDefined, is_defined_var->getValue(),
getStringConstantPtr(node->id + '\0'));
// At this point we know the name must be defined (otherwise the assert would have fired):
_popFake(defined_name);
}
CompilerVariable* rtn = symbol_table[node->id];
......@@ -1271,30 +1090,29 @@ private:
snprintf(buf, 40, "!%s_%s", prefix, token);
return std::string(buf);
}
void _setFake(std::string name, CompilerVariable* val) {
assert(name[0] == '!');
CompilerVariable*& cur = symbol_table[name];
assert(cur == NULL);
cur = val;
}
CompilerVariable* _clearFake(std::string name) {
assert(name[0] == '!');
CompilerVariable* rtn = symbol_table[name];
assert(rtn == NULL);
symbol_table.erase(name);
return rtn;
}
CompilerVariable* _getFake(std::string name, bool allow_missing = false) {
assert(name[0] == '!');
CompilerVariable* rtn = symbol_table[name];
if (!allow_missing)
assert(rtn != NULL);
return rtn;
auto it = symbol_table.find(name);
if (it == symbol_table.end()) {
assert(allow_missing);
return NULL;
}
return it->second;
}
CompilerVariable* _popFake(std::string name, bool allow_missing = false) {
CompilerVariable* rtn = _getFake(name, allow_missing);
symbol_table.erase(name);
if (!allow_missing)
assert(rtn != NULL);
return rtn;
}
......@@ -1454,6 +1272,16 @@ private:
ScopeInfo* scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node);
assert(scope_info);
if (node->bases.size() == 0) {
printf("Warning: old-style class '%s' in file '%s' detected! Converting to a new-style class!\n",
node->name.c_str(), irstate->getSourceInfo()->parent_module->fn.c_str());
AST_Name* base = new AST_Name();
base->id = "object";
base->ctx_type = AST_TYPE::Load;
node->bases.push_back(base);
}
RELEASE_ASSERT(node->bases.size() == 1, "");
RELEASE_ASSERT(node->decorator_list.size() == 0, "");
......@@ -1569,13 +1397,33 @@ private:
}
CompilerVariable* created_closure = NULL;
ScopeInfo* scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node);
if (scope_info->takesClosure()) {
created_closure = _getFake(CREATED_CLOSURE_NAME, false);
bool takes_closure;
// Optimization: when compiling a module, it's nice to not have to run analyses into the
// entire module's source code.
// If we call getScopeInfoForNode, that will trigger an analysis of that function tree,
// but we're only using it here to figure out if that function takes a closure.
// Top level functions never take a closure, so we can skip the analysis.
if (irstate->getSourceInfo()->ast->type == AST_TYPE::Module)
takes_closure = false;
else {
takes_closure = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node)->takesClosure();
}
// TODO: this lines disables the optimization mentioned above...
bool is_generator = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node)->takesGenerator();
if (takes_closure) {
if (irstate->getScopeInfo()->createsClosure()) {
created_closure = _getFake(CREATED_CLOSURE_NAME, false);
} else {
assert(irstate->getScopeInfo()->passesThroughClosure());
created_closure = _getFake(PASSED_CLOSURE_NAME, false);
}
assert(created_closure);
}
CompilerVariable* func = makeFunction(emitter, cl, created_closure, scope_info->takesGenerator(), defaults);
CompilerVariable* func = makeFunction(emitter, cl, created_closure, is_generator, defaults);
for (auto d : defaults) {
d->decvref(emitter);
......@@ -1631,7 +1479,11 @@ private:
const std::string& name = alias->name;
const std::string& asname = alias->asname.size() ? alias->asname : alias->name;
CompilerVariable* v = module->getattr(emitter, getEmptyOpInfo(exc_info), &name, false);
// TODO add patchpoints to this?
llvm::Value* r = emitter.createCall2(exc_info, g.funcs.importFrom, module->getValue(),
embedConstantPtr(&name, g.llvm_str_type_ptr)).getInstruction();
CompilerVariable* v = new ConcreteCompilerVariable(UNKNOWN, r, true);
_doSet(asname, v, exc_info);
v->decvref(emitter);
}
......@@ -1692,6 +1544,11 @@ private:
rtn->ensureGrabbed(emitter);
val->decvref(emitter);
for (auto& p : symbol_table) {
p.second->decvref(emitter);
}
symbol_table.clear();
endBlock(DEAD);
ASSERT(rtn->getVrefs() == 1, "%d", rtn->getVrefs());
......@@ -1769,18 +1626,6 @@ private:
std::vector<ConcreteCompilerVariable*> converted_args;
SortedSymbolTable sorted_symbol_table(symbol_table.begin(), symbol_table.end());
/*
for (SortedSymbolTable::iterator it = sorted_symbol_table.begin(), end = sorted_symbol_table.end(); it != end; )
{
if (!source->liveness->isLiveAtEnd(it->first, myblock)) {
// I think this line can never get hit: nothing can die on a backedge, since control flow can eventually
// reach this block again, where the symbol was live (as shown by it being in the symbol table)
printf("Not sending %s to osr since it will die\n", it->first.c_str());
it = sorted_symbol_table.erase(it);
} else {
++it;
}
}*/
// For OSR calls, we use the same calling convention as in some other places; namely,
// arg1, arg2, arg3, argarray [nargs is ommitted]
......@@ -1814,11 +1659,6 @@ private:
int arg_num = -1;
for (const auto& p : sorted_symbol_table) {
arg_num++;
// I don't think this can fail, but if it can we should filter out dead symbols before
// passing them on:
ASSERT(startswith(p.first, "!is_defined")
|| irstate->getSourceInfo()->liveness->isLiveAtEnd(p.first, myblock),
"%d %s", myblock->idx, p.first.c_str());
// This line can never get hit right now since we unnecessarily force every variable to be concrete
// for a loop, since we generate all potential phis:
......@@ -1845,11 +1685,17 @@ private:
} else {
llvm::Value* ptr = emitter.getBuilder()->CreateConstGEP1_32(arg_array, arg_num - 3);
if (var->getType() == INT) {
if (var->getType() == INT || var->getType() == BOOL) {
val = emitter.getBuilder()->CreateIntToPtr(val, g.llvm_value_type_ptr);
} else if (var->getType() == FLOAT) {
// val = emitter.getBuilder()->CreateBitCast(val, g.llvm_value_type_ptr);
ptr = emitter.getBuilder()->CreateBitCast(ptr, g.double_->getPointerTo());
} else if (var->getType() == UNDEF) {
// TODO if there are any undef variables, we're in 'unreachable' territory.
// Do we even need to generate any of this code?
// Currently we represent 'undef's as 'i16 undef'
val = emitter.getBuilder()->CreateIntToPtr(val, g.llvm_value_type_ptr);
} else {
assert(val->getType() == g.llvm_value_type_ptr);
}
......@@ -1915,23 +1761,21 @@ private:
}
void doRaise(AST_Raise* node, ExcInfo exc_info) {
RELEASE_ASSERT(node->arg0 != NULL, "");
RELEASE_ASSERT(node->arg1 == NULL, "");
RELEASE_ASSERT(node->arg2 == NULL, "");
std::vector<llvm::Value*> args;
llvm::Value* raise_func = g.funcs.raise0;
CompilerVariable* arg0 = evalExpr(node->arg0, exc_info);
ConcreteCompilerVariable* converted_arg0 = arg0->makeConverted(emitter, arg0->getBoxType());
arg0->decvref(emitter);
if (node->arg0) {
raise_func = g.funcs.raise1;
llvm::Value* exc_mem
= emitter.getBuilder()->CreateCall(g.funcs.__cxa_allocate_exception, getConstantInt(sizeof(void*), g.i64));
llvm::Value* bitcasted = emitter.getBuilder()->CreateBitCast(exc_mem, g.llvm_value_type_ptr->getPointerTo());
emitter.getBuilder()->CreateStore(converted_arg0->getValue(), bitcasted);
converted_arg0->decvref(emitter);
CompilerVariable* arg0 = evalExpr(node->arg0, exc_info);
ConcreteCompilerVariable* converted_arg0 = arg0->makeConverted(emitter, arg0->getBoxType());
arg0->decvref(emitter);
args.push_back(converted_arg0->getValue());
}
RELEASE_ASSERT(node->arg1 == NULL, "");
RELEASE_ASSERT(node->arg2 == NULL, "");
void* type_id = &_ZTIPN6pyston3BoxE /* &typeid(Box*) */;
emitter.createCall(exc_info, g.funcs.__cxa_throw,
{ exc_mem, embedConstantPtr(type_id, g.i8_ptr), embedConstantPtr(nullptr, g.i8_ptr) });
emitter.createCall(exc_info, raise_func, args);
emitter.getBuilder()->CreateUnreachable();
endBlock(DEAD);
......@@ -2064,11 +1908,14 @@ private:
++it;
} else {
#ifndef NDEBUG
// TODO getTypeAtBlockEnd will automatically convert up to the concrete type, which we don't want here,
// but this is just for debugging so I guess let it happen for now:
ConcreteCompilerType* ending_type = types->getTypeAtBlockEnd(it->first, myblock);
ASSERT(it->second->canConvertTo(ending_type), "%s is supposed to be %s, but somehow is %s",
it->first.c_str(), ending_type->debugName().c_str(), it->second->getType()->debugName().c_str());
if (myblock->successors.size()) {
// TODO getTypeAtBlockEnd will automatically convert up to the concrete type, which we don't want
// here, but this is just for debugging so I guess let it happen for now:
ConcreteCompilerType* ending_type = types->getTypeAtBlockEnd(it->first, myblock);
ASSERT(it->second->canConvertTo(ending_type), "%s is supposed to be %s, but somehow is %s",
it->first.c_str(), ending_type->debugName().c_str(),
it->second->getType()->debugName().c_str());
}
#endif
++it;
......@@ -2123,20 +1970,13 @@ public:
SymbolTable* st = new SymbolTable(symbol_table);
ConcreteSymbolTable* phi_st = new ConcreteSymbolTable();
for (SymbolTable::iterator it = st->begin(); it != st->end(); it++) {
if (it->first[0] == '!') {
// ASSERT(startswith(it->first, _getFakeName("is_defined", "")), "left a fake variable in the real
// symbol table? '%s'", it->first.c_str());
} else {
ASSERT(source->liveness->isLiveAtEnd(it->first, myblock), "%s", it->first.c_str());
}
}
if (myblock->successors.size() == 0) {
st->erase(CREATED_CLOSURE_NAME);
st->erase(PASSED_CLOSURE_NAME);
st->erase(PASSED_GENERATOR_NAME);
assert(st->size() == 0); // shouldn't have anything live if there are no successors!
for (auto& p : *st) {
p.second->decvref(emitter);
}
st->clear();
symbol_table.clear();
return EndingState(st, phi_st, curblock);
} else if (myblock->successors.size() > 1) {
// Since there are no critical edges, all successors come directly from this node,
......
......@@ -102,6 +102,12 @@ Val fetch(llvm::Value* v, const llvm::DataLayout& dl, const SymMap& symbols) {
case llvm::Value::ConstantExprVal: {
llvm::ConstantExpr* ce = llvm::cast<llvm::ConstantExpr>(v);
if (ce->isCast()) {
if (ce->getOpcode() == llvm::Instruction::IntToPtr && ce->getOperand(0)->getType() == g.i1) {
// inttoptr is specified to zero-extend
Val o = fetch(ce->getOperand(0), dl, symbols);
return o.n & 0x1;
}
assert(width(ce->getOperand(0), dl) == 8 && width(ce, dl) == 8);
Val o = fetch(ce->getOperand(0), dl, symbols);
......@@ -283,7 +289,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
int arg_num = -1;
int closure_indicator = closure ? 1 : 0;
int generator_indicator = generator ? 1 : 0;
int argOffset = closure_indicator + generator_indicator;
int arg_offset = closure_indicator + generator_indicator;
for (llvm::Argument& arg : f->args()) {
arg_num++;
......@@ -291,15 +297,15 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(closure)));
else if ((arg_num == 0 || (arg_num == 1 && closure)) && generator)
symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(generator)));
else if (arg_num == 0 + argOffset)
else if (arg_num == 0 + arg_offset)
symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg1)));
else if (arg_num == 1 + argOffset)
else if (arg_num == 1 + arg_offset)
symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg2)));
else if (arg_num == 2 + argOffset)
else if (arg_num == 2 + arg_offset)
symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg3)));
else {
assert(arg_num == 3 + argOffset);
assert(f->getArgumentList().size() == 4 + argOffset);
assert(arg_num == 3 + arg_offset);
assert(f->getArgumentList().size() == 4 + arg_offset);
assert(f->getArgumentList().back().getType() == g.llvm_value_type_ptr->getPointerTo());
symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val((int64_t)args)));
// printf("loading %%4 with %p\n", (void*)args);
......@@ -310,6 +316,14 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
llvm::BasicBlock* prevblock = NULL;
llvm::BasicBlock* curblock = &f->getEntryBlock();
// The symbol table at the end of the previous BB
// This is important for the following case:
// %a = phi [0, %l1], [1, %l2]
// %b = phi [0, %l1], [%a, %l2]
// The reference to %a in the definition of %b resolves to the *previous* value of %a,
// not the value of %a that we just set in the phi.
SymMap prev_symbols;
struct {
Box* exc_obj;
int64_t exc_selector;
......@@ -521,8 +535,12 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
SET(fetch(bc->getOperand(0), dl, symbols));
continue;
} else if (llvm::IntToPtrInst* bc = llvm::dyn_cast<llvm::IntToPtrInst>(inst)) {
assert(width(bc->getOperand(0), dl) == 8);
SET(fetch(bc->getOperand(0), dl, symbols));
if (bc->getOperand(0)->getType() == g.i1) {
SET(fetch(bc->getOperand(0), dl, symbols).n & 0xff);
} else {
assert(width(bc->getOperand(0), dl) == 8);
SET(fetch(bc->getOperand(0), dl, symbols));
}
continue;
//} else if (llvm::CallInst* ci = llvm::dyn_cast<llvm::CallInst>(inst)) {
} else if (llvm::isa<llvm::CallInst>(inst) || llvm::isa<llvm::InvokeInst>(inst)) {
......@@ -615,14 +633,18 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
r = reinterpret_cast<int64_t (*)(int64_t, double, double)>(f)(args[0].n, args[1].d,
args[2].d);
break;
case 0b100000:
case 0b100000: // 32
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t)>(f)(
args[0].n, args[1].n, args[2].n, args[3].n);
break;
case 0b100001:
case 0b100001: // 33
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, double)>(f)(
args[0].n, args[1].n, args[2].n, args[3].d);
break;
case 0b100010: // 34
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, double, int64_t)>(f)(
args[0].n, args[1].n, args[2].d, args[3].n);
break;
case 0b100110:
r = reinterpret_cast<int64_t (*)(int64_t, double, double, int64_t)>(f)(
args[0].n, args[1].d, args[2].d, args[3].n);
......@@ -631,15 +653,15 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
r = reinterpret_cast<int64_t (*)(double, int, double, int64_t)>(f)(args[0].d, args[1].n,
args[2].d, args[3].n);
break;
case 0b1000000:
case 0b1000000: // 64
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t)>(f)(
args[0].n, args[1].n, args[2].n, args[3].n, args[4].n);
break;
case 0b10000000:
case 0b10000000: // 128
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t)>(f)(
args[0].n, args[1].n, args[2].n, args[3].n, args[4].n, args[5].n);
break;
case 0b100000000:
case 0b100000000: // 256
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t,
int64_t)>(f)(args[0].n, args[1].n, args[2].n, args[3].n,
args[4].n, args[5].n, args[6].n);
......@@ -667,6 +689,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
if (invoke != nullptr) {
prevblock = curblock;
curblock = invoke->getNormalDest();
prev_symbols = symbols;
}
} catch (Box* e) {
if (VERBOSITY("interpreter") >= 2) {
......@@ -678,6 +701,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
prevblock = curblock;
curblock = invoke->getUnwindDest();
prev_symbols = symbols;
landingpad_value.exc_obj = e;
landingpad_value.exc_selector
......@@ -700,7 +724,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
continue;
} else if (llvm::PHINode* phi = llvm::dyn_cast<llvm::PHINode>(inst)) {
assert(prevblock);
SET(fetch(phi->getIncomingValueForBlock(prevblock), dl, symbols));
SET(fetch(phi->getIncomingValueForBlock(prevblock), dl, prev_symbols));
continue;
} else if (llvm::BranchInst* br = llvm::dyn_cast<llvm::BranchInst>(inst)) {
prevblock = curblock;
......@@ -714,6 +738,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
} else {
curblock = br->getSuccessor(0);
}
prev_symbols = symbols;
// if (VERBOSITY()) {
// printf("jumped to %s\n", curblock->getName().data());
//}
......
......@@ -881,7 +881,7 @@ AST_Module* parse(const char* fn) {
#define MAGIC_STRING "a\nch"
#define MAGIC_STRING_LENGTH 4
#define LENGTH_SUFFIX_LENGTH 4
#define CHECKSUM_LENGTH 4
static void _reparse(const char* fn, const std::string& cache_fn) {
FILE* parser = popen(getParserCommandLine(fn).c_str(), "r");
......@@ -890,7 +890,14 @@ static void _reparse(const char* fn, const std::string& cache_fn) {
fwrite(MAGIC_STRING, 1, MAGIC_STRING_LENGTH, cache_fp);
int bytes_written = 0;
int checksum_start = ftell(cache_fp);
int bytes_written = -1;
// Currently just use the length as the checksum
static_assert(sizeof(bytes_written) >= CHECKSUM_LENGTH, "");
fwrite(&bytes_written, 1, CHECKSUM_LENGTH, cache_fp);
bytes_written = 0;
char buf[80];
while (true) {
int nread = fread(buf, 1, 80, parser);
......@@ -900,13 +907,12 @@ static void _reparse(const char* fn, const std::string& cache_fn) {
fwrite(buf, 1, nread, cache_fp);
}
// Ideally this should be a full checksum rather than just a length.
// And maybe it should be put at the beginning?
static_assert(sizeof(bytes_written) >= LENGTH_SUFFIX_LENGTH, "");
fwrite(&bytes_written, 1, LENGTH_SUFFIX_LENGTH, cache_fp);
int code = pclose(parser);
assert(code == 0);
fseek(cache_fp, checksum_start, SEEK_SET);
fwrite(&bytes_written, 1, CHECKSUM_LENGTH, cache_fp);
fclose(cache_fp);
}
......@@ -940,20 +946,25 @@ AST_Module* caching_parse(const char* fn) {
char buf[MAGIC_STRING_LENGTH];
int read = fread(buf, 1, MAGIC_STRING_LENGTH, fp);
if (read != MAGIC_STRING_LENGTH || strncmp(buf, MAGIC_STRING, MAGIC_STRING_LENGTH) != 0) {
if (VERBOSITY()) {
printf("Warning: corrupt or non-Pyston .pyc file found; ignoring\n");
}
good = false;
}
}
if (good) {
int length = 0;
fseek(fp, -LENGTH_SUFFIX_LENGTH, SEEK_END);
static_assert(sizeof(length) >= LENGTH_SUFFIX_LENGTH, "");
int read = fread(&length, 1, LENGTH_SUFFIX_LENGTH, fp);
fseek(fp, MAGIC_STRING_LENGTH, SEEK_SET);
static_assert(sizeof(length) >= CHECKSUM_LENGTH, "");
int read = fread(&length, 1, CHECKSUM_LENGTH, fp);
int expected_length = MAGIC_STRING_LENGTH + LENGTH_SUFFIX_LENGTH + length;
int expected_total_length = MAGIC_STRING_LENGTH + CHECKSUM_LENGTH + length;
if (read != LENGTH_SUFFIX_LENGTH || expected_length != cache_stat.st_size) {
if (read != CHECKSUM_LENGTH || expected_total_length != cache_stat.st_size) {
if (VERBOSITY()) {
printf("Warning: truncated .pyc file found; ignoring\n");
}
good = false;
}
}
......@@ -974,7 +985,7 @@ AST_Module* caching_parse(const char* fn) {
BufferedReader* reader = new BufferedReader(fp);
AST* rtn = readASTMisc(reader);
reader->fill();
assert(reader->bytesBuffered() == LENGTH_SUFFIX_LENGTH);
assert(reader->bytesBuffered() == 0);
delete reader;
assert(rtn->type == AST_TYPE::Module);
......
......@@ -42,8 +42,6 @@
extern "C" void* __cxa_begin_catch(void*);
extern "C" void __cxa_end_catch();
extern "C" void* __cxa_allocate_exception(size_t);
extern "C" void __cxa_throw(void*, void*, void (*)(void*));
namespace pyston {
......@@ -135,9 +133,11 @@ void initGlobalFuncs(GlobalState& g) {
g.llvm_str_type_ptr = lookupFunction("boxStringPtr")->arg_begin()->getType();
auto vector_type = g.stdlib_module->getTypeByName("class.std::vector");
assert(vector_type);
g.vector_ptr = vector_type->getPointerTo();
// The LLVM vector type for the arguments that we pass to runtimeCall and related functions.
// It will be a pointer to a type named something like class.std::vector or
// class.std::vector.##. We can figure out exactly what it is by looking at the last
// argument of runtimeCall.
g.vector_ptr = (--lookupFunction("runtimeCall")->getArgumentList().end())->getType();
g.llvm_closure_type_ptr = g.stdlib_module->getTypeByName("class.pyston::BoxedClosure")->getPointerTo();
assert(g.llvm_closure_type_ptr);
......@@ -187,6 +187,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(getclsattr);
GET(unaryop);
GET(import);
GET(importFrom);
GET(repr);
GET(isinstance);
GET(yield);
......@@ -225,8 +226,8 @@ void initGlobalFuncs(GlobalState& g) {
GET(__cxa_begin_catch);
g.funcs.__cxa_end_catch = addFunc((void*)__cxa_end_catch, g.void_);
g.funcs.__cxa_allocate_exception = addFunc((void*)__cxa_allocate_exception, g.i8_ptr, g.i64);
g.funcs.__cxa_throw = addFunc((void*)__cxa_throw, g.void_, g.i8_ptr, g.i8_ptr, g.i8_ptr);
GET(raise0);
GET(raise1);
g.funcs.div_i64_i64 = getFunc((void*)div_i64_i64, "div_i64_i64");
g.funcs.mod_i64_i64 = getFunc((void*)mod_i64_i64, "mod_i64_i64");
......
......@@ -34,7 +34,7 @@ struct GlobalFuncs {
*boxInstanceMethod, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice,
*createUserClass, *createClosure, *createGenerator, *insideGenerator;
llvm::Value* getattr, *setattr, *print, *nonzero, *binop, *compare, *augbinop, *unboxedLen, *getitem, *getclsattr,
*yield, *getGlobal, *setitem, *delitem, *unaryop, *import, *repr, *isinstance;
*getGlobal, *setitem, *delitem, *unaryop, *import, *importFrom, *repr, *isinstance, *yield;
llvm::Value* checkUnpackingLength, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError,
*assertNameDefined, *assertFail;
......@@ -43,7 +43,8 @@ struct GlobalFuncs {
llvm::Value* callattr0, *callattr1, *callattr2, *callattr3, *callattr;
llvm::Value* reoptCompiledFunc, *compilePartialFunc;
llvm::Value* __cxa_begin_catch, *__cxa_end_catch, *__cxa_allocate_exception, *__cxa_throw;
llvm::Value* __cxa_begin_catch, *__cxa_end_catch;
llvm::Value* raise0, *raise1;
llvm::Value* div_i64_i64, *mod_i64_i64, *pow_i64_i64;
llvm::Value* div_float_float, *mod_float_float, *pow_float_float;
......
......@@ -1314,6 +1314,9 @@ bool PrintVisitor::visit_langprimitive(AST_LangPrimitive* node) {
case AST_LangPrimitive::LANDINGPAD:
printf("landingpad");
break;
case AST_LangPrimitive::LOCALS:
printf("locals");
break;
default:
RELEASE_ASSERT(0, "%d", node->opcode);
}
......
......@@ -879,6 +879,7 @@ public:
enum Opcodes {
ISINSTANCE,
LANDINGPAD,
LOCALS,
} opcode;
std::vector<AST_expr*> args;
......
......@@ -379,6 +379,8 @@ private:
AST_expr* remapAttribute(AST_Attribute* node) {
AST_Attribute* rtn = new AST_Attribute();
rtn->col_offset = node->col_offset;
rtn->lineno = node->lineno;
rtn->ctx_type = node->ctx_type;
rtn->attr = node->attr;
rtn->value = remapExpr(node->value);
......@@ -483,6 +485,8 @@ private:
AST_expr* remapClsAttribute(AST_ClsAttribute* node) {
AST_ClsAttribute* rtn = new AST_ClsAttribute();
rtn->col_offset = node->col_offset;
rtn->lineno = node->lineno;
rtn->attr = node->attr;
rtn->value = remapExpr(node->value);
return rtn;
......@@ -622,28 +626,20 @@ private:
}
AST_expr* remapLambda(AST_Lambda* node) {
if (node->args->defaults.empty()) {
return node;
}
// Remap in place: see note in visit_functiondef for why.
AST_Lambda* rtn = new AST_Lambda();
rtn->lineno = node->lineno;
rtn->col_offset = node->col_offset;
rtn->args = new AST_arguments();
rtn->args->args = node->args->args;
rtn->args->vararg = node->args->vararg;
rtn->args->kwarg = node->args->kwarg;
for (auto d : node->args->defaults) {
rtn->args->defaults.push_back(remapExpr(d));
for (int i = 0; i < node->args->defaults.size(); i++) {
node->args->defaults[i] = remapExpr(node->args->defaults[i]);
}
rtn->body = node->body;
return rtn;
return node;
}
AST_expr* remapLangPrimitive(AST_LangPrimitive* node) {
AST_LangPrimitive* rtn = new AST_LangPrimitive(node->opcode);
rtn->col_offset = node->col_offset;
rtn->lineno = node->lineno;
for (AST_expr* arg : node->args) {
rtn->args.push_back(remapExpr(arg));
}
......@@ -859,6 +855,8 @@ public:
AST_Invoke* invoke = new AST_Invoke(node);
invoke->normal_dest = normal_dest;
invoke->exc_dest = exc_dest;
invoke->col_offset = node->col_offset;
invoke->lineno = node->lineno;
curblock->push_back(invoke);
curblock->connectTo(normal_dest);
......@@ -878,36 +876,42 @@ public:
}
virtual bool visit_classdef(AST_ClassDef* node) {
// Remap in place: see note in visit_functiondef for why.
// Decorators are evaluated before the defaults:
for (int i = 0; i < node->decorator_list.size(); i++) {
node->decorator_list[i] = remapExpr(node->decorator_list[i]);
}
for (int i = 0; i < node->bases.size(); i++) {
node->bases[i] = remapExpr(node->bases[i]);
}
push_back(node);
return true;
}
virtual bool visit_functiondef(AST_FunctionDef* node) {
if (node->args->defaults.size() == 0 && node->decorator_list.size() == 0) {
push_back(node);
} else {
AST_FunctionDef* remapped = new AST_FunctionDef();
// As much as I don't like it, for now we're remapping these in place.
// This is because we do certain analyses pre-remapping, and associate the
// results with the node. We can either do some refactoring and have a way
// of associating the new node with the same results, or just do the remapping
// in-place.
// Doing it in-place seems ugly, but I can't think of anything it should break,
// so just do that for now.
// TODO If we remap these (functiondefs, lambdas, classdefs) in place, we should probably
// remap everything in place?
remapped->name = node->name;
remapped->lineno = node->lineno;
remapped->col_offset = node->col_offset;
remapped->args = new AST_arguments();
remapped->body = node->body; // hmm shouldnt have to copy this
// Decorators are evaluated before the defaults:
for (auto d : node->decorator_list) {
remapped->decorator_list.push_back(remapExpr(d));
}
remapped->args->args = node->args->args;
remapped->args->vararg = node->args->vararg;
remapped->args->kwarg = node->args->kwarg;
for (auto d : node->args->defaults) {
remapped->args->defaults.push_back(remapExpr(d));
}
// Decorators are evaluated before the defaults:
for (int i = 0; i < node->decorator_list.size(); i++) {
node->decorator_list[i] = remapExpr(node->decorator_list[i]);
}
push_back(remapped);
for (int i = 0; i < node->args->defaults.size(); i++) {
node->args->defaults[i] = remapExpr(node->args->defaults[i]);
}
push_back(node);
return true;
}
......@@ -1027,11 +1031,15 @@ public:
s_target->value = remapExpr(s->value);
s_target->slice = remapExpr(s->slice);
s_target->ctx_type = AST_TYPE::Store;
s_target->col_offset = s->col_offset;
s_target->lineno = s->lineno;
remapped_target = s_target;
AST_Subscript* s_lhs = new AST_Subscript();
s_lhs->value = s_target->value;
s_lhs->slice = s_target->slice;
s_lhs->col_offset = s->col_offset;
s_lhs->lineno = s->lineno;
s_lhs->ctx_type = AST_TYPE::Load;
remapped_lhs = remapExpr(s_lhs);
......@@ -1045,12 +1053,16 @@ public:
a_target->value = remapExpr(a->value);
a_target->attr = a->attr;
a_target->ctx_type = AST_TYPE::Store;
a_target->col_offset = a->col_offset;
a_target->lineno = a->lineno;
remapped_target = a_target;
AST_Attribute* a_lhs = new AST_Attribute();
a_lhs->value = a_target->value;
a_lhs->attr = a->attr;
a_lhs->ctx_type = AST_TYPE::Load;
a_lhs->col_offset = a->col_offset;
a_lhs->lineno = a->lineno;
remapped_lhs = remapExpr(a_lhs);
break;
......@@ -1063,6 +1075,8 @@ public:
binop->op_type = node->op_type;
binop->left = remapped_lhs;
binop->right = remapExpr(node->value);
binop->col_offset = node->col_offset;
binop->lineno = node->lineno;
AST_stmt* assign = makeAssign(remapped_target, binop);
push_back(assign);
return true;
......@@ -1109,6 +1123,7 @@ public:
int i = 0;
for (auto v : node->values) {
AST_Print* remapped = new AST_Print();
remapped->col_offset = node->col_offset;
remapped->lineno = node->lineno;
// TODO not good to reuse 'dest' like this
remapped->dest = dest;
......@@ -1128,6 +1143,8 @@ public:
assert(node->nl);
AST_Print* final = new AST_Print();
final->col_offset = node->col_offset;
final->lineno = node->lineno;
// TODO not good to reuse 'dest' like this
final->dest = dest;
final->nl = node->nl;
......@@ -1417,6 +1434,9 @@ public:
bool visit_raise(AST_Raise* node) override {
AST_Raise* remapped = new AST_Raise();
remapped->col_offset = node->col_offset;
remapped->lineno = node->lineno;
if (node->arg0)
remapped->arg0 = remapExpr(node->arg0);
if (node->arg1)
......@@ -1425,6 +1445,9 @@ public:
remapped->arg2 = remapExpr(node->arg2);
push_back(remapped);
if (!curblock)
return true;
curblock->push_back(new AST_Unreachable());
curblock = NULL;
......@@ -1518,7 +1541,6 @@ public:
if (!caught_all) {
AST_Raise* raise = new AST_Raise();
raise->arg0 = exc_obj;
push_back(raise);
curblock->push_back(new AST_Unreachable());
curblock = NULL;
......@@ -1709,20 +1731,10 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
if (source->ast->type == AST_TYPE::ClassDef) {
ScopeInfo* scope_info = source->scoping->getScopeInfoForNode(source->ast);
auto written_names = scope_info->getClassDefLocalNames();
AST_Dict* rtn_dict = new AST_Dict();
// Even if the user never explicitly wrote to __module__, there was an
// implicit write:
assert(written_names.count("__module__"));
for (auto s : written_names) {
rtn_dict->keys.push_back(new AST_Str(s));
rtn_dict->values.push_back(makeName(s, AST_TYPE::Load));
}
AST_LangPrimitive* locals = new AST_LangPrimitive(AST_LangPrimitive::LOCALS);
AST_Return* rtn = new AST_Return();
rtn->value = rtn_dict;
rtn->value = locals;
visitor.push_back(rtn);
} else {
// Put a fake "return" statement at the end of every function just to make sure they all have one;
......
......@@ -42,6 +42,18 @@ void registerStaticRootObj(void* obj) {
roots.push(obj);
}
static std::unordered_set<StaticRootHandle*>* getRootHandles() {
static std::unordered_set<StaticRootHandle*> root_handles;
return &root_handles;
}
StaticRootHandle::StaticRootHandle() {
getRootHandles()->insert(this);
}
StaticRootHandle::~StaticRootHandle() {
getRootHandles()->erase(this);
}
bool TraceStackGCVisitor::isValid(void* p) {
return global_heap.getAllocationFromInteriorPointer(p);
}
......@@ -105,6 +117,10 @@ static void markPhase() {
TraceStackGCVisitor visitor(&stack);
for (auto h : *getRootHandles()) {
visitor.visitPotential(h->value);
}
// if (VERBOSITY()) printf("Found %d roots\n", stack.size());
while (void* p = stack.pop()) {
assert(((intptr_t)p) % 8 == 0);
......
......@@ -83,6 +83,19 @@ public:
// (that should be registerStaticRootPtr)
void registerStaticRootObj(void* root_obj);
void runCollection();
// If you want to have a static root "location" where multiple values could be stored, use this:
class StaticRootHandle {
public:
Box* value;
StaticRootHandle();
~StaticRootHandle();
void operator=(Box* b) { value = b; }
operator Box*() { return value; }
};
}
}
......
// Copyright (c) 2014 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cmath>
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/types.h"
#include "runtime/util.h"
namespace pyston {
BoxedModule* errno_module;
void setupErrno() {
errno_module = createModule("errno", "__builtin__");
}
}
// Copyright (c) 2014 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cmath>
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/types.h"
#include "runtime/util.h"
namespace pyston {
BoxedModule* posix_module;
void setupPosix() {
posix_module = createModule("posix", "__builtin__");
}
}
......@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <algorithm>
#include <cmath>
#include "core/types.h"
......@@ -87,4 +88,16 @@ void setupSys() {
sys_module->giveAttr("stdin", new BoxedFile(stdin));
sys_module->giveAttr("stderr", new BoxedFile(stderr));
}
void setupSysEnd() {
BoxedTuple::GCVector builtin_module_names;
for (auto& p : sys_modules_dict->d) {
builtin_module_names.push_back(p.first);
}
std::sort<decltype(builtin_module_names)::iterator, PyLt>(builtin_module_names.begin(), builtin_module_names.end(),
PyLt());
sys_module->giveAttr("builtin_module_names", new BoxedTuple(std::move(builtin_module_names)));
}
}
......@@ -76,6 +76,7 @@ void force() {
FORCE(delitem);
FORCE(unaryop);
FORCE(import);
FORCE(importFrom);
FORCE(repr);
FORCE(isinstance);
FORCE(yield);
......@@ -93,6 +94,9 @@ void force() {
FORCE(runtimeCall);
FORCE(callattr);
FORCE(raise0);
FORCE(raise1);
FORCE(div_i64_i64);
FORCE(mod_i64_i64);
FORCE(pow_i64_i64);
......
......@@ -545,6 +545,7 @@ void setupList() {
list_cls->giveAttr("pop", new BoxedFunction(boxRTFunction((void*)listPop, UNKNOWN, 2, 1, false, false), { None }));
list_cls->giveAttr("append", new BoxedFunction(boxRTFunction((void*)listAppend, NONE, 2)));
list_cls->giveAttr("extend", new BoxedFunction(boxRTFunction((void*)listIAdd, NONE, 2)));
CLFunction* setitem = createRTFunction(3, 0, false, false);
addRTFunction(setitem, (void*)listSetitemInt, NONE, std::vector<ConcreteCompilerType*>{ LIST, BOXED_INT, UNKNOWN });
......
......@@ -1772,7 +1772,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
rewrite_args->rewriter->loadConst(0, (intptr_t)closure);
if (func->isGenerator)
rewrite_args->rewriter->loadConst(0, (intptr_t)0 /*generator*/);
rewrite_args->rewriter->loadConst(0, (intptr_t)func->isGenerator);
// We might have trouble if we have more output args than input args,
// such as if we need more space to pass defaults.
......@@ -1963,7 +1963,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
return createGenerator(func, oarg1, oarg2, oarg3, oargs);
}
return callCLFunc(f, rewrite_args, num_output_args, closure, NULL, oarg1, oarg2, oarg3, oargs);
return callCLFunc(f, rewrite_args, num_output_args, closure, (BoxedGenerator*)func->isGenerator, oarg1, oarg2, oarg3, oargs);
}
Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_args, BoxedClosure* closure,
......@@ -2981,4 +2981,16 @@ extern "C" Box* import(const std::string* name) {
raiseExcHelper(ImportError, "No module named %s", name->c_str());
}
extern "C" Box* importFrom(Box* _m, const std::string* name) {
assert(_m->cls == module_cls);
BoxedModule* m = static_cast<BoxedModule*>(_m);
Box* r = m->getattr(*name, NULL, NULL);
if (r)
return r;
raiseExcHelper(ImportError, "cannot import name %s", name->c_str());
}
}
......@@ -29,7 +29,14 @@ class BoxedList;
class BoxedString;
class BoxedGenerator;
void raiseExc(Box*) __attribute__((__noreturn__));
// user-level raise functions that implement python-level semantics
extern "C" void raise0() __attribute__((__noreturn__));
extern "C" void raise1(Box*) __attribute__((__noreturn__));
extern "C" void raise2(Box*, Box*) __attribute__((__noreturn__));
extern "C" void raise3(Box*, Box*, Box*) __attribute__((__noreturn__));
void raiseExc(Box* exc_obj) __attribute__((__noreturn__));
// helper function for raising from the runtime:
void raiseExcHelper(BoxedClass*, const char* fmt, ...) __attribute__((__noreturn__));
extern "C" const std::string* getTypeName(Box* o);
......@@ -37,6 +44,7 @@ extern "C" const std::string* getNameOfClass(BoxedClass* cls);
// TODO sort this
extern "C" void my_assert(bool b);
extern "C" Box* importFrom(Box* obj, const std::string* attr);
extern "C" Box* getattr(Box* obj, const char* attr);
extern "C" void setattr(Box* obj, const char* attr, Box* attr_val);
extern "C" bool nonzero(Box* obj);
......
......@@ -20,6 +20,7 @@
#include "codegen/codegen.h"
#include "codegen/llvm_interpreter.h"
#include "core/options.h"
#include "gc/collector.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -99,17 +100,27 @@ void unwindExc(Box* exc_obj) {
abort();
}
void raiseExc(Box* exc_obj) {
static std::vector<const LineInfo*> getTracebackEntries();
static gc::StaticRootHandle last_exc;
static std::vector<const LineInfo*> last_tb;
void raiseRaw(Box* exc_obj) __attribute__((__noreturn__));
void raiseRaw(Box* exc_obj) {
// Using libgcc:
throw exc_obj;
// Using libunwind
// unwindExc(exc_obj);
}
abort();
void raiseExc(Box* exc_obj) {
auto entries = getTracebackEntries();
last_tb = std::move(entries);
last_exc = exc_obj;
raiseRaw(exc_obj);
}
static std::vector<const LineInfo*> last_tb;
void printLastTraceback() {
fprintf(stderr, "Traceback (most recent call last):\n");
......@@ -183,10 +194,28 @@ static std::vector<const LineInfo*> getTracebackEntries() {
return entries;
}
void raiseExcHelper(BoxedClass* cls, const char* msg, ...) {
auto entries = getTracebackEntries();
last_tb = std::move(entries);
void raise0() {
raiseRaw(last_exc);
}
void raise1(Box* b) {
if (b->cls == type_cls) {
BoxedClass* c = static_cast<BoxedClass*>(b);
if (isSubclass(c, Exception)) {
auto exc_obj = exceptionNew1(c);
raiseExc(exc_obj);
} else {
raiseExcHelper(TypeError, "exceptions must be old-style classes or derived from BaseException, not %s",
getTypeName(b)->c_str());
}
}
// TODO: should only allow throwing of old-style classes or things derived
// from BaseException:
raiseExc(b);
}
void raiseExcHelper(BoxedClass* cls, const char* msg, ...) {
if (msg != NULL) {
va_list ap;
va_start(ap, msg);
......@@ -223,6 +252,8 @@ std::string formatException(Box* b) {
assert(r->cls == str_cls);
const std::string* msg = &r->s;
return *name + ": " + *msg;
if (msg->size())
return *name + ": " + *msg;
return *name;
}
}
......@@ -191,6 +191,46 @@ extern "C" BoxedString* strMul(BoxedString* lhs, BoxedInt* rhs) {
return new BoxedString(buf);
}
extern "C" Box* strLt(BoxedString* lhs, Box* rhs) {
assert(lhs->cls == str_cls);
if (rhs->cls != str_cls)
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s < srhs->s);
}
extern "C" Box* strLe(BoxedString* lhs, Box* rhs) {
assert(lhs->cls == str_cls);
if (rhs->cls != str_cls)
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s <= srhs->s);
}
extern "C" Box* strGt(BoxedString* lhs, Box* rhs) {
assert(lhs->cls == str_cls);
if (rhs->cls != str_cls)
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s > srhs->s);
}
extern "C" Box* strGe(BoxedString* lhs, Box* rhs) {
assert(lhs->cls == str_cls);
if (rhs->cls != str_cls)
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s >= srhs->s);
}
extern "C" Box* strEq(BoxedString* lhs, Box* rhs) {
assert(lhs->cls == str_cls);
......@@ -201,6 +241,16 @@ extern "C" Box* strEq(BoxedString* lhs, Box* rhs) {
return boxBool(lhs->s == srhs->s);
}
extern "C" Box* strNe(BoxedString* lhs, Box* rhs) {
assert(lhs->cls == str_cls);
if (rhs->cls != str_cls)
return boxBool(true);
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s != srhs->s);
}
extern "C" Box* strLen(BoxedString* self) {
assert(self->cls == str_cls);
......@@ -572,7 +622,14 @@ void setupStr() {
str_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)strAdd, UNKNOWN, 2)));
str_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)strMod, STR, 2)));
str_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2)));
str_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)strLt, UNKNOWN, 2)));
str_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)strLe, UNKNOWN, 2)));
str_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)strGt, UNKNOWN, 2)));
str_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)strGe, UNKNOWN, 2)));
str_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)strEq, UNKNOWN, 2)));
str_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)strNe, UNKNOWN, 2)));
str_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)strGetitem, STR, 2)));
str_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)strIter, typeFromClass(str_iterator_cls), 1)));
......
......@@ -652,9 +652,13 @@ void setupRuntime() {
setupMath();
setupTime();
setupThread();
setupErrno();
setupPosix();
setupCAPI();
setupSysEnd();
TRACK_ALLOCATIONS = true;
}
......
......@@ -61,6 +61,9 @@ void setupBuiltins();
void setupMath();
void setupTime();
void setupThread();
void setupErrno();
void setupPosix();
void setupSysEnd();
BoxedDict* getSysModulesDict();
BoxedList* getSysPath();
......
# expected: fail
# - WIP
X = 0
Y = 0
Z = 0
......@@ -37,10 +34,10 @@ def wrapper():
# The defaults for a and b should resolve to the classdef definitions, and the default
# for c should resolve to the wrapper() definition
def f(self, a=X, b=Y, c=Z, d=W):
print a, b, c, W # "2 2 0 1"
print a, b, c, d # "2 2 0 1"
# These references should skip all of the classdef directives,
# and hit the definitions in the wrapper() function
print X, Y # "1 1"
print X, Y, Z, W # "1 1 1 1"
print "done with classdef"
print hasattr(C, 'X')
......
# expected: fail
# - decorators
def f(o, msg):
print msg
return o
@f(lambda c: f(c, "calling decorator"), "evaluating decorator object")
class C(f(object, "evaluating base")):
print "in classdef"
x3 = 0
def bad_addr3(_x):
if 0:
x3 = _
def g(y3):
return x3 + y3
return g
print bad_addr3(1)(2)
......@@ -43,11 +43,29 @@ def make_addr3(x3):
return g
print make_addr3(10)(2)
def bad_addr3(_x):
if 0:
x3 = _
def f4(args):
def inner():
for a in args:
print a
return inner
print f4([1, 2, 3])()
def g(y3):
return x3 + y3
return g
print bad_addr3(1)(2)
def f5():
x = 12039
def i1():
def i2():
print x
i2()
i1()
f5()
def f6():
x = 131
# Regression test:
# default args shouldn't mess with closure analysis
def inner(a=1):
print x
inner()
print (lambda a=1: x)()
f6()
# expected: fail
# - deletes on names
x = 1
def f():
if 0:
# the del marks 'x' as a name written to in this scope
del x
print x
f()
......@@ -15,3 +15,12 @@ del a[:]
print a
a.append(1)
print a
# Make sure that del's work correctly in sub-scopes:
x = 1
def f1():
x = range(5)
def f2():
del x[1]
return f2
f1()()
try:
import non_existent_module
assert 0, "shouldn't get here"
except ImportError:
pass
try:
from non_existent_module import a
assert 0, "shouldn't get here"
except ImportError:
pass
try:
from sys import non_existent_attribute
assert 0, "shouldn't get here"
except ImportError:
pass
......@@ -67,3 +67,7 @@ for i in xrange(100):
l.append(i)
while l:
del l[0]
l = range(5)
l.extend(range(5))
print l
......@@ -39,3 +39,17 @@ for c in "hello world":
for i in xrange(1, 10):
for j in xrange(1, 4):
print ("a"*i).count("a"*j)
def test_comparisons(a, b):
print "%s < %s = " % (a, b), a < b
print "%s <= %s = " % (a, b), a <= b
print "%s > %s = " % (a, b), a > b
print "%s >= %s = " % (a, b), a >= b
print "%s == %s = " % (a, b), a == b
print "%s != %s = " % (a, b), a != b
test_comparisons("a", "a")
test_comparisons("a", "A")
test_comparisons("a", "aa")
test_comparisons("ab", "aa")
print sorted([str(i) for i in xrange(25)])
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