Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
Pyston
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
Pyston
Commits
60850a52
Commit
60850a52
authored
Aug 14, 2015
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #834 from kmod/perf3
improve getattr() speed
parents
86e550e5
91ecafb0
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
348 additions
and
78 deletions
+348
-78
.gitignore
.gitignore
+0
-3
from_cpython/Include/pyerrors.h
from_cpython/Include/pyerrors.h
+11
-5
from_cpython/Objects/exceptions.c
from_cpython/Objects/exceptions.c
+40
-0
microbenchmarks/django_template3_reduced.py
microbenchmarks/django_template3_reduced.py
+152
-0
src/codegen/ast_interpreter.cpp
src/codegen/ast_interpreter.cpp
+1
-1
src/codegen/irgen/irgenerator.cpp
src/codegen/irgen/irgenerator.cpp
+3
-2
src/core/types.h
src/core/types.h
+1
-6
src/runtime/builtin_modules/builtins.cpp
src/runtime/builtin_modules/builtins.cpp
+79
-9
src/runtime/capi.cpp
src/runtime/capi.cpp
+11
-21
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+1
-2
src/runtime/types.cpp
src/runtime/types.cpp
+48
-29
test/tests/.gitignore
test/tests/.gitignore
+1
-0
No files found.
.gitignore
View file @
60850a52
...
...
@@ -30,9 +30,6 @@ pystontmp*/
/*_unittest
*.cache
tests/t.py
tests/t2.py
tests/t3.py
*.bc
stdlib.ll
*.o
...
...
from_cpython/Include/pyerrors.h
View file @
60850a52
...
...
@@ -100,16 +100,16 @@ PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**) PY
/* */
// Pyston change: made these function calls for now
#if 0
#define PyExceptionClass_Check(x) \
(PyClass_Check((x)) || (PyType_Check((x)) && \
PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS)))
#define PyExceptionInstance_Check(x) \
(PyInstance_Check((x)) || \
PyType_FastSubclass(
(x)->ob_type
, Py_TPFLAGS_BASE_EXC_SUBCLASS))
PyType_FastSubclass(
Py_TYPE(x)
, Py_TPFLAGS_BASE_EXC_SUBCLASS))
// Pyston change: made these function calls for now
#if 0
#define PyExceptionClass_Name(x) \
(PyClass_Check((x)) \
? PyString_AS_STRING(((PyClassObject*)(x))->cl_name) \
...
...
@@ -121,8 +121,6 @@ PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**) PY
: (PyObject*)((x)->ob_type)))
#endif
// (We might have to make these wrapper macros that do appropriate casting to PyObject)
PyAPI_FUNC
(
int
)
PyExceptionClass_Check
(
PyObject
*
)
PYSTON_NOEXCEPT
;
PyAPI_FUNC
(
int
)
PyExceptionInstance_Check
(
PyObject
*
)
PYSTON_NOEXCEPT
;
PyAPI_FUNC
(
const
char
*
)
PyExceptionClass_Name
(
PyObject
*
)
PYSTON_NOEXCEPT
;
PyAPI_FUNC
(
PyObject
*
)
PyExceptionInstance_Class
(
PyObject
*
)
PYSTON_NOEXCEPT
;
...
...
@@ -244,6 +242,14 @@ PyAPI_FUNC(PyObject *) PyErr_NewExceptionWithDoc(
char
*
name
,
char
*
doc
,
PyObject
*
base
,
PyObject
*
dict
)
PYSTON_NOEXCEPT
;
PyAPI_FUNC
(
void
)
PyErr_WriteUnraisable
(
PyObject
*
)
PYSTON_NOEXCEPT
;
// Pyston addition: allocate + initialize an instance of type `type`.
// arg represents the single value that will be passed to the constructor;
// a NULL value represents passing zero arguments, and a tuple value will
// not be expanded into multiple arguments.
// In the common cases this will be faster than creating the instance using
// PyObject_Call(type, PyTuple_Pack(1, arg), NULL)
PyAPI_FUNC
(
PyObject
*
)
PyErr_CreateExceptionInstance
(
PyObject
*
type
,
PyObject
*
arg
)
PYSTON_NOEXCEPT
;
/* In sigcheck.c or signalmodule.c */
PyAPI_FUNC
(
int
)
PyErr_CheckSignals
(
void
)
PYSTON_NOEXCEPT
;
PyAPI_FUNC
(
void
)
PyErr_SetInterrupt
(
void
)
PYSTON_NOEXCEPT
;
...
...
from_cpython/Objects/exceptions.c
View file @
60850a52
...
...
@@ -72,6 +72,46 @@ BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds)
return
0
;
}
PyObject
*
PyErr_CreateExceptionInstance
(
PyObject
*
_type
,
PyObject
*
arg
)
{
if
(
PyType_Check
(
_type
)
&&
((
PyTypeObject
*
)
_type
)
->
tp_new
==
(
newfunc
)
BaseException_new
&&
((
PyTypeObject
*
)
_type
)
->
tp_init
==
(
initproc
)
BaseException_init
)
{
PyTypeObject
*
type
=
(
PyTypeObject
*
)
_type
;
// Fast path: inline new and init
PyBaseExceptionObject
*
self
;
self
=
(
PyBaseExceptionObject
*
)
type
->
tp_alloc
(
type
,
0
);
if
(
!
self
)
return
NULL
;
self
->
dict
=
NULL
;
if
(
arg
)
{
self
->
args
=
PyTuple_Pack
(
1
,
arg
);
if
(
!
self
->
args
)
return
NULL
;
self
->
message
=
arg
;
}
else
{
self
->
args
=
PyTuple_New
(
0
);
self
->
message
=
PyString_FromString
(
""
);
if
(
!
self
->
message
)
return
NULL
;
}
return
(
PyObject
*
)
self
;
}
else
{
// Fallback
PyObject
*
args
;
if
(
arg
==
NULL
)
args
=
PyTuple_New
(
0
);
else
args
=
PyTuple_Pack
(
1
,
arg
);
if
(
args
==
NULL
)
return
NULL
;
return
PyObject_Call
(
_type
,
args
,
NULL
);
}
}
static
int
BaseException_clear
(
PyBaseExceptionObject
*
self
)
{
...
...
microbenchmarks/django_template3_reduced.py
0 → 100644
View file @
60850a52
import
os
import
sys
sys
.
path
.
append
(
os
.
path
.
join
(
os
.
path
.
dirname
(
__file__
),
"../test/testsuite/lib/django"
))
BENCHMARK_SUITE_DIR
=
os
.
path
.
join
(
os
.
path
.
dirname
(
__file__
),
"../../pyston-perf/benchmarking/benchmark_suite"
)
sys
.
path
.
extend
([
os
.
path
.
join
(
BENCHMARK_SUITE_DIR
,
"django_template2_site"
)])
from
django.template.base
import
Origin
,
Template
,
Context
,
TemplateDoesNotExist
from
django.conf
import
settings
from
django.apps
import
apps
import
time
import
shutil
# Copy the "base" db so we always start with a knownn state:
os
.
environ
.
setdefault
(
"DJANGO_SETTINGS_MODULE"
,
"testsite.settings"
)
try
:
import
__pyston__
pyston_loaded
=
True
except
:
pyston_loaded
=
False
template_source
=
"""
{% load admin_static %}{% load firstof from future %}<!DOCTYPE html>
<html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
<head>
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}" />
{% block extrastyle %}{% endblock %}
<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="{% block stylesheet_ie %}{% static "admin/css/ie.css" %}{% endblock %}" /><![endif]-->
{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}" />{% endif %}
<script type="text/javascript">window.__admin_media_prefix__ = "{% filter escapejs %}{% static "admin/" %}{% endfilter %}";</script>
<script type="text/javascript">window.__admin_utc_offset__ = "{% filter escapejs %}{% now "Z" %}{% endfilter %}";</script>
{% block extrahead %}{% endblock %}
{% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE" />{% endblock %}
</head>
{% load i18n %}
<body class="{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}">
<!-- Container -->
<div id="container">
{% if not is_popup %}
<!-- Header -->
<div id="header">
<div id="branding">
{% block branding %}{% endblock %}
</div>
{% if user.is_active and user.is_staff %}
<div id="user-tools">
{% block welcome-msg %}
{% trans 'Welcome,' %}
<strong>{% firstof user.get_short_name user.get_username %}</strong>.
{% endblock %}
{% block userlinks %}
{% url 'django-admindocs-docroot' as docsroot %}
{% if docsroot %}
<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> /
{% endif %}
{% if user.has_usable_password %}
<a href="{% url 'admin:password_change' %}">{% trans 'Change password' %}</a> /
{% endif %}
<a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>
{% endblock %}
</div>
{% endif %}
{% block nav-global %}{% endblock %}
</div>
<!-- END Header -->
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
{% if title %} › {{ title }}{% endif %}
</div>
{% endblock %}
{% endif %}
{% block messages %}
{% if messages %}
<ul class="messagelist">{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message|capfirst }}</li>
{% endfor %}</ul>
{% endif %}
{% endblock messages %}
<!-- Content -->
<div id="content" class="{% block coltype %}colM{% endblock %}">
{% block pretitle %}{% endblock %}
{% block content_title %}{% if title %}<h1>{{ title }}</h1>{% endif %}{% endblock %}
{% block content %}
{% block object-tools %}{% endblock %}
{{ content }}
{% endblock %}
{% block sidebar %}{% endblock %}
<br class="clear" />
</div>
<!-- END Content -->
{% block footer %}<div id="footer"></div>{% endblock %}
</div>
<!-- END Container -->
</body>
</html>
"""
apps
.
populate
((
'django.contrib.admin'
,
'django.contrib.auth'
,
'django.contrib.contenttypes'
,
'django.contrib.sessions'
,
'django.contrib.messages'
,
'django.contrib.staticfiles'
,
))
settings
.
TEMPLATE_LOADERS
=
(
(
'django.template.loaders.cached.Loader'
,
(
'django.template.loaders.filesystem.Loader'
,
'django.template.loaders.app_directories.Loader'
,
)),
)
elapsed
=
0
template
=
Template
(
template_source
,
None
,
"admin/index.html"
)
d
=
{}
from
django.contrib.auth.models
import
User
d
[
'user'
]
=
User
(
2
)
# This list was created by running an empty django instance and seeing what it passed for app_list:
d
[
'app_list'
]
=
[{
'app_url'
:
'/admin/auth/'
,
'models'
:
[{
'perms'
:
{
'add'
:
True
,
'change'
:
True
,
'delete'
:
True
},
'admin_url'
:
'/admin/auth/group/'
,
'object_name'
:
'Group'
,
'name'
:
"<name>"
,
'add_url'
:
'/admin/auth/group/add/'
},
{
'perms'
:
{
'add'
:
True
,
'change'
:
True
,
'delete'
:
True
},
'admin_url'
:
'/admin/auth/user/'
,
'object_name'
:
'User'
,
'name'
:
"<name>"
,
'add_url'
:
'/admin/auth/user/add/'
}],
'has_module_perms'
:
True
,
'name'
:
"<name>"
,
'app_label'
:
'auth'
}]
context
=
Context
(
d
)
def
measure_iters
():
for
i
in
xrange
(
6000
):
start
=
time
.
time
()
template
.
render
(
context
)
elapsed
=
time
.
time
()
-
start
print
elapsed
print
"took %4.1fms for last iteration"
%
(
elapsed
*
1000.0
,)
def
measure_by_nodetype
():
times
=
{}
for
i
in
xrange
(
6000
):
for
n
in
template
.
nodelist
:
start
=
time
.
time
()
n
.
render
(
context
)
elapsed
=
time
.
time
()
-
start
times
[
type
(
n
)]
=
times
.
get
(
type
(
n
),
0
)
+
elapsed
for
k
,
v
in
sorted
(
times
.
items
(),
key
=
lambda
(
k
,
v
):
k
.
__name__
):
print
k
.
__name__
,
v
measure_by_nodetype
()
src/codegen/ast_interpreter.cpp
View file @
60850a52
...
...
@@ -1474,7 +1474,7 @@ Value ASTInterpreter::visit_set(AST_Set* node) {
Value
ASTInterpreter
::
visit_str
(
AST_Str
*
node
)
{
Box
*
o
=
NULL
;
if
(
node
->
str_type
==
AST_Str
::
STR
)
{
o
=
parent_module
->
getStringConstant
(
node
->
str_data
);
o
=
parent_module
->
getStringConstant
(
node
->
str_data
,
true
);
}
else
if
(
node
->
str_type
==
AST_Str
::
UNICODE
)
{
o
=
parent_module
->
getUnicodeConstant
(
node
->
str_data
);
}
else
{
...
...
src/codegen/irgen/irgenerator.cpp
View file @
60850a52
...
...
@@ -1278,8 +1278,9 @@ private:
CompilerVariable
*
evalStr
(
AST_Str
*
node
,
const
UnwindInfo
&
unw_info
)
{
if
(
node
->
str_type
==
AST_Str
::
STR
)
{
llvm
::
Value
*
rtn
=
embedRelocatablePtr
(
irstate
->
getSourceInfo
()
->
parent_module
->
getStringConstant
(
node
->
str_data
),
g
.
llvm_value_type_ptr
);
llvm
::
Value
*
rtn
=
embedRelocatablePtr
(
irstate
->
getSourceInfo
()
->
parent_module
->
getStringConstant
(
node
->
str_data
,
true
),
g
.
llvm_value_type_ptr
);
return
new
ConcreteCompilerVariable
(
STR
,
rtn
,
true
);
}
else
if
(
node
->
str_type
==
AST_Str
::
UNICODE
)
{
...
...
src/core/types.h
View file @
60850a52
...
...
@@ -482,13 +482,8 @@ BoxedString* internStringImmortal(llvm::StringRef s);
// Callers should use this function if they can accept mortal string objects.
// FIXME For now it just returns immortal strings, but at least we can use it
// to start documenting the places that can take mortal strings.
inline
BoxedString
*
internStringMortal
(
const
char
*
s
)
{
return
internStringImmortal
(
s
);
}
inline
BoxedString
*
internStringMortal
(
llvm
::
StringRef
s
)
{
assert
(
s
.
data
()[
s
.
size
()]
==
'\0'
);
return
internStringMortal
(
s
.
data
());
return
internStringImmortal
(
s
);
}
// TODO this is an immortal intern for now
...
...
src/runtime/builtin_modules/builtins.cpp
View file @
60850a52
...
...
@@ -37,6 +37,7 @@
#include "runtime/list.h"
#include "runtime/long.h"
#include "runtime/objmodel.h"
#include "runtime/rewrite_args.h"
#include "runtime/set.h"
#include "runtime/super.h"
#include "runtime/types.h"
...
...
@@ -457,7 +458,47 @@ Box* delattrFunc(Box* obj, Box* _str) {
return
None
;
}
template
<
ExceptionStyle
S
>
Box
*
getattrFunc
(
Box
*
obj
,
Box
*
_str
,
Box
*
default_value
)
noexcept
(
S
==
CAPI
)
{
static
Box
*
getattrFuncHelper
(
Box
*
return_val
,
Box
*
obj
,
BoxedString
*
str
,
Box
*
default_val
)
noexcept
{
if
(
return_val
)
return
return_val
;
bool
exc
=
PyErr_Occurred
();
if
(
exc
&&
!
PyErr_ExceptionMatches
(
AttributeError
))
return
NULL
;
if
(
default_val
)
{
if
(
exc
)
PyErr_Clear
();
return
default_val
;
}
if
(
!
exc
)
raiseAttributeErrorCapi
(
obj
,
str
->
s
());
return
NULL
;
}
template
<
ExceptionStyle
S
>
Box
*
getattrFuncInternal
(
BoxedFunctionBase
*
func
,
CallRewriteArgs
*
rewrite_args
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
,
const
std
::
vector
<
BoxedString
*>*
keyword_names
)
{
if
(
argspec
!=
ArgPassSpec
(
2
,
0
,
false
,
false
)
||
argspec
!=
ArgPassSpec
(
3
,
0
,
false
,
false
))
{
static
Box
*
defaults
[]
=
{
NULL
};
bool
rewrite_success
=
false
;
rearrangeArguments
(
ParamReceiveSpec
(
3
,
1
,
false
,
false
),
NULL
,
"getattr"
,
defaults
,
rewrite_args
,
rewrite_success
,
argspec
,
arg1
,
arg2
,
arg3
,
args
,
NULL
,
keyword_names
);
if
(
!
rewrite_success
)
rewrite_args
=
NULL
;
}
Box
*
obj
=
arg1
;
Box
*
_str
=
arg2
;
Box
*
default_value
=
arg3
;
if
(
rewrite_args
)
{
if
(
!
PyString_Check
(
_str
))
rewrite_args
=
NULL
;
else
rewrite_args
->
arg2
->
addGuard
((
intptr_t
)
arg2
);
}
try
{
_str
=
coerceUnicodeToStr
(
_str
);
}
catch
(
ExcInfo
e
)
{
...
...
@@ -476,15 +517,43 @@ template <ExceptionStyle S> Box* getattrFunc(Box* obj, Box* _str, Box* default_v
raiseExcHelper
(
TypeError
,
"getattr(): attribute name must be string"
);
}
Box
*
rtn
=
PyObject_GetAttr
(
obj
,
_str
);
if
(
rtn
==
NULL
&&
default_value
!=
NULL
&&
PyErr_ExceptionMatches
(
AttributeError
))
{
PyErr_Clear
();
return
default_value
;
BoxedString
*
str
=
static_cast
<
BoxedString
*>
(
_str
);
if
(
!
PyString_CHECK_INTERNED
(
str
))
{
internStringMortalInplace
(
str
);
rewrite_args
=
NULL
;
}
Box
*
rtn
;
RewriterVar
*
r_rtn
;
if
(
rewrite_args
)
{
GetattrRewriteArgs
grewrite_args
(
rewrite_args
->
rewriter
,
rewrite_args
->
arg1
,
rewrite_args
->
destination
);
rtn
=
getattrInternal
<
CAPI
>
(
obj
,
str
,
&
grewrite_args
);
if
(
!
grewrite_args
.
out_success
)
rewrite_args
=
NULL
;
else
{
if
(
!
rtn
&&
!
PyErr_Occurred
())
r_rtn
=
rewrite_args
->
rewriter
->
loadConst
(
0
);
else
r_rtn
=
grewrite_args
.
out_rtn
;
}
}
else
{
rtn
=
getattrInternal
<
CAPI
>
(
obj
,
str
,
NULL
);
}
if
(
S
==
CXX
&&
!
rtn
)
if
(
rewrite_args
)
{
RewriterVar
*
final_rtn
=
rewrite_args
->
rewriter
->
call
(
false
,
(
void
*
)
getattrFuncHelper
,
r_rtn
,
rewrite_args
->
arg1
,
rewrite_args
->
arg2
,
rewrite_args
->
arg3
);
if
(
S
==
CXX
)
rewrite_args
->
rewriter
->
checkAndThrowCAPIException
(
final_rtn
);
rewrite_args
->
out_success
=
true
;
rewrite_args
->
out_rtn
=
final_rtn
;
}
Box
*
r
=
getattrFuncHelper
(
rtn
,
obj
,
str
,
default_value
);
if
(
S
==
CXX
&&
!
r
)
throwCAPIException
();
return
r
tn
;
return
r
;
}
Box
*
setattrFunc
(
Box
*
obj
,
Box
*
_str
,
Box
*
value
)
{
...
...
@@ -1449,8 +1518,9 @@ void setupBuiltins() {
builtins_module
->
giveAttr
(
"delattr"
,
new
BoxedBuiltinFunctionOrMethod
(
boxRTFunction
((
void
*
)
delattrFunc
,
NONE
,
2
),
"delattr"
));
auto
getattr_func
=
boxRTFunction
((
void
*
)
getattrFunc
<
CXX
>
,
UNKNOWN
,
3
,
1
,
false
,
false
,
ParamNames
::
empty
(),
CXX
);
addRTFunction
(
getattr_func
,
(
void
*
)
getattrFunc
<
CAPI
>
,
UNKNOWN
,
CAPI
);
auto
getattr_func
=
createRTFunction
(
3
,
1
,
1
,
1
,
ParamNames
::
empty
());
getattr_func
->
internal_callable
.
capi_val
=
&
getattrFuncInternal
<
CAPI
>
;
getattr_func
->
internal_callable
.
cxx_val
=
&
getattrFuncInternal
<
CXX
>
;
builtins_module
->
giveAttr
(
"getattr"
,
new
BoxedBuiltinFunctionOrMethod
(
getattr_func
,
"getattr"
,
{
NULL
}));
builtins_module
->
giveAttr
(
...
...
src/runtime/capi.cpp
View file @
60850a52
...
...
@@ -703,23 +703,21 @@ extern "C" void PyErr_NormalizeException(PyObject** exc, PyObject** val, PyObjec
class.
*/
if
(
!
inclass
||
!
PyObject_IsSubclass
(
inclass
,
type
))
{
PyObject
*
args
,
*
res
;
// Pyston change: rewrote this section
if
(
value
==
Py_None
)
args
=
PyTuple_New
(
0
);
else
if
(
PyTuple_Check
(
value
))
{
Py_INCREF
(
value
);
args
=
value
;
}
else
args
=
PyTuple_Pack
(
1
,
value
);
PyObject
*
res
;
if
(
!
PyTuple_Check
(
value
))
{
res
=
PyErr_CreateExceptionInstance
(
type
,
value
==
Py_None
?
NULL
:
value
);
}
else
{
PyObject
*
args
=
value
;
// Pyston change:
// res = PyEval_CallObject(type, args);
res
=
PyObject_Call
(
type
,
args
,
NULL
);
}
if
(
args
==
NULL
)
goto
finally
;
res
=
PyEval_CallObject
(
type
,
args
);
Py_DECREF
(
args
);
if
(
res
==
NULL
)
goto
finally
;
Py_DECREF
(
value
);
value
=
res
;
}
/* if the class of the instance doesn't exactly match the
...
...
@@ -909,14 +907,6 @@ extern "C" PyObject* PyErr_NoMemory() noexcept {
return
nullptr
;
}
extern
"C"
int
PyExceptionClass_Check
(
PyObject
*
o
)
noexcept
{
return
PyClass_Check
(
o
)
||
(
PyType_Check
(
o
)
&&
isSubclass
(
static_cast
<
BoxedClass
*>
(
o
),
BaseException
));
}
extern
"C"
int
PyExceptionInstance_Check
(
PyObject
*
o
)
noexcept
{
return
PyInstance_Check
(
o
)
||
isSubclass
(
o
->
cls
,
BaseException
);
}
extern
"C"
const
char
*
PyExceptionClass_Name
(
PyObject
*
o
)
noexcept
{
return
PyClass_Check
(
o
)
?
PyString_AS_STRING
(
static_cast
<
BoxedClassobj
*>
(
o
)
->
name
)
:
static_cast
<
BoxedClass
*>
(
o
)
->
tp_name
;
...
...
src/runtime/objmodel.cpp
View file @
60850a52
...
...
@@ -3940,9 +3940,8 @@ static Box* runtimeCallEntry(Box* obj, ArgPassSpec argspec, Box* arg1, Box* arg2
if
(
!
rewrite_args
.
out_success
)
{
rewriter
.
reset
(
NULL
);
}
else
if
(
rtn
)
{
}
else
rewriter
->
commitReturning
(
rewrite_args
.
out_rtn
);
}
}
else
{
rtn
=
runtimeCallInternal
<
S
>
(
obj
,
NULL
,
argspec
,
arg1
,
arg2
,
arg3
,
args
,
keyword_names
);
}
...
...
src/runtime/types.cpp
View file @
60850a52
...
...
@@ -599,6 +599,35 @@ extern "C" CLFunction* unboxCLFunction(Box* b) {
return
static_cast
<
BoxedFunction
*>
(
b
)
->
f
;
}
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
;
}
template
<
ExceptionStyle
S
>
static
Box
*
typeCallInner
(
CallRewriteArgs
*
rewrite_args
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
,
const
std
::
vector
<
BoxedString
*>*
keyword_names
)
noexcept
(
S
==
CAPI
);
...
...
@@ -608,6 +637,25 @@ static Box* typeTppCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSpec ar
Box
**
args
,
const
std
::
vector
<
BoxedString
*>*
keyword_names
)
noexcept
(
S
==
CAPI
)
{
int
npassed_args
=
argspec
.
totalPassed
();
// Common CAPI path call this function with *args, **kw.
if
(
argspec
==
ArgPassSpec
(
0
,
0
,
true
,
false
)
||
argspec
==
ArgPassSpec
(
0
,
0
,
true
,
true
))
{
// Wouldn't be able to rewrite anyway:
assert
(
!
rewrite_args
||
!
rewrite_args
->
out_success
);
arg1
=
PySequence_Tuple
(
arg1
);
if
(
!
arg1
)
{
if
(
S
==
CAPI
)
return
NULL
;
else
throwCAPIException
();
}
Box
*
r
=
cpython_type_call
(
static_cast
<
BoxedClass
*>
(
self
),
arg1
,
argspec
.
has_kwargs
?
arg2
:
NULL
);
if
(
S
==
CXX
&&
!
r
)
throwCAPIException
();
return
r
;
}
if
(
argspec
.
has_starargs
||
argspec
.
has_kwargs
)
{
// This would fail in typeCallInner
rewrite_args
=
NULL
;
...
...
@@ -654,35 +702,6 @@ 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
)
...
...
test/tests/.gitignore
View file @
60850a52
t.py
t2.py
t3.py
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment