Commit 874ea0ee authored by Kevin Modzelewski's avatar Kevin Modzelewski

Give CApiFunctions their own custom 'internal callable'

The 'internal callable' (bad name, sorry) is what defines how
the arguments get mapped to the parameters, and potentially also does
rewriting.

By providing a custom internal callable, we can make use of special knowledge
about how C API functions work.  In particular, we can skip the allocation
of the args + kwargs objects when we are calling an object with the METH_O
signature.

This patch includes rewriting support, though we don't currently allow
rewriting CAPI functions as part of callattrs.
parent b9282cb6
......@@ -508,6 +508,12 @@ void Rewriter::_loadConst(RewriterVar* result, int64_t val, Location dest) {
assertConsistent();
}
RewriterVar* Rewriter::call(bool can_call_into_python, void* func_addr) {
std::vector<RewriterVar*> args = {};
std::vector<RewriterVar*> args_xmm = {};
return call(can_call_into_python, func_addr, args, args_xmm);
}
RewriterVar* Rewriter::call(bool can_call_into_python, void* func_addr, RewriterVar* arg0) {
std::vector<RewriterVar*> args = { arg0 };
std::vector<RewriterVar*> args_xmm = {};
......
......@@ -445,6 +445,7 @@ public:
RewriterVar* loadConst(int64_t val, Location loc = Location::any());
RewriterVar* call(bool can_call_into_python, void* func_addr, const std::vector<RewriterVar*>& args,
const std::vector<RewriterVar*>& args_xmm = std::vector<RewriterVar*>());
RewriterVar* call(bool can_call_into_python, void* func_addr);
RewriterVar* call(bool can_call_into_python, void* func_addr, RewriterVar* arg0);
RewriterVar* call(bool can_call_into_python, void* func_addr, RewriterVar* arg0, RewriterVar* arg1);
RewriterVar* add(RewriterVar* a, int64_t b, Location dest);
......
......@@ -82,6 +82,9 @@ public:
assert(rtn && "should have set + thrown an exception!");
return rtn;
}
static Box* callInternal(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1,
Box* arg2, Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names);
};
class BoxedWrapperDescriptor : public Box {
......
......@@ -62,6 +62,8 @@ struct ArgPassSpec {
&& 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); }
uintptr_t asInt() const { return *reinterpret_cast<const uintptr_t*>(this); }
......
......@@ -27,6 +27,7 @@
#include "runtime/classobj.h"
#include "runtime/import.h"
#include "runtime/objmodel.h"
#include "runtime/rewrite_args.h"
#include "runtime/types.h"
namespace pyston {
......@@ -1441,6 +1442,30 @@ BoxedModule* importTestExtension(const std::string& name) {
return m;
}
Box* BoxedCApiFunction::callInternal(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1,
Box* arg2, Box* arg3, Box** args,
const std::vector<const std::string*>* keyword_names) {
if (argspec != ArgPassSpec(2))
return callFunc(func, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
assert(arg1->cls == capifunc_cls);
BoxedCApiFunction* capifunc = static_cast<BoxedCApiFunction*>(arg1);
if (capifunc->ml_flags != METH_O)
return callFunc(func, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
if (rewrite_args) {
rewrite_args->arg1->addGuard((intptr_t)arg1);
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)capifunc->func, rewrite_args->arg1, rewrite_args->arg2);
rewrite_args->rewriter->call(true, (void*)checkAndThrowCAPIException);
rewrite_args->out_success = true;
}
Box* r = capifunc->func(arg1, arg2);
checkAndThrowCAPIException();
assert(r);
return r;
}
void setupCAPI() {
capifunc_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedCApiFunction), false);
capifunc_cls->giveAttr("__name__", boxStrConstant("capifunc"));
......@@ -1448,8 +1473,9 @@ void setupCAPI() {
capifunc_cls->giveAttr("__repr__",
new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__repr__, UNKNOWN, 1)));
capifunc_cls->giveAttr(
"__call__", new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__call__, UNKNOWN, 1, 0, true, true)));
auto capi_call = new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__call__, UNKNOWN, 1, 0, true, true));
capi_call->f->internal_callable = BoxedCApiFunction::callInternal;
capifunc_cls->giveAttr("__call__", capi_call);
capifunc_cls->freeze();
......
......@@ -45,6 +45,7 @@
#include "runtime/ics.h"
#include "runtime/iterobject.h"
#include "runtime/long.h"
#include "runtime/rewrite_args.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -88,95 +89,6 @@ void REWRITE_ABORTED(const char* reason) {
#define REWRITE_ABORTED(reason) ((void)(reason))
#endif
struct GetattrRewriteArgs {
Rewriter* rewriter;
RewriterVar* obj;
Location destination;
bool out_success;
RewriterVar* out_rtn;
bool obj_hcls_guarded;
GetattrRewriteArgs(Rewriter* rewriter, RewriterVar* obj, Location destination)
: rewriter(rewriter), obj(obj), destination(destination), out_success(false), out_rtn(NULL),
obj_hcls_guarded(false) {}
};
struct SetattrRewriteArgs {
Rewriter* rewriter;
RewriterVar* obj;
RewriterVar* attrval;
bool out_success;
SetattrRewriteArgs(Rewriter* rewriter, RewriterVar* obj, RewriterVar* attrval)
: rewriter(rewriter), obj(obj), attrval(attrval), out_success(false) {}
};
struct DelattrRewriteArgs {
Rewriter* rewriter;
RewriterVar* obj;
bool out_success;
DelattrRewriteArgs(Rewriter* rewriter, RewriterVar* obj) : rewriter(rewriter), obj(obj), out_success(false) {}
};
struct LenRewriteArgs {
Rewriter* rewriter;
RewriterVar* obj;
Location destination;
bool out_success;
RewriterVar* out_rtn;
LenRewriteArgs(Rewriter* rewriter, RewriterVar* obj, Location destination)
: rewriter(rewriter), obj(obj), destination(destination), out_success(false), out_rtn(NULL) {}
};
struct CallRewriteArgs {
Rewriter* rewriter;
RewriterVar* obj;
RewriterVar* arg1, *arg2, *arg3, *args;
bool func_guarded;
bool args_guarded;
Location destination;
bool out_success;
RewriterVar* out_rtn;
CallRewriteArgs(Rewriter* rewriter, RewriterVar* obj, Location destination)
: rewriter(rewriter), obj(obj), arg1(NULL), arg2(NULL), arg3(NULL), args(NULL), func_guarded(false),
args_guarded(false), destination(destination), out_success(false), out_rtn(NULL) {}
};
struct BinopRewriteArgs {
Rewriter* rewriter;
RewriterVar* lhs;
RewriterVar* rhs;
Location destination;
bool out_success;
RewriterVar* out_rtn;
BinopRewriteArgs(Rewriter* rewriter, RewriterVar* lhs, RewriterVar* rhs, Location destination)
: rewriter(rewriter), lhs(lhs), rhs(rhs), destination(destination), out_success(false), out_rtn(NULL) {}
};
struct CompareRewriteArgs {
Rewriter* rewriter;
RewriterVar* lhs;
RewriterVar* rhs;
Location destination;
bool out_success;
RewriterVar* out_rtn;
CompareRewriteArgs(Rewriter* rewriter, RewriterVar* lhs, RewriterVar* rhs, Location destination)
: rewriter(rewriter), lhs(lhs), rhs(rhs), destination(destination), out_success(false), out_rtn(NULL) {}
};
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);
static Box* (*runtimeCallInternal0)(Box*, CallRewriteArgs*, ArgPassSpec)
......
......@@ -103,6 +103,9 @@ struct CallRewriteArgs;
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);
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);
enum LookupScope {
CLASS_ONLY = 1,
INST_ONLY = 2,
......
// Copyright (c) 2014-2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PYSTON_RUNTIME_REWRITEARGS_H
#define PYSTON_RUNTIME_REWRITEARGS_H
#include "asm_writing/rewriter.h"
namespace pyston {
struct GetattrRewriteArgs {
Rewriter* rewriter;
RewriterVar* obj;
Location destination;
bool out_success;
RewriterVar* out_rtn;
bool obj_hcls_guarded;
GetattrRewriteArgs(Rewriter* rewriter, RewriterVar* obj, Location destination)
: rewriter(rewriter), obj(obj), destination(destination), out_success(false), out_rtn(NULL),
obj_hcls_guarded(false) {}
};
struct SetattrRewriteArgs {
Rewriter* rewriter;
RewriterVar* obj;
RewriterVar* attrval;
bool out_success;
SetattrRewriteArgs(Rewriter* rewriter, RewriterVar* obj, RewriterVar* attrval)
: rewriter(rewriter), obj(obj), attrval(attrval), out_success(false) {}
};
struct DelattrRewriteArgs {
Rewriter* rewriter;
RewriterVar* obj;
bool out_success;
DelattrRewriteArgs(Rewriter* rewriter, RewriterVar* obj) : rewriter(rewriter), obj(obj), out_success(false) {}
};
struct LenRewriteArgs {
Rewriter* rewriter;
RewriterVar* obj;
Location destination;
bool out_success;
RewriterVar* out_rtn;
LenRewriteArgs(Rewriter* rewriter, RewriterVar* obj, Location destination)
: rewriter(rewriter), obj(obj), destination(destination), out_success(false), out_rtn(NULL) {}
};
struct CallRewriteArgs {
Rewriter* rewriter;
RewriterVar* obj;
RewriterVar* arg1, *arg2, *arg3, *args;
bool func_guarded;
bool args_guarded;
Location destination;
bool out_success;
RewriterVar* out_rtn;
CallRewriteArgs(Rewriter* rewriter, RewriterVar* obj, Location destination)
: rewriter(rewriter), obj(obj), arg1(NULL), arg2(NULL), arg3(NULL), args(NULL), func_guarded(false),
args_guarded(false), destination(destination), out_success(false), out_rtn(NULL) {}
};
struct BinopRewriteArgs {
Rewriter* rewriter;
RewriterVar* lhs;
RewriterVar* rhs;
Location destination;
bool out_success;
RewriterVar* out_rtn;
BinopRewriteArgs(Rewriter* rewriter, RewriterVar* lhs, RewriterVar* rhs, Location destination)
: rewriter(rewriter), lhs(lhs), rhs(rhs), destination(destination), out_success(false), out_rtn(NULL) {}
};
struct CompareRewriteArgs {
Rewriter* rewriter;
RewriterVar* lhs;
RewriterVar* rhs;
Location destination;
bool out_success;
RewriterVar* out_rtn;
CompareRewriteArgs(Rewriter* rewriter, RewriterVar* lhs, RewriterVar* rhs, Location destination)
: rewriter(rewriter), lhs(lhs), rhs(rhs), destination(destination), out_success(false), out_rtn(NULL) {}
};
} // namespace pyston
#endif
......@@ -3,3 +3,11 @@ try:
print math.sqrt(-1)
except ValueError, e:
print e
s = math.sqrt
for i in xrange(5):
print s(1.0)
try:
print s(-1)
except ValueError, e:
print e
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