Commit b73cb68e authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add a fastpath in callFunc for simple cases

parent ec20c12f
...@@ -65,6 +65,9 @@ public: ...@@ -65,6 +65,9 @@ public:
#else #else
struct Stats { struct Stats {
static void dump() { printf("(Stats disabled)\n"); } static void dump() { printf("(Stats disabled)\n"); }
static void log(int id, int count = 1) {}
static int getStatId(const std::string& name) { return 0; }
static void endOfInit() {}
}; };
struct StatCounter { struct StatCounter {
StatCounter(const char* name) {} StatCounter(const char* name) {}
......
...@@ -66,14 +66,15 @@ struct ArgPassSpec { ...@@ -66,14 +66,15 @@ struct ArgPassSpec {
int totalPassed() { return num_args + num_keywords + (has_starargs ? 1 : 0) + (has_kwargs ? 1 : 0); } 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); } uint32_t asInt() const { return *reinterpret_cast<const uint32_t*>(this); }
void dump() { void dump() {
printf("(has_starargs=%s, has_kwargs=%s, num_keywords=%d, num_args=%d)\n", has_starargs ? "true" : "false", 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); has_kwargs ? "true" : "false", num_keywords, num_args);
} }
}; };
static_assert(sizeof(ArgPassSpec) <= sizeof(void*), "ArgPassSpec doesn't fit in register!"); 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 { namespace gc {
......
...@@ -187,6 +187,8 @@ static int main(int argc, char** argv) { ...@@ -187,6 +187,8 @@ static int main(int argc, char** argv) {
} catch (ExcInfo e) { } catch (ExcInfo e) {
int retcode = 1; int retcode = 1;
(void)handle_toplevel_exn(e, &retcode); (void)handle_toplevel_exn(e, &retcode);
if (stats)
Stats::dump();
return retcode; return retcode;
} }
} }
...@@ -210,6 +212,8 @@ static int main(int argc, char** argv) { ...@@ -210,6 +212,8 @@ static int main(int argc, char** argv) {
} catch (ExcInfo e) { } catch (ExcInfo e) {
int retcode = 1; int retcode = 1;
(void)handle_toplevel_exn(e, &retcode); (void)handle_toplevel_exn(e, &retcode);
if (stats)
Stats::dump();
return retcode; return retcode;
} }
} }
...@@ -257,8 +261,11 @@ static int main(int argc, char** argv) { ...@@ -257,8 +261,11 @@ static int main(int argc, char** argv) {
compileAndRunModule(m, main_module); compileAndRunModule(m, main_module);
} catch (ExcInfo e) { } catch (ExcInfo e) {
int retcode = 0xdeadbeef; // should never be seen int retcode = 0xdeadbeef; // should never be seen
if (handle_toplevel_exn(e, &retcode)) if (handle_toplevel_exn(e, &retcode)) {
if (stats)
Stats::dump();
return retcode; return retcode;
}
} }
} }
} }
...@@ -275,7 +282,7 @@ static int main(int argc, char** argv) { ...@@ -275,7 +282,7 @@ static int main(int argc, char** argv) {
int rtncode = joinRuntime(); int rtncode = joinRuntime();
_t.split("finishing up"); _t.split("finishing up");
if (VERBOSITY() >= 1 || stats) if (stats)
Stats::dump(); Stats::dump();
return rtncode; return rtncode;
......
...@@ -2551,6 +2551,8 @@ static KeywordDest placeKeyword(const ParamNames& param_names, llvm::SmallVector ...@@ -2551,6 +2551,8 @@ static KeywordDest placeKeyword(const ParamNames& param_names, llvm::SmallVector
} }
} }
static StatCounter slowpath_callfunc("slowpath_callfunc");
static StatCounter slowpath_callfunc_slowpath("slowpath_callfunc_slowpath");
Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names) { Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names) {
...@@ -2562,17 +2564,14 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe ...@@ -2562,17 +2564,14 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
* - error about missing parameters * - error about missing parameters
*/ */
static StatCounter slowpath_resolveclfunc("slowpath_callfunc"); BoxedClosure* closure = func->closure;
slowpath_resolveclfunc.log();
CLFunction* f = func->f; CLFunction* f = func->f;
FunctionList& versions = f->versions;
slowpath_callfunc.log();
int num_output_args = f->numReceivedArgs(); int num_output_args = f->numReceivedArgs();
int num_passed_args = argspec.totalPassed(); int num_passed_args = argspec.totalPassed();
BoxedClosure* closure = func->closure;
if (argspec.has_starargs || argspec.has_kwargs || func->isGenerator) { if (argspec.has_starargs || argspec.has_kwargs || func->isGenerator) {
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED(""); REWRITE_ABORTED("");
...@@ -2605,6 +2604,16 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe ...@@ -2605,6 +2604,16 @@ 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 (!func->isGenerator) {
if (argspec.num_keywords == 0 && !argspec.has_starargs && !argspec.has_kwargs && argspec.num_args == f->num_args
&& !f->takes_varargs && !f->takes_kwargs) {
return callCLFunc(f, rewrite_args, argspec.num_args, closure, NULL, arg1, arg2, arg3, args);
}
}
slowpath_callfunc_slowpath.log();
if (rewrite_args) { if (rewrite_args) {
// We might have trouble if we have more output args than input args, // We might have trouble if we have more output args than input args,
// such as if we need more space to pass defaults. // such as if we need more space to pass defaults.
......
...@@ -195,7 +195,7 @@ def run_test(fn, check_stats, run_memcheck): ...@@ -195,7 +195,7 @@ def run_test(fn, check_stats, run_memcheck):
out = "\n".join(out_lines) out = "\n".join(out_lines)
stats = None stats = None
if code == 0 and collect_stats: if code >= 0 and collect_stats:
stats = {} stats = {}
assert out.count("Stats:") == 1 assert out.count("Stats:") == 1
out, stats_str = out.split("Stats:") out, stats_str = out.split("Stats:")
......
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