Commit 9a33763c authored by Kevin Modzelewski's avatar Kevin Modzelewski

Some initial refactoring work for arg passing

Replace a simple "num_args" argument with a packed struct that takes
num_args and adds num_keywords, has_varargs, and has_kwargs.  Tried
to add asserts in all the places that don't allow
keywords/varargs/starargs

Started refactoring things; got to the point of attempting
argument->parameter shuffling, but it's tricky if we allow every
compilation to have a different signature (used by builtins).
Really they all have the same signatures but different
specializations; to get to that point, need to add defaults.
parent a8c83341
...@@ -273,7 +273,7 @@ pyston_all: pyston_dbg pyston pyston_oprof pyston_prof $(OPTIONAL_SRCS:.cpp=.o) ...@@ -273,7 +273,7 @@ pyston_all: pyston_dbg pyston pyston_oprof pyston_prof $(OPTIONAL_SRCS:.cpp=.o)
ALL_HEADERS := $(wildcard */*.h) $(wildcard */*/*.h) ALL_HEADERS := $(wildcard */*.h) $(wildcard */*/*.h)
tags: $(SRCS) $(OPTIONAL_SRCS) $(ALL_HEADERS) tags: $(SRCS) $(OPTIONAL_SRCS) $(ALL_HEADERS)
$(ECHO) Computing tags... $(ECHO) Calculating tags...
$(VERB) ctags $^ $(VERB) ctags $^
$(UNITTEST_SRCS:.cpp=.o): CXXFLAGS := $(CXXFLAGS) -isystem $(GTEST_DIR)/include $(UNITTEST_SRCS:.cpp=.o): CXXFLAGS := $(CXXFLAGS) -isystem $(GTEST_DIR)/include
......
...@@ -210,7 +210,7 @@ private: ...@@ -210,7 +210,7 @@ private:
std::vector<CompilerType*> arg_types; std::vector<CompilerType*> arg_types;
arg_types.push_back(right); arg_types.push_back(right);
CompilerType* rtn = attr_type->callType(arg_types); CompilerType* rtn = attr_type->callType(ArgPassSpec(2), arg_types, NULL);
if (left == right && (left == INT || left == FLOAT)) { if (left == right && (left == INT || left == FLOAT)) {
ASSERT((rtn == left || rtn == UNKNOWN) && "not strictly required but probably something worth looking into", ASSERT((rtn == left || rtn == UNKNOWN) && "not strictly required but probably something worth looking into",
...@@ -237,7 +237,7 @@ private: ...@@ -237,7 +237,7 @@ private:
std::vector<CompilerType*> arg_types; std::vector<CompilerType*> arg_types;
arg_types.push_back(right); arg_types.push_back(right);
CompilerType* rtn = attr_type->callType(arg_types); CompilerType* rtn = attr_type->callType(ArgPassSpec(2), arg_types, NULL);
if (left == right && (left == INT || left == FLOAT)) { if (left == right && (left == INT || left == FLOAT)) {
ASSERT((rtn == left || rtn == UNKNOWN) && "not strictly required but probably something worth looking into", ASSERT((rtn == left || rtn == UNKNOWN) && "not strictly required but probably something worth looking into",
...@@ -287,7 +287,7 @@ private: ...@@ -287,7 +287,7 @@ private:
return UNKNOWN; return UNKNOWN;
} }
CompilerType* rtn_type = func->callType(arg_types); CompilerType* rtn_type = func->callType(ArgPassSpec(arg_types.size()), arg_types, NULL);
// Should be unboxing things before getting here: // Should be unboxing things before getting here:
ASSERT(rtn_type == unboxedType(rtn_type->getConcreteType()), "%s", rtn_type->debugName().c_str()); ASSERT(rtn_type == unboxedType(rtn_type->getConcreteType()), "%s", rtn_type->debugName().c_str());
...@@ -322,7 +322,7 @@ private: ...@@ -322,7 +322,7 @@ private:
std::vector<CompilerType*> arg_types; std::vector<CompilerType*> arg_types;
arg_types.push_back(right); arg_types.push_back(right);
return attr_type->callType(arg_types); return attr_type->callType(ArgPassSpec(2), arg_types, NULL);
} }
virtual void* visit_dict(AST_Dict* node) { virtual void* visit_dict(AST_Dict* node) {
...@@ -404,7 +404,7 @@ private: ...@@ -404,7 +404,7 @@ private:
CompilerType* getitem_type = val->getattrType(&name, true); CompilerType* getitem_type = val->getattrType(&name, true);
std::vector<CompilerType*> args; std::vector<CompilerType*> args;
args.push_back(slice); args.push_back(slice);
return getitem_type->callType(args); return getitem_type->callType(ArgPassSpec(1), args, NULL);
} }
virtual void* visit_tuple(AST_Tuple* node) { virtual void* visit_tuple(AST_Tuple* node) {
...@@ -422,7 +422,7 @@ private: ...@@ -422,7 +422,7 @@ private:
const std::string& name = getOpName(node->op_type); const std::string& name = getOpName(node->op_type);
CompilerType* attr_type = operand->getattrType(&name, true); CompilerType* attr_type = operand->getattrType(&name, true);
std::vector<CompilerType*> arg_types; std::vector<CompilerType*> arg_types;
return attr_type->callType(arg_types); return attr_type->callType(ArgPassSpec(0), arg_types, NULL);
} }
......
...@@ -72,6 +72,7 @@ struct GlobalState { ...@@ -72,6 +72,7 @@ struct GlobalState {
llvm::Type* llvm_clfunction_type_ptr; llvm::Type* llvm_clfunction_type_ptr;
llvm::Type* llvm_module_type_ptr, *llvm_bool_type_ptr; llvm::Type* llvm_module_type_ptr, *llvm_bool_type_ptr;
llvm::Type* i1, *i8, *i8_ptr, *i32, *i64, *void_, *double_; llvm::Type* i1, *i8, *i8_ptr, *i32, *i64, *void_, *double_;
llvm::Type* vector_ptr;
GlobalFuncs funcs; GlobalFuncs funcs;
......
...@@ -79,15 +79,19 @@ public: ...@@ -79,15 +79,19 @@ public:
return rtn; return rtn;
} }
virtual CompilerType* callType(std::vector<CompilerType*>& arg_types) { virtual CompilerType* callType(ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types,
const std::vector<const std::string*>* keyword_names) {
std::vector<CompilerType*> new_args(arg_types); std::vector<CompilerType*> new_args(arg_types);
new_args.insert(new_args.begin(), obj_type); new_args.insert(new_args.begin(), obj_type);
return function_type->callType(new_args);
ArgPassSpec new_argspec(argspec.num_args + 1u, argspec.num_keywords, argspec.has_starargs, argspec.has_kwargs);
return function_type->callType(new_argspec, new_args, keyword_names);
} }
std::string debugName() { std::string debugName() {
return "instanceMethod(" + obj_type->debugName() + " ; " + function_type->debugName() + ")"; return "instanceMethod(" + obj_type->debugName() + " ; " + function_type->debugName() + ")";
} }
virtual void drop(IREmitter& emitter, VAR* var) { virtual void drop(IREmitter& emitter, VAR* var) {
checkVar(var); checkVar(var);
RawInstanceMethod* val = var->getValue(); RawInstanceMethod* val = var->getValue();
...@@ -95,14 +99,19 @@ public: ...@@ -95,14 +99,19 @@ public:
val->func->decvref(emitter); val->func->decvref(emitter);
delete val; delete val;
} }
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info,
ValuedCompilerVariable<RawInstanceMethod*>* var, ValuedCompilerVariable<RawInstanceMethod*>* var, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args) { const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
std::vector<CompilerVariable*> new_args; std::vector<CompilerVariable*> new_args;
new_args.push_back(var->getValue()->obj); new_args.push_back(var->getValue()->obj);
new_args.insert(new_args.end(), args.begin(), args.end()); new_args.insert(new_args.end(), args.begin(), args.end());
return var->getValue()->func->call(emitter, info, new_args);
ArgPassSpec new_argspec(argspec.num_args + 1u, argspec.num_keywords, argspec.has_starargs, argspec.has_kwargs);
return var->getValue()->func->call(emitter, info, new_argspec, new_args, keyword_names);
} }
virtual bool canConvertTo(ConcreteCompilerType* other_type) { return other_type == UNKNOWN; } virtual bool canConvertTo(ConcreteCompilerType* other_type) { return other_type == UNKNOWN; }
virtual ConcreteCompilerType* getConcreteType() { return typeFromClass(instancemethod_cls); } virtual ConcreteCompilerType* getConcreteType() { return typeFromClass(instancemethod_cls); }
virtual ConcreteCompilerType* getBoxType() { return getConcreteType(); } virtual ConcreteCompilerType* getBoxType() { return getConcreteType(); }
...@@ -176,10 +185,12 @@ public: ...@@ -176,10 +185,12 @@ public:
virtual CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, virtual CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool cls_only); const std::string* attr, bool cls_only);
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::vector<CompilerVariable*>& args); ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names);
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool clsonly, const std::string* attr, bool clsonly, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args); const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names);
virtual ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var); virtual ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var);
void setattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, const std::string* attr, void setattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, const std::string* attr,
...@@ -218,7 +229,10 @@ public: ...@@ -218,7 +229,10 @@ public:
} }
virtual CompilerType* getattrType(const std::string* attr, bool cls_only) { return UNKNOWN; } virtual CompilerType* getattrType(const std::string* attr, bool cls_only) { return UNKNOWN; }
virtual CompilerType* callType(std::vector<CompilerType*>& arg_types) { return UNKNOWN; } virtual CompilerType* callType(ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types,
const std::vector<const std::string*>* keyword_names) {
return UNKNOWN;
}
virtual BoxedClass* guaranteedClass() { return NULL; } virtual BoxedClass* guaranteedClass() { return NULL; }
virtual ConcreteCompilerType* getBoxType() { return this; } virtual ConcreteCompilerType* getBoxType() { return this; }
virtual ConcreteCompilerVariable* makeConverted(IREmitter& emitter, ConcreteCompilerVariable* var, virtual ConcreteCompilerVariable* makeConverted(IREmitter& emitter, ConcreteCompilerVariable* var,
...@@ -312,8 +326,13 @@ CompilerVariable* UnknownType::getattr(IREmitter& emitter, const OpInfo& info, C ...@@ -312,8 +326,13 @@ CompilerVariable* UnknownType::getattr(IREmitter& emitter, const OpInfo& info, C
} }
static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, llvm::Value* func, void* func_addr, static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, llvm::Value* func, void* func_addr,
const std::vector<llvm::Value*> other_args, const std::vector<llvm::Value*> other_args, ArgPassSpec argspec,
const std::vector<CompilerVariable*> args, ConcreteCompilerType* rtn_type) { const std::vector<CompilerVariable*> args,
const std::vector<const std::string*>* keyword_names,
ConcreteCompilerType* rtn_type) {
bool pass_keyword_names = (keyword_names != nullptr);
assert(pass_keyword_names == (argspec.num_keywords > 0));
std::vector<BoxedClass*> guaranteed_classes; std::vector<BoxedClass*> guaranteed_classes;
std::vector<ConcreteCompilerVariable*> converted_args; std::vector<ConcreteCompilerVariable*> converted_args;
for (int i = 0; i < args.size(); i++) { for (int i = 0; i < args.size(); i++) {
...@@ -327,12 +346,20 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l ...@@ -327,12 +346,20 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l
if (args.size() >= 1) { if (args.size() >= 1) {
llvm_args.push_back(converted_args[0]->getValue()); llvm_args.push_back(converted_args[0]->getValue());
} else if (pass_keyword_names) {
llvm_args.push_back(embedConstantPtr(NULL, g.llvm_value_type_ptr));
} }
if (args.size() >= 2) { if (args.size() >= 2) {
llvm_args.push_back(converted_args[1]->getValue()); llvm_args.push_back(converted_args[1]->getValue());
} else if (pass_keyword_names) {
llvm_args.push_back(embedConstantPtr(NULL, g.llvm_value_type_ptr));
} }
if (args.size() >= 3) { if (args.size() >= 3) {
llvm_args.push_back(converted_args[2]->getValue()); llvm_args.push_back(converted_args[2]->getValue());
} else if (pass_keyword_names) {
llvm_args.push_back(embedConstantPtr(NULL, g.llvm_value_type_ptr));
} }
llvm::Value* mallocsave = NULL; llvm::Value* mallocsave = NULL;
...@@ -358,6 +385,11 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l ...@@ -358,6 +385,11 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l
emitter.getBuilder()->CreateStore(converted_args[i]->getValue(), ptr); emitter.getBuilder()->CreateStore(converted_args[i]->getValue(), ptr);
} }
llvm_args.push_back(arg_array); llvm_args.push_back(arg_array);
llvm_args.push_back(embedConstantPtr(keyword_names, g.vector_ptr));
} else if (pass_keyword_names) {
llvm_args.push_back(embedConstantPtr(NULL, g.llvm_value_type_ptr->getPointerTo()));
llvm_args.push_back(embedConstantPtr(keyword_names, g.vector_ptr));
} }
// f->dump(); // f->dump();
...@@ -368,6 +400,10 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l ...@@ -368,6 +400,10 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l
llvm::Value* rtn; llvm::Value* rtn;
// func->dump();
// for (auto a : llvm_args)
// a->dump();
bool do_patchpoint = ENABLE_ICCALLSITES && !info.isInterpreted() bool do_patchpoint = ENABLE_ICCALLSITES && !info.isInterpreted()
&& (func_addr == runtimeCall || func_addr == pyston::callattr); && (func_addr == runtimeCall || func_addr == pyston::callattr);
if (do_patchpoint) { if (do_patchpoint) {
...@@ -405,15 +441,21 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l ...@@ -405,15 +441,21 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l
} }
CompilerVariable* UnknownType::call(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, CompilerVariable* UnknownType::call(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::vector<CompilerVariable*>& args) { ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
bool pass_keywords = (argspec.num_keywords != 0);
int npassed_args = argspec.totalPassed();
llvm::Value* func; llvm::Value* func;
if (args.size() == 0) if (pass_keywords)
func = g.funcs.runtimeCall;
else if (npassed_args == 0)
func = g.funcs.runtimeCall0; func = g.funcs.runtimeCall0;
else if (args.size() == 1) else if (npassed_args == 1)
func = g.funcs.runtimeCall1; func = g.funcs.runtimeCall1;
else if (args.size() == 2) else if (npassed_args == 2)
func = g.funcs.runtimeCall2; func = g.funcs.runtimeCall2;
else if (args.size() == 3) else if (npassed_args == 3)
func = g.funcs.runtimeCall3; func = g.funcs.runtimeCall3;
else else
func = g.funcs.runtimeCall; func = g.funcs.runtimeCall;
...@@ -421,14 +463,19 @@ CompilerVariable* UnknownType::call(IREmitter& emitter, const OpInfo& info, Conc ...@@ -421,14 +463,19 @@ CompilerVariable* UnknownType::call(IREmitter& emitter, const OpInfo& info, Conc
std::vector<llvm::Value*> other_args; std::vector<llvm::Value*> other_args;
other_args.push_back(var->getValue()); other_args.push_back(var->getValue());
llvm::Value* nargs = llvm::ConstantInt::get(g.i64, args.size(), false); llvm::Value* llvm_argspec = llvm::ConstantInt::get(g.i32, argspec.asInt(), false);
other_args.push_back(nargs); other_args.push_back(llvm_argspec);
return _call(emitter, info, func, (void*)runtimeCall, other_args, args, UNKNOWN); return _call(emitter, info, func, (void*)runtimeCall, other_args, argspec, args, keyword_names, UNKNOWN);
} }
CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool clsonly, const std::string* attr, bool clsonly, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args) { const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
RELEASE_ASSERT(!argspec.has_starargs, "");
RELEASE_ASSERT(!argspec.has_kwargs, "");
RELEASE_ASSERT(argspec.num_keywords == 0, "");
llvm::Value* func; llvm::Value* func;
if (args.size() == 0) if (args.size() == 0)
func = g.funcs.callattr0; func = g.funcs.callattr0;
...@@ -446,9 +493,9 @@ CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info, ...@@ -446,9 +493,9 @@ CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info,
other_args.push_back(embedConstantPtr(attr, g.llvm_str_type_ptr)); other_args.push_back(embedConstantPtr(attr, g.llvm_str_type_ptr));
other_args.push_back(getConstantInt(clsonly, g.i1)); other_args.push_back(getConstantInt(clsonly, g.i1));
llvm::Value* nargs = llvm::ConstantInt::get(g.i64, args.size(), false); llvm::Value* llvm_argspec = llvm::ConstantInt::get(g.i32, argspec.asInt(), false);
other_args.push_back(nargs); other_args.push_back(llvm_argspec);
return _call(emitter, info, func, (void*)pyston::callattr, other_args, args, UNKNOWN); return _call(emitter, info, func, (void*)pyston::callattr, other_args, argspec, args, keyword_names, UNKNOWN);
} }
ConcreteCompilerVariable* UnknownType::nonzero(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) { ConcreteCompilerVariable* UnknownType::nonzero(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) {
...@@ -500,7 +547,12 @@ public: ...@@ -500,7 +547,12 @@ public:
virtual CompilerType* getattrType(const std::string* attr, bool cls_only) { return UNDEF; } virtual CompilerType* getattrType(const std::string* attr, bool cls_only) { return UNDEF; }
virtual CompilerType* callType(std::vector<CompilerType*>& arg_types) { virtual CompilerType* callType(ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types,
const std::vector<const std::string*>* keyword_names) {
RELEASE_ASSERT(!argspec.has_starargs, "");
RELEASE_ASSERT(!argspec.has_kwargs, "");
RELEASE_ASSERT(argspec.num_keywords == 0, "");
for (int i = 0; i < sigs.size(); i++) { for (int i = 0; i < sigs.size(); i++) {
Sig* sig = sigs[i]; Sig* sig = sigs[i];
if (sig->arg_types.size() != arg_types.size()) if (sig->arg_types.size() != arg_types.size())
...@@ -612,10 +664,11 @@ public: ...@@ -612,10 +664,11 @@ public:
} }
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool clsonly, const std::string* attr, bool clsonly, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args) { const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_INT); ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_INT);
CompilerVariable* rtn = converted->callattr(emitter, info, attr, clsonly, args); CompilerVariable* rtn = converted->callattr(emitter, info, attr, clsonly, argspec, args, keyword_names);
converted->decvref(emitter); converted->decvref(emitter);
return rtn; return rtn;
} }
...@@ -789,7 +842,12 @@ public: ...@@ -789,7 +842,12 @@ public:
return rtn; return rtn;
} }
virtual CompilerType* callType(std::vector<CompilerType*>& arg_types) { virtual CompilerType* callType(ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types,
const std::vector<const std::string*>* keyword_names) {
RELEASE_ASSERT(!argspec.has_starargs, "");
RELEASE_ASSERT(!argspec.has_kwargs, "");
RELEASE_ASSERT(argspec.num_keywords == 0, "");
bool is_well_defined = (cls == xrange_cls); bool is_well_defined = (cls == xrange_cls);
assert(is_well_defined); assert(is_well_defined);
return typeFromClass(cls); return typeFromClass(cls);
...@@ -856,7 +914,11 @@ public: ...@@ -856,7 +914,11 @@ public:
return UNKNOWN; return UNKNOWN;
} }
virtual CompilerType* callType(std::vector<CompilerType*>& arg_types) { return UNKNOWN; }
virtual CompilerType* callType(ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types,
const std::vector<const std::string*>* keyword_names) {
return UNKNOWN;
}
CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool cls_only) { const std::string* attr, bool cls_only) {
...@@ -917,16 +979,18 @@ public: ...@@ -917,16 +979,18 @@ public:
} }
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::vector<CompilerVariable*>& args) { ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN); ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
CompilerVariable* rtn = converted->call(emitter, info, args); CompilerVariable* rtn = converted->call(emitter, info, argspec, args, keyword_names);
converted->decvref(emitter); converted->decvref(emitter);
return rtn; return rtn;
} }
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool clsonly, const std::string* attr, bool clsonly, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args) { const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
if (cls->is_constant && !cls->instancesHaveAttrs() && cls->hasGenericGetattr()) { if (cls->is_constant && !cls->instancesHaveAttrs() && cls->hasGenericGetattr()) {
Box* rtattr = cls->getattr(*attr); Box* rtattr = cls->getattr(*attr);
if (rtattr == NULL) { if (rtattr == NULL) {
...@@ -938,6 +1002,12 @@ public: ...@@ -938,6 +1002,12 @@ public:
} }
if (rtattr->cls == function_cls) { if (rtattr->cls == function_cls) {
// Functions themselves can't remunge their passed arguments;
// that should either happen here, or we skip things that aren't a simple match
RELEASE_ASSERT(!argspec.has_starargs, "");
RELEASE_ASSERT(!argspec.has_kwargs, "");
RELEASE_ASSERT(argspec.num_keywords == 0, "");
CLFunction* cl = unboxRTFunction(rtattr); CLFunction* cl = unboxRTFunction(rtattr);
assert(cl); assert(cl);
...@@ -997,8 +1067,8 @@ public: ...@@ -997,8 +1067,8 @@ public:
std::vector<llvm::Value*> other_args; std::vector<llvm::Value*> other_args;
ConcreteCompilerVariable* rtn ConcreteCompilerVariable* rtn = _call(emitter, info, linked_function, cf->code, other_args, argspec,
= _call(emitter, info, linked_function, cf->code, other_args, new_args, cf->sig->rtn_type); new_args, keyword_names, cf->sig->rtn_type);
assert(rtn->getType() == cf->sig->rtn_type); assert(rtn->getType() == cf->sig->rtn_type);
assert(cf->sig->rtn_type != BOXED_INT); assert(cf->sig->rtn_type != BOXED_INT);
...@@ -1010,7 +1080,7 @@ public: ...@@ -1010,7 +1080,7 @@ public:
} }
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN); ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
CompilerVariable* rtn = converted->callattr(emitter, info, attr, clsonly, args); CompilerVariable* rtn = converted->callattr(emitter, info, attr, clsonly, argspec, args, keyword_names);
converted->decvref(emitter); converted->decvref(emitter);
return rtn; return rtn;
} }
...@@ -1071,9 +1141,10 @@ public: ...@@ -1071,9 +1141,10 @@ public:
} }
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr, virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool clsonly, const std::vector<CompilerVariable*>& args) { bool clsonly, ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, STR); ConcreteCompilerVariable* converted = var->makeConverted(emitter, STR);
CompilerVariable* rtn = converted->callattr(emitter, info, attr, clsonly, args); CompilerVariable* rtn = converted->callattr(emitter, info, attr, clsonly, argspec, args, keyword_names);
converted->decvref(emitter); converted->decvref(emitter);
return rtn; return rtn;
} }
...@@ -1308,8 +1379,10 @@ public: ...@@ -1308,8 +1379,10 @@ public:
} }
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr, virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool clsonly, const std::vector<CompilerVariable*>& args) { bool clsonly, ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
return makeConverted(emitter, var, getConcreteType())->callattr(emitter, info, attr, clsonly, args); const std::vector<const std::string*>* keyword_names) {
return makeConverted(emitter, var, getConcreteType())
->callattr(emitter, info, attr, clsonly, argspec, args, keyword_names);
} }
}; };
...@@ -1339,8 +1412,9 @@ public: ...@@ -1339,8 +1412,9 @@ public:
return llvm::Type::getInt16Ty(g.context); return llvm::Type::getInt16Ty(g.context);
} }
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, VAR* var, virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, VAR* var, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args) { const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
return undefVariable(); return undefVariable();
} }
virtual void drop(IREmitter& emitter, VAR* var) {} virtual void drop(IREmitter& emitter, VAR* var) {}
...@@ -1366,11 +1440,15 @@ public: ...@@ -1366,11 +1440,15 @@ public:
} }
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr, virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool clsonly, const std::vector<CompilerVariable*>& args) { bool clsonly, ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
return undefVariable(); return undefVariable();
} }
virtual CompilerType* callType(std::vector<CompilerType*>& arg_types) { return UNDEF; } virtual CompilerType* callType(ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types,
const std::vector<const std::string*>* keyword_names) {
return UNDEF;
}
virtual ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, VAR* var) { virtual ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, VAR* var) {
return new ConcreteCompilerVariable(BOOL, llvm::UndefValue::get(g.i1), true); return new ConcreteCompilerVariable(BOOL, llvm::UndefValue::get(g.i1), true);
......
...@@ -40,7 +40,8 @@ public: ...@@ -40,7 +40,8 @@ public:
virtual ConcreteCompilerType* getBoxType() = 0; virtual ConcreteCompilerType* getBoxType() = 0;
virtual bool canConvertTo(ConcreteCompilerType* other_type) = 0; virtual bool canConvertTo(ConcreteCompilerType* other_type) = 0;
virtual CompilerType* getattrType(const std::string* attr, bool cls_only) = 0; virtual CompilerType* getattrType(const std::string* attr, bool cls_only) = 0;
virtual CompilerType* callType(std::vector<CompilerType*>& arg_types) = 0; virtual CompilerType* callType(ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types,
const std::vector<const std::string*>* keyword_names) = 0;
virtual BoxedClass* guaranteedClass() = 0; virtual BoxedClass* guaranteedClass() = 0;
}; };
...@@ -93,12 +94,15 @@ public: ...@@ -93,12 +94,15 @@ public:
abort(); abort();
} }
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr, virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr,
bool clsonly, const std::vector<CompilerVariable*>& args) { 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()); printf("callattr not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, VAR* value, virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, VAR* value, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args) { const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
printf("call not defined for %s\n", debugName().c_str()); printf("call not defined for %s\n", debugName().c_str());
abort(); abort();
} }
...@@ -122,7 +126,8 @@ public: ...@@ -122,7 +126,8 @@ public:
printf("getattrType not defined for %s\n", debugName().c_str()); printf("getattrType not defined for %s\n", debugName().c_str());
abort(); abort();
} }
CompilerType* callType(std::vector<CompilerType*>& arg_types) override { CompilerType* callType(struct ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types,
const std::vector<const std::string*>* keyword_names) override {
printf("callType not defined for %s\n", debugName().c_str()); printf("callType not defined for %s\n", debugName().c_str());
abort(); abort();
} }
...@@ -213,9 +218,11 @@ public: ...@@ -213,9 +218,11 @@ public:
= 0; = 0;
virtual void setattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, CompilerVariable* v) = 0; virtual void setattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, CompilerVariable* v) = 0;
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool clsonly, virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool clsonly,
const std::vector<CompilerVariable*>& args) = 0; struct ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, const std::vector<CompilerVariable*>& args) const std::vector<const std::string*>* keyword_names) = 0;
= 0; virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) = 0;
virtual void print(IREmitter& emitter, const OpInfo& info) = 0; virtual void print(IREmitter& emitter, const OpInfo& info) = 0;
virtual ConcreteCompilerVariable* len(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* getitem(IREmitter& emitter, const OpInfo& info, CompilerVariable*) = 0;
...@@ -273,12 +280,14 @@ public: ...@@ -273,12 +280,14 @@ public:
type->setattr(emitter, info, this, attr, v); type->setattr(emitter, info, this, attr, v);
} }
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool clsonly, virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool clsonly,
const std::vector<CompilerVariable*>& args) { struct ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
return type->callattr(emitter, info, this, attr, clsonly, args); const std::vector<const std::string*>* keyword_names) {
} return type->callattr(emitter, info, this, attr, clsonly, argspec, args, keyword_names);
CompilerVariable* call(IREmitter& emitter, const OpInfo& info, }
const std::vector<CompilerVariable*>& args) override { CompilerVariable* call(IREmitter& emitter, const OpInfo& info, struct ArgPassSpec argspec,
return type->call(emitter, info, this, args); const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) override {
return type->call(emitter, info, this, argspec, args, keyword_names);
} }
void print(IREmitter& emitter, const OpInfo& info) override { type->print(emitter, info, this); } void print(IREmitter& emitter, const OpInfo& info) override { type->print(emitter, info, this); }
ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info) override { ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info) override {
......
...@@ -881,10 +881,10 @@ static std::string getUniqueFunctionName(std::string nameprefix, EffortLevel::Ef ...@@ -881,10 +881,10 @@ static std::string getUniqueFunctionName(std::string nameprefix, EffortLevel::Ef
return os.str(); return os.str();
} }
CompiledFunction* compileFunction(SourceInfo* source, const OSREntryDescriptor* entry_descriptor, CompiledFunction* doCompile(SourceInfo* source, const OSREntryDescriptor* entry_descriptor,
EffortLevel::EffortLevel effort, FunctionSignature* sig, EffortLevel::EffortLevel effort, FunctionSignature* sig,
const std::vector<AST_expr*>& arg_names, std::string nameprefix) { const std::vector<AST_expr*>& arg_names, std::string nameprefix) {
Timer _t("in compileFunction"); Timer _t("in doCompile");
if (VERBOSITY("irgen") >= 1) if (VERBOSITY("irgen") >= 1)
source->cfg->print(); source->cfg->print();
......
...@@ -76,7 +76,7 @@ public: ...@@ -76,7 +76,7 @@ public:
const std::vector<llvm::Value*>& args, ExcInfo exc_info) = 0; const std::vector<llvm::Value*>& args, ExcInfo exc_info) = 0;
}; };
CompiledFunction* compileFunction(SourceInfo* source, const OSREntryDescriptor* entry_descriptor, CompiledFunction* doCompile(SourceInfo* source, const OSREntryDescriptor* entry_descriptor,
EffortLevel::EffortLevel effort, FunctionSignature* sig, EffortLevel::EffortLevel effort, FunctionSignature* sig,
const std::vector<AST_expr*>& arg_names, std::string nameprefix); const std::vector<AST_expr*>& arg_names, std::string nameprefix);
......
...@@ -68,6 +68,7 @@ AST_arguments* SourceInfo::getArgsAST() { ...@@ -68,6 +68,7 @@ AST_arguments* SourceInfo::getArgsAST() {
const std::vector<AST_expr*>& SourceInfo::getArgNames() { const std::vector<AST_expr*>& SourceInfo::getArgNames() {
static std::vector<AST_expr*> empty; static std::vector<AST_expr*> empty;
assert(this);
AST_arguments* args = getArgsAST(); AST_arguments* args = getArgsAST();
if (args == NULL) if (args == NULL)
...@@ -87,6 +88,14 @@ const std::vector<AST_stmt*>& SourceInfo::getBody() { ...@@ -87,6 +88,14 @@ const std::vector<AST_stmt*>& SourceInfo::getBody() {
} }
} }
EffortLevel::EffortLevel initialEffort() {
if (FORCE_OPTIMIZE)
return EffortLevel::MAXIMAL;
if (ENABLE_INTERPRETER)
return EffortLevel::INTERPRETED;
return EffortLevel::MINIMAL;
}
static void compileIR(CompiledFunction* cf, EffortLevel::EffortLevel effort) { static void compileIR(CompiledFunction* cf, EffortLevel::EffortLevel effort) {
assert(cf); assert(cf);
assert(cf->func); assert(cf->func);
...@@ -126,9 +135,9 @@ static void compileIR(CompiledFunction* cf, EffortLevel::EffortLevel effort) { ...@@ -126,9 +135,9 @@ static void compileIR(CompiledFunction* cf, EffortLevel::EffortLevel effort) {
// Compiles a new version of the function with the given signature and adds it to the list; // Compiles a new version of the function with the given signature and adds it to the list;
// should only be called after checking to see if the other versions would work. // should only be called after checking to see if the other versions would work.
static CompiledFunction* _doCompile(CLFunction* f, FunctionSignature* sig, EffortLevel::EffortLevel effort, CompiledFunction* compileFunction(CLFunction* f, FunctionSignature* sig, EffortLevel::EffortLevel effort,
const OSREntryDescriptor* entry) { const OSREntryDescriptor* entry) {
Timer _t("for _doCompile()"); Timer _t("for compileFunction()");
assert(sig); assert(sig);
ASSERT(f->versions.size() < 20, "%ld", f->versions.size()); ASSERT(f->versions.size() < 20, "%ld", f->versions.size());
...@@ -178,7 +187,7 @@ static CompiledFunction* _doCompile(CLFunction* f, FunctionSignature* sig, Effor ...@@ -178,7 +187,7 @@ static CompiledFunction* _doCompile(CLFunction* f, FunctionSignature* sig, Effor
source->scoping->getScopeInfoForNode(source->ast)); source->scoping->getScopeInfoForNode(source->ast));
} }
CompiledFunction* cf = compileFunction(source, entry, effort, sig, arg_names, name); CompiledFunction* cf = doCompile(source, entry, effort, sig, arg_names, name);
compileIR(cf, effort); compileIR(cf, effort);
f->addVersion(cf); f->addVersion(cf);
...@@ -224,14 +233,6 @@ static CompiledFunction* _doCompile(CLFunction* f, FunctionSignature* sig, Effor ...@@ -224,14 +233,6 @@ static CompiledFunction* _doCompile(CLFunction* f, FunctionSignature* sig, Effor
return cf; return cf;
} }
static EffortLevel::EffortLevel initialEffort() {
if (FORCE_OPTIMIZE)
return EffortLevel::MAXIMAL;
if (ENABLE_INTERPRETER)
return EffortLevel::INTERPRETED;
return EffortLevel::MINIMAL;
}
void compileAndRunModule(AST_Module* m, BoxedModule* bm) { void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
Timer _t("for compileModule()"); Timer _t("for compileModule()");
...@@ -247,7 +248,8 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) { ...@@ -247,7 +248,8 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
EffortLevel::EffortLevel effort = initialEffort(); EffortLevel::EffortLevel effort = initialEffort();
CompiledFunction* cf = _doCompile(cl_f, new FunctionSignature(VOID, false), effort, NULL); CompiledFunction* cf
= compileFunction(cl_f, new FunctionSignature(VOID, &si->getArgNames(), 0, false, false), effort, NULL);
assert(cf->clfunc->versions.size()); assert(cf->clfunc->versions.size());
_t.end(); _t.end();
...@@ -279,7 +281,7 @@ static CompiledFunction* _doReopt(CompiledFunction* cf, EffortLevel::EffortLevel ...@@ -279,7 +281,7 @@ static CompiledFunction* _doReopt(CompiledFunction* cf, EffortLevel::EffortLevel
versions.erase(versions.begin() + i); versions.erase(versions.begin() + i);
CompiledFunction* new_cf CompiledFunction* new_cf
= _doCompile(clfunc, cf->sig, new_effort, = compileFunction(clfunc, cf->sig, new_effort,
NULL); // this pushes the new CompiledVersion to the back of the version list NULL); // this pushes the new CompiledVersion to the back of the version list
cf->dependent_callsites.invalidateAll(); cf->dependent_callsites.invalidateAll();
...@@ -308,7 +310,8 @@ void* compilePartialFunc(OSRExit* exit) { ...@@ -308,7 +310,8 @@ void* compilePartialFunc(OSRExit* exit) {
new_effort = EffortLevel::MINIMAL; new_effort = EffortLevel::MINIMAL;
// EffortLevel::EffortLevel new_effort = (EffortLevel::EffortLevel)(exit->parent_cf->effort + 1); // EffortLevel::EffortLevel new_effort = (EffortLevel::EffortLevel)(exit->parent_cf->effort + 1);
// new_effort = EffortLevel::MAXIMAL; // new_effort = EffortLevel::MAXIMAL;
CompiledFunction* compiled = _doCompile(exit->parent_cf->clfunc, exit->parent_cf->sig, new_effort, exit->entry); CompiledFunction* compiled
= compileFunction(exit->parent_cf->clfunc, exit->parent_cf->sig, new_effort, exit->entry);
assert(compiled = new_cf); assert(compiled = new_cf);
} }
...@@ -328,187 +331,22 @@ extern "C" char* reoptCompiledFunc(CompiledFunction* cf) { ...@@ -328,187 +331,22 @@ extern "C" char* reoptCompiledFunc(CompiledFunction* cf) {
return (char*)new_cf->code; return (char*)new_cf->code;
} }
CompiledFunction* resolveCLFunc(CLFunction* f, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args) {
static StatCounter slowpath_resolveclfunc("slowpath_resolveclfunc");
slowpath_resolveclfunc.log();
FunctionList& versions = f->versions;
for (int i = 0; i < versions.size(); i++) {
CompiledFunction* cf = versions[i];
FunctionSignature* sig = cf->sig;
if (sig->rtn_type->llvmType() != g.llvm_value_type_ptr)
continue;
if ((!sig->is_vararg && sig->arg_types.size() != nargs) || (sig->is_vararg && nargs < sig->arg_types.size()))
continue;
int nsig_args = sig->arg_types.size();
if (nsig_args >= 1) {
if (sig->arg_types[0]->isFitBy(arg1->cls)) {
// pass
} else {
continue;
}
}
if (nsig_args >= 2) {
if (sig->arg_types[1]->isFitBy(arg2->cls)) {
// pass
} else {
continue;
}
}
if (nsig_args >= 3) {
if (sig->arg_types[2]->isFitBy(arg3->cls)) {
// pass
} else {
continue;
}
}
bool bad = false;
for (int j = 3; j < nsig_args; j++) {
if (sig->arg_types[j]->isFitBy(args[j - 3]->cls)) {
// pass
} else {
bad = true;
break;
}
}
if (bad)
continue;
assert(cf);
assert(!cf->entry_descriptor);
assert(cf->is_interpreted == (cf->code == NULL));
return cf;
}
if (f->source == NULL) {
printf("Error: couldn't find suitable function version and no source to recompile!\n");
printf("%ld args:", nargs);
for (int i = 0; i < nargs; i++) {
if (i == 3) {
printf(" [and more]");
break;
}
Box* firstargs[] = { arg1, arg2, arg3 };
printf(" %s", getTypeName(firstargs[i])->c_str());
}
printf("\n");
for (int j = 0; j < f->versions.size(); j++) {
std::string func_name = g.func_addr_registry.getFuncNameAtAddress(f->versions[j]->code, true);
printf("Version %d, %s:", j, func_name.c_str());
FunctionSignature* sig = f->versions[j]->sig;
for (int i = 0; i < sig->arg_types.size(); i++) {
printf(" %s", sig->arg_types[i]->debugName().c_str());
}
if (sig->is_vararg)
printf(" *vararg");
printf("\n");
// printf(" @%p %s\n", f->versions[j]->code, func_name.c_str());
}
abort();
}
assert(f->source->getArgsAST()->vararg.size() == 0);
bool is_vararg = false;
std::vector<ConcreteCompilerType*> arg_types;
if (nargs >= 1) {
arg_types.push_back(typeFromClass(arg1->cls));
}
if (nargs >= 2) {
arg_types.push_back(typeFromClass(arg2->cls));
}
if (nargs >= 3) {
arg_types.push_back(typeFromClass(arg3->cls));
}
for (int j = 3; j < nargs; j++) {
arg_types.push_back(typeFromClass(args[j - 3]->cls));
}
FunctionSignature* sig = new FunctionSignature(UNKNOWN, arg_types, is_vararg);
EffortLevel::EffortLevel new_effort = initialEffort();
CompiledFunction* cf
= _doCompile(f, sig, new_effort, NULL); // this pushes the new CompiledVersion to the back of the version list
assert(cf->is_interpreted == (cf->code == NULL));
return cf;
}
Box* callCompiledFunc(CompiledFunction* cf, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args) {
assert(cf);
// TODO these shouldn't have to be initialized, but I don't want to issue a #pragma
// that disables the warning for the whole file:
Box* rarg1 = arg1, *rarg2 = arg2, *rarg3 = arg3;
Box** rargs = NULL;
if (nargs > 3) {
if (cf->sig->is_vararg) {
// the +2 is for the varargs and kwargs
rargs = (Box**)alloca((nargs - 3 + 2) * sizeof(Box*));
memcpy(rargs, args, (nargs - 3) * sizeof(Box*));
} else {
rargs = args;
}
assert(rargs);
}
int nsig_args = cf->sig->arg_types.size();
BoxedList* made_vararg = NULL;
if (cf->sig->is_vararg) {
made_vararg = (BoxedList*)createList();
if (nsig_args == 0)
rarg1 = made_vararg;
else if (nsig_args == 1)
rarg2 = made_vararg;
else if (nsig_args == 2)
rarg3 = made_vararg;
else
rargs[nsig_args - 3] = made_vararg;
for (int i = nsig_args; i < nargs; i++) {
if (i == 0)
listAppendInternal(made_vararg, arg1);
else if (i == 1)
listAppendInternal(made_vararg, arg2);
else if (i == 2)
listAppendInternal(made_vararg, arg3);
else
listAppendInternal(made_vararg, args[i - 3]);
}
}
if (!cf->is_interpreted) {
if (cf->sig->is_vararg) {
Box* rtn = cf->call(rarg1, rarg2, rarg3, rargs);
return rtn;
} else {
return cf->call(rarg1, rarg2, rarg3, rargs);
}
} else {
return interpretFunction(cf->func, nargs, rarg1, rarg2, rarg3, rargs);
}
}
CLFunction* createRTFunction() { CLFunction* createRTFunction() {
return new CLFunction(NULL); return new CLFunction(NULL);
} }
extern "C" CLFunction* boxRTFunction(void* f, ConcreteCompilerType* rtn_type, int nargs, bool is_vararg) { extern "C" CLFunction* boxRTFunction(void* f, ConcreteCompilerType* rtn_type, int nargs, bool takes_varargs,
bool takes_kwargs) {
CLFunction* cl_f = createRTFunction(); CLFunction* cl_f = createRTFunction();
addRTFunction(cl_f, f, rtn_type, nargs, is_vararg); addRTFunction(cl_f, f, rtn_type, nargs, takes_varargs, takes_kwargs);
return cl_f; return cl_f;
} }
void addRTFunction(CLFunction* cl_f, void* f, ConcreteCompilerType* rtn_type, int nargs, bool is_vararg) { void addRTFunction(CLFunction* cl_f, void* f, ConcreteCompilerType* rtn_type, int nargs, bool takes_varargs,
bool takes_kwargs) {
std::vector<ConcreteCompilerType*> arg_types(nargs, NULL); std::vector<ConcreteCompilerType*> arg_types(nargs, NULL);
return addRTFunction(cl_f, f, rtn_type, arg_types, is_vararg); return addRTFunction(cl_f, f, rtn_type, arg_types, takes_varargs, takes_kwargs);
} }
static ConcreteCompilerType* processType(ConcreteCompilerType* type) { static ConcreteCompilerType* processType(ConcreteCompilerType* type) {
...@@ -518,11 +356,24 @@ static ConcreteCompilerType* processType(ConcreteCompilerType* type) { ...@@ -518,11 +356,24 @@ static ConcreteCompilerType* processType(ConcreteCompilerType* type) {
} }
void addRTFunction(CLFunction* cl_f, void* f, ConcreteCompilerType* rtn_type, void addRTFunction(CLFunction* cl_f, void* f, ConcreteCompilerType* rtn_type,
const std::vector<ConcreteCompilerType*>& arg_types, bool is_vararg) { const std::vector<ConcreteCompilerType*>& arg_types, bool takes_varargs, bool takes_kwargs) {
FunctionSignature* sig = new FunctionSignature(processType(rtn_type), is_vararg); FunctionSignature* sig = new FunctionSignature(processType(rtn_type), NULL, 0, takes_varargs, takes_kwargs);
std::vector<llvm::Type*> llvm_arg_types;
for (int i = 0; i < arg_types.size(); i++) { for (int i = 0; i < arg_types.size(); i++) {
sig->arg_types.push_back(processType(arg_types[i])); sig->arg_types.push_back(processType(arg_types[i]));
}
std::vector<llvm::Type*> llvm_arg_types;
int npassed_args = arg_types.size();
if (takes_varargs)
npassed_args++;
if (takes_kwargs)
npassed_args++;
for (int i = 0; i < npassed_args; i++) {
if (i == 3) {
llvm_arg_types.push_back(g.llvm_value_type_ptr->getPointerTo());
break;
}
llvm_arg_types.push_back(g.llvm_value_type_ptr); llvm_arg_types.push_back(g.llvm_value_type_ptr);
} }
......
...@@ -190,6 +190,17 @@ IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock) { ...@@ -190,6 +190,17 @@ IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock) {
return new IREmitterImpl(irstate, curblock); return new IREmitterImpl(irstate, curblock);
} }
static std::unordered_map<AST_expr*, std::vector<const std::string*>*> made_keyword_storage;
static std::vector<const std::string*>* getKeywordNameStorage(AST_Call* node) {
auto it = made_keyword_storage.find(node);
if (it != made_keyword_storage.end())
return it->second;
auto rtn = new std::vector<const std::string*>();
made_keyword_storage.insert(it, std::make_pair(node, rtn));
return rtn;
}
class IRGeneratorImpl : public IRGenerator { class IRGeneratorImpl : public IRGenerator {
private: private:
IRGenState* irstate; IRGenState* irstate;
...@@ -623,10 +634,6 @@ private: ...@@ -623,10 +634,6 @@ private:
CompilerVariable* evalCall(AST_Call* node, ExcInfo exc_info) { CompilerVariable* evalCall(AST_Call* node, ExcInfo exc_info) {
assert(state != PARTIAL); assert(state != PARTIAL);
assert(!node->starargs);
assert(!node->kwargs);
assert(!node->keywords.size());
bool is_callattr; bool is_callattr;
bool callattr_clsonly = false; bool callattr_clsonly = false;
std::string* attr = NULL; std::string* attr = NULL;
...@@ -649,19 +656,42 @@ private: ...@@ -649,19 +656,42 @@ private:
} }
std::vector<CompilerVariable*> args; std::vector<CompilerVariable*> args;
std::vector<const std::string*>* keyword_names;
if (node->keywords.size()) {
keyword_names = getKeywordNameStorage(node);
} else {
keyword_names = NULL;
}
for (int i = 0; i < node->args.size(); i++) { for (int i = 0; i < node->args.size(); i++) {
CompilerVariable* a = evalExpr(node->args[i], exc_info); CompilerVariable* a = evalExpr(node->args[i], exc_info);
args.push_back(a); args.push_back(a);
} }
for (int i = 0; i < node->keywords.size(); i++) {
CompilerVariable* a = evalExpr(node->keywords[i]->value, exc_info);
args.push_back(a);
keyword_names->push_back(&node->keywords[i]->arg);
}
if (node->starargs)
args.push_back(evalExpr(node->starargs, exc_info));
if (node->kwargs)
args.push_back(evalExpr(node->kwargs, exc_info));
struct ArgPassSpec argspec(node->args.size(), node->keywords.size(), node->starargs != NULL,
node->kwargs != NULL);
// if (VERBOSITY("irgen") >= 1) // if (VERBOSITY("irgen") >= 1)
//_addAnnotation("before_call"); //_addAnnotation("before_call");
CompilerVariable* rtn; CompilerVariable* rtn;
if (is_callattr) { if (is_callattr) {
rtn = func->callattr(emitter, getOpInfoForNode(node, exc_info), attr, callattr_clsonly, args); rtn = func->callattr(emitter, getOpInfoForNode(node, exc_info), attr, callattr_clsonly, argspec, args,
keyword_names);
} else { } else {
rtn = func->call(emitter, getOpInfoForNode(node, exc_info), args); rtn = func->call(emitter, getOpInfoForNode(node, exc_info), argspec, args, keyword_names);
} }
func->decvref(emitter); func->decvref(emitter);
...@@ -669,9 +699,6 @@ private: ...@@ -669,9 +699,6 @@ private:
args[i]->decvref(emitter); args[i]->decvref(emitter);
} }
// if (VERBOSITY("irgen") >= 1)
//_addAnnotation("end_of_call");
return rtn; return rtn;
} }
...@@ -693,7 +720,7 @@ private: ...@@ -693,7 +720,7 @@ private:
args.push_back(key); args.push_back(key);
args.push_back(value); args.push_back(value);
// TODO could use the internal _listAppend function to avoid incref/decref'ing None // TODO could use the internal _listAppend function to avoid incref/decref'ing None
CompilerVariable* rtn = setitem->call(emitter, getEmptyOpInfo(exc_info), args); CompilerVariable* rtn = setitem->call(emitter, getEmptyOpInfo(exc_info), ArgPassSpec(2), args, NULL);
rtn->decvref(emitter); rtn->decvref(emitter);
key->decvref(emitter); key->decvref(emitter);
......
...@@ -642,12 +642,18 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* arg1, Box* arg2, Box* ...@@ -642,12 +642,18 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* arg1, Box* arg2, Box*
int64_t)>(f)(args[0].n, args[1].n, args[2].n, args[3].n, int64_t)>(f)(args[0].n, args[1].n, args[2].n, args[3].n,
args[4].n, args[5].n, args[6].n); args[4].n, args[5].n, args[6].n);
break; break;
case 0b1000000000: case 0b1000000000: // 512
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, r = reinterpret_cast<int64_t (*)(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, int64_t, int64_t)>(f)(args[0].n, args[1].n, args[2].n,
args[3].n, args[4].n, args[5].n, args[3].n, args[4].n, args[5].n,
args[6].n, args[7].n); args[6].n, args[7].n);
break; break;
case 0b10000000000: // 1024
r = reinterpret_cast<int64_t (*)(int64_t, 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,
args[7].n, args[8].n);
break;
default: default:
inst->dump(); inst->dump();
RELEASE_ASSERT(0, "%d", mask); RELEASE_ASSERT(0, "%d", mask);
......
...@@ -132,6 +132,9 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -132,6 +132,9 @@ void initGlobalFuncs(GlobalState& g) {
g.llvm_str_type_ptr = lookupFunction("boxStringPtr")->arg_begin()->getType(); 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();
#define GET(N) g.funcs.N = getFunc((void*)N, STRINGIFY(N)) #define GET(N) g.funcs.N = getFunc((void*)N, STRINGIFY(N))
...@@ -185,23 +188,23 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -185,23 +188,23 @@ void initGlobalFuncs(GlobalState& g) {
GET(listAppendInternal); GET(listAppendInternal);
g.funcs.runtimeCall = getFunc((void*)runtimeCall, "runtimeCall"); g.funcs.runtimeCall = getFunc((void*)runtimeCall, "runtimeCall");
g.funcs.runtimeCall0 = addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i64); g.funcs.runtimeCall0 = addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i32);
g.funcs.runtimeCall1 g.funcs.runtimeCall1
= addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i64, g.llvm_value_type_ptr); = addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i32, g.llvm_value_type_ptr);
g.funcs.runtimeCall2 = addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i64, g.funcs.runtimeCall2 = addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i32,
g.llvm_value_type_ptr, g.llvm_value_type_ptr); g.llvm_value_type_ptr, g.llvm_value_type_ptr);
g.funcs.runtimeCall3 = addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i64, g.funcs.runtimeCall3 = addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i32,
g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_value_type_ptr); g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_value_type_ptr);
g.funcs.callattr = getFunc((void*)callattr, "callattr"); g.funcs.callattr = getFunc((void*)callattr, "callattr");
g.funcs.callattr0 g.funcs.callattr0
= addFunc((void*)callattr, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_str_type_ptr, g.i1, g.i64); = addFunc((void*)callattr, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_str_type_ptr, g.i1, g.i32);
g.funcs.callattr1 = addFunc((void*)callattr, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_str_type_ptr, g.funcs.callattr1 = addFunc((void*)callattr, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_str_type_ptr,
g.i1, g.i64, g.llvm_value_type_ptr); g.i1, g.i32, g.llvm_value_type_ptr);
g.funcs.callattr2 = addFunc((void*)callattr, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_str_type_ptr, g.funcs.callattr2 = addFunc((void*)callattr, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_str_type_ptr,
g.i1, g.i64, g.llvm_value_type_ptr, g.llvm_value_type_ptr); g.i1, g.i32, g.llvm_value_type_ptr, g.llvm_value_type_ptr);
g.funcs.callattr3 = addFunc((void*)callattr, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_str_type_ptr, g.funcs.callattr3 = addFunc((void*)callattr, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_str_type_ptr,
g.i1, g.i64, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_value_type_ptr); g.i1, g.i32, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_value_type_ptr);
g.funcs.reoptCompiledFunc = addFunc((void*)reoptCompiledFunc, g.i8_ptr, g.i8_ptr); g.funcs.reoptCompiledFunc = addFunc((void*)reoptCompiledFunc, g.i8_ptr, g.i8_ptr);
g.funcs.compilePartialFunc = addFunc((void*)compilePartialFunc, g.i8_ptr, g.i8_ptr); g.funcs.compilePartialFunc = addFunc((void*)compilePartialFunc, g.i8_ptr, g.i8_ptr);
......
...@@ -32,6 +32,31 @@ class Value; ...@@ -32,6 +32,31 @@ class Value;
namespace pyston { namespace pyston {
struct ArgPassSpec {
bool has_starargs : 1;
bool has_kwargs : 1;
unsigned int num_keywords : 14;
unsigned int num_args : 16;
static const int MAX_ARGS = (1 << 16) - 1;
static const int MAX_KEYWORDS = (1 << 14) - 1;
explicit ArgPassSpec(int num_args) : has_starargs(false), has_kwargs(false), num_keywords(0), num_args(num_args) {
assert(num_args <= MAX_ARGS);
assert(num_keywords <= MAX_KEYWORDS);
}
explicit ArgPassSpec(int num_args, int num_keywords, bool has_starargs, bool has_kwargs)
: has_starargs(has_starargs), has_kwargs(has_kwargs), num_keywords(num_keywords), num_args(num_args) {
assert(num_args <= MAX_ARGS);
assert(num_keywords <= MAX_KEYWORDS);
}
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); }
};
static_assert(sizeof(ArgPassSpec) <= sizeof(void*), "ArgPassSpec doesn't fit in register!");
class GCVisitor { class GCVisitor {
public: public:
virtual ~GCVisitor() {} virtual ~GCVisitor() {}
...@@ -129,20 +154,30 @@ public: ...@@ -129,20 +154,30 @@ public:
struct FunctionSignature { struct FunctionSignature {
ConcreteCompilerType* rtn_type; ConcreteCompilerType* rtn_type;
const std::vector<AST_expr*>* arg_names;
std::vector<ConcreteCompilerType*> arg_types; std::vector<ConcreteCompilerType*> arg_types;
bool is_vararg; int ndefaults;
bool takes_varargs, takes_kwargs;
FunctionSignature(ConcreteCompilerType* rtn_type, bool is_vararg) : rtn_type(rtn_type), is_vararg(is_vararg) {}
FunctionSignature(ConcreteCompilerType* rtn_type, const std::vector<AST_expr*>* arg_names, int ndefaults,
FunctionSignature(ConcreteCompilerType* rtn_type, ConcreteCompilerType* arg1, ConcreteCompilerType* arg2, bool takes_varargs, bool takes_kwargs)
bool is_vararg) : rtn_type(rtn_type), arg_names(arg_names), ndefaults(ndefaults), takes_varargs(takes_varargs),
: rtn_type(rtn_type), is_vararg(is_vararg) { takes_kwargs(takes_kwargs) {}
FunctionSignature(ConcreteCompilerType* rtn_type, const std::vector<AST_expr*>* arg_names,
ConcreteCompilerType* arg1, ConcreteCompilerType* arg2, int ndefaults, bool takes_varargs,
bool takes_kwargs)
: rtn_type(rtn_type), arg_names(arg_names), ndefaults(ndefaults), takes_varargs(takes_varargs),
takes_kwargs(takes_kwargs) {
arg_types.push_back(arg1); arg_types.push_back(arg1);
arg_types.push_back(arg2); arg_types.push_back(arg2);
} }
FunctionSignature(ConcreteCompilerType* rtn_type, std::vector<ConcreteCompilerType*>& arg_types, bool is_vararg) FunctionSignature(ConcreteCompilerType* rtn_type, const std::vector<AST_expr*>* arg_names,
: rtn_type(rtn_type), arg_types(arg_types), is_vararg(is_vararg) {} std::vector<ConcreteCompilerType*>& arg_types, int ndefaults, bool takes_varargs,
bool takes_kwargs)
: rtn_type(rtn_type), arg_names(arg_names), arg_types(arg_types), ndefaults(ndefaults),
takes_varargs(takes_varargs), takes_kwargs(takes_kwargs) {}
}; };
struct CompiledFunction { struct CompiledFunction {
...@@ -190,13 +225,23 @@ public: ...@@ -190,13 +225,23 @@ public:
SourceInfo(BoxedModule* m, ScopingAnalysis* scoping) SourceInfo(BoxedModule* m, ScopingAnalysis* scoping)
: parent_module(m), scoping(scoping), ast(NULL), cfg(NULL), liveness(NULL), phis(NULL) {} : parent_module(m), scoping(scoping), ast(NULL), cfg(NULL), liveness(NULL), phis(NULL) {}
}; };
typedef std::vector<CompiledFunction*> FunctionList; typedef std::vector<CompiledFunction*> FunctionList;
class CallRewriteArgs;
struct CLFunction { struct CLFunction {
SourceInfo* source; SourceInfo* source;
FunctionList FunctionList
versions; // any compiled versions along with their type parameters; in order from most preferred to least versions; // any compiled versions along with their type parameters; in order from most preferred to least
std::unordered_map<const OSREntryDescriptor*, CompiledFunction*> osr_versions; std::unordered_map<const OSREntryDescriptor*, CompiledFunction*> osr_versions;
// Functions can provide an "internal" version, which will get called instead
// 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**,
const std::vector<const std::string*>*);
InternalCallable internal_callable = NULL;
CLFunction(SourceInfo* source) : source(source) {} CLFunction(SourceInfo* source) : source(source) {}
void addVersion(CompiledFunction* compiled) { void addVersion(CompiledFunction* compiled) {
...@@ -215,14 +260,20 @@ struct CLFunction { ...@@ -215,14 +260,20 @@ struct CLFunction {
}; };
extern "C" CLFunction* createRTFunction(); extern "C" CLFunction* createRTFunction();
extern "C" CLFunction* boxRTFunction(void* f, ConcreteCompilerType* rtn_type, int nargs, bool is_vararg); extern "C" CLFunction* boxRTFunction(void* f, ConcreteCompilerType* rtn_type, int nargs, bool takes_varargs = false,
void addRTFunction(CLFunction* cf, void* f, ConcreteCompilerType* rtn_type, int nargs, bool is_vararg); bool takes_kwargs = false);
void addRTFunction(CLFunction* cf, void* f, ConcreteCompilerType* rtn_type, int nargs, bool takes_varargs = false,
bool takes_kwargs = false);
void addRTFunction(CLFunction* cf, void* f, ConcreteCompilerType* rtn_type, void addRTFunction(CLFunction* cf, void* f, ConcreteCompilerType* rtn_type,
const std::vector<ConcreteCompilerType*>& arg_types, bool is_vararg); const std::vector<ConcreteCompilerType*>& arg_types, bool takes_varargs = false,
bool takes_kwargs = false);
CLFunction* unboxRTFunction(Box*); CLFunction* unboxRTFunction(Box*);
// extern "C" CLFunction* boxRTFunctionVariadic(const char* name, int nargs_min, int nargs_max, void* f);
extern "C" CompiledFunction* resolveCLFunc(CLFunction* f, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args); // Compiles a new version of the function with the given signature and adds it to the list;
extern "C" Box* callCompiledFunc(CompiledFunction* cf, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args); // should only be called after checking to see if the other versions would work.
CompiledFunction* compileFunction(CLFunction* f, FunctionSignature* sig, EffortLevel::EffortLevel effort,
const OSREntryDescriptor* entry);
EffortLevel::EffortLevel initialEffort();
typedef bool i1; typedef bool i1;
typedef int64_t i64; typedef int64_t i64;
......
...@@ -40,7 +40,8 @@ extern "C" Box* dir1(Box* obj) { ...@@ -40,7 +40,8 @@ extern "C" Box* dir1(Box* obj) {
BoxedList* result = nullptr; BoxedList* result = nullptr;
// If __dir__ is present just call it and return what it returns // If __dir__ is present just call it and return what it returns
static std::string attr_dir = "__dir__"; static std::string attr_dir = "__dir__";
Box* dir_result = callattrInternal(obj, &attr_dir, CLASS_ONLY, nullptr, 0, nullptr, nullptr, nullptr, nullptr); Box* dir_result = callattrInternal(obj, &attr_dir, CLASS_ONLY, nullptr, ArgPassSpec(0), nullptr, nullptr, nullptr,
nullptr, nullptr);
if (dir_result && dir_result->cls == list_cls) { if (dir_result && dir_result->cls == list_cls) {
return dir_result; return dir_result;
} }
...@@ -366,7 +367,7 @@ Box* hasattr(Box* obj, Box* _str) { ...@@ -366,7 +367,7 @@ Box* hasattr(Box* obj, Box* _str) {
Box* map2(Box* f, Box* container) { Box* map2(Box* f, Box* container) {
Box* rtn = new BoxedList(); Box* rtn = new BoxedList();
for (Box* e : container->pyElements()) { for (Box* e : container->pyElements()) {
listAppendInternal(rtn, runtimeCall(f, 1, e, NULL, NULL, NULL)); listAppendInternal(rtn, runtimeCall(f, ArgPassSpec(1), e, NULL, NULL, NULL, NULL));
} }
return rtn; return rtn;
} }
......
...@@ -27,7 +27,9 @@ ...@@ -27,7 +27,9 @@
#include "asm_writing/icinfo.h" #include "asm_writing/icinfo.h"
#include "asm_writing/rewriter.h" #include "asm_writing/rewriter.h"
#include "asm_writing/rewriter2.h" #include "asm_writing/rewriter2.h"
#include "codegen/compvars.h"
#include "codegen/irgen/hooks.h" #include "codegen/irgen/hooks.h"
#include "codegen/llvm_interpreter.h"
#include "codegen/parser.h" #include "codegen/parser.h"
#include "codegen/type_recording.h" #include "codegen/type_recording.h"
#include "core/ast.h" #include "core/ast.h"
...@@ -144,24 +146,23 @@ struct CompareRewriteArgs { ...@@ -144,24 +146,23 @@ struct CompareRewriteArgs {
: rewriter(rewriter), lhs(lhs), rhs(rhs), out_success(false) {} : rewriter(rewriter), lhs(lhs), rhs(rhs), out_success(false) {}
}; };
Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args); Box** args, const std::vector<const std::string*>* keyword_names);
static Box* (*runtimeCallInternal0)(Box*, CallRewriteArgs*, int64_t) static Box* (*runtimeCallInternal0)(Box*, CallRewriteArgs*, ArgPassSpec)
= (Box * (*)(Box*, CallRewriteArgs*, int64_t))runtimeCallInternal; = (Box * (*)(Box*, CallRewriteArgs*, ArgPassSpec))runtimeCallInternal;
static Box* (*runtimeCallInternal1)(Box*, CallRewriteArgs*, int64_t, Box*) static Box* (*runtimeCallInternal1)(Box*, CallRewriteArgs*, ArgPassSpec, Box*)
= (Box * (*)(Box*, CallRewriteArgs*, int64_t, Box*))runtimeCallInternal; = (Box * (*)(Box*, CallRewriteArgs*, ArgPassSpec, Box*))runtimeCallInternal;
static Box* (*runtimeCallInternal2)(Box*, CallRewriteArgs*, int64_t, Box*, Box*) static Box* (*runtimeCallInternal2)(Box*, CallRewriteArgs*, ArgPassSpec, Box*, Box*)
= (Box * (*)(Box*, CallRewriteArgs*, int64_t, Box*, Box*))runtimeCallInternal; = (Box * (*)(Box*, CallRewriteArgs*, ArgPassSpec, Box*, Box*))runtimeCallInternal;
static Box* (*runtimeCallInternal3)(Box*, CallRewriteArgs*, int64_t, Box*, Box*, Box*) static Box* (*runtimeCallInternal3)(Box*, CallRewriteArgs*, ArgPassSpec, Box*, Box*, Box*)
= (Box * (*)(Box*, CallRewriteArgs*, int64_t, Box*, Box*, Box*))runtimeCallInternal; = (Box * (*)(Box*, CallRewriteArgs*, ArgPassSpec, Box*, Box*, Box*))runtimeCallInternal;
Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* obj, Box* arg1, Box* arg2, Box** args); static Box* (*typeCallInternal1)(BoxedFunction*, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box*)
static Box* (*typeCallInternal1)(CallRewriteArgs* rewrite_args, int64_t nargs, Box*) = (Box * (*)(BoxedFunction*, CallRewriteArgs*, ArgPassSpec, Box*))typeCallInternal;
= (Box * (*)(CallRewriteArgs*, int64_t, Box*))typeCallInternal; static Box* (*typeCallInternal2)(BoxedFunction*, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box*, Box*)
static Box* (*typeCallInternal2)(CallRewriteArgs* rewrite_args, int64_t nargs, Box*, Box*) = (Box * (*)(BoxedFunction*, CallRewriteArgs*, ArgPassSpec, Box*, Box*))typeCallInternal;
= (Box * (*)(CallRewriteArgs*, int64_t, Box*, Box*))typeCallInternal; static Box* (*typeCallInternal3)(BoxedFunction*, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box*, Box*, Box*)
static Box* (*typeCallInternal3)(CallRewriteArgs* rewrite_args, int64_t nargs, Box*, Box*, Box*) = (Box * (*)(BoxedFunction*, CallRewriteArgs*, ArgPassSpec, Box*, Box*, Box*))typeCallInternal;
= (Box * (*)(CallRewriteArgs*, int64_t, Box*, Box*, Box*))typeCallInternal;
bool checkClass(LookupScope scope) { bool checkClass(LookupScope scope) {
return (scope & CLASS_ONLY) != 0; return (scope & CLASS_ONLY) != 0;
...@@ -169,14 +170,15 @@ bool checkClass(LookupScope scope) { ...@@ -169,14 +170,15 @@ bool checkClass(LookupScope scope) {
bool checkInst(LookupScope scope) { bool checkInst(LookupScope scope) {
return (scope & INST_ONLY) != 0; return (scope & INST_ONLY) != 0;
} }
static Box* (*callattrInternal0)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t) static Box* (*callattrInternal0)(Box*, const std::string*, LookupScope, CallRewriteArgs*, ArgPassSpec)
= (Box * (*)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t))callattrInternal; = (Box * (*)(Box*, const std::string*, LookupScope, CallRewriteArgs*, ArgPassSpec))callattrInternal;
static Box* (*callattrInternal1)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t, Box*) static Box* (*callattrInternal1)(Box*, const std::string*, LookupScope, CallRewriteArgs*, ArgPassSpec, Box*)
= (Box * (*)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t, Box*))callattrInternal; = (Box * (*)(Box*, const std::string*, LookupScope, CallRewriteArgs*, ArgPassSpec, Box*))callattrInternal;
static Box* (*callattrInternal2)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t, Box*, Box*) static Box* (*callattrInternal2)(Box*, const std::string*, LookupScope, CallRewriteArgs*, ArgPassSpec, Box*, Box*)
= (Box * (*)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t, Box*, Box*))callattrInternal; = (Box * (*)(Box*, const std::string*, LookupScope, CallRewriteArgs*, ArgPassSpec, Box*, Box*))callattrInternal;
static Box* (*callattrInternal3)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t, Box*, Box*, Box*) static Box* (*callattrInternal3)(Box*, const std::string*, LookupScope, CallRewriteArgs*, ArgPassSpec, Box*, Box*, Box*)
= (Box * (*)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t, Box*, Box*, Box*))callattrInternal; = (Box
* (*)(Box*, const std::string*, LookupScope, CallRewriteArgs*, ArgPassSpec, Box*, Box*, Box*))callattrInternal;
size_t PyHasher::operator()(Box* b) const { size_t PyHasher::operator()(Box* b) const {
if (b->cls == str_cls) { if (b->cls == str_cls) {
...@@ -714,10 +716,11 @@ RELEASE_ASSERT(gotten, "%s:%s", getTypeName(obj)->c_str(), attr); ...@@ -714,10 +716,11 @@ RELEASE_ASSERT(gotten, "%s:%s", getTypeName(obj)->c_str(), attr);
return gotten; return gotten;
} }
static Box* (*runtimeCall0)(Box*, int64_t) = (Box * (*)(Box*, int64_t))runtimeCall; static Box* (*runtimeCall0)(Box*, ArgPassSpec) = (Box * (*)(Box*, ArgPassSpec))runtimeCall;
static Box* (*runtimeCall1)(Box*, int64_t, Box*) = (Box * (*)(Box*, int64_t, Box*))runtimeCall; static Box* (*runtimeCall1)(Box*, ArgPassSpec, Box*) = (Box * (*)(Box*, ArgPassSpec, Box*))runtimeCall;
static Box* (*runtimeCall2)(Box*, int64_t, Box*, Box*) = (Box * (*)(Box*, int64_t, Box*, Box*))runtimeCall; static Box* (*runtimeCall2)(Box*, ArgPassSpec, Box*, Box*) = (Box * (*)(Box*, ArgPassSpec, Box*, Box*))runtimeCall;
static Box* (*runtimeCall3)(Box*, int64_t, Box*, Box*, Box*) = (Box * (*)(Box*, int64_t, Box*, Box*, Box*))runtimeCall; static Box* (*runtimeCall3)(Box*, ArgPassSpec, Box*, Box*, Box*)
= (Box * (*)(Box*, ArgPassSpec, Box*, Box*, Box*))runtimeCall;
Box* getattr_internal(Box* obj, const std::string& attr, bool check_cls, bool allow_custom, Box* getattr_internal(Box* obj, const std::string& attr, bool check_cls, bool allow_custom,
GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2) { GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2) {
...@@ -728,7 +731,7 @@ Box* getattr_internal(Box* obj, const std::string& attr, bool check_cls, bool al ...@@ -728,7 +731,7 @@ Box* getattr_internal(Box* obj, const std::string& attr, bool check_cls, bool al
if (getattribute) { if (getattribute) {
// TODO this is a good candidate for interning? // TODO this is a good candidate for interning?
Box* boxstr = boxString(attr); Box* boxstr = boxString(attr);
Box* rtn = runtimeCall1(getattribute, 1, boxstr); Box* rtn = runtimeCall1(getattribute, ArgPassSpec(1), boxstr);
return rtn; return rtn;
} }
...@@ -795,7 +798,7 @@ Box* getattr_internal(Box* obj, const std::string& attr, bool check_cls, bool al ...@@ -795,7 +798,7 @@ Box* getattr_internal(Box* obj, const std::string& attr, bool check_cls, bool al
Box* getattr = getclsattr_internal(obj, "__getattr__", NULL, NULL); Box* getattr = getclsattr_internal(obj, "__getattr__", NULL, NULL);
if (getattr) { if (getattr) {
Box* boxstr = boxString(attr); Box* boxstr = boxString(attr);
Box* rtn = runtimeCall1(getattr, 1, boxstr); Box* rtn = runtimeCall1(getattr, ArgPassSpec(1), boxstr);
return rtn; return rtn;
} }
...@@ -991,7 +994,7 @@ extern "C" bool nonzero(Box* obj) { ...@@ -991,7 +994,7 @@ extern "C" bool nonzero(Box* obj) {
return true; return true;
} }
Box* r = runtimeCall0(func, 0); Box* r = runtimeCall0(func, ArgPassSpec(0));
if (r->cls == bool_cls) { if (r->cls == bool_cls) {
BoxedBool* b = static_cast<BoxedBool*>(r); BoxedBool* b = static_cast<BoxedBool*>(r);
bool rtn = b->b; bool rtn = b->b;
...@@ -1019,7 +1022,7 @@ extern "C" BoxedString* str(Box* obj) { ...@@ -1019,7 +1022,7 @@ extern "C" BoxedString* str(Box* obj) {
snprintf(buf, 80, "<%s object at %p>", getTypeName(obj)->c_str(), obj); snprintf(buf, 80, "<%s object at %p>", getTypeName(obj)->c_str(), obj);
return boxStrConstant(buf); return boxStrConstant(buf);
} else { } else {
obj = runtimeCallInternal0(str, NULL, 0); obj = runtimeCallInternal0(str, NULL, ArgPassSpec(0));
} }
} }
if (obj->cls != str_cls) { if (obj->cls != str_cls) {
...@@ -1045,7 +1048,7 @@ extern "C" Box* repr(Box* obj) { ...@@ -1045,7 +1048,7 @@ extern "C" Box* repr(Box* obj) {
} }
return boxStrConstant(buf); return boxStrConstant(buf);
} else { } else {
obj = runtimeCall0(repr, 0); obj = runtimeCall0(repr, ArgPassSpec(0));
} }
if (obj->cls != str_cls) { if (obj->cls != str_cls) {
...@@ -1100,7 +1103,7 @@ extern "C" BoxedInt* hash(Box* obj) { ...@@ -1100,7 +1103,7 @@ extern "C" BoxedInt* hash(Box* obj) {
return static_cast<BoxedInt*>(boxInt((i64)obj)); return static_cast<BoxedInt*>(boxInt((i64)obj));
} }
Box* rtn = runtimeCall0(hash, 0); Box* rtn = runtimeCall0(hash, ArgPassSpec(0));
if (rtn->cls != int_cls) { if (rtn->cls != int_cls) {
raiseExcHelper(TypeError, "an integer is required"); raiseExcHelper(TypeError, "an integer is required");
} }
...@@ -1113,13 +1116,13 @@ extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) { ...@@ -1113,13 +1116,13 @@ extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) {
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj); CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj);
crewrite_args.preferred_dest_reg = rewrite_args->preferred_dest_reg; crewrite_args.preferred_dest_reg = rewrite_args->preferred_dest_reg;
rtn = callattrInternal0(obj, &attr_str, CLASS_ONLY, &crewrite_args, 0); rtn = callattrInternal0(obj, &attr_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(0));
if (!crewrite_args.out_success) if (!crewrite_args.out_success)
rewrite_args = NULL; rewrite_args = NULL;
else if (rtn) else if (rtn)
rewrite_args->out_rtn = crewrite_args.out_rtn; rewrite_args->out_rtn = crewrite_args.out_rtn;
} else { } else {
rtn = callattrInternal0(obj, &attr_str, CLASS_ONLY, NULL, 0); rtn = callattrInternal0(obj, &attr_str, CLASS_ONLY, NULL, ArgPassSpec(0));
} }
if (rtn == NULL) { if (rtn == NULL) {
...@@ -1218,14 +1221,21 @@ extern "C" void dump(void* p) { ...@@ -1218,14 +1221,21 @@ extern "C" void dump(void* p) {
// For rewriting purposes, this function assumes that nargs will be constant. // For rewriting purposes, this function assumes that nargs will be constant.
// That's probably fine for some uses (ex binops), but otherwise it should be guarded on beforehand. // That's probably fine for some uses (ex binops), but otherwise it should be guarded on beforehand.
extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope scope, CallRewriteArgs* rewrite_args, extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope scope, CallRewriteArgs* rewrite_args,
int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args) { ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<const std::string*>* keyword_names) {
RELEASE_ASSERT(!argspec.has_starargs, "");
RELEASE_ASSERT(!argspec.has_kwargs, "");
RELEASE_ASSERT(argspec.num_keywords == 0, "");
int npassed_args = argspec.totalPassed();
if (rewrite_args) { if (rewrite_args) {
// if (VERBOSITY()) { // if (VERBOSITY()) {
// printf("callattrInternal: %d", rewrite_args->obj.getArgnum()); // printf("callattrInternal: %d", rewrite_args->obj.getArgnum());
// if (nargs >= 1) printf(" %d", rewrite_args->arg1.getArgnum()); // if (npassed_args >= 1) printf(" %d", rewrite_args->arg1.getArgnum());
// if (nargs >= 2) printf(" %d", rewrite_args->arg2.getArgnum()); // if (npassed_args >= 2) printf(" %d", rewrite_args->arg2.getArgnum());
// if (nargs >= 3) printf(" %d", rewrite_args->arg3.getArgnum()); // if (npassed_args >= 3) printf(" %d", rewrite_args->arg3.getArgnum());
// if (nargs >= 4) printf(" %d", rewrite_args->args.getArgnum()); // if (npassed_args >= 4) printf(" %d", rewrite_args->args.getArgnum());
// printf("\n"); // printf("\n");
//} //}
if (rewrite_args->obj.getArgnum() == -1) { if (rewrite_args->obj.getArgnum() == -1) {
...@@ -1240,19 +1250,19 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1240,19 +1250,19 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
// already fit, either since the type inferencer could determine that, // already fit, either since the type inferencer could determine that,
// or because they only need to fit into an UNKNOWN slot. // or because they only need to fit into an UNKNOWN slot.
if (nargs >= 1) if (npassed_args >= 1)
rewrite_args->arg1.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg1->cls); rewrite_args->arg1.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg1->cls);
if (nargs >= 2) if (npassed_args >= 2)
rewrite_args->arg2.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg2->cls); rewrite_args->arg2.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg2->cls);
// Have to move(-1) since the arg is (probably/maybe) on the stack; // Have to move(-1) since the arg is (probably/maybe) on the stack;
// TODO ideally would handle that case, but for now just do the move() which // TODO ideally would handle that case, but for now just do the move() which
// it knows how to handle // it knows how to handle
if (nargs >= 3) if (npassed_args >= 3)
rewrite_args->arg3.move(-2).addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg3->cls); rewrite_args->arg3.move(-2).addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg3->cls);
if (nargs > 3) { if (npassed_args > 3) {
RewriterVar r_args = rewrite_args->args.move(-3); RewriterVar r_args = rewrite_args->args.move(-3);
for (int i = 3; i < nargs; i++) { for (int i = 3; i < npassed_args; i++) {
// TODO if there are a lot of args (>16), might be better to increment a pointer // TODO if there are a lot of args (>16), might be better to increment a pointer
// rather index them directly? // rather index them directly?
r_args.getAttr((i - 3) * sizeof(Box*), -2).addAttrGuard(BOX_CLS_OFFSET, (intptr_t)args[i - 3]->cls); r_args.getAttr((i - 3) * sizeof(Box*), -2).addAttrGuard(BOX_CLS_OFFSET, (intptr_t)args[i - 3]->cls);
...@@ -1290,13 +1300,13 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1290,13 +1300,13 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
r_instattr.addGuard((intptr_t)inst_attr); r_instattr.addGuard((intptr_t)inst_attr);
rewrite_args->func_guarded = true; rewrite_args->func_guarded = true;
rtn = runtimeCallInternal(inst_attr, rewrite_args, nargs, arg1, arg2, arg3, args); rtn = runtimeCallInternal(inst_attr, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
if (rewrite_args->out_success) { if (rewrite_args->out_success) {
r_instattr = rewrite_args->rewriter->pop(0); r_instattr = rewrite_args->rewriter->pop(0);
} }
} else { } else {
rtn = runtimeCallInternal(inst_attr, NULL, nargs, arg1, arg2, arg3, args); rtn = runtimeCallInternal(inst_attr, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
} }
if (!rtn) { if (!rtn) {
...@@ -1341,23 +1351,26 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1341,23 +1351,26 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
// TODO copy from runtimeCall // TODO copy from runtimeCall
// TODO these two branches could probably be folded together (the first one is becoming // TODO these two branches could probably be folded together (the first one is becoming
// a subset of the second) // a subset of the second)
if (nargs <= 2) { if (npassed_args <= 2) {
Box* rtn; Box* rtn;
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_clsattr); CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_clsattr);
srewrite_args.arg1 = rewrite_args->obj; srewrite_args.arg1 = rewrite_args->obj;
// should be no-ops: // should be no-ops:
if (nargs >= 1) if (npassed_args >= 1)
srewrite_args.arg2 = rewrite_args->arg1; srewrite_args.arg2 = rewrite_args->arg1;
if (nargs >= 2) if (npassed_args >= 2)
srewrite_args.arg3 = rewrite_args->arg2; srewrite_args.arg3 = rewrite_args->arg2;
srewrite_args.func_guarded = true; srewrite_args.func_guarded = true;
srewrite_args.args_guarded = true; srewrite_args.args_guarded = true;
r_clsattr.push(); r_clsattr.push();
rtn = runtimeCallInternal(clsattr, &srewrite_args, nargs + 1, obj, arg1, arg2, NULL); rtn = runtimeCallInternal(
clsattr, &srewrite_args,
ArgPassSpec(argspec.num_args + 1, argspec.num_keywords, argspec.has_starargs, argspec.has_kwargs),
obj, arg1, arg2, NULL, keyword_names);
if (!srewrite_args.out_success) { if (!srewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
...@@ -1366,18 +1379,20 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1366,18 +1379,20 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
rewrite_args->out_rtn = srewrite_args.out_rtn; rewrite_args->out_rtn = srewrite_args.out_rtn;
} }
} else { } else {
rtn = runtimeCallInternal(clsattr, NULL, nargs + 1, obj, arg1, arg2, NULL); rtn = runtimeCallInternal(clsattr, NULL, ArgPassSpec(argspec.num_args + 1, argspec.num_keywords,
argspec.has_starargs, argspec.has_kwargs),
obj, arg1, arg2, NULL, keyword_names);
} }
if (rewrite_args) if (rewrite_args)
rewrite_args->out_success = true; rewrite_args->out_success = true;
return rtn; return rtn;
} else { } else {
int alloca_size = sizeof(Box*) * (nargs + 1 - 3); int alloca_size = sizeof(Box*) * (npassed_args + 1 - 3);
Box** new_args = (Box**)alloca(alloca_size); Box** new_args = (Box**)alloca(alloca_size);
new_args[0] = arg3; new_args[0] = arg3;
memcpy(new_args + 1, args, (nargs - 3) * sizeof(Box*)); memcpy(new_args + 1, args, (npassed_args - 3) * sizeof(Box*));
Box* rtn; Box* rtn;
if (rewrite_args) { if (rewrite_args) {
...@@ -1392,10 +1407,10 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1392,10 +1407,10 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
// Want to move them to // Want to move them to
// 1 2 X X // 1 2 X X
// if (nargs >= 1) rewrite_args->arg1 = rewrite_args->arg1.move(1); // if (npassed_args >= 1) rewrite_args->arg1 = rewrite_args->arg1.move(1);
// if (nargs >= 2) rewrite_args->arg2 = rewrite_args->arg2.move(2); // if (npassed_args >= 2) rewrite_args->arg2 = rewrite_args->arg2.move(2);
// if (nargs >= 3) rewrite_args->arg3 = rewrite_args->arg3.move(4); // if (npassed_args >= 3) rewrite_args->arg3 = rewrite_args->arg3.move(4);
// if (nargs >= 4) rewrite_args->args = rewrite_args->args.move(5); // if (npassed_args >= 4) rewrite_args->args = rewrite_args->args.move(5);
// There's nothing critical that these are in these registers, // There's nothing critical that these are in these registers,
// just that the register assignments for the rest of this // just that the register assignments for the rest of this
...@@ -1414,7 +1429,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1414,7 +1429,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
} }
// arg3 is now dead // arg3 is now dead
for (int i = 0; i < nargs - 3; i++) { for (int i = 0; i < npassed_args - 3; i++) {
RewriterVar arg; RewriterVar arg;
if (rewrite_args->args.isInReg()) if (rewrite_args->args.isInReg())
arg = rewrite_args->args.getAttr(i * sizeof(Box*), -2); arg = rewrite_args->args.getAttr(i * sizeof(Box*), -2);
...@@ -1428,18 +1443,21 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1428,18 +1443,21 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_clsattr); CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_clsattr);
srewrite_args.arg1 = rewrite_args->obj; srewrite_args.arg1 = rewrite_args->obj;
if (nargs >= 1) if (npassed_args >= 1)
srewrite_args.arg2 = rewrite_args->arg1; srewrite_args.arg2 = rewrite_args->arg1;
if (nargs >= 2) if (npassed_args >= 2)
srewrite_args.arg3 = rewrite_args->arg2; srewrite_args.arg3 = rewrite_args->arg2;
if (nargs >= 3) if (npassed_args >= 3)
srewrite_args.args = r_new_args; srewrite_args.args = r_new_args;
srewrite_args.args_guarded = true; srewrite_args.args_guarded = true;
srewrite_args.func_guarded = true; srewrite_args.func_guarded = true;
if (annotate) if (annotate)
rewrite_args->rewriter->annotate(0); rewrite_args->rewriter->annotate(0);
rtn = runtimeCallInternal(clsattr, &srewrite_args, nargs + 1, obj, arg1, arg2, new_args); rtn = runtimeCallInternal(
clsattr, &srewrite_args,
ArgPassSpec(argspec.num_args + 1, argspec.num_keywords, argspec.has_starargs, argspec.has_kwargs),
obj, arg1, arg2, new_args, keyword_names);
if (annotate) if (annotate)
rewrite_args->rewriter->annotate(1); rewrite_args->rewriter->annotate(1);
...@@ -1456,7 +1474,9 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1456,7 +1474,9 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
if (annotate) if (annotate)
rewrite_args->rewriter->annotate(2); rewrite_args->rewriter->annotate(2);
} else { } else {
rtn = runtimeCallInternal(clsattr, NULL, nargs + 1, obj, arg1, arg2, new_args); rtn = runtimeCallInternal(clsattr, NULL, ArgPassSpec(argspec.num_args + 1, argspec.num_keywords,
argspec.has_starargs, argspec.has_kwargs),
obj, arg1, arg2, new_args, keyword_names);
} }
return rtn; return rtn;
} }
...@@ -1467,24 +1487,24 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1467,24 +1487,24 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_clsattr); CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_clsattr);
if (nargs >= 1) if (npassed_args >= 1)
srewrite_args.arg1 = rewrite_args->arg1; srewrite_args.arg1 = rewrite_args->arg1;
if (nargs >= 2) if (npassed_args >= 2)
srewrite_args.arg2 = rewrite_args->arg2; srewrite_args.arg2 = rewrite_args->arg2;
if (nargs >= 3) if (npassed_args >= 3)
srewrite_args.arg3 = rewrite_args->arg3; srewrite_args.arg3 = rewrite_args->arg3;
if (nargs >= 4) if (npassed_args >= 4)
srewrite_args.args = rewrite_args->args; srewrite_args.args = rewrite_args->args;
srewrite_args.args_guarded = true; srewrite_args.args_guarded = true;
rtn = runtimeCallInternal(clsattr, &srewrite_args, nargs, arg1, arg2, arg3, args); rtn = runtimeCallInternal(clsattr, &srewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
if (!srewrite_args.out_success) if (!srewrite_args.out_success)
rewrite_args = NULL; rewrite_args = NULL;
else else
rewrite_args->out_rtn = srewrite_args.out_rtn; rewrite_args->out_rtn = srewrite_args.out_rtn;
} else { } else {
rtn = runtimeCallInternal(clsattr, NULL, nargs, arg1, arg2, arg3, args); rtn = runtimeCallInternal(clsattr, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
} }
if (!rtn) { if (!rtn) {
...@@ -1497,14 +1517,22 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1497,14 +1517,22 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
} }
} }
extern "C" Box* callattr(Box* obj, std::string* attr, bool clsonly, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, extern "C" Box* callattr(Box* obj, std::string* attr, bool clsonly, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box** args) { Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names) {
RELEASE_ASSERT(!argspec.has_starargs, "");
RELEASE_ASSERT(!argspec.has_kwargs, "");
RELEASE_ASSERT(argspec.num_keywords == 0, "");
int npassed_args = argspec.totalPassed();
static StatCounter slowpath_callattr("slowpath_callattr"); static StatCounter slowpath_callattr("slowpath_callattr");
slowpath_callattr.log(); slowpath_callattr.log();
assert(attr); assert(attr);
int num_orig_args = 4 + std::min(4L, nargs); int num_orig_args = 4 + std::min(4, npassed_args);
if (keyword_names)
num_orig_args++;
std::unique_ptr<Rewriter> rewriter(Rewriter::createRewriter( std::unique_ptr<Rewriter> rewriter(Rewriter::createRewriter(
__builtin_extract_return_addr(__builtin_return_address(0)), num_orig_args, 2, "callattr")); __builtin_extract_return_addr(__builtin_return_address(0)), num_orig_args, 2, "callattr"));
Box* rtn; Box* rtn;
...@@ -1516,18 +1544,18 @@ extern "C" Box* callattr(Box* obj, std::string* attr, bool clsonly, int64_t narg ...@@ -1516,18 +1544,18 @@ extern "C" Box* callattr(Box* obj, std::string* attr, bool clsonly, int64_t narg
// TODO feel weird about doing this; it either isn't necessary // TODO feel weird about doing this; it either isn't necessary
// or this kind of thing is necessary in a lot more places // or this kind of thing is necessary in a lot more places
// rewriter->getArg(3).addGuard(nargs); // rewriter->getArg(3).addGuard(npassed_args);
CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0));
if (nargs >= 1) if (npassed_args >= 1)
rewrite_args.arg1 = rewriter->getArg(4); rewrite_args.arg1 = rewriter->getArg(4);
if (nargs >= 2) if (npassed_args >= 2)
rewrite_args.arg2 = rewriter->getArg(5); rewrite_args.arg2 = rewriter->getArg(5);
if (nargs >= 3) if (npassed_args >= 3)
rewrite_args.arg3 = rewriter->getArg(6); rewrite_args.arg3 = rewriter->getArg(6);
if (nargs >= 4) if (npassed_args >= 4)
rewrite_args.args = rewriter->getArg(7); rewrite_args.args = rewriter->getArg(7);
rtn = callattrInternal(obj, attr, scope, &rewrite_args, nargs, arg1, arg2, arg3, args); rtn = callattrInternal(obj, attr, scope, &rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
if (!rewrite_args.out_success) { if (!rewrite_args.out_success) {
rewriter.reset(NULL); rewriter.reset(NULL);
...@@ -1535,7 +1563,7 @@ extern "C" Box* callattr(Box* obj, std::string* attr, bool clsonly, int64_t narg ...@@ -1535,7 +1563,7 @@ extern "C" Box* callattr(Box* obj, std::string* attr, bool clsonly, int64_t narg
rewrite_args.out_rtn.move(-1); rewrite_args.out_rtn.move(-1);
} }
} else { } else {
rtn = callattrInternal(obj, attr, scope, NULL, nargs, arg1, arg2, arg3, args); rtn = callattrInternal(obj, attr, scope, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
} }
if (rtn == NULL) { if (rtn == NULL) {
...@@ -1547,122 +1575,349 @@ extern "C" Box* callattr(Box* obj, std::string* attr, bool clsonly, int64_t narg ...@@ -1547,122 +1575,349 @@ extern "C" Box* callattr(Box* obj, std::string* attr, bool clsonly, int64_t narg
return rtn; return rtn;
} }
Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, CompiledFunction* resolveCLFunc(CLFunction* f, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
Box** args) { const std::vector<const std::string*>* keyword_names) {
// the 10M upper bound isn't a hard max, just almost certainly a bug RELEASE_ASSERT(!argspec.has_starargs, "");
// (also the alloca later will probably fail anyway) RELEASE_ASSERT(!argspec.has_kwargs, "");
ASSERT(nargs >= 0 && nargs < 10000000, "%ld", nargs); RELEASE_ASSERT(argspec.num_keywords == 0, "");
Box* orig_obj = obj; int64_t nargs = argspec.totalPassed();
if (obj->cls != function_cls && obj->cls != instancemethod_cls) { static StatCounter slowpath_resolveclfunc("slowpath_resolveclfunc");
Box* rtn; slowpath_resolveclfunc.log();
if (rewrite_args) {
// TODO is this ok? FunctionList& versions = f->versions;
// rewrite_args->rewriter->trap();
rtn = callattrInternal(obj, &_call_str, CLASS_ONLY, rewrite_args, nargs, arg1, arg2, arg3, args); for (int i = 0; i < versions.size(); i++) {
CompiledFunction* cf = versions[i];
FunctionSignature* sig = cf->sig;
assert(!sig->takes_kwargs && "not handled yet");
if (sig->rtn_type->llvmType() != UNKNOWN->llvmType())
continue;
if ((!sig->takes_varargs && sig->arg_types.size() != nargs)
|| (sig->takes_varargs && nargs < sig->arg_types.size()))
continue;
int nsig_args = sig->arg_types.size();
if (nsig_args >= 1) {
if (sig->arg_types[0]->isFitBy(arg1->cls)) {
// pass
} else { } else {
rtn = callattrInternal(obj, &_call_str, CLASS_ONLY, NULL, nargs, arg1, arg2, arg3, args); continue;
}
}
if (nsig_args >= 2) {
if (sig->arg_types[1]->isFitBy(arg2->cls)) {
// pass
} else {
continue;
}
}
if (nsig_args >= 3) {
if (sig->arg_types[2]->isFitBy(arg3->cls)) {
// pass
} else {
continue;
} }
if (!rtn)
raiseExcHelper(TypeError, "'%s' object is not callable", getTypeName(obj)->c_str());
return rtn;
} }
bool bad = false;
for (int j = 3; j < nsig_args; j++) {
if (sig->arg_types[j]->isFitBy(args[j - 3]->cls)) {
// pass
} else {
bad = true;
break;
}
}
if (bad)
continue;
if (rewrite_args) { assert(cf);
if (!rewrite_args->args_guarded) { assert(!cf->entry_descriptor);
// TODO should know which args don't need to be guarded, ex if we're guaranteed that they assert(cf->is_interpreted == (cf->code == NULL));
// already fit, either since the type inferencer could determine that,
// or because they only need to fit into an UNKNOWN slot.
if (nargs >= 1) return cf;
rewrite_args->arg1.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg1->cls);
if (nargs >= 2)
rewrite_args->arg2.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg2->cls);
if (nargs >= 3)
rewrite_args->arg3.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg3->cls);
for (int i = 3; i < nargs; i++) {
rewrite_args->args.getAttr((i - 3) * sizeof(Box*), -1)
.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)args[i - 3]->cls);
} }
if (f->source == NULL) {
printf("Error: couldn't find suitable function version and no source to recompile!\n");
printf("%ld args:", nargs);
for (int i = 0; i < nargs; i++) {
if (i == 3) {
printf(" [and more]");
break;
} }
rewrite_args->rewriter->addDecision(obj->cls == function_cls ? 1 : 0); Box* firstargs[] = { arg1, arg2, arg3 };
printf(" %s", getTypeName(firstargs[i])->c_str());
}
printf("\n");
for (int j = 0; j < f->versions.size(); j++) {
std::string func_name = g.func_addr_registry.getFuncNameAtAddress(f->versions[j]->code, true);
printf("Version %d, %s:", j, func_name.c_str());
FunctionSignature* sig = f->versions[j]->sig;
for (int i = 0; i < sig->arg_types.size(); i++) {
printf(" %s", sig->arg_types[i]->debugName().c_str());
}
if (sig->takes_varargs)
printf(" *vararg");
if (sig->takes_kwargs)
printf(" *kwarg");
printf("\n");
// printf(" @%p %s\n", f->versions[j]->code, func_name.c_str());
}
abort();
} }
if (obj->cls == function_cls) { assert(f->source->getArgsAST()->vararg.size() == 0);
BoxedFunction* f = static_cast<BoxedFunction*>(obj); assert(f->source->getArgsAST()->kwarg.size() == 0);
assert(f->source->getArgsAST()->defaults.size() == 0);
bool takes_varargs = false;
bool takes_kwargs = false;
int ndefaults = 0;
std::vector<ConcreteCompilerType*> arg_types;
if (nargs >= 1) {
arg_types.push_back(typeFromClass(arg1->cls));
}
if (nargs >= 2) {
arg_types.push_back(typeFromClass(arg2->cls));
}
if (nargs >= 3) {
arg_types.push_back(typeFromClass(arg3->cls));
}
for (int j = 3; j < nargs; j++) {
arg_types.push_back(typeFromClass(args[j - 3]->cls));
}
FunctionSignature* sig
= new FunctionSignature(UNKNOWN, &f->source->getArgNames(), arg_types, ndefaults, takes_varargs, takes_kwargs);
CompiledFunction* cf = resolveCLFunc(f->f, nargs, arg1, arg2, arg3, args); EffortLevel::EffortLevel new_effort = initialEffort();
// typeCall (ie the base for constructors) is important enough that it knows CompiledFunction* cf = compileFunction(f, sig, new_effort,
// how to do rewrites, so lets cut directly to the internal function rather NULL); // this pushes the new CompiledVersion to the back of the version list
// than hitting its python bindings: assert(cf->is_interpreted == (cf->code == NULL));
if (cf->code == typeCall) {
Box* rtn; return cf;
if (rewrite_args) { }
CallRewriteArgs srewrite_args(rewrite_args->rewriter, RewriterVar());
if (nargs >= 1) Box* callCompiledFunc(CompiledFunction* cf, ArgPassSpec argspec, Box* iarg1, Box* iarg2, Box* iarg3, Box** iargs,
srewrite_args.arg1 = rewrite_args->arg1; const std::vector<const std::string*>* keyword_names) {
if (nargs >= 2) RELEASE_ASSERT(!argspec.has_starargs, "");
srewrite_args.arg2 = rewrite_args->arg2; RELEASE_ASSERT(!argspec.has_kwargs, "");
if (nargs >= 3)
srewrite_args.arg3 = rewrite_args->arg3; int64_t npassed_args = argspec.totalPassed();
if (nargs >= 4)
srewrite_args.args = rewrite_args->args; assert(cf);
rtn = typeCallInternal(&srewrite_args, nargs, arg1, arg2, arg3, args);
if (!srewrite_args.out_success) // TODO these shouldn't have to be initialized, but I don't want to issue a #pragma
rewrite_args = NULL; // that disables the warning for the whole file:
Box* oarg1 = NULL, *oarg2 = NULL, *oarg3 = NULL;
Box** oargs = NULL;
int num_out_args = npassed_args;
if (cf->sig->takes_varargs)
num_out_args++;
assert(!cf->sig->takes_kwargs);
if (cf->sig->takes_kwargs)
num_out_args++;
assert(!cf->sig->ndefaults);
num_out_args += cf->sig->ndefaults;
if (num_out_args > 3)
oargs = (Box**)alloca((num_out_args - 3) * sizeof(Box*));
int nsig_args = cf->sig->arg_types.size();
std::vector<bool> keywords_used(false, argspec.num_keywords);
// First, fill formal parameters from positional arguments:
for (int i = 0; i < std::min((int)argspec.num_args, nsig_args); i++) {
if (i == 0)
oarg1 = iarg1;
else if (i == 1)
oarg2 = iarg2;
else if (i == 2)
oarg3 = iarg3;
else else
rewrite_args->out_rtn = srewrite_args.out_rtn; oargs[i - 3] = iargs[i - 3];
}
// Then, fill any remaining formal parameters from keywords:
if (argspec.num_args < nsig_args) {
const std::vector<AST_expr*>* arg_names = cf->sig->arg_names;
assert(arg_names);
assert(arg_names->size() == nsig_args);
for (int j = argspec.num_args; j < nsig_args; j++) {
assert((*arg_names)[j]->type == AST_TYPE::Name); // we should already have picked a good signature
const std::string& name = ast_cast<AST_Name>((*arg_names)[j])->id;
bool found = false;
for (int i = 0; i < keyword_names->size(); i++) {
if (keywords_used[i])
continue;
if (*(*keyword_names)[i] == name) {
found = true;
keywords_used[i] = true;
int from_arg = argspec.num_args + i;
Box* arg;
if (from_arg == 0)
arg = iarg1;
else if (from_arg == 1)
arg = iarg2;
else if (from_arg == 2)
arg = iarg3;
else
arg = iargs[from_arg - 3];
if (j == 0)
oarg1 = arg;
else if (j == 1)
oarg2 = arg;
else if (j == 2)
oarg3 = arg;
else
oargs[j - 3] = arg;
break;
}
}
assert(found); // should have been disallowed
}
}
assert(!cf->sig->takes_kwargs);
for (bool b : keywords_used)
assert(b);
if (cf->sig->takes_varargs) {
BoxedList* made_vararg = (BoxedList*)createList();
if (nsig_args == 0)
oarg1 = made_vararg;
else if (nsig_args == 1)
oarg2 = made_vararg;
else if (nsig_args == 2)
oarg3 = made_vararg;
else
oargs[nsig_args - 3] = made_vararg;
assert(argspec.num_args == npassed_args);
for (int i = nsig_args; i < npassed_args; i++) {
if (i == 0)
listAppendInternal(made_vararg, iarg1);
else if (i == 1)
listAppendInternal(made_vararg, iarg2);
else if (i == 2)
listAppendInternal(made_vararg, iarg3);
else
listAppendInternal(made_vararg, iargs[i - 3]);
}
} else { } else {
rtn = typeCallInternal(NULL, nargs, arg1, arg2, arg3, args); assert(!cf->sig->takes_kwargs);
assert(nsig_args == npassed_args);
} }
if (rewrite_args) if (!cf->is_interpreted) {
rewrite_args->out_success = true; return cf->call(oarg1, oarg2, oarg3, oargs);
return rtn; } else {
return interpretFunction(cf->func, num_out_args, oarg1, oarg2, oarg3, oargs);
} }
}
Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<const std::string*>* keyword_names) {
int npassed_args = argspec.totalPassed();
if (cf->sig->is_vararg) { CompiledFunction* cf = resolveCLFunc(func->f, argspec, arg1, arg2, arg3, args, keyword_names);
if (cf->sig->takes_varargs || cf->sig->takes_kwargs || argspec.num_keywords || argspec.has_starargs
|| argspec.has_kwargs) {
if (rewrite_args && VERBOSITY()) if (rewrite_args && VERBOSITY())
printf("Not patchpointing this varargs function\n"); printf("Not patchpointing this non-simple function call\n");
rewrite_args = NULL; rewrite_args = NULL;
} }
if (cf->is_interpreted) if (cf->is_interpreted)
rewrite_args = NULL; rewrite_args = NULL;
if (rewrite_args) { if (rewrite_args) {
// TODO should it be the func object or its CLFunction?
if (!rewrite_args->func_guarded) if (!rewrite_args->func_guarded)
rewrite_args->obj.addGuard((intptr_t)obj); rewrite_args->obj.addGuard((intptr_t)func);
rewrite_args->rewriter->addDependenceOn(cf->dependent_callsites); rewrite_args->rewriter->addDependenceOn(cf->dependent_callsites);
// if (VERBOSITY()) { if (npassed_args >= 1)
// printf("runtimeCallInternal: %d", rewrite_args->obj.getArgnum());
// if (nargs >= 1) printf(" %d", rewrite_args->arg1.getArgnum());
// if (nargs >= 2) printf(" %d", rewrite_args->arg2.getArgnum());
// if (nargs >= 3) printf(" %d", rewrite_args->arg3.getArgnum());
// if (nargs >= 4) printf(" %d", rewrite_args->args.getArgnum());
// printf("\n");
//}
if (nargs >= 1)
rewrite_args->arg1.move(0); rewrite_args->arg1.move(0);
if (nargs >= 2) if (npassed_args >= 2)
rewrite_args->arg2.move(1); rewrite_args->arg2.move(1);
if (nargs >= 3) if (npassed_args >= 3)
rewrite_args->arg3.move(2); rewrite_args->arg3.move(2);
if (nargs >= 4) if (npassed_args >= 4)
rewrite_args->args.move(3); rewrite_args->args.move(3);
RewriterVar r_rtn = rewrite_args->rewriter->call(cf->code); RewriterVar r_rtn = rewrite_args->rewriter->call(cf->code);
rewrite_args->out_rtn = r_rtn.move(-1); rewrite_args->out_rtn = r_rtn.move(-1);
} }
Box* rtn = callCompiledFunc(cf, nargs, arg1, arg2, arg3, args); Box* rtn = callCompiledFunc(cf, argspec, arg1, arg2, arg3, args, keyword_names);
if (rewrite_args) if (rewrite_args)
rewrite_args->out_success = true; rewrite_args->out_success = true;
return rtn; return rtn;
}
Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<const std::string*>* keyword_names) {
int npassed_args = argspec.totalPassed();
Box* orig_obj = obj;
if (obj->cls != function_cls && obj->cls != instancemethod_cls) {
Box* rtn;
if (rewrite_args) {
// TODO is this ok?
// rewrite_args->rewriter->trap();
rtn = callattrInternal(obj, &_call_str, CLASS_ONLY, rewrite_args, argspec, arg1, arg2, arg3, args,
keyword_names);
} else {
rtn = callattrInternal(obj, &_call_str, CLASS_ONLY, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
}
if (!rtn)
raiseExcHelper(TypeError, "'%s' object is not callable", getTypeName(obj)->c_str());
return rtn;
}
if (rewrite_args) {
if (!rewrite_args->args_guarded) {
// TODO should know which args don't need to be guarded, ex if we're guaranteed that they
// already fit, either since the type inferencer could determine that,
// or because they only need to fit into an UNKNOWN slot.
if (npassed_args >= 1)
rewrite_args->arg1.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg1->cls);
if (npassed_args >= 2)
rewrite_args->arg2.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg2->cls);
if (npassed_args >= 3)
rewrite_args->arg3.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg3->cls);
for (int i = 3; i < npassed_args; i++) {
rewrite_args->args.getAttr((i - 3) * sizeof(Box*), -1)
.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)args[i - 3]->cls);
}
}
rewrite_args->rewriter->addDecision(obj->cls == function_cls ? 1 : 0);
}
if (obj->cls == function_cls) {
BoxedFunction* f = static_cast<BoxedFunction*>(obj);
// Some functions are sufficiently important that we want them to be able to patchpoint themselves;
// they can do this by setting the "internal_callable" field:
CLFunction::InternalCallable callable = f->f->internal_callable;
if (callable == NULL)
callable = callFunc;
return callable(f, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
} else if (obj->cls == instancemethod_cls) { } else if (obj->cls == instancemethod_cls) {
// TODO it's dumb but I should implement patchpoints here as well // TODO it's dumb but I should implement patchpoints here as well
// duplicated with callattr // duplicated with callattr
...@@ -1672,7 +1927,7 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, int64_t nargs, ...@@ -1672,7 +1927,7 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, int64_t nargs,
rewrite_args->obj.addAttrGuard(INSTANCEMETHOD_FUNC_OFFSET, (intptr_t)im->func); rewrite_args->obj.addAttrGuard(INSTANCEMETHOD_FUNC_OFFSET, (intptr_t)im->func);
} }
if (nargs <= 2) { if (npassed_args <= 2) {
Box* rtn; Box* rtn;
if (rewrite_args) { if (rewrite_args) {
// Kind of weird that we don't need to give this a valid RewriterVar, but it shouldn't need to access it // Kind of weird that we don't need to give this a valid RewriterVar, but it shouldn't need to access it
...@@ -1682,12 +1937,15 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, int64_t nargs, ...@@ -1682,12 +1937,15 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, int64_t nargs,
srewrite_args.arg1 = rewrite_args->obj.getAttr(INSTANCEMETHOD_OBJ_OFFSET, 0); srewrite_args.arg1 = rewrite_args->obj.getAttr(INSTANCEMETHOD_OBJ_OFFSET, 0);
srewrite_args.func_guarded = true; srewrite_args.func_guarded = true;
srewrite_args.args_guarded = true; srewrite_args.args_guarded = true;
if (nargs >= 1) if (npassed_args >= 1)
srewrite_args.arg2 = rewrite_args->arg1; srewrite_args.arg2 = rewrite_args->arg1;
if (nargs >= 2) if (npassed_args >= 2)
srewrite_args.arg3 = rewrite_args->arg2; srewrite_args.arg3 = rewrite_args->arg2;
rtn = runtimeCallInternal(im->func, &srewrite_args, nargs + 1, im->obj, arg1, arg2, NULL); rtn = runtimeCallInternal(
im->func, &srewrite_args,
ArgPassSpec(argspec.num_args + 1, argspec.num_keywords, argspec.has_starargs, argspec.has_kwargs),
im->obj, arg1, arg2, NULL, keyword_names);
if (!srewrite_args.out_success) { if (!srewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
...@@ -1695,16 +1953,20 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, int64_t nargs, ...@@ -1695,16 +1953,20 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, int64_t nargs,
rewrite_args->out_rtn = srewrite_args.out_rtn.move(-1); rewrite_args->out_rtn = srewrite_args.out_rtn.move(-1);
} }
} else { } else {
rtn = runtimeCallInternal(im->func, NULL, nargs + 1, im->obj, arg1, arg2, NULL); rtn = runtimeCallInternal(im->func, NULL, ArgPassSpec(argspec.num_args + 1, argspec.num_keywords,
argspec.has_starargs, argspec.has_kwargs),
im->obj, arg1, arg2, NULL, keyword_names);
} }
if (rewrite_args) if (rewrite_args)
rewrite_args->out_success = true; rewrite_args->out_success = true;
return rtn; return rtn;
} else { } else {
Box** new_args = (Box**)alloca(sizeof(Box*) * (nargs + 1 - 3)); Box** new_args = (Box**)alloca(sizeof(Box*) * (npassed_args + 1 - 3));
new_args[0] = arg3; new_args[0] = arg3;
memcpy(new_args + 1, args, (nargs - 3) * sizeof(Box*)); memcpy(new_args + 1, args, (npassed_args - 3) * sizeof(Box*));
Box* rtn = runtimeCall(im->func, nargs + 1, im->obj, arg1, arg2, new_args); Box* rtn = runtimeCall(im->func, ArgPassSpec(argspec.num_args + 1, argspec.num_keywords,
argspec.has_starargs, argspec.has_kwargs),
im->obj, arg1, arg2, new_args, keyword_names);
return rtn; return rtn;
} }
} }
...@@ -1712,11 +1974,16 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, int64_t nargs, ...@@ -1712,11 +1974,16 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, int64_t nargs,
abort(); abort();
} }
extern "C" Box* runtimeCall(Box* obj, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args) { extern "C" Box* runtimeCall(Box* obj, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<const std::string*>* keyword_names) {
int npassed_args = argspec.totalPassed();
static StatCounter slowpath_runtimecall("slowpath_runtimecall"); static StatCounter slowpath_runtimecall("slowpath_runtimecall");
slowpath_runtimecall.log(); slowpath_runtimecall.log();
int num_orig_args = 2 + std::min(4L, nargs); int num_orig_args = 2 + std::min(4, npassed_args);
if (argspec.num_keywords > 0)
num_orig_args++;
std::unique_ptr<Rewriter> rewriter(Rewriter::createRewriter( std::unique_ptr<Rewriter> rewriter(Rewriter::createRewriter(
__builtin_extract_return_addr(__builtin_return_address(0)), num_orig_args, 2, "runtimeCall")); __builtin_extract_return_addr(__builtin_return_address(0)), num_orig_args, 2, "runtimeCall"));
Box* rtn; Box* rtn;
...@@ -1726,18 +1993,18 @@ extern "C" Box* runtimeCall(Box* obj, int64_t nargs, Box* arg1, Box* arg2, Box* ...@@ -1726,18 +1993,18 @@ extern "C" Box* runtimeCall(Box* obj, int64_t nargs, Box* arg1, Box* arg2, Box*
// TODO feel weird about doing this; it either isn't necessary // TODO feel weird about doing this; it either isn't necessary
// or this kind of thing is necessary in a lot more places // or this kind of thing is necessary in a lot more places
// rewriter->getArg(1).addGuard(nargs); // rewriter->getArg(1).addGuard(npassed_args);
CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0));
if (nargs >= 1) if (npassed_args >= 1)
rewrite_args.arg1 = rewriter->getArg(2); rewrite_args.arg1 = rewriter->getArg(2);
if (nargs >= 2) if (npassed_args >= 2)
rewrite_args.arg2 = rewriter->getArg(3); rewrite_args.arg2 = rewriter->getArg(3);
if (nargs >= 3) if (npassed_args >= 3)
rewrite_args.arg3 = rewriter->getArg(4); rewrite_args.arg3 = rewriter->getArg(4);
if (nargs >= 4) if (npassed_args >= 4)
rewrite_args.args = rewriter->getArg(5); rewrite_args.args = rewriter->getArg(5);
rtn = runtimeCallInternal(obj, &rewrite_args, nargs, arg1, arg2, arg3, args); rtn = runtimeCallInternal(obj, &rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
if (!rewrite_args.out_success) { if (!rewrite_args.out_success) {
rewriter.reset(NULL); rewriter.reset(NULL);
...@@ -1745,7 +2012,7 @@ extern "C" Box* runtimeCall(Box* obj, int64_t nargs, Box* arg1, Box* arg2, Box* ...@@ -1745,7 +2012,7 @@ extern "C" Box* runtimeCall(Box* obj, int64_t nargs, Box* arg1, Box* arg2, Box*
rewrite_args.out_rtn.move(-1); rewrite_args.out_rtn.move(-1);
} }
} else { } else {
rtn = runtimeCallInternal(obj, NULL, nargs, arg1, arg2, arg3, args); rtn = runtimeCallInternal(obj, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
} }
assert(rtn); assert(rtn);
...@@ -1780,14 +2047,14 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin ...@@ -1780,14 +2047,14 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, rewrite_args->lhs); CallRewriteArgs srewrite_args(rewrite_args->rewriter, rewrite_args->lhs);
srewrite_args.arg1 = rewrite_args->rhs; srewrite_args.arg1 = rewrite_args->rhs;
irtn = callattrInternal1(lhs, &iop_name, CLASS_ONLY, &srewrite_args, 1, rhs); irtn = callattrInternal1(lhs, &iop_name, CLASS_ONLY, &srewrite_args, ArgPassSpec(1), rhs);
if (!srewrite_args.out_success) if (!srewrite_args.out_success)
rewrite_args = NULL; rewrite_args = NULL;
else if (irtn) else if (irtn)
rewrite_args->out_rtn = srewrite_args.out_rtn.move(-1); rewrite_args->out_rtn = srewrite_args.out_rtn.move(-1);
} else { } else {
irtn = callattrInternal1(lhs, &iop_name, CLASS_ONLY, NULL, 1, rhs); irtn = callattrInternal1(lhs, &iop_name, CLASS_ONLY, NULL, ArgPassSpec(1), rhs);
} }
if (irtn) { if (irtn) {
...@@ -1807,14 +2074,14 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin ...@@ -1807,14 +2074,14 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, rewrite_args->lhs); CallRewriteArgs srewrite_args(rewrite_args->rewriter, rewrite_args->lhs);
srewrite_args.arg1 = rewrite_args->rhs; srewrite_args.arg1 = rewrite_args->rhs;
lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, &srewrite_args, 1, rhs); lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, &srewrite_args, ArgPassSpec(1), rhs);
if (!srewrite_args.out_success) if (!srewrite_args.out_success)
rewrite_args = NULL; rewrite_args = NULL;
else if (lrtn) else if (lrtn)
rewrite_args->out_rtn = srewrite_args.out_rtn.move(-1); rewrite_args->out_rtn = srewrite_args.out_rtn.move(-1);
} else { } else {
lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, NULL, 1, rhs); lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, NULL, ArgPassSpec(1), rhs);
} }
...@@ -1834,7 +2101,7 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin ...@@ -1834,7 +2101,7 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin
} }
std::string rop_name = getReverseOpName(op_type); std::string rop_name = getReverseOpName(op_type);
Box* rrtn = callattrInternal1(rhs, &rop_name, CLASS_ONLY, NULL, 1, lhs); Box* rrtn = callattrInternal1(rhs, &rop_name, CLASS_ONLY, NULL, ArgPassSpec(1), lhs);
if (rrtn != NULL && rrtn != NotImplemented) if (rrtn != NULL && rrtn != NotImplemented)
return rrtn; return rrtn;
...@@ -1966,10 +2233,10 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit ...@@ -1966,10 +2233,10 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
// TODO do rewrite // TODO do rewrite
static const std::string str_contains("__contains__"); static const std::string str_contains("__contains__");
Box* contained = callattrInternal1(rhs, &str_contains, CLASS_ONLY, NULL, 1, lhs); Box* contained = callattrInternal1(rhs, &str_contains, CLASS_ONLY, NULL, ArgPassSpec(1), lhs);
if (contained == NULL) { if (contained == NULL) {
static const std::string str_iter("__iter__"); static const std::string str_iter("__iter__");
Box* iter = callattrInternal0(rhs, &str_iter, CLASS_ONLY, NULL, 0); Box* iter = callattrInternal0(rhs, &str_iter, CLASS_ONLY, NULL, ArgPassSpec(0));
if (iter) if (iter)
ASSERT(isUserDefined(rhs->cls), "%s should probably have a __contains__", getTypeName(rhs)->c_str()); ASSERT(isUserDefined(rhs->cls), "%s should probably have a __contains__", getTypeName(rhs)->c_str());
RELEASE_ASSERT(iter == NULL, "need to try iterating"); RELEASE_ASSERT(iter == NULL, "need to try iterating");
...@@ -2006,14 +2273,14 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit ...@@ -2006,14 +2273,14 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->lhs); CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->lhs);
crewrite_args.arg1 = rewrite_args->rhs; crewrite_args.arg1 = rewrite_args->rhs;
lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, &crewrite_args, 1, rhs); lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, &crewrite_args, ArgPassSpec(1), rhs);
if (!crewrite_args.out_success) if (!crewrite_args.out_success)
rewrite_args = NULL; rewrite_args = NULL;
else if (lrtn) else if (lrtn)
rewrite_args->out_rtn = crewrite_args.out_rtn; rewrite_args->out_rtn = crewrite_args.out_rtn;
} else { } else {
lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, NULL, 1, rhs); lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, NULL, ArgPassSpec(1), rhs);
} }
if (lrtn) { if (lrtn) {
...@@ -2035,7 +2302,7 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit ...@@ -2035,7 +2302,7 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
} }
std::string rop_name = getReverseOpName(op_type); std::string rop_name = getReverseOpName(op_type);
Box* rrtn = callattrInternal1(rhs, &rop_name, CLASS_ONLY, NULL, 1, lhs); Box* rrtn = callattrInternal1(rhs, &rop_name, CLASS_ONLY, NULL, ArgPassSpec(1), lhs);
if (rrtn != NULL && rrtn != NotImplemented) if (rrtn != NULL && rrtn != NotImplemented)
return rrtn; return rrtn;
...@@ -2117,7 +2384,7 @@ extern "C" Box* unaryop(Box* operand, int op_type) { ...@@ -2117,7 +2384,7 @@ extern "C" Box* unaryop(Box* operand, int op_type) {
ASSERT(attr_func, "%s.%s", getTypeName(operand)->c_str(), op_name.c_str()); ASSERT(attr_func, "%s.%s", getTypeName(operand)->c_str(), op_name.c_str());
Box* rtn = runtimeCall0(attr_func, 0); Box* rtn = runtimeCall0(attr_func, ArgPassSpec(0));
return rtn; return rtn;
} }
...@@ -2138,14 +2405,14 @@ extern "C" Box* getitem(Box* value, Box* slice) { ...@@ -2138,14 +2405,14 @@ extern "C" Box* getitem(Box* value, Box* slice) {
CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0));
rewrite_args.arg1 = rewriter->getArg(1); rewrite_args.arg1 = rewriter->getArg(1);
rtn = callattrInternal1(value, &str_getitem, CLASS_ONLY, &rewrite_args, 1, slice); rtn = callattrInternal1(value, &str_getitem, CLASS_ONLY, &rewrite_args, ArgPassSpec(1), slice);
if (!rewrite_args.out_success) if (!rewrite_args.out_success)
rewriter.reset(NULL); rewriter.reset(NULL);
else if (rtn) else if (rtn)
rewrite_args.out_rtn.move(-1); rewrite_args.out_rtn.move(-1);
} else { } else {
rtn = callattrInternal1(value, &str_getitem, CLASS_ONLY, NULL, 1, slice); rtn = callattrInternal1(value, &str_getitem, CLASS_ONLY, NULL, ArgPassSpec(1), slice);
} }
if (rtn == NULL) { if (rtn == NULL) {
...@@ -2181,14 +2448,14 @@ extern "C" void setitem(Box* target, Box* slice, Box* value) { ...@@ -2181,14 +2448,14 @@ extern "C" void setitem(Box* target, Box* slice, Box* value) {
rewrite_args.arg1 = rewriter->getArg(1); rewrite_args.arg1 = rewriter->getArg(1);
rewrite_args.arg2 = rewriter->getArg(2); rewrite_args.arg2 = rewriter->getArg(2);
rtn = callattrInternal2(target, &str_setitem, CLASS_ONLY, &rewrite_args, 2, slice, value); rtn = callattrInternal2(target, &str_setitem, CLASS_ONLY, &rewrite_args, ArgPassSpec(2), slice, value);
if (!rewrite_args.out_success) if (!rewrite_args.out_success)
rewriter.reset(NULL); rewriter.reset(NULL);
else if (rtn) else if (rtn)
r_rtn = rewrite_args.out_rtn; r_rtn = rewrite_args.out_rtn;
} else { } else {
rtn = callattrInternal2(target, &str_setitem, CLASS_ONLY, NULL, 2, slice, value); rtn = callattrInternal2(target, &str_setitem, CLASS_ONLY, NULL, ArgPassSpec(2), slice, value);
} }
if (rtn == NULL) { if (rtn == NULL) {
...@@ -2215,14 +2482,14 @@ extern "C" void delitem(Box* target, Box* slice) { ...@@ -2215,14 +2482,14 @@ extern "C" void delitem(Box* target, Box* slice) {
CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0));
rewrite_args.arg1 = rewriter->getArg(1); rewrite_args.arg1 = rewriter->getArg(1);
rtn = callattrInternal1(target, &str_delitem, CLASS_ONLY, &rewrite_args, 1, slice); rtn = callattrInternal1(target, &str_delitem, CLASS_ONLY, &rewrite_args, ArgPassSpec(1), slice);
if (!rewrite_args.out_success) if (!rewrite_args.out_success)
rewriter.reset(NULL); rewriter.reset(NULL);
else if (rtn) else if (rtn)
r_rtn = rewrite_args.out_rtn; r_rtn = rewrite_args.out_rtn;
} else { } else {
rtn = callattrInternal1(target, &str_delitem, CLASS_ONLY, NULL, 1, slice); rtn = callattrInternal1(target, &str_delitem, CLASS_ONLY, NULL, ArgPassSpec(1), slice);
} }
if (rtn == NULL) { if (rtn == NULL) {
...@@ -2241,16 +2508,23 @@ static void assertInitNone(Box* obj) { ...@@ -2241,16 +2508,23 @@ static void assertInitNone(Box* obj) {
} }
} }
Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args) { Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names) {
RELEASE_ASSERT(!argspec.has_starargs, "");
RELEASE_ASSERT(!argspec.has_kwargs, "");
RELEASE_ASSERT(argspec.num_keywords == 0, "");
int npassed_args = argspec.totalPassed();
static StatCounter slowpath_typecall("slowpath_typecall"); static StatCounter slowpath_typecall("slowpath_typecall");
slowpath_typecall.log(); slowpath_typecall.log();
// if (rewrite_args && VERBOSITY()) { // if (rewrite_args && VERBOSITY()) {
// printf("typeCallInternal: %d", rewrite_args->obj.getArgnum()); // printf("typeCallInternal: %d", rewrite_args->obj.getArgnum());
// if (nargs >= 1) printf(" %d", rewrite_args->arg1.getArgnum()); // if (npassed_args >= 1) printf(" %d", rewrite_args->arg1.getArgnum());
// if (nargs >= 2) printf(" %d", rewrite_args->arg2.getArgnum()); // if (npassed_args >= 2) printf(" %d", rewrite_args->arg2.getArgnum());
// if (nargs >= 3) printf(" %d", rewrite_args->arg3.getArgnum()); // if (npassed_args >= 3) printf(" %d", rewrite_args->arg3.getArgnum());
// if (nargs >= 4) printf(" %d", rewrite_args->args.getArgnum()); // if (npassed_args >= 4) printf(" %d", rewrite_args->args.getArgnum());
// printf("\n"); // printf("\n");
//} //}
...@@ -2315,39 +2589,41 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B ...@@ -2315,39 +2589,41 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B
if (rewrite_args) { if (rewrite_args) {
if (init_attr) if (init_attr)
r_init.push(); r_init.push();
if (nargs >= 1) if (npassed_args >= 1)
r_ccls.push(); r_ccls.push();
if (nargs >= 2) if (npassed_args >= 2)
rewrite_args->arg2.push(); rewrite_args->arg2.push();
if (nargs >= 3) if (npassed_args >= 3)
rewrite_args->arg3.push(); rewrite_args->arg3.push();
if (nargs >= 4) if (npassed_args >= 4)
rewrite_args->args.push(); rewrite_args->args.push();
CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_new); CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_new);
if (nargs >= 1) if (npassed_args >= 1)
srewrite_args.arg1 = r_ccls; srewrite_args.arg1 = r_ccls;
if (nargs >= 2) if (npassed_args >= 2)
srewrite_args.arg2 = rewrite_args->arg2; srewrite_args.arg2 = rewrite_args->arg2;
if (nargs >= 3) if (npassed_args >= 3)
srewrite_args.arg3 = rewrite_args->arg3; srewrite_args.arg3 = rewrite_args->arg3;
if (nargs >= 4) if (npassed_args >= 4)
srewrite_args.args = rewrite_args->args; srewrite_args.args = rewrite_args->args;
srewrite_args.args_guarded = true; srewrite_args.args_guarded = true;
srewrite_args.func_guarded = true; srewrite_args.func_guarded = true;
r_new.push(); r_new.push();
int new_args = nargs; auto new_argspec = argspec;
if (nargs > 1 && new_attr == typeLookup(object_cls, _new_str, NULL, NULL)) { auto new_keyword_names = keyword_names;
if (npassed_args > 1 && new_attr == typeLookup(object_cls, _new_str, NULL, NULL)) {
if (init_attr == typeLookup(object_cls, _init_str, NULL, NULL)) { if (init_attr == typeLookup(object_cls, _init_str, NULL, NULL)) {
raiseExcHelper(TypeError, "object.__new__() takes no parameters"); raiseExcHelper(TypeError, "object.__new__() takes no parameters");
} else { } else {
new_args = 1; new_argspec = ArgPassSpec(1);
new_keyword_names = NULL;
} }
} }
made = runtimeCallInternal(new_attr, &srewrite_args, new_args, cls, arg2, arg3, args); made = runtimeCallInternal(new_attr, &srewrite_args, new_argspec, cls, arg2, arg3, args, new_keyword_names);
if (!srewrite_args.out_success) if (!srewrite_args.out_success)
rewrite_args = NULL; rewrite_args = NULL;
...@@ -2357,19 +2633,19 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B ...@@ -2357,19 +2633,19 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B
r_new = rewrite_args->rewriter->pop(0); r_new = rewrite_args->rewriter->pop(0);
r_made = r_made.move(-1); r_made = r_made.move(-1);
if (nargs >= 4) if (npassed_args >= 4)
rewrite_args->args = rewrite_args->rewriter->pop(3); rewrite_args->args = rewrite_args->rewriter->pop(3);
if (nargs >= 3) if (npassed_args >= 3)
rewrite_args->arg3 = rewrite_args->rewriter->pop(2); rewrite_args->arg3 = rewrite_args->rewriter->pop(2);
if (nargs >= 2) if (npassed_args >= 2)
rewrite_args->arg2 = rewrite_args->rewriter->pop(1); rewrite_args->arg2 = rewrite_args->rewriter->pop(1);
if (nargs >= 1) if (npassed_args >= 1)
r_ccls = rewrite_args->arg1 = rewrite_args->rewriter->pop(0); r_ccls = rewrite_args->arg1 = rewrite_args->rewriter->pop(0);
if (init_attr) if (init_attr)
r_init = rewrite_args->rewriter->pop(-2); r_init = rewrite_args->rewriter->pop(-2);
} }
} else { } else {
made = runtimeCallInternal(new_attr, NULL, nargs, cls, arg2, arg3, args); made = runtimeCallInternal(new_attr, NULL, argspec, cls, arg2, arg3, args, keyword_names);
} }
assert(made); assert(made);
...@@ -2380,21 +2656,22 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B ...@@ -2380,21 +2656,22 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B
Box* initrtn; Box* initrtn;
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_init); CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_init);
if (nargs >= 1) if (npassed_args >= 1)
srewrite_args.arg1 = r_made; srewrite_args.arg1 = r_made;
if (nargs >= 2) if (npassed_args >= 2)
srewrite_args.arg2 = rewrite_args->arg2; srewrite_args.arg2 = rewrite_args->arg2;
if (nargs >= 3) if (npassed_args >= 3)
srewrite_args.arg3 = rewrite_args->arg3; srewrite_args.arg3 = rewrite_args->arg3;
if (nargs >= 4) if (npassed_args >= 4)
srewrite_args.args = rewrite_args->args; srewrite_args.args = rewrite_args->args;
srewrite_args.args_guarded = true; srewrite_args.args_guarded = true;
srewrite_args.func_guarded = true; srewrite_args.func_guarded = true;
r_made.push(); r_made.push();
r_init.push(); r_init.push();
// initrtn = callattrInternal(ccls, &_init_str, INST_ONLY, &srewrite_args, nargs, made, arg2, arg3, args); // initrtn = callattrInternal(ccls, &_init_str, INST_ONLY, &srewrite_args, argspec, made, arg2, arg3, args,
initrtn = runtimeCallInternal(init_attr, &srewrite_args, nargs, made, arg2, arg3, args); // keyword_names);
initrtn = runtimeCallInternal(init_attr, &srewrite_args, argspec, made, arg2, arg3, args, keyword_names);
if (!srewrite_args.out_success) if (!srewrite_args.out_success)
rewrite_args = NULL; rewrite_args = NULL;
...@@ -2406,14 +2683,16 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B ...@@ -2406,14 +2683,16 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B
r_made = rewrite_args->rewriter->pop(-1); r_made = rewrite_args->rewriter->pop(-1);
} }
} else { } else {
// initrtn = callattrInternal(ccls, &_init_str, INST_ONLY, NULL, nargs, made, arg2, arg3, args); // initrtn = callattrInternal(ccls, &_init_str, INST_ONLY, NULL, argspec, made, arg2, arg3, args,
initrtn = runtimeCallInternal(init_attr, NULL, nargs, made, arg2, arg3, args); // keyword_names);
initrtn = runtimeCallInternal(init_attr, NULL, argspec, made, arg2, arg3, args, keyword_names);
} }
assertInitNone(initrtn); assertInitNone(initrtn);
} else { } else {
// TODO this shouldn't be reached // TODO this shouldn't be reached
// assert(0 && "I don't think this should be reached"); // assert(0 && "I don't think this should be reached");
if (new_attr == NULL && nargs != 1) { if (new_attr == NULL && npassed_args != 1) {
// TODO not npassed args, since the starargs or kwargs could be null
raiseExcHelper(TypeError, "object.__new__() takes no parameters"); raiseExcHelper(TypeError, "object.__new__() takes no parameters");
} }
} }
...@@ -2428,14 +2707,14 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B ...@@ -2428,14 +2707,14 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B
Box* typeCall(Box* obj, BoxedList* vararg) { Box* typeCall(Box* obj, BoxedList* vararg) {
assert(vararg->cls == list_cls); assert(vararg->cls == list_cls);
if (vararg->size == 0) if (vararg->size == 0)
return typeCallInternal1(NULL, 1, obj); return typeCallInternal1(NULL, NULL, ArgPassSpec(1), obj);
else if (vararg->size == 1) else if (vararg->size == 1)
return typeCallInternal2(NULL, 2, obj, vararg->elts->elts[0]); return typeCallInternal2(NULL, NULL, ArgPassSpec(2), obj, vararg->elts->elts[0]);
else if (vararg->size == 2) else if (vararg->size == 2)
return typeCallInternal3(NULL, 3, obj, vararg->elts->elts[0], vararg->elts->elts[1]); return typeCallInternal3(NULL, NULL, ArgPassSpec(3), obj, vararg->elts->elts[0], vararg->elts->elts[1]);
else else
return typeCallInternal(NULL, 1 + vararg->size, obj, vararg->elts->elts[0], vararg->elts->elts[1], return typeCallInternal(NULL, NULL, ArgPassSpec(1 + vararg->size), obj, vararg->elts->elts[0],
&vararg->elts->elts[2]); vararg->elts->elts[1], &vararg->elts->elts[2], NULL);
} }
Box* typeNew(Box* cls, Box* obj) { Box* typeNew(Box* cls, Box* obj) {
......
...@@ -39,8 +39,9 @@ extern "C" void my_assert(bool b); ...@@ -39,8 +39,9 @@ extern "C" void my_assert(bool b);
extern "C" Box* getattr(Box* obj, const char* attr); extern "C" Box* getattr(Box* obj, const char* attr);
extern "C" void setattr(Box* obj, const char* attr, Box* attr_val); extern "C" void setattr(Box* obj, const char* attr, Box* attr_val);
extern "C" bool nonzero(Box* obj); extern "C" bool nonzero(Box* obj);
extern "C" Box* runtimeCall(Box*, int64_t, Box*, Box*, Box*, Box**); extern "C" Box* runtimeCall(Box*, ArgPassSpec, Box*, Box*, Box*, Box**, const std::vector<const std::string*>*);
extern "C" Box* callattr(Box*, std::string*, bool, int64_t, Box*, Box*, Box*, Box**); extern "C" Box* callattr(Box*, std::string*, bool, ArgPassSpec, Box*, Box*, Box*, Box**,
const std::vector<const std::string*>*);
extern "C" BoxedString* str(Box* obj); extern "C" BoxedString* str(Box* obj);
extern "C" Box* repr(Box* obj); extern "C" Box* repr(Box* obj);
extern "C" BoxedString* reprOrNull(Box* obj); // similar to repr, but returns NULL on exception extern "C" BoxedString* reprOrNull(Box* obj); // similar to repr, but returns NULL on exception
...@@ -73,6 +74,9 @@ extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent); ...@@ -73,6 +74,9 @@ extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent);
class BinopRewriteArgs; class BinopRewriteArgs;
extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, BinopRewriteArgs* rewrite_args); extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, BinopRewriteArgs* rewrite_args);
Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names);
class CallRewriteArgs; class CallRewriteArgs;
enum LookupScope { enum LookupScope {
CLASS_ONLY = 1, CLASS_ONLY = 1,
...@@ -80,7 +84,8 @@ enum LookupScope { ...@@ -80,7 +84,8 @@ enum LookupScope {
CLASS_OR_INST = 3, 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, CallRewriteArgs* rewrite_args,
int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args); ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<const std::string*>* keyword_names);
struct CompareRewriteArgs; struct CompareRewriteArgs;
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args); Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args);
......
...@@ -43,9 +43,9 @@ BoxIterator& BoxIterator::operator++() { ...@@ -43,9 +43,9 @@ BoxIterator& BoxIterator::operator++() {
static std::string hasnext_str("__hasnext__"); static std::string hasnext_str("__hasnext__");
static std::string next_str("next"); static std::string next_str("next");
Box* hasnext = callattrInternal(iter, &hasnext_str, CLASS_ONLY, NULL, 0, NULL, NULL, NULL, NULL); Box* hasnext = callattrInternal(iter, &hasnext_str, CLASS_ONLY, NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
if (nonzero(hasnext)) { if (nonzero(hasnext)) {
value = callattrInternal(iter, &next_str, CLASS_ONLY, NULL, 0, NULL, NULL, NULL, NULL); value = callattrInternal(iter, &next_str, CLASS_ONLY, NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
} else { } else {
iter = nullptr; iter = nullptr;
value = nullptr; value = nullptr;
...@@ -56,7 +56,7 @@ BoxIterator& BoxIterator::operator++() { ...@@ -56,7 +56,7 @@ BoxIterator& BoxIterator::operator++() {
llvm::iterator_range<BoxIterator> Box::pyElements() { llvm::iterator_range<BoxIterator> Box::pyElements() {
static std::string iter_str("__iter__"); static std::string iter_str("__iter__");
Box* iter = callattr(const_cast<Box*>(this), &iter_str, true, 0, NULL, NULL, NULL, NULL); Box* iter = callattr(const_cast<Box*>(this), &iter_str, true, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
if (iter) { if (iter) {
return llvm::iterator_range<BoxIterator>(++BoxIterator(iter), BoxIterator(nullptr)); return llvm::iterator_range<BoxIterator>(++BoxIterator(iter), BoxIterator(nullptr));
} }
...@@ -466,8 +466,11 @@ void setupRuntime() { ...@@ -466,8 +466,11 @@ void setupRuntime() {
object_cls->giveAttr("__new__", new BoxedFunction(object_new)); object_cls->giveAttr("__new__", new BoxedFunction(object_new));
object_cls->freeze(); object_cls->freeze();
auto typeCallObj = boxRTFunction((void*)typeCall, NULL, 1, true);
typeCallObj->internal_callable = &typeCallInternal;
type_cls->giveAttr("__call__", new BoxedFunction(typeCallObj));
type_cls->giveAttr("__name__", boxStrConstant("type")); type_cls->giveAttr("__name__", boxStrConstant("type"));
type_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)typeCall, NULL, 1, true)));
type_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)typeNew, NULL, 2, true))); type_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)typeNew, NULL, 2, true)));
type_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)typeRepr, NULL, 1, true))); type_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)typeRepr, NULL, 1, true)));
type_cls->giveAttr("__str__", type_cls->getattr("__repr__")); type_cls->giveAttr("__str__", type_cls->getattr("__repr__"));
......
# expected: fail
# - keywords
def f(a, b, c):
print a, b, c
f(1, 2, 3)
f(1, b=2, c=3)
f(1, b=2, c=3)
f(1, c=2, b=3)
f(1, b="2", c=3)
f(1, b=2, c="3")
f(1, c="2", b=3)
f(1, c=2, b="3")
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