Commit 5a81a329 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Consolidate param info into ParamReceiveSpec

Similar to ArgPassSpec.  Previously we kept them on the CLFunction,
but there are places where we want to specify a certain parameter
signature without having a clfunction available.
parent 52924ca9
......@@ -828,7 +828,7 @@ public:
Sig* type_sig = new Sig();
type_sig->rtn_type = fspec->rtn_type;
type_sig->ndefaults = clf->num_defaults;
type_sig->ndefaults = clf->paramspec.num_defaults;
if (stripfirst) {
assert(fspec->arg_types.size() >= 1);
......@@ -1545,12 +1545,14 @@ public:
CLFunction* cl = rtattr_func->f;
assert(cl);
if (cl->takes_varargs || cl->takes_kwargs)
ParamReceiveSpec paramspec = cl->paramspec;
if (paramspec.takes_varargs || paramspec.takes_kwargs)
return NULL;
RELEASE_ASSERT(cl->num_args == cl->numReceivedArgs(), "");
RELEASE_ASSERT(args.size() + 1 >= cl->num_args - cl->num_defaults && args.size() + 1 <= cl->num_args, "%d",
info.unw_info.current_stmt->lineno);
RELEASE_ASSERT(paramspec.num_args == cl->numReceivedArgs(), "");
RELEASE_ASSERT(args.size() + 1 >= paramspec.num_args - paramspec.num_defaults
&& args.size() + 1 <= paramspec.num_args,
"%d", info.unw_info.current_stmt->lineno);
CompiledFunction* cf = NULL;
bool found = false;
......@@ -1578,8 +1580,8 @@ public:
assert(cf->code);
std::vector<llvm::Type*> arg_types;
RELEASE_ASSERT(cl->num_args == cl->numReceivedArgs(), "");
for (int i = 0; i < cl->num_args; i++) {
RELEASE_ASSERT(paramspec.num_args == cl->numReceivedArgs(), "");
for (int i = 0; i < paramspec.num_args; i++) {
// TODO support passing unboxed values as arguments
assert(cf->spec->arg_types[i]->llvmType() == g.llvm_value_type_ptr);
......@@ -1602,9 +1604,9 @@ public:
new_args.push_back(var);
new_args.insert(new_args.end(), args.begin(), args.end());
for (int i = args.size() + 1; i < cl->num_args; i++) {
for (int i = args.size() + 1; i < paramspec.num_args; i++) {
// TODO should _call() be able to take llvm::Value's directly?
auto value = rtattr_func->defaults->elts[i - cl->num_args + cl->num_defaults];
auto value = rtattr_func->defaults->elts[i - paramspec.num_args + paramspec.num_defaults];
llvm::Value* llvm_value;
if (value)
llvm_value = embedRelocatablePtr(value, g.llvm_value_type_ptr);
......
......@@ -38,44 +38,6 @@ class Value;
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);
}
bool operator==(ArgPassSpec rhs) {
return has_starargs == rhs.has_starargs && has_kwargs == rhs.has_kwargs && num_keywords == rhs.num_keywords
&& num_args == rhs.num_args;
}
bool operator!=(ArgPassSpec rhs) { return !(*this == rhs); }
int totalPassed() { return num_args + num_keywords + (has_starargs ? 1 : 0) + (has_kwargs ? 1 : 0); }
uint32_t asInt() const { return *reinterpret_cast<const uint32_t*>(this); }
void dump() {
printf("(has_starargs=%s, has_kwargs=%s, num_keywords=%d, num_args=%d)\n", has_starargs ? "true" : "false",
has_kwargs ? "true" : "false", num_keywords, num_args);
}
};
static_assert(sizeof(ArgPassSpec) <= sizeof(void*), "ArgPassSpec doesn't fit in register! (CC is probably wrong)");
static_assert(sizeof(ArgPassSpec) == sizeof(uint32_t), "ArgPassSpec::asInt needs to be updated");
namespace gc {
class TraceStack;
......@@ -144,6 +106,92 @@ class ScopingAnalysis;
class CLFunction;
class OSREntryDescriptor;
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);
}
bool operator==(ArgPassSpec rhs) {
return has_starargs == rhs.has_starargs && has_kwargs == rhs.has_kwargs && num_keywords == rhs.num_keywords
&& num_args == rhs.num_args;
}
bool operator!=(ArgPassSpec rhs) { return !(*this == rhs); }
int totalPassed() { return num_args + num_keywords + (has_starargs ? 1 : 0) + (has_kwargs ? 1 : 0); }
uint32_t asInt() const { return *reinterpret_cast<const uint32_t*>(this); }
void dump() {
printf("(has_starargs=%s, has_kwargs=%s, num_keywords=%d, num_args=%d)\n", has_starargs ? "true" : "false",
has_kwargs ? "true" : "false", num_keywords, num_args);
}
};
static_assert(sizeof(ArgPassSpec) <= sizeof(void*), "ArgPassSpec doesn't fit in register! (CC is probably wrong)");
static_assert(sizeof(ArgPassSpec) == sizeof(uint32_t), "ArgPassSpec::asInt needs to be updated");
struct ParamNames {
bool takes_param_names;
std::vector<llvm::StringRef> args;
llvm::StringRef vararg, kwarg;
explicit ParamNames(AST* ast, InternedStringPool& pool);
ParamNames(const std::vector<llvm::StringRef>& args, llvm::StringRef vararg, llvm::StringRef kwarg);
static ParamNames empty() { return ParamNames(); }
int totalParameters() const {
return args.size() + (vararg.str().size() == 0 ? 0 : 1) + (kwarg.str().size() == 0 ? 0 : 1);
}
private:
ParamNames() : takes_param_names(false) {}
};
// Probably overkill to copy this from ArgPassSpec
struct ParamReceiveSpec {
bool takes_varargs : 1;
bool takes_kwargs : 1;
unsigned int num_defaults : 14;
unsigned int num_args : 16;
static const int MAX_ARGS = (1 << 16) - 1;
static const int MAX_DEFAULTS = (1 << 14) - 1;
explicit ParamReceiveSpec(int num_args)
: takes_varargs(false), takes_kwargs(false), num_defaults(0), num_args(num_args) {
assert(num_args <= MAX_ARGS);
assert(num_defaults <= MAX_DEFAULTS);
}
explicit ParamReceiveSpec(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs)
: takes_varargs(takes_varargs), takes_kwargs(takes_kwargs), num_defaults(num_defaults), num_args(num_args) {
assert(num_args <= MAX_ARGS);
assert(num_defaults <= MAX_DEFAULTS);
}
bool operator==(ParamReceiveSpec rhs) {
return takes_varargs == rhs.takes_varargs && takes_kwargs == rhs.takes_kwargs
&& num_defaults == rhs.num_defaults && num_args == rhs.num_args;
}
bool operator!=(ParamReceiveSpec rhs) { return !(*this == rhs); }
int totalReceived() { return num_args + (takes_varargs ? 1 : 0) + (takes_kwargs ? 1 : 0); }
};
class ICInvalidator {
private:
int64_t cur_version;
......@@ -229,23 +277,6 @@ public:
void speculationFailed();
};
struct ParamNames {
bool takes_param_names;
std::vector<llvm::StringRef> args;
llvm::StringRef vararg, kwarg;
explicit ParamNames(AST* ast, InternedStringPool& pool);
ParamNames(const std::vector<llvm::StringRef>& args, llvm::StringRef vararg, llvm::StringRef kwarg);
static ParamNames empty() { return ParamNames(); }
int totalParameters() const {
return args.size() + (vararg.str().size() == 0 ? 0 : 1) + (kwarg.str().size() == 0 ? 0 : 1);
}
private:
ParamNames() : takes_param_names(false) {}
};
typedef int FutureFlags;
class BoxedModule;
......@@ -283,9 +314,7 @@ struct CallRewriteArgs;
class BoxedCode;
class CLFunction {
public:
int num_args;
int num_defaults;
bool takes_varargs, takes_kwargs;
ParamReceiveSpec paramspec;
std::unique_ptr<SourceInfo> source;
ParamNames param_names;
......@@ -308,10 +337,7 @@ public:
CLFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs,
std::unique_ptr<SourceInfo> source)
: num_args(num_args),
num_defaults(num_defaults),
takes_varargs(takes_varargs),
takes_kwargs(takes_kwargs),
: paramspec(num_args, num_defaults, takes_varargs, takes_kwargs),
source(std::move(source)),
param_names(this->source->ast, this->source->getInternedStrings()),
always_use_version(NULL),
......@@ -319,10 +345,7 @@ public:
assert(num_args >= num_defaults);
}
CLFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs, const ParamNames& param_names)
: num_args(num_args),
num_defaults(num_defaults),
takes_varargs(takes_varargs),
takes_kwargs(takes_kwargs),
: paramspec(num_args, num_defaults, takes_varargs, takes_kwargs),
source(nullptr),
param_names(param_names),
always_use_version(NULL),
......@@ -330,7 +353,7 @@ public:
assert(num_args >= num_defaults);
}
int numReceivedArgs() { return num_args + (takes_varargs ? 1 : 0) + (takes_kwargs ? 1 : 0); }
int numReceivedArgs() { return paramspec.totalReceived(); }
void addVersion(CompiledFunction* compiled) {
assert(compiled);
......@@ -344,7 +367,7 @@ public:
&& compiled->spec->boxed_return_value)
always_use_version = compiled;
assert(compiled->spec->arg_types.size() == num_args + (takes_varargs ? 1 : 0) + (takes_kwargs ? 1 : 0));
assert(compiled->spec->arg_types.size() == paramspec.totalReceived());
versions.push_back(compiled);
} else {
osr_versions[compiled->entry_descriptor] = compiled;
......
......@@ -72,7 +72,7 @@ public:
static Box* argcount(Box* b, void*) {
RELEASE_ASSERT(b->cls == code_cls, "");
return boxInt(static_cast<BoxedCode*>(b)->f->num_args);
return boxInt(static_cast<BoxedCode*>(b)->f->paramspec.num_args);
}
static Box* varnames(Box* b, void*) {
......
......@@ -310,7 +310,7 @@ extern "C" BoxedGenerator::BoxedGenerator(BoxedFunctionBase* function, Box* arg1
#endif
{
int numArgs = function->f->num_args;
int numArgs = function->f->numReceivedArgs();
if (numArgs > 3) {
numArgs -= 3;
this->args = new (numArgs) GCdArray();
......@@ -384,7 +384,7 @@ extern "C" void generatorGCHandler(GCVisitor* v, Box* b) {
BoxedGenerator* g = (BoxedGenerator*)b;
v->visit(g->function);
int num_args = g->function->f->num_args;
int num_args = g->function->f->numReceivedArgs();
if (num_args >= 1)
v->visit(g->arg1);
if (num_args >= 2)
......
......@@ -2977,7 +2977,7 @@ enum class KeywordDest {
POSITIONAL,
KWARGS,
};
static KeywordDest placeKeyword(const ParamNames& param_names, llvm::SmallVector<bool, 8>& params_filled,
static KeywordDest placeKeyword(const ParamNames* param_names, llvm::SmallVector<bool, 8>& params_filled,
BoxedString* kw_name, Box* kw_val, Box*& oarg1, Box*& oarg2, Box*& oarg3, Box** oargs,
BoxedDict* okwargs, CLFunction* cl) {
assert(kw_val);
......@@ -2985,8 +2985,8 @@ static KeywordDest placeKeyword(const ParamNames& param_names, llvm::SmallVector
assert(kw_name);
assert(gc::isValidGCObject(kw_name));
for (int j = 0; j < param_names.args.size(); j++) {
if (param_names.args[j] == kw_name->s() && kw_name->size() > 0) {
for (int j = 0; j < param_names->args.size(); j++) {
if (param_names->args[j] == kw_name->s() && kw_name->size() > 0) {
if (params_filled[j]) {
raiseExcHelper(TypeError, "%.200s() got multiple values for keyword argument '%s'",
getFunctionName(cl).c_str(), kw_name->c_str());
......@@ -3040,6 +3040,8 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
BoxedClosure* closure = func->closure;
CLFunction* f = func->f;
ParamReceiveSpec paramspec = f->paramspec;
slowpath_callfunc.log();
int num_output_args = f->numReceivedArgs();
......@@ -3079,8 +3081,8 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
// Fast path: if it's a simple-enough call, we don't have to do anything special. On a simple
// django-admin test this covers something like 93% of all calls to callFunc.
if (!f->isGenerator()) {
if (argspec.num_keywords == 0 && argspec.has_starargs == f->takes_varargs && !argspec.has_kwargs
&& !f->takes_kwargs && argspec.num_args == f->num_args) {
if (argspec.num_keywords == 0 && argspec.has_starargs == paramspec.takes_varargs && !argspec.has_kwargs
&& !paramspec.takes_kwargs && argspec.num_args == paramspec.num_args) {
// If the caller passed starargs, we can only pass those directly to the callee if it's a tuple,
// since otherwise modifications by the callee would be visible to the caller (hence why varargs
// received by the caller are always tuples).
......@@ -3121,8 +3123,8 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
#if 0
char buf[80];
snprintf(buf, sizeof(buf), "zzz_aborted_%d_args_%d_%d_%d_%d_params_%d_%d_%d_%d", f->isGenerator(),
argspec.num_args, argspec.num_keywords, argspec.has_starargs, argspec.has_kwargs, f->num_args,
f->num_defaults, f->takes_varargs, f->takes_kwargs);
argspec.num_args, argspec.num_keywords, argspec.has_starargs, argspec.has_kwargs, paramspec.num_args,
paramspec.num_defaults, paramspec.takes_varargs, paramspec.takes_kwargs);
uint64_t* counter = Stats::getStatCounter(buf);
Stats::log(counter);
#endif
......@@ -3207,14 +3209,14 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
////
// First, match up positional parameters to positional/varargs:
int positional_to_positional = std::min((int)argspec.num_args, f->num_args);
int positional_to_positional = std::min(argspec.num_args, paramspec.num_args);
for (int i = 0; i < positional_to_positional; i++) {
getArg(i, oarg1, oarg2, oarg3, oargs) = getArg(i, arg1, arg2, arg3, args);
// we already moved the positional args into position
}
int varargs_to_positional = std::min((int)varargs.size(), f->num_args - positional_to_positional);
int varargs_to_positional = std::min((int)varargs.size(), paramspec.num_args - positional_to_positional);
for (int i = 0; i < varargs_to_positional; i++) {
assert(!rewrite_args && "would need to be handled here");
getArg(i + positional_to_positional, oarg1, oarg2, oarg3, oargs) = varargs[i];
......@@ -3246,8 +3248,8 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
unused_positional.push_back(varargs[i]);
}
if (f->takes_varargs) {
int varargs_idx = f->num_args;
if (paramspec.takes_varargs) {
int varargs_idx = paramspec.num_args;
if (rewrite_args) {
assert(!varargs.size());
assert(!argspec.has_starargs);
......@@ -3289,7 +3291,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
getArg(varargs_idx, oarg1, oarg2, oarg3, oargs) = ovarargs;
} else if (unused_positional.size()) {
raiseExcHelper(TypeError, "%s() takes at most %d argument%s (%d given)", getFunctionName(f).c_str(),
f->num_args, (f->num_args == 1 ? "" : "s"),
paramspec.num_args, (paramspec.num_args == 1 ? "" : "s"),
argspec.num_args + argspec.num_keywords + varargs.size());
}
......@@ -3297,8 +3299,8 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
// Second, apply any keywords:
BoxedDict* okwargs = NULL;
if (f->takes_kwargs) {
int kwargs_idx = f->num_args + (f->takes_varargs ? 1 : 0);
if (paramspec.takes_kwargs) {
int kwargs_idx = paramspec.num_args + (paramspec.takes_varargs ? 1 : 0);
if (rewrite_args) {
RewriterVar* r_kwargs = rewrite_args->rewriter->call(true, (void*)createDict);
......@@ -3316,8 +3318,8 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
getArg(kwargs_idx, oarg1, oarg2, oarg3, oargs) = okwargs;
}
const ParamNames& param_names = f->param_names;
if (!param_names.takes_param_names && argspec.num_keywords && !f->takes_kwargs) {
const ParamNames* param_names = &f->param_names;
if ((!param_names || !param_names->takes_param_names) && argspec.num_keywords && !paramspec.takes_kwargs) {
raiseExcHelper(TypeError, "%s() doesn't take keyword arguments", getFunctionName(f).c_str());
}
......@@ -3330,7 +3332,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
int arg_idx = i + argspec.num_args;
Box* kw_val = getArg(arg_idx, arg1, arg2, arg3, args);
if (!param_names.takes_param_names) {
if (!param_names || !param_names->takes_param_names) {
assert(okwargs);
rewrite_args = NULL; // would need to add it to r_kwargs
okwargs->d[(*keyword_names)[i]] = kw_val;
......@@ -3364,7 +3366,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
BoxedString* s = static_cast<BoxedString*>(k);
if (param_names.takes_param_names) {
if (param_names && param_names->takes_param_names) {
assert(!rewrite_args && "would need to make sure that this didn't need to go into r_kwargs");
placeKeyword(param_names, params_filled, s, p.second, oarg1, oarg2, oarg3, oargs, okwargs, f);
} else {
......@@ -3384,7 +3386,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
// Fill with defaults:
for (int i = 0; i < f->num_args - f->num_defaults; i++) {
for (int i = 0; i < paramspec.num_args - paramspec.num_defaults; i++) {
if (params_filled[i])
continue;
// TODO not right error message
......@@ -3396,11 +3398,11 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
r_defaults_array = rewrite_args->obj->getAttr(offsetof(BoxedFunctionBase, defaults), Location::any());
}
for (int i = f->num_args - f->num_defaults; i < f->num_args; i++) {
for (int i = paramspec.num_args - paramspec.num_defaults; i < paramspec.num_args; i++) {
if (params_filled[i])
continue;
int default_idx = i + f->num_defaults - f->num_args;
int default_idx = i + paramspec.num_defaults - paramspec.num_args;
Box* default_obj = func->defaults->elts[default_idx];
if (rewrite_args) {
......
......@@ -316,7 +316,7 @@ extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f)
this->doc = None;
}
assert(f->num_defaults == ndefaults);
assert(f->paramspec.num_defaults == ndefaults);
}
extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f, std::initializer_list<Box*> defaults,
......@@ -338,7 +338,7 @@ extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f, std::initializer_
this->doc = None;
}
assert(f->num_defaults == ndefaults);
assert(f->paramspec.num_defaults == ndefaults);
}
BoxedFunction::BoxedFunction(CLFunction* f) : BoxedFunction(f, {}) {
......
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