Commit be68face authored by Kevin Modzelewski's avatar Kevin Modzelewski

Optimize creation of extension objects

We can't rewrite into the object-creation behavior, but
we can rewrite the decision to just use CPython's c slots.
parent 0ccfdcb8
def f():
u = u"a" * 100
c = unicode
for i in xrange(2000000):
c(u)
f()
...@@ -743,10 +743,13 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr ...@@ -743,10 +743,13 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
if (has_side_effects) { if (has_side_effects) {
// We need some fixed amount of space at the beginning of the IC that we can use to invalidate // We need some fixed amount of space at the beginning of the IC that we can use to invalidate
// it by writing a jmp. // it by writing a jmp.
// FIXME this check is conservative, since actually we just have to verify that the return // TODO this check is conservative, since actually we just have to verify that the return
// address is at least IC_INVALDITION_HEADER_SIZE bytes past the beginning, but we're // address is at least IC_INVALDITION_HEADER_SIZE bytes past the beginning, but we're
// checking based on the beginning of the call. I think the load+call might actually // checking based on the beginning of the call. I think the load+call might actually
// always larger than the invalidation jmp. // always larger than the invalidation jmp.
while (assembler->bytesWritten() < IC_INVALDITION_HEADER_SIZE)
assembler->nop();
assert(assembler->bytesWritten() >= IC_INVALDITION_HEADER_SIZE); assert(assembler->bytesWritten() >= IC_INVALDITION_HEADER_SIZE);
} }
......
...@@ -957,7 +957,7 @@ static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept { ...@@ -957,7 +957,7 @@ static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept {
return res; return res;
} }
static PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept { /* Pyston change: static */ PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept {
STAT_TIMER(t0, "us_timer_slot_tpnew", SLOT_AVOIDABILITY(self)); STAT_TIMER(t0, "us_timer_slot_tpnew", SLOT_AVOIDABILITY(self));
try { try {
......
...@@ -36,6 +36,7 @@ int type_set_bases(PyTypeObject* type, PyObject* value, void* context) noexcept; ...@@ -36,6 +36,7 @@ int type_set_bases(PyTypeObject* type, PyObject* value, void* context) noexcept;
PyObject* slot_tp_richcompare(PyObject* self, PyObject* other, int op) noexcept; PyObject* slot_tp_richcompare(PyObject* self, PyObject* other, int op) noexcept;
PyObject* slot_tp_iternext(PyObject* self) noexcept; PyObject* slot_tp_iternext(PyObject* self) noexcept;
PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept;
} }
#endif #endif
...@@ -604,6 +604,42 @@ static void assertInitNone(Box* obj) { ...@@ -604,6 +604,42 @@ static void assertInitNone(Box* obj) {
} }
} }
static PyObject* cpython_type_call(PyTypeObject* type, PyObject* args, PyObject* kwds) noexcept {
PyObject* obj;
if (type->tp_new == NULL) {
PyErr_Format(PyExc_TypeError, "cannot create '%.100s' instances", type->tp_name);
return NULL;
}
obj = type->tp_new(type, args, kwds);
if (obj != NULL) {
/* Ugly exception: when the call was type(something),
* don't call tp_init on the result. */
if (type == &PyType_Type && PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1
&& (kwds == NULL || (PyDict_Check(kwds) && PyDict_Size(kwds) == 0)))
return obj;
/* If the returned object is not an instance of type,
* it won't be initialized. */
if (!PyType_IsSubtype(obj->cls, type))
return obj;
type = obj->cls;
if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS) && type->tp_init != NULL
&& type->tp_init(obj, args, kwds) < 0) {
Py_DECREF(obj);
obj = NULL;
}
}
return obj;
}
static PyObject* cpythonTypeCall(BoxedClass* type, PyObject* args, PyObject* kwds) {
Box* r = cpython_type_call(type, args, kwds);
if (!r)
throwCAPIException();
return r;
}
static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<BoxedString*>* keyword_names) { Box** args, const std::vector<BoxedString*>* keyword_names) {
int npassed_args = argspec.totalPassed(); int npassed_args = argspec.totalPassed();
...@@ -618,6 +654,29 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -618,6 +654,29 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
BoxedClass* cls = static_cast<BoxedClass*>(_cls); BoxedClass* cls = static_cast<BoxedClass*>(_cls);
if (cls->tp_new != object_cls->tp_new && cls->tp_new != slot_tp_new) {
// Looks like we're calling an extension class and we're not going to be able to
// separately rewrite the new + init calls. But we can rewrite the fact that we
// should just call the cpython version, which will end up working pretty well.
ParamReceiveSpec paramspec(1, false, true, true);
bool rewrite_success = false;
Box* oarg1, *oarg2, *oarg3, ** oargs = NULL;
rearrangeArguments(paramspec, NULL, "", NULL, rewrite_args, rewrite_success, argspec, arg1, arg2, arg3, args,
keyword_names, oarg1, oarg2, oarg3, oargs);
assert(oarg1 == cls);
if (!rewrite_success)
rewrite_args = NULL;
if (rewrite_args) {
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)cpythonTypeCall, rewrite_args->arg1,
rewrite_args->arg2, rewrite_args->arg3);
rewrite_args->out_success = true;
}
return cpythonTypeCall(cls, oarg2, oarg3);
}
RewriterVar* r_ccls = NULL; RewriterVar* r_ccls = NULL;
RewriterVar* r_new = NULL; RewriterVar* r_new = NULL;
RewriterVar* r_init = NULL; RewriterVar* r_init = NULL;
...@@ -793,7 +852,10 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -793,7 +852,10 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
"We should only have allowed the rewrite to continue if we were guaranteed that made " "We should only have allowed the rewrite to continue if we were guaranteed that made "
"would have class cls!"); "would have class cls!");
} else { } else {
made = runtimeCallInternal(new_attr, NULL, new_argspec, cls, arg2, arg3, args, keyword_names); if (cls->tp_new == object_cls->tp_new && cls->tp_init != object_cls->tp_init)
made = objectNewNoArgs(cls);
else
made = runtimeCallInternal(new_attr, NULL, new_argspec, cls, arg2, arg3, args, keyword_names);
} }
assert(made); assert(made);
......
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