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
181d5850
Commit
181d5850
authored
May 08, 2015
by
Marius Wachtler
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'upstream/master' into intern
parents
d7d47656
9030ec59
Changes
48
Hide whitespace changes
Inline
Side-by-side
Showing
48 changed files
with
1883 additions
and
807 deletions
+1883
-807
.travis.yml
.travis.yml
+2
-1
Makefile
Makefile
+13
-0
from_cpython/Include/pyconfig.h
from_cpython/Include/pyconfig.h
+5
-0
from_cpython/Modules/_collectionsmodule.c
from_cpython/Modules/_collectionsmodule.c
+3
-1
minibenchmarks/django-template.py
minibenchmarks/django-template.py
+115
-0
src/CMakeLists.txt
src/CMakeLists.txt
+0
-1
src/capi/abstract.cpp
src/capi/abstract.cpp
+38
-2
src/capi/descrobject.cpp
src/capi/descrobject.cpp
+1
-0
src/capi/float.cpp
src/capi/float.cpp
+0
-496
src/capi/typeobject.cpp
src/capi/typeobject.cpp
+29
-0
src/capi/types.h
src/capi/types.h
+3
-0
src/codegen/ast_interpreter.cpp
src/codegen/ast_interpreter.cpp
+6
-7
src/codegen/entry.cpp
src/codegen/entry.cpp
+1
-1
src/codegen/irgen/hooks.cpp
src/codegen/irgen/hooks.cpp
+6
-2
src/codegen/parser.cpp
src/codegen/parser.cpp
+3
-1
src/codegen/unwinding.cpp
src/codegen/unwinding.cpp
+4
-0
src/core/stats.cpp
src/core/stats.cpp
+155
-4
src/core/stats.h
src/core/stats.h
+82
-7
src/core/stringpool.h
src/core/stringpool.h
+2
-0
src/core/types.h
src/core/types.h
+13
-0
src/core/util.cpp
src/core/util.cpp
+25
-8
src/core/util.h
src/core/util.h
+12
-6
src/gc/collector.cpp
src/gc/collector.cpp
+2
-0
src/gc/gc_alloc.h
src/gc/gc_alloc.h
+9
-1
src/jit.cpp
src/jit.cpp
+279
-174
src/runtime/builtin_modules/builtins.cpp
src/runtime/builtin_modules/builtins.cpp
+49
-8
src/runtime/dict.cpp
src/runtime/dict.cpp
+8
-0
src/runtime/float.cpp
src/runtime/float.cpp
+563
-0
src/runtime/generator.cpp
src/runtime/generator.cpp
+39
-17
src/runtime/import.cpp
src/runtime/import.cpp
+8
-14
src/runtime/int.cpp
src/runtime/int.cpp
+8
-3
src/runtime/iterobject.cpp
src/runtime/iterobject.cpp
+3
-2
src/runtime/list.cpp
src/runtime/list.cpp
+15
-14
src/runtime/long.cpp
src/runtime/long.cpp
+48
-2
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+143
-27
src/runtime/objmodel.h
src/runtime/objmodel.h
+6
-0
src/runtime/stacktrace.cpp
src/runtime/stacktrace.cpp
+3
-0
src/runtime/str.cpp
src/runtime/str.cpp
+13
-1
src/runtime/tuple.cpp
src/runtime/tuple.cpp
+2
-0
src/runtime/types.cpp
src/runtime/types.cpp
+42
-1
src/runtime/types.h
src/runtime/types.h
+61
-0
test/integration/virtualenv_test.py
test/integration/virtualenv_test.py
+2
-1
test/tests/builtins.py
test/tests/builtins.py
+2
-2
test/tests/import_globals.py
test/tests/import_globals.py
+24
-0
test/tests/intmethods.py
test/tests/intmethods.py
+3
-0
test/tests/list.py
test/tests/list.py
+7
-1
test/tests/list_subclassing.py
test/tests/list_subclassing.py
+23
-2
tools/tester.py
tools/tester.py
+3
-0
No files found.
.travis.yml
View file @
181d5850
...
...
@@ -23,6 +23,7 @@ addons:
-
clang-3.5
-
cmake
-
g++-4.8
-
gdb
-
libgmp3-dev
-
liblzma-dev
-
libncurses5-dev
...
...
@@ -51,7 +52,7 @@ script:
-
ccache -z
-
ninja -j4 pyston
-
ccache -s
-
ninja check-pyston
-
PYSTON_RUN_ARGS=G
ninja check-pyston
os
:
-
linux
...
...
Makefile
View file @
181d5850
...
...
@@ -112,12 +112,25 @@ ifeq ($(NEED_OLD_JIT),1)
LLVM_LINK_LIBS
+=
jit
endif
LLVM_CONFIG_DBG
:=
$(LLVM_BUILD)
/Release+Asserts/bin/llvm-config
ifneq
($(wildcard $(LLVM_CONFIG_DBG)),)
LLVM_CXXFLAGS
:=
$(
shell
$(LLVM_BUILD)
/Release+Asserts/bin/llvm-config
--cxxflags
)
LLVM_LDFLAGS
:=
$(
shell
$(LLVM_BUILD)
/Release+Asserts/bin/llvm-config
--ldflags
--system-libs
--libs
$(LLVM_LINK_LIBS)
)
LLVM_LIB_DEPS
:=
$(
wildcard
$(LLVM_BUILD)
/Release+Asserts/lib/
*
)
else
LLVM_CXXFLAGS
:=
DBG_NOT_BUILT
LLVM_LDFLAGS
:=
DBG_NOT_BUILT
LLVM_LIB_DEPS
:=
DBG_NOT_BUILT
endif
LLVM_CONFIG_DEBUG
:=
$(LLVM_BUILD)
/Debug+Asserts/bin/llvm-config
ifneq
($(wildcard $(LLVM_CONFIG_DBG)),)
LLVM_DEBUG_LDFLAGS
:=
$(
shell
$(LLVM_BUILD)
/Debug+Asserts/bin/llvm-config
--ldflags
--system-libs
--libs
$(LLVM_LINK_LIBS)
)
LLVM_DEBUG_LIB_DEPS
:=
$(
wildcard
$(LLVM_BUILD)
/Debug+Asserts/lib/
*
)
else
LLVM_DEBUG_LDFLAGS
:=
DEBUG_NOT_BUILT
LLVM_DEBUG_LIB_DEPS
:=
DEBUG_NOT_BUILT
endif
LLVM_CONFIG_RELEASE
:=
$(LLVM_BUILD)
/Release/bin/llvm-config
ifneq
($(wildcard $(LLVM_CONFIG_RELEASE)),)
...
...
from_cpython/Include/pyconfig.h
View file @
181d5850
...
...
@@ -27,6 +27,8 @@
#define SIZEOF_INT 4
#define SIZEOF_LONG 8
#define SIZEOF_LONG_LONG 8
#define SIZEOF_DOUBLE 8
#define SIZEOF_FLOAT 4
#define SIZEOF_OFF_T 8
#define SIZEOF_PTHREAD_T 8
#define HAVE_COPYSIGN 1
...
...
@@ -59,6 +61,9 @@
#define HAVE_STRUCT_TM_TM_ZONE 1
#define HAVE_MKTIME 1
#define TIME_WITH_SYS_TIME
#define HAVE_GETTIMEOFDAY 1
#define PY_FORMAT_LONG_LONG "ll"
#define PY_FORMAT_SIZE_T "z"
...
...
from_cpython/Modules/_collectionsmodule.c
View file @
181d5850
...
...
@@ -55,7 +55,9 @@ typedef struct BLOCK {
struct
BLOCK
*
leftlink
;
}
block
;
#define MAXFREEBLOCKS 10
// Pyston change: disable free block cache
// #define MAXFREEBLOCKS 10
#define MAXFREEBLOCKS 0
static
Py_ssize_t
numfreeblocks
=
0
;
static
block
*
freeblocks
[
MAXFREEBLOCKS
];
...
...
minibenchmarks/django-template.py
0 → 100644
View file @
181d5850
from
django.template.base
import
Origin
,
Template
,
Context
,
TemplateDoesNotExist
from
django.conf
import
settings
from
django.apps
import
apps
import
time
try
:
import
__pyston__
pyston_loaded
=
True
except
:
pyston_loaded
=
False
template_source
=
"""
{% extends "admin/base_site.html" %}
{% load i18n admin_static %}
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/dashboard.css" %}" />{% endblock %}
{% block coltype %}colMS{% endblock %}
{% block bodyclass %}{{ block.super }} dashboard{% endblock %}
{% block breadcrumbs %}{% endblock %}
{% block content %}
<div id="content-main">
{% if app_list %}
{% for app in app_list %}
<div class="app-{{ app.app_label }} module">
<table>
<caption>
<a href="{{ app.app_url }}" class="section" title="{% blocktrans with name=app.name %}Models in the {{ name }} application{% endblocktrans %}">{{ app.name }}</a>
</caption>
{% for model in app.models %}
<tr class="model-{{ model.object_name|lower }}">
{% if model.admin_url %}
<th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
{% else %}
<th scope="row">{{ model.name }}</th>
{% endif %}
{% if model.add_url %}
<td><a href="{{ model.add_url }}" class="addlink">{% trans 'Add' %}</a></td>
{% else %}
<td> </td>
{% endif %}
{% if model.admin_url %}
<td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
{% else %}
<td> </td>
{% endif %}
</tr>
{% endfor %}
</table>
</div>
{% endfor %}
{% else %}
<p>{% trans "You don't have permission to edit anything." %}</p>
{% endif %}
</div>
{% endblock %}
{% block sidebar %}
<div id="content-related">
<div class="module" id="recent-actions-module">
<h2>{% trans 'Recent Actions' %}</h2>
<h3>{% trans 'My Actions' %}</h3>
{% load log %}
{% get_admin_log 10 as admin_log for_user user %}
{% if not admin_log %}
<p>{% trans 'None available' %}</p>
{% else %}
<ul class="actionlist">
{% for entry in admin_log %}
<li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">
{% if entry.is_deletion or not entry.get_admin_url %}
{{ entry.object_repr }}
{% else %}
<a href="{{ entry.get_admin_url }}">{{ entry.object_repr }}</a>
{% endif %}
<br/>
{% if entry.content_type %}
<span class="mini quiet">{% filter capfirst %}{% trans entry.content_type.name %}{% endfilter %}</span>
{% else %}
<span class="mini quiet">{% trans 'Unknown content' %}</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
{% endblock %}
"""
settings
.
configure
()
apps
.
populate
((
'django.contrib.admin'
,
'django.contrib.auth'
,
'django.contrib.contenttypes'
,
'django.contrib.sessions'
,
'django.contrib.messages'
,
'django.contrib.staticfiles'
,
))
elapsed
=
0
for
i
in
xrange
(
500
):
#if pyston_loaded:
# __pyston__.clearStats()
start
=
time
.
time
()
template
=
Template
(
template_source
,
None
,
"admin/index.html"
)
elapsed
=
time
.
time
()
-
start
print
"took %4.1fms for last iteration"
%
(
elapsed
*
1000.0
,)
src/CMakeLists.txt
View file @
181d5850
...
...
@@ -30,7 +30,6 @@ add_library(PYSTON_OBJECTS OBJECT ${OPTIONAL_SRCS}
capi/codecs.cpp
capi/descrobject.cpp
capi/errors.cpp
capi/float.cpp
capi/modsupport.cpp
capi/object.cpp
capi/typeobject.cpp
...
...
src/capi/abstract.cpp
View file @
181d5850
...
...
@@ -557,8 +557,29 @@ extern "C" int PyObject_CheckReadBuffer(PyObject* obj) noexcept {
}
extern
"C"
int
PyObject_AsReadBuffer
(
PyObject
*
obj
,
const
void
**
buffer
,
Py_ssize_t
*
buffer_len
)
noexcept
{
fatalOrError
(
PyExc_NotImplementedError
,
"unimplemented"
);
return
-
1
;
PyBufferProcs
*
pb
;
void
*
pp
;
Py_ssize_t
len
;
if
(
obj
==
NULL
||
buffer
==
NULL
||
buffer_len
==
NULL
)
{
null_error
();
return
-
1
;
}
pb
=
obj
->
cls
->
tp_as_buffer
;
if
(
pb
==
NULL
||
pb
->
bf_getreadbuffer
==
NULL
||
pb
->
bf_getsegcount
==
NULL
)
{
PyErr_SetString
(
PyExc_TypeError
,
"expected a readable buffer object"
);
return
-
1
;
}
if
((
*
pb
->
bf_getsegcount
)(
obj
,
NULL
)
!=
1
)
{
PyErr_SetString
(
PyExc_TypeError
,
"expected a single-segment buffer object"
);
return
-
1
;
}
len
=
(
*
pb
->
bf_getreadbuffer
)(
obj
,
0
,
&
pp
);
if
(
len
<
0
)
return
-
1
;
*
buffer
=
pp
;
*
buffer_len
=
len
;
return
0
;
}
static
PyObject
*
call_function_tail
(
PyObject
*
callable
,
PyObject
*
args
)
{
...
...
@@ -1818,6 +1839,21 @@ extern "C" PyObject* PyNumber_Long(PyObject* o) noexcept {
}
extern
"C"
PyObject
*
PyNumber_Float
(
PyObject
*
o
)
noexcept
{
if
(
o
==
NULL
)
return
null_error
();
if
(
o
->
cls
==
float_cls
)
return
o
;
if
(
PyInt_Check
(
o
))
return
boxFloat
(((
BoxedInt
*
)
o
)
->
n
);
else
if
(
PyLong_Check
(
o
))
{
double
result
=
PyLong_AsDouble
(
o
);
if
(
result
==
-
1.0
&&
PyErr_Occurred
())
return
NULL
;
return
boxFloat
(
result
);
}
fatalOrError
(
PyExc_NotImplementedError
,
"unimplemented"
);
return
nullptr
;
}
...
...
src/capi/descrobject.cpp
View file @
181d5850
...
...
@@ -18,6 +18,7 @@
namespace
pyston
{
Box
*
BoxedMethodDescriptor
::
__call__
(
BoxedMethodDescriptor
*
self
,
Box
*
obj
,
BoxedTuple
*
varargs
,
Box
**
_args
)
{
STAT_TIMER
(
t0
,
"us_timer_boxedmethoddescriptor__call__"
);
BoxedDict
*
kwargs
=
static_cast
<
BoxedDict
*>
(
_args
[
0
]);
assert
(
self
->
cls
==
method_cls
);
...
...
src/capi/float.cpp
deleted
100644 → 0
View file @
d7d47656
// 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.
// This file is mostly copied from CPython
#include "Python.h"
#include "core/types.h"
#include "runtime/types.h"
namespace
pyston
{
extern
"C"
{
typedef
enum
{
unknown_format
,
ieee_big_endian_format
,
ieee_little_endian_format
}
float_format_type
;
static
float_format_type
double_format
,
float_format
;
static
float_format_type
detected_double_format
,
detected_float_format
;
static
PyObject
*
float_getformat
(
PyTypeObject
*
v
,
PyObject
*
arg
)
noexcept
{
float_format_type
r
;
BoxedString
*
str
=
static_cast
<
BoxedString
*>
(
arg
);
if
(
!
PyString_Check
(
arg
))
{
PyErr_Format
(
PyExc_TypeError
,
"__getformat__() argument must be string, not %.500s"
,
Py_TYPE
(
arg
)
->
tp_name
);
return
NULL
;
}
if
(
str
->
s
==
"double"
)
{
r
=
double_format
;
}
else
if
(
str
->
s
==
"float"
)
{
r
=
float_format
;
}
else
{
PyErr_SetString
(
PyExc_ValueError
,
"__getformat__() argument 1 must be "
"'double' or 'float'"
);
return
NULL
;
}
switch
(
r
)
{
case
unknown_format
:
return
static_cast
<
PyObject
*>
(
boxStrConstant
(
"unknown"
));
case
ieee_little_endian_format
:
return
static_cast
<
PyObject
*>
(
boxStrConstant
(
"IEEE, little-endian"
));
case
ieee_big_endian_format
:
return
static_cast
<
PyObject
*>
(
boxStrConstant
(
"IEEE, big-endian"
));
default:
Py_FatalError
(
"insane float_format or double_format"
);
return
NULL
;
}
}
PyDoc_STRVAR
(
float_getformat_doc
,
"float.__getformat__(typestr) -> string
\n
"
"
\n
"
"You probably don't want to use this function. It exists mainly to be
\n
"
"used in Python's test suite.
\n
"
"
\n
"
"typestr must be 'double' or 'float'. This function returns whichever of
\n
"
"'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the
\n
"
"format of floating point numbers used by the C type named by typestr."
);
static
PyObject
*
float_setformat
(
PyTypeObject
*
v
,
PyObject
*
args
)
noexcept
{
char
*
typestr
;
char
*
format
;
float_format_type
f
;
float_format_type
detected
;
float_format_type
*
p
;
if
(
!
PyArg_ParseTuple
(
args
,
"ss:__setformat__"
,
&
typestr
,
&
format
))
return
NULL
;
if
(
strcmp
(
typestr
,
"double"
)
==
0
)
{
p
=
&
double_format
;
detected
=
detected_double_format
;
}
else
if
(
strcmp
(
typestr
,
"float"
)
==
0
)
{
p
=
&
float_format
;
detected
=
detected_float_format
;
}
else
{
PyErr_SetString
(
PyExc_ValueError
,
"__setformat__() argument 1 must "
"be 'double' or 'float'"
);
return
NULL
;
}
if
(
strcmp
(
format
,
"unknown"
)
==
0
)
{
f
=
unknown_format
;
}
else
if
(
strcmp
(
format
,
"IEEE, little-endian"
)
==
0
)
{
f
=
ieee_little_endian_format
;
}
else
if
(
strcmp
(
format
,
"IEEE, big-endian"
)
==
0
)
{
f
=
ieee_big_endian_format
;
}
else
{
PyErr_SetString
(
PyExc_ValueError
,
"__setformat__() argument 2 must be "
"'unknown', 'IEEE, little-endian' or "
"'IEEE, big-endian'"
);
return
NULL
;
}
if
(
f
!=
unknown_format
&&
f
!=
detected
)
{
PyErr_Format
(
PyExc_ValueError
,
"can only set %s format to 'unknown' or the "
"detected platform value"
,
typestr
);
return
NULL
;
}
*
p
=
f
;
Py_RETURN_NONE
;
}
/*----------------------------------------------------------------------------
* _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h.
*/
extern
"C"
int
_PyFloat_Pack4
(
double
x
,
unsigned
char
*
p
,
int
le
)
noexcept
{
if
(
float_format
==
unknown_format
)
{
unsigned
char
sign
;
int
e
;
double
f
;
unsigned
int
fbits
;
int
incr
=
1
;
if
(
le
)
{
p
+=
3
;
incr
=
-
1
;
}
if
(
x
<
0
)
{
sign
=
1
;
x
=
-
x
;
}
else
sign
=
0
;
f
=
frexp
(
x
,
&
e
);
/* Normalize f to be in the range [1.0, 2.0) */
if
(
0.5
<=
f
&&
f
<
1.0
)
{
f
*=
2.0
;
e
--
;
}
else
if
(
f
==
0.0
)
e
=
0
;
else
{
PyErr_SetString
(
PyExc_SystemError
,
"frexp() result out of range"
);
return
-
1
;
}
if
(
e
>=
128
)
goto
Overflow
;
else
if
(
e
<
-
126
)
{
/* Gradual underflow */
f
=
ldexp
(
f
,
126
+
e
);
e
=
0
;
}
else
if
(
!
(
e
==
0
&&
f
==
0.0
))
{
e
+=
127
;
f
-=
1.0
;
/* Get rid of leading 1 */
}
f
*=
8388608.0
;
/* 2**23 */
fbits
=
(
unsigned
int
)(
f
+
0.5
);
/* Round */
assert
(
fbits
<=
8388608
);
if
(
fbits
>>
23
)
{
/* The carry propagated out of a string of 23 1 bits. */
fbits
=
0
;
++
e
;
if
(
e
>=
255
)
goto
Overflow
;
}
/* First byte */
*
p
=
(
sign
<<
7
)
|
(
e
>>
1
);
p
+=
incr
;
/* Second byte */
*
p
=
(
char
)(((
e
&
1
)
<<
7
)
|
(
fbits
>>
16
));
p
+=
incr
;
/* Third byte */
*
p
=
(
fbits
>>
8
)
&
0xFF
;
p
+=
incr
;
/* Fourth byte */
*
p
=
fbits
&
0xFF
;
/* Done */
return
0
;
}
else
{
float
y
=
(
float
)
x
;
const
char
*
s
=
(
char
*
)
&
y
;
int
i
,
incr
=
1
;
if
(
Py_IS_INFINITY
(
y
)
&&
!
Py_IS_INFINITY
(
x
))
goto
Overflow
;
if
((
float_format
==
ieee_little_endian_format
&&
!
le
)
||
(
float_format
==
ieee_big_endian_format
&&
le
))
{
p
+=
3
;
incr
=
-
1
;
}
for
(
i
=
0
;
i
<
4
;
i
++
)
{
*
p
=
*
s
++
;
p
+=
incr
;
}
return
0
;
}
Overflow:
PyErr_SetString
(
PyExc_OverflowError
,
"float too large to pack with f format"
);
return
-
1
;
}
extern
"C"
int
_PyFloat_Pack8
(
double
x
,
unsigned
char
*
p
,
int
le
)
noexcept
{
if
(
double_format
==
unknown_format
)
{
unsigned
char
sign
;
int
e
;
double
f
;
unsigned
int
fhi
,
flo
;
int
incr
=
1
;
if
(
le
)
{
p
+=
7
;
incr
=
-
1
;
}
if
(
x
<
0
)
{
sign
=
1
;
x
=
-
x
;
}
else
sign
=
0
;
f
=
frexp
(
x
,
&
e
);
/* Normalize f to be in the range [1.0, 2.0) */
if
(
0.5
<=
f
&&
f
<
1.0
)
{
f
*=
2.0
;
e
--
;
}
else
if
(
f
==
0.0
)
e
=
0
;
else
{
PyErr_SetString
(
PyExc_SystemError
,
"frexp() result out of range"
);
return
-
1
;
}
if
(
e
>=
1024
)
goto
Overflow
;
else
if
(
e
<
-
1022
)
{
/* Gradual underflow */
f
=
ldexp
(
f
,
1022
+
e
);
e
=
0
;
}
else
if
(
!
(
e
==
0
&&
f
==
0.0
))
{
e
+=
1023
;
f
-=
1.0
;
/* Get rid of leading 1 */
}
/* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */
f
*=
268435456.0
;
/* 2**28 */
fhi
=
(
unsigned
int
)
f
;
/* Truncate */
assert
(
fhi
<
268435456
);
f
-=
(
double
)
fhi
;
f
*=
16777216.0
;
/* 2**24 */
flo
=
(
unsigned
int
)(
f
+
0.5
);
/* Round */
assert
(
flo
<=
16777216
);
if
(
flo
>>
24
)
{
/* The carry propagated out of a string of 24 1 bits. */
flo
=
0
;
++
fhi
;
if
(
fhi
>>
28
)
{
/* And it also progagated out of the next 28 bits. */
fhi
=
0
;
++
e
;
if
(
e
>=
2047
)
goto
Overflow
;
}
}
/* First byte */
*
p
=
(
sign
<<
7
)
|
(
e
>>
4
);
p
+=
incr
;
/* Second byte */
*
p
=
(
unsigned
char
)(((
e
&
0xF
)
<<
4
)
|
(
fhi
>>
24
));
p
+=
incr
;
/* Third byte */
*
p
=
(
fhi
>>
16
)
&
0xFF
;
p
+=
incr
;
/* Fourth byte */
*
p
=
(
fhi
>>
8
)
&
0xFF
;
p
+=
incr
;
/* Fifth byte */
*
p
=
fhi
&
0xFF
;
p
+=
incr
;
/* Sixth byte */
*
p
=
(
flo
>>
16
)
&
0xFF
;
p
+=
incr
;
/* Seventh byte */
*
p
=
(
flo
>>
8
)
&
0xFF
;
p
+=
incr
;
/* Eighth byte */
*
p
=
flo
&
0xFF
;
/* p += incr; Unneeded (for now) */
/* Done */
return
0
;
Overflow:
PyErr_SetString
(
PyExc_OverflowError
,
"float too large to pack with d format"
);
return
-
1
;
}
else
{
const
char
*
s
=
(
char
*
)
&
x
;
int
i
,
incr
=
1
;
if
((
double_format
==
ieee_little_endian_format
&&
!
le
)
||
(
double_format
==
ieee_big_endian_format
&&
le
))
{
p
+=
7
;
incr
=
-
1
;
}
for
(
i
=
0
;
i
<
8
;
i
++
)
{
*
p
=
*
s
++
;
p
+=
incr
;
}
return
0
;
}
}
double
_PyFloat_Unpack4
(
const
unsigned
char
*
p
,
int
le
)
noexcept
{
if
(
float_format
==
unknown_format
)
{
unsigned
char
sign
;
int
e
;
unsigned
int
f
;
double
x
;
int
incr
=
1
;
if
(
le
)
{
p
+=
3
;
incr
=
-
1
;
}
/* First byte */
sign
=
(
*
p
>>
7
)
&
1
;
e
=
(
*
p
&
0x7F
)
<<
1
;
p
+=
incr
;
/* Second byte */
e
|=
(
*
p
>>
7
)
&
1
;
f
=
(
*
p
&
0x7F
)
<<
16
;
p
+=
incr
;
if
(
e
==
255
)
{
PyErr_SetString
(
PyExc_ValueError
,
"can't unpack IEEE 754 special value "
"on non-IEEE platform"
);
return
-
1
;
}
/* Third byte */
f
|=
*
p
<<
8
;
p
+=
incr
;
/* Fourth byte */
f
|=
*
p
;
x
=
(
double
)
f
/
8388608.0
;
/* XXX This sadly ignores Inf/NaN issues */
if
(
e
==
0
)
e
=
-
126
;
else
{
x
+=
1.0
;
e
-=
127
;
}
x
=
ldexp
(
x
,
e
);
if
(
sign
)
x
=
-
x
;
return
x
;
}
else
{
float
x
;
if
((
float_format
==
ieee_little_endian_format
&&
!
le
)
||
(
float_format
==
ieee_big_endian_format
&&
le
))
{
char
buf
[
4
];
char
*
d
=
&
buf
[
3
];
int
i
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
*
d
--
=
*
p
++
;
}
memcpy
(
&
x
,
buf
,
4
);
}
else
{
memcpy
(
&
x
,
p
,
4
);
}
return
x
;
}
}
double
_PyFloat_Unpack8
(
const
unsigned
char
*
p
,
int
le
)
noexcept
{
if
(
double_format
==
unknown_format
)
{
unsigned
char
sign
;
int
e
;
unsigned
int
fhi
,
flo
;
double
x
;
int
incr
=
1
;
if
(
le
)
{
p
+=
7
;
incr
=
-
1
;
}
/* First byte */
sign
=
(
*
p
>>
7
)
&
1
;
e
=
(
*
p
&
0x7F
)
<<
4
;
p
+=
incr
;
/* Second byte */
e
|=
(
*
p
>>
4
)
&
0xF
;
fhi
=
(
*
p
&
0xF
)
<<
24
;
p
+=
incr
;
if
(
e
==
2047
)
{
PyErr_SetString
(
PyExc_ValueError
,
"can't unpack IEEE 754 special value "
"on non-IEEE platform"
);
return
-
1.0
;
}
/* Third byte */
fhi
|=
*
p
<<
16
;
p
+=
incr
;
/* Fourth byte */
fhi
|=
*
p
<<
8
;
p
+=
incr
;
/* Fifth byte */
fhi
|=
*
p
;
p
+=
incr
;
/* Sixth byte */
flo
=
*
p
<<
16
;
p
+=
incr
;
/* Seventh byte */
flo
|=
*
p
<<
8
;
p
+=
incr
;
/* Eighth byte */
flo
|=
*
p
;
x
=
(
double
)
fhi
+
(
double
)
flo
/
16777216.0
;
/* 2**24 */
x
/=
268435456.0
;
/* 2**28 */
if
(
e
==
0
)
e
=
-
1022
;
else
{
x
+=
1.0
;
e
-=
1023
;
}
x
=
ldexp
(
x
,
e
);
if
(
sign
)
x
=
-
x
;
return
x
;
}
else
{
double
x
;
if
((
double_format
==
ieee_little_endian_format
&&
!
le
)
||
(
double_format
==
ieee_big_endian_format
&&
le
))
{
char
buf
[
8
];
char
*
d
=
&
buf
[
7
];
int
i
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
*
d
--
=
*
p
++
;
}
memcpy
(
&
x
,
buf
,
8
);
}
else
{
memcpy
(
&
x
,
p
,
8
);
}
return
x
;
}
}
}
}
src/capi/typeobject.cpp
View file @
181d5850
...
...
@@ -58,6 +58,7 @@ static int hackcheck(PyObject* self, setattrofunc func, const char* what) noexce
}
static
PyObject
*
wrap_setattr
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_setattr"
);
setattrofunc
func
=
(
setattrofunc
)
wrapped
;
int
res
;
PyObject
*
name
,
*
value
;
...
...
@@ -74,6 +75,7 @@ static PyObject* wrap_setattr(PyObject* self, PyObject* args, void* wrapped) noe
}
static
PyObject
*
wrap_delattr
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_delattr"
);
setattrofunc
func
=
(
setattrofunc
)
wrapped
;
int
res
;
PyObject
*
name
;
...
...
@@ -91,6 +93,7 @@ static PyObject* wrap_delattr(PyObject* self, PyObject* args, void* wrapped) noe
}
static
PyObject
*
wrap_hashfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_hashfunc"
);
hashfunc
func
=
(
hashfunc
)
wrapped
;
long
res
;
...
...
@@ -103,12 +106,14 @@ static PyObject* wrap_hashfunc(PyObject* self, PyObject* args, void* wrapped) no
}
static
PyObject
*
wrap_call
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
,
PyObject
*
kwds
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_call"
);
ternaryfunc
func
=
(
ternaryfunc
)
wrapped
;
return
(
*
func
)(
self
,
args
,
kwds
);
}
static
PyObject
*
wrap_richcmpfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
,
int
op
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_richcmpfunc"
);
richcmpfunc
func
=
(
richcmpfunc
)
wrapped
;
PyObject
*
other
;
...
...
@@ -132,6 +137,7 @@ RICHCMP_WRAPPER(gt, Py_GT)
RICHCMP_WRAPPER
(
ge
,
Py_GE
)
static
PyObject
*
wrap_next
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
{
STAT_TIMER
(
t0
,
"us_timer_wrap_next"
);
unaryfunc
func
=
(
unaryfunc
)
wrapped
;
PyObject
*
res
;
...
...
@@ -144,6 +150,7 @@ static PyObject* wrap_next(PyObject* self, PyObject* args, void* wrapped) {
}
static
PyObject
*
wrap_descr_get
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_descr_get"
);
descrgetfunc
func
=
(
descrgetfunc
)
wrapped
;
PyObject
*
obj
;
PyObject
*
type
=
NULL
;
...
...
@@ -162,6 +169,7 @@ static PyObject* wrap_descr_get(PyObject* self, PyObject* args, void* wrapped) n
}
static
PyObject
*
wrap_coercefunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_coercefunc"
);
coercion
func
=
(
coercion
)
wrapped
;
PyObject
*
other
,
*
res
;
int
ok
;
...
...
@@ -188,6 +196,7 @@ static PyObject* wrap_coercefunc(PyObject* self, PyObject* args, void* wrapped)
}
static
PyObject
*
wrap_ternaryfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_ternaryfunc"
);
ternaryfunc
func
=
(
ternaryfunc
)
wrapped
;
PyObject
*
other
;
PyObject
*
third
=
Py_None
;
...
...
@@ -200,6 +209,7 @@ static PyObject* wrap_ternaryfunc(PyObject* self, PyObject* args, void* wrapped)
}
static
PyObject
*
wrap_ternaryfunc_r
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_ternaryfunc_r"
);
ternaryfunc
func
=
(
ternaryfunc
)
wrapped
;
PyObject
*
other
;
PyObject
*
third
=
Py_None
;
...
...
@@ -212,6 +222,7 @@ static PyObject* wrap_ternaryfunc_r(PyObject* self, PyObject* args, void* wrappe
}
static
PyObject
*
wrap_unaryfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_unaryfunc"
);
unaryfunc
func
=
(
unaryfunc
)
wrapped
;
if
(
!
check_num_args
(
args
,
0
))
...
...
@@ -220,6 +231,7 @@ static PyObject* wrap_unaryfunc(PyObject* self, PyObject* args, void* wrapped) n
}
static
PyObject
*
wrap_inquirypred
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_inquirypred"
);
inquiry
func
=
(
inquiry
)
wrapped
;
int
res
;
...
...
@@ -232,6 +244,7 @@ static PyObject* wrap_inquirypred(PyObject* self, PyObject* args, void* wrapped)
}
static
PyObject
*
wrapInquirypred
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
{
STAT_TIMER
(
t0
,
"us_timer_wrapInquirypred"
);
inquiry
func
=
(
inquiry
)
wrapped
;
int
res
;
...
...
@@ -244,6 +257,7 @@ static PyObject* wrapInquirypred(PyObject* self, PyObject* args, void* wrapped)
}
static
PyObject
*
wrap_binaryfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_binaryfunc"
);
binaryfunc
func
=
(
binaryfunc
)
wrapped
;
PyObject
*
other
;
...
...
@@ -254,6 +268,7 @@ static PyObject* wrap_binaryfunc(PyObject* self, PyObject* args, void* wrapped)
}
static
PyObject
*
wrap_binaryfunc_l
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_binaryfunc_l"
);
binaryfunc
func
=
(
binaryfunc
)
wrapped
;
PyObject
*
other
;
...
...
@@ -268,6 +283,7 @@ static PyObject* wrap_binaryfunc_l(PyObject* self, PyObject* args, void* wrapped
}
static
PyObject
*
wrap_binaryfunc_r
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_binaryfunc_r"
);
binaryfunc
func
=
(
binaryfunc
)
wrapped
;
PyObject
*
other
;
...
...
@@ -300,6 +316,7 @@ static Py_ssize_t getindex(PyObject* self, PyObject* arg) noexcept {
}
static
PyObject
*
wrap_lenfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_lenfunc"
);
lenfunc
func
=
(
lenfunc
)
wrapped
;
Py_ssize_t
res
;
...
...
@@ -312,6 +329,7 @@ static PyObject* wrap_lenfunc(PyObject* self, PyObject* args, void* wrapped) noe
}
static
PyObject
*
wrap_indexargfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_indexargfunc"
);
ssizeargfunc
func
=
(
ssizeargfunc
)
wrapped
;
PyObject
*
o
;
Py_ssize_t
i
;
...
...
@@ -325,6 +343,7 @@ static PyObject* wrap_indexargfunc(PyObject* self, PyObject* args, void* wrapped
}
static
PyObject
*
wrap_sq_item
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_sq_item"
);
ssizeargfunc
func
=
(
ssizeargfunc
)
wrapped
;
PyObject
*
arg
;
Py_ssize_t
i
;
...
...
@@ -342,6 +361,7 @@ static PyObject* wrap_sq_item(PyObject* self, PyObject* args, void* wrapped) noe
}
static
PyObject
*
wrap_ssizessizeargfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_ssizessizeargfunc"
);
ssizessizeargfunc
func
=
(
ssizessizeargfunc
)
wrapped
;
Py_ssize_t
i
,
j
;
...
...
@@ -351,6 +371,7 @@ static PyObject* wrap_ssizessizeargfunc(PyObject* self, PyObject* args, void* wr
}
static
PyObject
*
wrap_sq_setitem
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_sq_setitem"
);
ssizeobjargproc
func
=
(
ssizeobjargproc
)
wrapped
;
Py_ssize_t
i
;
int
res
;
...
...
@@ -369,6 +390,7 @@ static PyObject* wrap_sq_setitem(PyObject* self, PyObject* args, void* wrapped)
}
static
PyObject
*
wrap_sq_delitem
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_sq_delitem"
);
ssizeobjargproc
func
=
(
ssizeobjargproc
)
wrapped
;
Py_ssize_t
i
;
int
res
;
...
...
@@ -388,6 +410,7 @@ static PyObject* wrap_sq_delitem(PyObject* self, PyObject* args, void* wrapped)
}
static
PyObject
*
wrap_ssizessizeobjargproc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_ssizessizeobjargproc"
);
ssizessizeobjargproc
func
=
(
ssizessizeobjargproc
)
wrapped
;
Py_ssize_t
i
,
j
;
int
res
;
...
...
@@ -403,6 +426,7 @@ static PyObject* wrap_ssizessizeobjargproc(PyObject* self, PyObject* args, void*
}
static
PyObject
*
wrap_delslice
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_delslice"
);
ssizessizeobjargproc
func
=
(
ssizessizeobjargproc
)
wrapped
;
Py_ssize_t
i
,
j
;
int
res
;
...
...
@@ -418,6 +442,7 @@ static PyObject* wrap_delslice(PyObject* self, PyObject* args, void* wrapped) no
/* XXX objobjproc is a misnomer; should be objargpred */
static
PyObject
*
wrap_objobjproc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_objobjproc"
);
objobjproc
func
=
(
objobjproc
)
wrapped
;
int
res
;
PyObject
*
value
;
...
...
@@ -433,6 +458,7 @@ static PyObject* wrap_objobjproc(PyObject* self, PyObject* args, void* wrapped)
}
static
PyObject
*
wrap_objobjargproc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_objobjargproc"
);
objobjargproc
func
=
(
objobjargproc
)
wrapped
;
int
res
;
PyObject
*
key
,
*
value
;
...
...
@@ -447,6 +473,7 @@ static PyObject* wrap_objobjargproc(PyObject* self, PyObject* args, void* wrappe
}
static
PyObject
*
wrap_delitem
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_delitem"
);
objobjargproc
func
=
(
objobjargproc
)
wrapped
;
int
res
;
PyObject
*
key
;
...
...
@@ -462,6 +489,7 @@ static PyObject* wrap_delitem(PyObject* self, PyObject* args, void* wrapped) noe
}
static
PyObject
*
wrap_cmpfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_cmpfunc"
);
cmpfunc
func
=
(
cmpfunc
)
wrapped
;
int
res
;
PyObject
*
other
;
...
...
@@ -482,6 +510,7 @@ static PyObject* wrap_cmpfunc(PyObject* self, PyObject* args, void* wrapped) noe
static
PyObject
*
wrap_init
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
,
PyObject
*
kwds
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_wrap_init"
);
initproc
func
=
(
initproc
)
wrapped
;
if
(
func
(
self
,
args
,
kwds
)
<
0
)
...
...
src/capi/types.h
View file @
181d5850
...
...
@@ -54,6 +54,7 @@ public:
}
static
Box
*
__call__
(
BoxedCApiFunction
*
self
,
BoxedTuple
*
varargs
,
BoxedDict
*
kwargs
)
{
STAT_TIMER
(
t0
,
"us_timer_boxedcapifunction__call__"
);
assert
(
self
->
cls
==
capifunc_cls
);
assert
(
varargs
->
cls
==
tuple_cls
);
assert
(
kwargs
->
cls
==
dict_cls
);
...
...
@@ -111,6 +112,8 @@ public:
DEFAULT_CLASS
(
wrapperobject_cls
);
static
Box
*
__call__
(
BoxedWrapperObject
*
self
,
Box
*
args
,
Box
*
kwds
)
{
STAT_TIMER
(
t0
,
"us_timer_boxedwrapperobject__call__"
);
assert
(
self
->
cls
==
wrapperobject_cls
);
assert
(
args
->
cls
==
tuple_cls
);
assert
(
kwds
->
cls
==
dict_cls
);
...
...
src/codegen/ast_interpreter.cpp
View file @
181d5850
...
...
@@ -284,6 +284,8 @@ public:
Value
ASTInterpreter
::
execute
(
ASTInterpreter
&
interpreter
,
CFGBlock
*
start_block
,
AST_stmt
*
start_at
)
{
threading
::
allowGLReadPreemption
();
STAT_TIMER
(
t0
,
"us_timer_astinterpreter_execute"
);
void
*
frame_addr
=
__builtin_frame_address
(
0
);
RegisterHelper
frame_registerer
(
&
interpreter
,
frame_addr
);
...
...
@@ -340,12 +342,7 @@ Value ASTInterpreter::doBinOp(Box* left, Box* right, int op, BinExpType exp_type
void
ASTInterpreter
::
doStore
(
InternedString
name
,
Value
value
)
{
ScopeInfo
::
VarScopeType
vst
=
scope_info
->
getScopeTypeOfName
(
name
);
if
(
vst
==
ScopeInfo
::
VarScopeType
::
GLOBAL
)
{
if
(
globals
->
cls
==
module_cls
)
{
setattr
(
static_cast
<
BoxedModule
*>
(
globals
),
name
.
c_str
(),
value
.
o
);
}
else
{
assert
(
globals
->
cls
==
dict_cls
);
static_cast
<
BoxedDict
*>
(
globals
)
->
d
[
boxString
(
name
.
str
())]
=
value
.
o
;
}
setGlobal
(
globals
,
name
,
value
.
o
);
}
else
if
(
vst
==
ScopeInfo
::
VarScopeType
::
NAME
)
{
assert
(
frame_info
.
boxedLocals
!=
NULL
);
// TODO should probably pre-box the names when it's a scope that usesNameLookup
...
...
@@ -540,6 +537,7 @@ Value ASTInterpreter::visit_jump(AST_Jump* node) {
arg_array
.
push_back
(
it
.
second
);
}
STAT_TIMER
(
t0
,
"us_timer_astinterpreter_jump_osrexit"
);
CompiledFunction
*
partial_func
=
compilePartialFuncInternal
(
&
exit
);
auto
arg_tuple
=
getTupleFromArgsArray
(
&
arg_array
[
0
],
arg_array
.
size
());
Box
*
r
=
partial_func
->
call
(
std
::
get
<
0
>
(
arg_tuple
),
std
::
get
<
1
>
(
arg_tuple
),
std
::
get
<
2
>
(
arg_tuple
),
...
...
@@ -876,7 +874,6 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) {
ScopeInfo
::
VarScopeType
vst
=
scope_info
->
getScopeTypeOfName
(
target
->
id
);
if
(
vst
==
ScopeInfo
::
VarScopeType
::
GLOBAL
)
{
// Can't use delattr since the errors are different:
delGlobal
(
globals
,
&
target
->
id
.
str
());
continue
;
}
else
if
(
vst
==
ScopeInfo
::
VarScopeType
::
NAME
)
{
...
...
@@ -927,6 +924,8 @@ Value ASTInterpreter::visit_print(AST_Print* node) {
static
const
std
::
string
newline_str
(
"
\n
"
);
static
const
std
::
string
space_str
(
" "
);
STAT_TIMER
(
t0
,
"us_timer_visit_print"
);
Box
*
dest
=
node
->
dest
?
visit_expr
(
node
->
dest
).
o
:
getSysStdout
();
int
nvals
=
node
->
values
.
size
();
assert
(
nvals
<=
1
&&
"cfg should have lowered it to 0 or 1 values"
);
...
...
src/codegen/entry.cpp
View file @
181d5850
...
...
@@ -362,7 +362,7 @@ static void handle_sigint(int signum) {
// For now, just call abort(), so that we get a traceback at least.
fprintf
(
stderr
,
"SIGINT!
\n
"
);
joinRuntime
();
Stats
::
dump
();
Stats
::
dump
(
false
);
abort
();
}
...
...
src/codegen/irgen/hooks.cpp
View file @
181d5850
...
...
@@ -182,6 +182,7 @@ static void compileIR(CompiledFunction* cf, EffortLevel effort) {
// The codegen_lock needs to be held in W mode before calling this function:
CompiledFunction
*
compileFunction
(
CLFunction
*
f
,
FunctionSpecialization
*
spec
,
EffortLevel
effort
,
const
OSREntryDescriptor
*
entry_descriptor
)
{
STAT_TIMER
(
t0
,
"us_timer_compileFunction"
);
Timer
_t
(
"for compileFunction()"
,
1000
);
assert
((
entry_descriptor
!=
NULL
)
+
(
spec
!=
NULL
)
==
1
);
...
...
@@ -315,10 +316,13 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
assert
(
cf
->
clfunc
->
versions
.
size
());
}
if
(
cf
->
is_interpreted
)
if
(
cf
->
is_interpreted
)
{
STAT_TIMER
(
t0
,
"us_timer_interpreted_module_toplevel"
);
astInterpretFunction
(
cf
,
0
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
else
}
else
{
STAT_TIMER
(
t1
,
"us_timer_jitted_module_toplevel"
);
((
void
(
*
)())
cf
->
code
)();
}
}
Box
*
evalOrExec
(
CLFunction
*
cl
,
Box
*
globals
,
Box
*
boxedLocals
)
{
...
...
src/codegen/parser.cpp
View file @
181d5850
...
...
@@ -982,6 +982,7 @@ AST_Module* parse_string(const char* code) {
}
AST_Module
*
parse_file
(
const
char
*
fn
)
{
STAT_TIMER
(
t0
,
"us_timer_cpyton_parsing"
);
Timer
_t
(
"parsing"
);
if
(
ENABLE_PYPA_PARSER
)
{
...
...
@@ -1071,9 +1072,10 @@ static ParseResult _reparse(const char* fn, const std::string& cache_fn, AST_Mod
// it's not a huge deal right now, but this caching version can significantly cut down
// on the startup time (40ms -> 10ms).
AST_Module
*
caching_parse_file
(
const
char
*
fn
)
{
STAT_TIMER
(
t0
,
"us_timer_caching_parse_file"
);
static
StatCounter
us_parsing
(
"us_parsing"
);
Timer
_t
(
"parsing"
);
_t
.
setExitCallback
([](
long
t
)
{
us_parsing
.
log
(
t
);
});
_t
.
setExitCallback
([](
uint64_t
t
)
{
us_parsing
.
log
(
t
);
});
int
code
;
std
::
string
cache_fn
=
std
::
string
(
fn
)
+
"c"
;
...
...
src/codegen/unwinding.cpp
View file @
181d5850
...
...
@@ -494,6 +494,7 @@ void unwindPythonStack(std::function<bool(std::unique_ptr<PythonFrameIteratorImp
}
static
std
::
unique_ptr
<
PythonFrameIteratorImpl
>
getTopPythonFrame
()
{
STAT_TIMER
(
t0
,
"us_timer_getTopPythonFrame"
);
std
::
unique_ptr
<
PythonFrameIteratorImpl
>
rtn
(
nullptr
);
unwindPythonStack
([
&
](
std
::
unique_ptr
<
PythonFrameIteratorImpl
>
iter
)
{
rtn
=
std
::
move
(
iter
);
...
...
@@ -514,6 +515,7 @@ static const LineInfo* lineInfoForFrame(PythonFrameIteratorImpl& frame_it) {
static
StatCounter
us_gettraceback
(
"us_gettraceback"
);
BoxedTraceback
*
getTraceback
()
{
STAT_TIMER
(
t0
,
"us_timer_gettraceback"
);
if
(
!
ENABLE_FRAME_INTROSPECTION
)
{
static
bool
printed_warning
=
false
;
if
(
!
printed_warning
)
{
...
...
@@ -597,6 +599,8 @@ CompiledFunction* getTopCompiledFunction() {
Box
*
getGlobals
()
{
auto
it
=
getTopPythonFrame
();
if
(
!
it
)
return
NULL
;
return
it
->
getGlobals
();
}
...
...
src/core/stats.cpp
View file @
181d5850
...
...
@@ -22,9 +22,105 @@
namespace
pyston
{
#if !DISABLE_STATS
std
::
vector
<
long
>*
Stats
::
counts
;
#if STAT_TIMERS
extern
"C"
const
char
*
getStatTimerNameById
(
int
id
)
{
return
Stats
::
getStatName
(
id
).
c_str
();
}
extern
"C"
int
getStatTimerId
()
{
return
StatTimer
::
getStack
()
->
getId
();
}
extern
"C"
const
char
*
getStatTimerName
()
{
return
getStatTimerNameById
(
getStatTimerId
());
}
__thread
StatTimer
*
StatTimer
::
stack
;
StatTimer
::
StatTimer
(
int
statid
,
bool
push
)
{
uint64_t
at_time
=
getCPUTicks
();
_start_time
=
0
;
_statid
=
statid
;
if
(
!
push
)
{
_prev
=
NULL
;
return
;
}
_prev
=
stack
;
stack
=
this
;
if
(
_prev
)
{
_prev
->
pause
(
at_time
);
}
resume
(
at_time
);
}
StatTimer
::
StatTimer
(
int
statid
,
uint64_t
at_time
)
{
_start_time
=
0
;
_statid
=
statid
;
_prev
=
stack
;
stack
=
this
;
if
(
_prev
)
{
_prev
->
pause
(
at_time
);
}
resume
(
at_time
);
}
StatTimer
::~
StatTimer
()
{
assert
(
stack
==
this
);
uint64_t
at_time
;
if
(
!
isPaused
())
{
at_time
=
getCPUTicks
();
pause
(
at_time
);
}
else
{
// fprintf (stderr, "WARNING: timer was paused.\n");
at_time
=
_last_pause_time
;
}
stack
=
_prev
;
if
(
stack
)
{
stack
->
resume
(
at_time
);
}
}
void
StatTimer
::
pause
(
uint64_t
at_time
)
{
assert
(
!
isPaused
());
assert
(
at_time
>
_start_time
);
uint64_t
_duration
=
at_time
-
_start_time
;
Stats
::
log
(
_statid
,
_duration
);
_start_time
=
0
;
_last_pause_time
=
at_time
;
// fprintf (stderr, "paused %d at %lu\n", _statid, at_time);
}
void
StatTimer
::
resume
(
uint64_t
at_time
)
{
assert
(
isPaused
());
_start_time
=
at_time
;
// fprintf (stderr, "resumed %d at %lu\n", _statid, at_time);
}
StatTimer
*
StatTimer
::
swapStack
(
StatTimer
*
s
,
uint64_t
at_time
)
{
StatTimer
*
prev_stack
=
stack
;
if
(
stack
)
{
stack
->
pause
(
at_time
);
}
stack
=
s
;
if
(
stack
)
{
stack
->
resume
(
at_time
);
}
return
prev_stack
;
}
#endif
std
::
vector
<
uint64_t
>*
Stats
::
counts
;
std
::
unordered_map
<
int
,
std
::
string
>*
Stats
::
names
;
bool
Stats
::
enabled
;
timespec
Stats
::
start_ts
;
uint64_t
Stats
::
start_tick
;
StatCounter
::
StatCounter
(
const
std
::
string
&
name
)
:
id
(
Stats
::
getStatId
(
name
))
{
}
...
...
@@ -38,7 +134,7 @@ int Stats::getStatId(const std::string& name) {
// hacky but easy way of getting around static constructor ordering issues for now:
static
std
::
unordered_map
<
int
,
std
::
string
>
names
;
Stats
::
names
=
&
names
;
static
std
::
vector
<
long
>
counts
;
static
std
::
vector
<
uint64_t
>
counts
;
Stats
::
counts
=
&
counts
;
static
std
::
unordered_map
<
std
::
string
,
int
>
made
;
...
...
@@ -52,11 +148,36 @@ int Stats::getStatId(const std::string& name) {
return
rtn
;
}
std
::
string
Stats
::
getStatName
(
int
id
)
{
return
(
*
names
)[
id
];
}
void
Stats
::
startEstimatingCPUFreq
()
{
if
(
!
Stats
::
enabled
)
return
;
clock_gettime
(
CLOCK_REALTIME
,
&
Stats
::
start_ts
);
Stats
::
start_tick
=
getCPUTicks
();
}
// returns our estimate of the MHz of the cpu. MHz is handy because we're mostly interested in microsoecond-resolution
// timing.
double
Stats
::
estimateCPUFreq
()
{
timespec
dump_ts
;
clock_gettime
(
CLOCK_REALTIME
,
&
dump_ts
);
uint64_t
end_tick
=
getCPUTicks
();
uint64_t
wall_clock_ns
=
(
dump_ts
.
tv_sec
-
start_ts
.
tv_sec
)
*
1000000000
+
(
dump_ts
.
tv_nsec
-
start_ts
.
tv_nsec
);
return
(
double
)(
end_tick
-
Stats
::
start_tick
)
*
1000
/
wall_clock_ns
;
}
void
Stats
::
dump
(
bool
includeZeros
)
{
if
(
!
Stats
::
enabled
)
return
;
double
cycles_per_us
=
Stats
::
estimateCPUFreq
();
fprintf
(
stderr
,
"Stats:
\n
"
);
fprintf
(
stderr
,
"estimated_cpu_mhz: %5.5f
\n
"
,
cycles_per_us
);
gc
::
dumpHeapStatistics
(
0
);
...
...
@@ -69,11 +190,41 @@ void Stats::dump(bool includeZeros) {
std
::
sort
(
pairs
.
begin
(),
pairs
.
end
());
uint64_t
ticks_in_main
=
0
;
uint64_t
accumulated_stat_timer_ticks
=
0
;
for
(
int
i
=
0
;
i
<
pairs
.
size
();
i
++
)
{
if
(
includeZeros
||
(
*
counts
)[
pairs
[
i
].
second
]
>
0
)
fprintf
(
stderr
,
"%s: %ld
\n
"
,
pairs
[
i
].
first
.
c_str
(),
(
*
counts
)[
pairs
[
i
].
second
]);
if
(
includeZeros
||
(
*
counts
)[
pairs
[
i
].
second
]
>
0
)
{
if
(
startswith
(
pairs
[
i
].
first
,
"us_"
)
||
startswith
(
pairs
[
i
].
first
,
"_init_us_"
))
{
fprintf
(
stderr
,
"%s: %lu
\n
"
,
pairs
[
i
].
first
.
c_str
(),
(
uint64_t
)((
*
counts
)[
pairs
[
i
].
second
]
/
cycles_per_us
));
}
else
fprintf
(
stderr
,
"%s: %lu
\n
"
,
pairs
[
i
].
first
.
c_str
(),
(
*
counts
)[
pairs
[
i
].
second
]);
if
(
startswith
(
pairs
[
i
].
first
,
"us_timer_"
))
accumulated_stat_timer_ticks
+=
(
*
counts
)[
pairs
[
i
].
second
];
if
(
pairs
[
i
].
first
==
"ticks_in_main"
)
ticks_in_main
=
(
*
counts
)[
pairs
[
i
].
second
];
}
}
if
(
includeZeros
||
accumulated_stat_timer_ticks
>
0
)
fprintf
(
stderr
,
"ticks_all_timers: %lu
\n
"
,
accumulated_stat_timer_ticks
);
#if 0
// I want to enable this, but am leaving it disabled for the time
// being because it causes test failures due to:
//
// 1) some tests exit from main from inside catch blocks, without
// going through the logic to stop the timers.
// 2) some tests create multiple threads which causes problems
// with our non-per thread stat timers.
if (ticks_in_main && ticks_in_main != accumulated_stat_timer_ticks) {
fprintf(stderr, "WARNING: accumulated stat timer ticks != ticks in main - don't trust timer output.");
}
#endif
fprintf
(
stderr
,
"(End of stats)
\n
"
);
}
...
...
src/core/stats.h
View file @
181d5850
...
...
@@ -22,23 +22,48 @@
#include <vector>
#include "core/options.h"
#include "core/util.h"
namespace
pyston
{
#define DISABLE_STATS 0
#define STAT_ALLOCATIONS 0 && !DISABLE_STATS
#define STAT_TIMERS 0 && !DISABLE_STATS
#if STAT_TIMERS
#define STAT_TIMER(id, name) \
static int _stid##id = Stats::getStatId(name); \
StatTimer _st##id(_stid##id)
#define STAT_TIMER2(id, name, at_time) \
static int _stid##id = Stats::getStatId(name); \
StatTimer _st##id(_stid##id, at_time)
#else
#define STAT_TIMER(id, name) StatTimer _st##id(0);
#define STAT_TIMER2(id, name, at_time) StatTimer _st##id(0);
#endif
#define STAT_TIMER_NAME(id) _st##id
#if !DISABLE_STATS
struct
Stats
{
private:
static
std
::
vector
<
long
>*
counts
;
static
std
::
vector
<
uint64_t
>*
counts
;
static
std
::
unordered_map
<
int
,
std
::
string
>*
names
;
static
bool
enabled
;
static
timespec
start_ts
;
static
uint64_t
start_tick
;
public:
static
void
startEstimatingCPUFreq
();
static
double
estimateCPUFreq
();
static
int
getStatId
(
const
std
::
string
&
name
);
static
std
::
string
getStatName
(
int
id
);
static
void
setEnabled
(
bool
enabled
)
{
Stats
::
enabled
=
enabled
;
}
static
void
log
(
int
id
,
in
t
count
=
1
)
{
(
*
counts
)[
id
]
+=
count
;
}
static
void
log
(
int
id
,
uint64_
t
count
=
1
)
{
(
*
counts
)[
id
]
+=
count
;
}
static
void
clear
()
{
std
::
fill
(
counts
->
begin
(),
counts
->
end
(),
0
);
}
static
void
dump
(
bool
includeZeros
=
true
);
...
...
@@ -52,7 +77,7 @@ private:
public:
StatCounter
(
const
std
::
string
&
name
);
void
log
(
in
t
count
=
1
)
{
Stats
::
log
(
id
,
count
);
}
void
log
(
uint64_
t
count
=
1
)
{
Stats
::
log
(
id
,
count
);
}
};
struct
StatPerThreadCounter
{
...
...
@@ -62,24 +87,74 @@ private:
public:
StatPerThreadCounter
(
const
std
::
string
&
name
);
void
log
(
in
t
count
=
1
)
{
Stats
::
log
(
id
,
count
);
}
void
log
(
uint64_
t
count
=
1
)
{
Stats
::
log
(
id
,
count
);
}
};
#else
struct
Stats
{
static
void
startEstimatingCPUFreq
()
{}
static
double
estimateCPUFreq
()
{
return
0
;
}
static
void
setEnabled
(
bool
enabled
)
{}
static
void
dump
()
{
printf
(
"(Stats disabled)
\n
"
);
}
static
void
dump
(
bool
includeZeros
=
true
)
{
printf
(
"(Stats disabled)
\n
"
);
}
static
void
clear
()
{}
static
void
log
(
int
id
,
int
count
=
1
)
{}
static
int
getStatId
(
const
std
::
string
&
name
)
{
return
0
;
}
static
void
endOfInit
()
{}
};
struct
StatCounter
{
StatCounter
(
const
char
*
name
)
{}
void
log
(
in
t
count
=
1
){};
void
log
(
uint64_
t
count
=
1
){};
};
struct
StatPerThreadCounter
{
StatPerThreadCounter
(
const
char
*
name
)
{}
void
log
(
int
count
=
1
){};
void
log
(
uint64_t
count
=
1
){};
};
#endif
#if STAT_TIMERS
class
StatTimer
{
private:
static
__thread
StatTimer
*
stack
;
// the start time of the current active segment (0 == paused)
uint64_t
_start_time
;
uint64_t
_last_pause_time
;
StatTimer
*
_prev
;
int
_statid
;
public:
StatTimer
(
int
statid
,
bool
push
=
true
);
StatTimer
(
int
statid
,
uint64_t
at_time
);
~
StatTimer
();
void
pause
(
uint64_t
at_time
);
void
resume
(
uint64_t
at_time
);
bool
isPaused
()
const
{
return
_start_time
==
0
;
}
int
getId
()
const
{
return
_statid
;
}
static
StatTimer
*
getStack
()
{
return
stack
;
}
static
StatTimer
*
swapStack
(
StatTimer
*
s
,
uint64_t
at_time
);
static
void
assertActive
()
{
RELEASE_ASSERT
(
stack
&&
!
stack
->
isPaused
(),
""
);
}
};
#else
struct
StatTimer
{
StatTimer
(
int
statid
,
bool
push
=
true
)
{}
StatTimer
(
int
statid
,
uint64_t
at_time
)
{}
~
StatTimer
()
{}
bool
isPaused
()
const
{
return
false
;
}
void
pause
(
uint64_t
at_time
)
{}
void
resume
(
uint64_t
at_time
)
{}
static
StatTimer
*
getStack
()
{
return
NULL
;
}
static
StatTimer
*
swapStack
(
StatTimer
*
s
,
uint64_t
at_time
)
{
return
NULL
;
}
static
void
assertActive
()
{}
};
#endif
}
...
...
src/core/stringpool.h
View file @
181d5850
...
...
@@ -80,6 +80,8 @@ public:
return
*
this
->
_str
<
*
rhs
.
_str
;
}
operator
llvm
::
StringRef
()
{
return
llvm
::
StringRef
(
*
_str
);
}
friend
class
InternedStringPool
;
friend
struct
std
::
hash
<
InternedString
>
;
friend
struct
std
::
less
<
InternedString
>
;
...
...
src/core/types.h
View file @
181d5850
...
...
@@ -485,13 +485,26 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
return Box::operator new(size, default_cls); \
}
#if STAT_ALLOCATIONS
#define ALLOC_STATS(cls) \
std::string per_name_alloc_name = "alloc." + std::string(cls->tp_name); \
std::string per_name_allocsize_name = "allocsize." + std::string(cls->tp_name); \
Stats::log(Stats::getStatId(per_name_alloc_name)); \
Stats::log(Stats::getStatId(per_name_allocsize_name), size);
#else
#define ALLOC_STATS(cls)
#endif
// The restrictions on when you can use the SIMPLE (ie fast) variant are encoded as
// asserts in the 1-arg operator new function:
#define DEFAULT_CLASS_SIMPLE(default_cls) \
void* operator new(size_t size, BoxedClass * cls) __attribute__((visibility("default"))) { \
ALLOC_STATS(cls); \
return Box::operator new(size, cls); \
} \
void* operator new(size_t size) __attribute__((visibility("default"))) { \
ALLOC_STATS(default_cls); \
/* In the simple cases, we can inline the following methods and simplify things a lot: \
* - Box::operator new \
* - cls->tp_alloc \
...
...
src/core/util.cpp
View file @
181d5850
...
...
@@ -16,6 +16,9 @@
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormattedStream.h"
...
...
@@ -26,6 +29,18 @@
namespace
pyston
{
static
inline
uint64_t
rdtsc
()
{
unsigned
long
lo
,
hi
;
asm
(
"rdtsc"
:
"=a"
(
lo
),
"=d"
(
hi
));
return
(
lo
|
(
hi
<<
32
));
}
uint64_t
getCPUTicks
()
{
// unsigned int _unused;
// return __rdtscp(&_unused);
return
rdtsc
();
}
int
Timer
::
level
=
0
;
Timer
::
Timer
(
const
char
*
desc
,
long
min_usec
)
:
min_usec
(
min_usec
),
ended
(
true
)
{
...
...
@@ -36,7 +51,7 @@ void Timer::restart(const char* newdesc) {
assert
(
ended
);
desc
=
newdesc
;
gettimeofday
(
&
start_time
,
NULL
);
start_time
=
getCPUTicks
(
);
Timer
::
level
++
;
ended
=
false
;
}
...
...
@@ -46,14 +61,14 @@ void Timer::restart(const char* newdesc, long new_min_usec) {
restart
(
newdesc
);
}
long
Timer
::
end
(
)
{
uint64_t
Timer
::
end
(
uint64_t
*
ended_at
)
{
if
(
!
ended
)
{
timeval
end
;
gettimeofday
(
&
end
,
NULL
);
long
us
=
1000000L
*
(
end
.
tv_sec
-
start_time
.
tv_sec
)
+
(
end
.
tv_usec
-
start_time
.
tv_usec
);
uint64_t
end
=
getCPUTicks
();
uint64_t
duration
=
end
-
start_time
;
Timer
::
level
--
;
if
(
VERBOSITY
(
"time"
)
>=
2
&&
desc
)
{
uint64_t
us
=
(
uint64_t
)(
duration
/
Stats
::
estimateCPUFreq
());
if
(
us
>
min_usec
)
{
for
(
int
i
=
0
;
i
<
Timer
::
level
;
i
++
)
{
putchar
(
' '
);
...
...
@@ -70,15 +85,17 @@ long Timer::end() {
fflush
(
stdout
);
}
}
if
(
ended_at
)
*
ended_at
=
end
;
ended
=
true
;
return
us
;
return
duration
;
}
return
-
1
;
}
Timer
::~
Timer
()
{
if
(
!
ended
)
{
long
t
=
end
();
uint64_t
t
=
end
();
if
(
exit_callback
)
exit_callback
(
t
);
}
...
...
src/core/util.h
View file @
181d5850
...
...
@@ -24,30 +24,36 @@
namespace
pyston
{
uint64_t
getCPUTicks
();
class
Timer
{
private:
static
int
level
;
timeval
start_time
;
uint64_t
start_time
;
const
char
*
desc
;
long
min_usec
;
bool
ended
;
std
::
function
<
void
(
long
)
>
exit_callback
;
std
::
function
<
void
(
uint64_t
)
>
exit_callback
;
public:
Timer
(
const
char
*
desc
=
NULL
,
long
min_usec
=
-
1
);
~
Timer
();
void
setExitCallback
(
std
::
function
<
void
(
long
)
>
_exit_callback
)
{
exit_callback
=
_exit_callback
;
}
void
setExitCallback
(
std
::
function
<
void
(
uint64_t
)
>
_exit_callback
)
{
exit_callback
=
_exit_callback
;
}
void
restart
(
const
char
*
newdesc
,
long
new_min_usec
);
void
restart
(
const
char
*
newdesc
=
NULL
);
long
end
();
long
split
(
const
char
*
newdesc
=
NULL
)
{
long
rtn
=
end
();
// returns the duration. if @ended_at is non-null, it's filled in
// with the tick the timer stopped at.
uint64_t
end
(
uint64_t
*
ended_at
=
NULL
);
uint64_t
split
(
const
char
*
newdesc
=
NULL
)
{
uint64_t
rtn
=
end
();
restart
(
newdesc
);
return
rtn
;
}
uint64_t
getStartTime
()
const
{
return
start_time
;
}
};
bool
startswith
(
const
std
::
string
&
s
,
const
std
::
string
&
pattern
);
...
...
src/gc/collector.cpp
View file @
181d5850
...
...
@@ -339,6 +339,8 @@ void runCollection() {
static
StatCounter
sc
(
"gc_collections"
);
sc
.
log
();
STAT_TIMER
(
t0
,
"us_timer_gc_collection"
);
ncollections
++
;
if
(
VERBOSITY
(
"gc"
)
>=
2
)
...
...
src/gc/gc_alloc.h
View file @
181d5850
...
...
@@ -28,7 +28,9 @@ namespace pyston {
namespace
gc
{
static
StatCounter
gc_alloc_bytes
(
"zzz_gc_alloc_bytes"
);
extern
"C"
inline
void
*
gc_alloc
(
size_t
bytes
,
GCKind
kind_id
)
{
STAT_TIMER
(
t0
,
"us_timer_gc_alloc"
);
size_t
alloc_bytes
=
bytes
+
sizeof
(
GCAllocation
);
#ifndef NVALGRIND
...
...
@@ -89,8 +91,10 @@ extern "C" inline void* gc_alloc(size_t bytes, GCKind kind_id) {
// if (VERBOSITY()) printf("Allocated %ld bytes at [%p, %p)\n", bytes, r, (char*)r + bytes);
#endif
// printf("Allocated %p\n", r);
#if STAT_ALLOCATIONS
gc_alloc_bytes
.
log
(
bytes
);
#endif
return
r
;
}
...
...
@@ -128,6 +132,10 @@ extern "C" inline void* gc_realloc(void* ptr, size_t bytes) {
alloc
->
kind_data
=
bytes
;
}
#if STAT_ALLOCATIONS
gc_alloc_bytes
.
log
(
bytes
);
#endif
return
rtn
;
}
...
...
src/jit.cpp
View file @
181d5850
...
...
@@ -16,10 +16,12 @@
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <readline/history.h>
#include <readline/readline.h>
#include <stdint.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
#include "llvm/Support/FileSystem.h"
...
...
@@ -90,6 +92,86 @@ static bool handle_toplevel_exn(const ExcInfo& e, int* retcode) {
static
bool
force_repl
=
false
;
static
bool
unbuffered
=
false
;
static
const
char
*
argv0
;
static
int
pipefds
[
2
];
static
void
handle_sigsegv
(
int
signum
)
{
assert
(
signum
==
SIGSEGV
);
// TODO: this should set a flag saying a KeyboardInterrupt is pending.
// For now, just call abort(), so that we get a traceback at least.
fprintf
(
stderr
,
"child encountered segfault! signalling parent watcher to backtrace.
\n
"
);
char
buf
[
1
];
int
r
=
write
(
pipefds
[
1
],
buf
,
1
);
RELEASE_ASSERT
(
r
==
1
,
""
);
while
(
true
)
{
sleep
(
1
);
}
}
static
int
gdb_child_pid
;
static
void
propagate_sig
(
int
signum
)
{
// fprintf(stderr, "parent received signal %d, passing to child and then ignoring\n", signum);
assert
(
gdb_child_pid
);
int
r
=
kill
(
gdb_child_pid
,
signum
);
assert
(
!
r
);
}
static
void
enableGdbSegfaultWatcher
()
{
int
r
=
pipe2
(
pipefds
,
0
);
RELEASE_ASSERT
(
r
==
0
,
""
);
gdb_child_pid
=
fork
();
if
(
gdb_child_pid
)
{
// parent watcher process
close
(
pipefds
[
1
]);
for
(
int
i
=
0
;
i
<
_NSIG
;
i
++
)
{
if
(
i
==
SIGCHLD
)
continue
;
signal
(
i
,
&
propagate_sig
);
}
while
(
true
)
{
char
buf
[
1
];
int
r
=
read
(
pipefds
[
0
],
buf
,
1
);
if
(
r
==
1
)
{
fprintf
(
stderr
,
"Parent process woken up by child; collecting backtrace and killing child
\n
"
);
char
pidbuf
[
20
];
snprintf
(
pidbuf
,
sizeof
(
pidbuf
),
"%d"
,
gdb_child_pid
);
close
(
STDOUT_FILENO
);
dup2
(
STDERR_FILENO
,
STDOUT_FILENO
);
r
=
execlp
(
"gdb"
,
"gdb"
,
"-p"
,
pidbuf
,
argv0
,
"-batch"
,
"-ex"
,
"set pagination 0"
,
"-ex"
,
"thread apply all bt"
,
"-ex"
,
"kill"
,
"-ex"
,
"quit -11"
,
NULL
);
RELEASE_ASSERT
(
0
,
"%d %d %s"
,
r
,
errno
,
strerror
(
errno
));
}
if
(
r
==
0
)
{
int
status
;
r
=
waitpid
(
gdb_child_pid
,
&
status
,
0
);
RELEASE_ASSERT
(
r
==
gdb_child_pid
,
"%d %d %s"
,
r
,
errno
,
strerror
(
errno
));
int
rtncode
=
0
;
if
(
WIFEXITED
(
status
))
rtncode
=
WEXITSTATUS
(
status
);
else
rtncode
=
128
+
WTERMSIG
(
status
);
exit
(
rtncode
);
}
RELEASE_ASSERT
(
0
,
"%d %d %s"
,
r
,
errno
,
strerror
(
errno
));
}
RELEASE_ASSERT
(
0
,
""
);
}
close
(
pipefds
[
0
]);
signal
(
SIGSEGV
,
&
handle_sigsegv
);
}
int
handleArg
(
char
code
)
{
if
(
code
==
'O'
)
FORCE_OPTIMIZE
=
true
;
...
...
@@ -131,6 +213,8 @@ int handleArg(char code) {
CONTINUE_AFTER_FATAL
=
true
;
}
else
if
(
code
==
'T'
)
{
ENABLE_TRACEBACKS
=
false
;
}
else
if
(
code
==
'G'
)
{
enableGdbSegfaultWatcher
();
}
else
{
fprintf
(
stderr
,
"Unknown option: -%c
\n
"
,
code
);
return
2
;
...
...
@@ -139,223 +223,244 @@ int handleArg(char code) {
}
static
int
main
(
int
argc
,
char
**
argv
)
{
argv0
=
argv
[
0
];
Timer
_t
(
"for jit startup"
);
// llvm::sys::PrintStackTraceOnErrorSignal();
// llvm::PrettyStackTraceProgram X(argc, argv);
llvm
::
llvm_shutdown_obj
Y
;
int
code
;
const
char
*
command
=
NULL
;
timespec
before_ts
,
after_ts
;
Timer
main_time
;
int
rtncode
;
{
STAT_TIMER2
(
t0
,
"us_timer_main_toplevel"
,
main_time
.
getStartTime
());
char
*
env_args
=
getenv
(
"PYSTON_RUN_ARGS"
);
int
code
;
const
char
*
command
=
NULL
;
if
(
env_args
)
{
while
(
*
env_args
)
{
int
r
=
handleArg
(
*
env_args
);
if
(
r
)
return
r
;
env_args
++
;
char
*
env_args
=
getenv
(
"PYSTON_RUN_ARGS"
);
if
(
env_args
)
{
while
(
*
env_args
)
{
int
r
=
handleArg
(
*
env_args
);
if
(
r
)
return
r
;
env_args
++
;
}
}
}
// Suppress getopt errors so we can throw them ourselves
opterr
=
0
;
while
((
code
=
getopt
(
argc
,
argv
,
"+:OqdIibpjtrsSvnxEc:FuPT"
))
!=
-
1
)
{
if
(
code
==
'c'
)
{
assert
(
optarg
);
command
=
optarg
;
// no more option parsing; the rest of our arguments go into sys.argv.
break
;
}
else
if
(
code
==
':'
)
{
fprintf
(
stderr
,
"Argument expected for the -%c option
\n
"
,
optopt
);
return
2
;
}
else
if
(
code
==
'?'
)
{
fprintf
(
stderr
,
"Unknown option: -%c
\n
"
,
optopt
);
return
2
;
}
else
{
int
r
=
handleArg
(
code
);
if
(
r
)
return
r
;
// Suppress getopt errors so we can throw them ourselves
opterr
=
0
;
while
((
code
=
getopt
(
argc
,
argv
,
"+:OqdIibpjtrsSvnxEc:FuPTG"
))
!=
-
1
)
{
if
(
code
==
'c'
)
{
assert
(
optarg
);
command
=
optarg
;
// no more option parsing; the rest of our arguments go into sys.argv.
break
;
}
else
if
(
code
==
':'
)
{
fprintf
(
stderr
,
"Argument expected for the -%c option
\n
"
,
optopt
);
return
2
;
}
else
if
(
code
==
'?'
)
{
fprintf
(
stderr
,
"Unknown option: -%c
\n
"
,
optopt
);
return
2
;
}
else
{
int
r
=
handleArg
(
code
);
if
(
r
)
return
r
;
}
}
}
const
char
*
fn
=
NULL
;
Stats
::
startEstimatingCPUFreq
()
;
threading
::
registerMainThread
();
threading
::
acquireGLRead
();
const
char
*
fn
=
NULL
;
Py_SetProgramName
(
argv
[
0
]);
threading
::
registerMainThread
();
threading
::
acquireGLRead
();
if
(
unbuffered
)
{
setvbuf
(
stdin
,
(
char
*
)
NULL
,
_IONBF
,
BUFSIZ
);
setvbuf
(
stdout
,
(
char
*
)
NULL
,
_IONBF
,
BUFSIZ
);
setvbuf
(
stderr
,
(
char
*
)
NULL
,
_IONBF
,
BUFSIZ
);
}
Py_SetProgramName
(
argv
[
0
]);
{
Timer
_t
(
"for initCodegen"
);
initCodegen
();
}
if
(
unbuffered
)
{
setvbuf
(
stdin
,
(
char
*
)
NULL
,
_IONBF
,
BUFSIZ
);
setvbuf
(
stdout
,
(
char
*
)
NULL
,
_IONBF
,
BUFSIZ
);
setvbuf
(
stderr
,
(
char
*
)
NULL
,
_IONBF
,
BUFSIZ
);
}
// Arguments left over after option parsing are of the form:
// [ script | - ] [ arguments... ]
// unless we've been already parsed a `-c command` option, in which case only:
// [ arguments...]
// are parsed.
if
(
command
)
addToSysArgv
(
"-c"
);
else
if
(
optind
!=
argc
)
{
addToSysArgv
(
argv
[
optind
]);
if
(
strcmp
(
"-"
,
argv
[
optind
])
!=
0
)
fn
=
argv
[
optind
];
++
optind
;
}
else
addToSysArgv
(
""
);
for
(
int
i
=
optind
;
i
<
argc
;
i
++
)
{
addToSysArgv
(
argv
[
i
]);
}
{
Timer
_t
(
"for initCodegen"
);
initCodegen
();
}
llvm
::
StringRef
module_search_path
=
Py_GetPath
();
while
(
true
)
{
std
::
pair
<
llvm
::
StringRef
,
llvm
::
StringRef
>
split_str
=
module_search_path
.
split
(
DELIM
);
if
(
split_str
.
first
==
module_search_path
)
break
;
// could not find the delimiter
appendToSysPath
(
split_str
.
first
);
module_search_path
=
split_str
.
second
;
}
// Arguments left over after option parsing are of the form:
// [ script | - ] [ arguments... ]
// unless we've been already parsed a `-c command` option, in which case only:
// [ arguments...]
// are parsed.
if
(
command
)
addToSysArgv
(
"-c"
);
else
if
(
optind
!=
argc
)
{
addToSysArgv
(
argv
[
optind
]);
if
(
strcmp
(
"-"
,
argv
[
optind
])
!=
0
)
fn
=
argv
[
optind
];
++
optind
;
}
else
addToSysArgv
(
""
);
for
(
int
i
=
optind
;
i
<
argc
;
i
++
)
{
addToSysArgv
(
argv
[
i
]);
}
if
(
!
fn
)
{
// if we are in repl or command mode prepend "" to the path
prependToSysPath
(
""
);
}
llvm
::
StringRef
module_search_path
=
Py_GetPath
();
while
(
true
)
{
std
::
pair
<
llvm
::
StringRef
,
llvm
::
StringRef
>
split_str
=
module_search_path
.
split
(
DELIM
);
if
(
split_str
.
first
==
module_search_path
)
break
;
// could not find the delimiter
appendToSysPath
(
split_str
.
first
);
module_search_path
=
split_str
.
second
;
}
if
(
!
Py_NoSiteFlag
)
{
try
{
std
::
string
module_name
=
"site"
;
importModuleLevel
(
module_name
,
None
,
None
,
0
);
}
catch
(
ExcInfo
e
)
{
e
.
printExcAndTraceback
();
return
1
;
if
(
!
fn
)
{
// if we are in repl or command mode prepend "" to the path
prependToSysPath
(
""
);
}
}
// Set encoding for standard streams. This needs to be done after
// sys.path is properly set up, so that we can import the
// encodings module.
setEncodingAndErrors
();
// end of argument parsing
_t
.
split
(
"to run"
);
BoxedModule
*
main_module
=
NULL
;
// if the user invoked `pyston -c command`
if
(
command
!=
NULL
)
{
try
{
main_module
=
createModule
(
"__main__"
,
"<string>"
);
AST_Module
*
m
=
parse_string
(
command
);
compileAndRunModule
(
m
,
main_module
);
}
catch
(
ExcInfo
e
)
{
int
retcode
=
1
;
(
void
)
handle_toplevel_exn
(
e
,
&
retcode
);
Stats
::
dump
();
return
retcode
;
if
(
!
Py_NoSiteFlag
)
{
try
{
std
::
string
module_name
=
"site"
;
importModuleLevel
(
module_name
,
None
,
None
,
0
);
}
catch
(
ExcInfo
e
)
{
e
.
printExcAndTraceback
();
return
1
;
}
}
}
if
(
fn
!=
NULL
)
{
llvm
::
SmallString
<
128
>
path
;
// Set encoding for standard streams. This needs to be done after
// sys.path is properly set up, so that we can import the
// encodings module.
setEncodingAndErrors
();
if
(
!
llvm
::
sys
::
path
::
is_absolute
(
fn
))
{
char
cwd_buf
[
1026
];
char
*
cwd
=
getcwd
(
cwd_buf
,
sizeof
(
cwd_buf
));
assert
(
cwd
);
path
=
cwd
;
}
// end of argument parsing
llvm
::
sys
::
path
::
append
(
path
,
fn
);
llvm
::
sys
::
path
::
remove_filename
(
path
)
;
prependToSysPath
(
path
.
str
());
main_module
=
createModule
(
"__main__"
,
fn
);
try
{
AST_Module
*
ast
=
caching_parse_file
(
fn
);
compileAndRunModule
(
ast
,
main_module
);
}
catch
(
ExcInfo
e
)
{
int
retcode
=
1
;
(
void
)
handle_toplevel_exn
(
e
,
&
retcode
)
;
if
(
!
force_repl
)
{
Stats
::
dump
();
_t
.
split
(
"to run"
);
BoxedModule
*
main_module
=
NULL
;
// if the user invoked `pyston -c command`
if
(
command
!=
NULL
)
{
try
{
main_module
=
createModule
(
"__main__"
,
"<string>"
);
AST_Module
*
m
=
parse_string
(
command
);
compileAndRunModule
(
m
,
main_module
);
}
catch
(
ExcInfo
e
)
{
int
retcode
=
1
;
(
void
)
handle_toplevel_exn
(
e
,
&
retcode
);
Stats
::
dump
(
false
);
return
retcode
;
}
}
}
if
(
force_repl
||
!
(
command
||
fn
))
{
printf
(
"Pyston v%d.%d (rev "
STRINGIFY
(
GITREV
)
")"
,
PYSTON_VERSION_MAJOR
,
PYSTON_VERSION_MINOR
);
printf
(
", targeting Python %d.%d.%d
\n
"
,
PYTHON_VERSION_MAJOR
,
PYTHON_VERSION_MINOR
,
PYTHON_VERSION_MICRO
);
if
(
!
main_module
)
{
main_module
=
createModule
(
"__main__"
,
"<stdin>"
);
}
else
{
// main_module->fn = "<stdin>";
}
if
(
fn
!=
NULL
)
{
llvm
::
SmallString
<
128
>
path
;
for
(;;)
{
char
*
line
=
readline
(
">> "
);
if
(
!
line
)
break
;
if
(
!
llvm
::
sys
::
path
::
is_absolute
(
fn
))
{
char
cwd_buf
[
1026
];
char
*
cwd
=
getcwd
(
cwd_buf
,
sizeof
(
cwd_buf
));
assert
(
cwd
);
path
=
cwd
;
}
add_history
(
line
);
llvm
::
sys
::
path
::
append
(
path
,
fn
);
llvm
::
sys
::
path
::
remove_filename
(
path
);
char
*
real_path
=
realpath
(
path
.
str
().
str
().
c_str
(),
NULL
);
// inefficient way of null-terminating the string
prependToSysPath
(
real_path
);
free
(
real_path
);
main_module
=
createModule
(
"__main__"
,
fn
);
try
{
AST_Module
*
m
=
parse_string
(
line
);
Timer
_t
(
"repl"
);
if
(
m
->
body
.
size
()
>
0
&&
m
->
body
[
0
]
->
type
==
AST_TYPE
::
Expr
)
{
AST_Expr
*
e
=
ast_cast
<
AST_Expr
>
(
m
->
body
[
0
]);
AST_Call
*
c
=
new
AST_Call
();
AST_Name
*
r
=
new
AST_Name
(
m
->
interned_strings
->
get
(
"repr"
),
AST_TYPE
::
Load
,
0
);
c
->
func
=
r
;
c
->
starargs
=
NULL
;
c
->
kwargs
=
NULL
;
c
->
args
.
push_back
(
e
->
value
);
c
->
lineno
=
0
;
AST_Print
*
p
=
new
AST_Print
();
p
->
dest
=
NULL
;
p
->
nl
=
true
;
p
->
values
.
push_back
(
c
);
p
->
lineno
=
0
;
m
->
body
[
0
]
=
p
;
}
compileAndRunModule
(
m
,
main_module
);
AST_Module
*
ast
=
caching_parse_file
(
fn
);
compileAndRunModule
(
ast
,
main_module
);
}
catch
(
ExcInfo
e
)
{
int
retcode
=
0xdeadbeef
;
// should never be seen
if
(
handle_toplevel_exn
(
e
,
&
retcode
))
{
Stats
::
dump
();
int
retcode
=
1
;
(
void
)
handle_toplevel_exn
(
e
,
&
retcode
);
if
(
!
force_repl
)
{
Stats
::
dump
(
false
);
return
retcode
;
}
}
}
}
threading
::
finishMainThread
();
if
(
force_repl
||
!
(
command
||
fn
))
{
printf
(
"Pyston v%d.%d (rev "
STRINGIFY
(
GITREV
)
")"
,
PYSTON_VERSION_MAJOR
,
PYSTON_VERSION_MINOR
);
printf
(
", targeting Python %d.%d.%d
\n
"
,
PYTHON_VERSION_MAJOR
,
PYTHON_VERSION_MINOR
,
PYTHON_VERSION_MICRO
);
// Acquire the GIL to make sure we stop the other threads, since we will tear down
// data structures they are potentially running on.
// Note: we will purposefully not release the GIL on exiting.
threading
::
promoteGL
();
if
(
!
main_module
)
{
main_module
=
createModule
(
"__main__"
,
"<stdin>"
);
}
else
{
// main_module->fn = "<stdin>";
}
for
(;;)
{
char
*
line
=
readline
(
">> "
);
if
(
!
line
)
break
;
add_history
(
line
);
try
{
AST_Module
*
m
=
parse_string
(
line
);
Timer
_t
(
"repl"
);
if
(
m
->
body
.
size
()
>
0
&&
m
->
body
[
0
]
->
type
==
AST_TYPE
::
Expr
)
{
AST_Expr
*
e
=
ast_cast
<
AST_Expr
>
(
m
->
body
[
0
]);
AST_Call
*
c
=
new
AST_Call
();
AST_Name
*
r
=
new
AST_Name
(
m
->
interned_strings
->
get
(
"repr"
),
AST_TYPE
::
Load
,
0
);
c
->
func
=
r
;
c
->
starargs
=
NULL
;
c
->
kwargs
=
NULL
;
c
->
args
.
push_back
(
e
->
value
);
c
->
lineno
=
0
;
AST_Print
*
p
=
new
AST_Print
();
p
->
dest
=
NULL
;
p
->
nl
=
true
;
p
->
values
.
push_back
(
c
);
p
->
lineno
=
0
;
m
->
body
[
0
]
=
p
;
}
compileAndRunModule
(
m
,
main_module
);
}
catch
(
ExcInfo
e
)
{
int
retcode
=
0xdeadbeef
;
// should never be seen
if
(
handle_toplevel_exn
(
e
,
&
retcode
))
{
Stats
::
dump
(
false
);
return
retcode
;
}
}
}
}
_t
.
split
(
"joinRuntime"
);
threading
::
finishMainThread
(
);
int
rtncode
=
joinRuntime
();
_t
.
split
(
"finishing up"
);
// Acquire the GIL to make sure we stop the other threads, since we will tear down
// data structures they are potentially running on.
// Note: we will purposefully not release the GIL on exiting.
threading
::
promoteGL
();
_t
.
split
(
"joinRuntime"
);
rtncode
=
joinRuntime
();
_t
.
split
(
"finishing up"
);
uint64_t
main_time_ended_at
;
uint64_t
main_time_duration
=
main_time
.
end
(
&
main_time_ended_at
);
static
StatCounter
mt
(
"ticks_in_main"
);
mt
.
log
(
main_time_duration
);
STAT_TIMER_NAME
(
t0
).
pause
(
main_time_ended_at
);
}
Stats
::
dump
(
true
);
Stats
::
dump
();
return
rtncode
;
}
...
...
src/runtime/builtin_modules/builtins.cpp
View file @
181d5850
...
...
@@ -13,6 +13,7 @@
// limitations under the License.
#include <algorithm>
#include <cfloat>
#include <cstddef>
#include <err.h>
...
...
@@ -303,6 +304,7 @@ extern "C" Box* ord(Box* obj) {
}
Box
*
range
(
Box
*
start
,
Box
*
stop
,
Box
*
step
)
{
STAT_TIMER
(
t0
,
"us_timer_builtin_range"
);
i64
istart
,
istop
,
istep
;
if
(
stop
==
NULL
)
{
istart
=
0
;
...
...
@@ -346,6 +348,7 @@ Box* notimplementedRepr(Box* self) {
}
Box
*
sorted
(
Box
*
obj
,
Box
*
cmp
,
Box
*
key
,
Box
**
args
)
{
STAT_TIMER
(
t0
,
"us_timer_builtin_sorted"
);
Box
*
reverse
=
args
[
0
];
BoxedList
*
rtn
=
new
BoxedList
();
...
...
@@ -358,6 +361,7 @@ Box* sorted(Box* obj, Box* cmp, Box* key, Box** args) {
}
Box
*
isinstance_func
(
Box
*
obj
,
Box
*
cls
)
{
STAT_TIMER
(
t0
,
"us_timer_builtin_isinstance"
);
int
rtn
=
PyObject_IsInstance
(
obj
,
cls
);
if
(
rtn
<
0
)
checkAndThrowCAPIException
();
...
...
@@ -365,16 +369,29 @@ Box* isinstance_func(Box* obj, Box* cls) {
}
Box
*
issubclass_func
(
Box
*
child
,
Box
*
parent
)
{
STAT_TIMER
(
t0
,
"us_timer_builtin_issubclass"
);
int
rtn
=
PyObject_IsSubclass
(
child
,
parent
);
if
(
rtn
<
0
)
checkAndThrowCAPIException
();
return
boxBool
(
rtn
);
}
Box
*
intern_func
(
Box
*
str
)
{
if
(
!
PyString_CheckExact
(
str
))
// have to use exact check!
raiseExcHelper
(
TypeError
,
"can't intern subclass of string"
);
PyString_InternInPlace
(
&
str
);
checkAndThrowCAPIException
();
return
str
;
}
Box
*
bltinImport
(
Box
*
name
,
Box
*
globals
,
Box
*
locals
,
Box
**
args
)
{
Box
*
fromlist
=
args
[
0
];
Box
*
level
=
args
[
1
];
// __import__ takes a 'locals' argument, but it doesn't get used in CPython.
// Well, it gets passed to PyImport_ImportModuleLevel() and then import_module_level(),
// which ignores it. So we don't even pass it through.
name
=
coerceUnicodeToStr
(
name
);
if
(
name
->
cls
!=
str_cls
)
{
...
...
@@ -586,7 +603,6 @@ public:
static
Box
*
__reduce__
(
Box
*
self
)
{
RELEASE_ASSERT
(
isSubclass
(
self
->
cls
,
BaseException
),
""
);
BoxedException
*
exc
=
static_cast
<
BoxedException
*>
(
self
);
return
BoxedTuple
::
create
({
self
->
cls
,
EmptyTuple
,
self
->
getAttrWrapper
()
});
}
};
...
...
@@ -973,16 +989,38 @@ Box* builtinRound(Box* _number, Box* _ndigits) {
raiseExcHelper
(
TypeError
,
"a float is required"
);
BoxedFloat
*
number
=
(
BoxedFloat
*
)
_number
;
double
x
=
number
->
d
;
if
(
isSubclass
(
_ndigits
->
cls
,
int_cls
))
{
BoxedInt
*
ndigits
=
(
BoxedInt
*
)
_ndigits
;
/* interpret 2nd argument as a Py_ssize_t; clip on overflow */
Py_ssize_t
ndigits
=
PyNumber_AsSsize_t
(
_ndigits
,
NULL
);
if
(
ndigits
==
-
1
&&
PyErr_Occurred
())
throwCAPIException
();
if
(
ndigits
->
n
==
0
)
return
boxFloat
(
round
(
number
->
d
));
/* nans, infinities and zeros round to themselves */
if
(
!
std
::
isfinite
(
x
)
||
x
==
0.0
)
return
boxFloat
(
x
);
/* Deal with extreme values for ndigits. For ndigits > NDIGITS_MAX, x
always rounds to itself. For ndigits < NDIGITS_MIN, x always
rounds to +-0.0. Here 0.30103 is an upper bound for log10(2). */
#define NDIGITS_MAX ((int)((DBL_MANT_DIG - DBL_MIN_EXP) * 0.30103))
#define NDIGITS_MIN (-(int)((DBL_MAX_EXP + 1) * 0.30103))
if
(
ndigits
>
NDIGITS_MAX
)
/* return x */
return
boxFloat
(
x
);
else
if
(
ndigits
<
NDIGITS_MIN
)
/* return 0.0, but with sign of x */
return
boxFloat
(
0.0
*
x
);
else
{
/* finite x, and ndigits is not unreasonably large */
/* _Py_double_round is defined in floatobject.c */
Box
*
rtn
=
_Py_double_round
(
x
,
(
int
)
ndigits
);
if
(
!
rtn
)
throwCAPIException
();
return
rtn
;
}
fatalOrError
(
PyExc_NotImplementedError
,
"unimplemented"
);
throwCAPIException
();
#undef NDIGITS_MAX
#undef NDIGITS_MIN
}
Box
*
builtinCmp
(
Box
*
a
,
Box
*
b
)
{
...
...
@@ -1109,6 +1147,9 @@ void setupBuiltins() {
=
new
BoxedBuiltinFunctionOrMethod
(
boxRTFunction
((
void
*
)
issubclass_func
,
BOXED_BOOL
,
2
),
"issubclass"
);
builtins_module
->
giveAttr
(
"issubclass"
,
issubclass_obj
);
Box
*
intern_obj
=
new
BoxedBuiltinFunctionOrMethod
(
boxRTFunction
((
void
*
)
intern_func
,
UNKNOWN
,
1
),
"intern"
);
builtins_module
->
giveAttr
(
"intern"
,
intern_obj
);
CLFunction
*
import_func
=
boxRTFunction
((
void
*
)
bltinImport
,
UNKNOWN
,
5
,
4
,
false
,
false
,
ParamNames
({
"name"
,
"globals"
,
"locals"
,
"fromlist"
,
"level"
},
""
,
""
));
builtins_module
->
giveAttr
(
"__import__"
,
new
BoxedBuiltinFunctionOrMethod
(
import_func
,
"__import__"
,
...
...
src/runtime/dict.cpp
View file @
181d5850
...
...
@@ -48,6 +48,7 @@ Box* dictRepr(BoxedDict* self) {
}
Box
*
dictClear
(
BoxedDict
*
self
)
{
STAT_TIMER
(
t0
,
"us_timer_dictClear"
);
if
(
!
isSubclass
(
self
->
cls
,
dict_cls
))
raiseExcHelper
(
TypeError
,
"descriptor 'clear' requires a 'dict' object but received a '%s'"
,
getTypeName
(
self
));
...
...
@@ -56,6 +57,7 @@ Box* dictClear(BoxedDict* self) {
}
Box
*
dictCopy
(
BoxedDict
*
self
)
{
STAT_TIMER
(
t0
,
"us_timer_dictCopy"
);
if
(
!
isSubclass
(
self
->
cls
,
dict_cls
))
raiseExcHelper
(
TypeError
,
"descriptor 'copy' requires a 'dict' object but received a '%s'"
,
getTypeName
(
self
));
...
...
@@ -65,6 +67,7 @@ Box* dictCopy(BoxedDict* self) {
}
Box
*
dictItems
(
BoxedDict
*
self
)
{
STAT_TIMER
(
t0
,
"us_timer_dictItems"
);
BoxedList
*
rtn
=
new
BoxedList
();
rtn
->
ensure
(
self
->
d
.
size
());
...
...
@@ -77,6 +80,7 @@ Box* dictItems(BoxedDict* self) {
}
Box
*
dictValues
(
BoxedDict
*
self
)
{
STAT_TIMER
(
t0
,
"us_timer_dictValues"
);
BoxedList
*
rtn
=
new
BoxedList
();
rtn
->
ensure
(
self
->
d
.
size
());
for
(
const
auto
&
p
:
self
->
d
)
{
...
...
@@ -86,6 +90,7 @@ Box* dictValues(BoxedDict* self) {
}
Box
*
dictKeys
(
BoxedDict
*
self
)
{
STAT_TIMER
(
t0
,
"us_timer_dictKeys"
);
RELEASE_ASSERT
(
isSubclass
(
self
->
cls
,
dict_cls
),
""
);
BoxedList
*
rtn
=
new
BoxedList
();
...
...
@@ -182,6 +187,7 @@ extern "C" int PyDict_Update(PyObject* a, PyObject* b) noexcept {
}
Box
*
dictGetitem
(
BoxedDict
*
self
,
Box
*
k
)
{
STAT_TIMER
(
t0
,
"us_timer_dictGetitem"
);
if
(
!
isSubclass
(
self
->
cls
,
dict_cls
))
raiseExcHelper
(
TypeError
,
"descriptor '__getitem__' requires a 'dict' object but received a '%s'"
,
getTypeName
(
self
));
...
...
@@ -306,6 +312,7 @@ extern "C" PyObject* PyDict_GetItemString(PyObject* dict, const char* key) noexc
}
Box
*
dictSetitem
(
BoxedDict
*
self
,
Box
*
k
,
Box
*
v
)
{
STAT_TIMER
(
t0
,
"us_timer_dictSetitem"
);
// printf("Starting setitem\n");
Box
*&
pos
=
self
->
d
[
k
];
// printf("Got the pos\n");
...
...
@@ -320,6 +327,7 @@ Box* dictSetitem(BoxedDict* self, Box* k, Box* v) {
}
Box
*
dictDelitem
(
BoxedDict
*
self
,
Box
*
k
)
{
STAT_TIMER
(
t0
,
"us_timer_dictDelitem"
);
if
(
!
isSubclass
(
self
->
cls
,
dict_cls
))
raiseExcHelper
(
TypeError
,
"descriptor '__delitem__' requires a 'dict' object but received a '%s'"
,
getTypeName
(
self
));
...
...
src/runtime/float.cpp
View file @
181d5850
...
...
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cfloat>
#include <cmath>
#include <cstring>
...
...
@@ -833,6 +834,568 @@ const char* floatGetFormatDoc = "float.__getformat__(typestr) -> string\n"
"'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the
\n
"
"format of floating point numbers used by the C type named by typestr."
;
static
PyObject
*
float_setformat
(
PyTypeObject
*
v
,
PyObject
*
args
)
noexcept
{
char
*
typestr
;
char
*
format
;
float_format_type
f
;
float_format_type
detected
;
float_format_type
*
p
;
if
(
!
PyArg_ParseTuple
(
args
,
"ss:__setformat__"
,
&
typestr
,
&
format
))
return
NULL
;
if
(
strcmp
(
typestr
,
"double"
)
==
0
)
{
p
=
&
double_format
;
detected
=
detected_double_format
;
}
else
if
(
strcmp
(
typestr
,
"float"
)
==
0
)
{
p
=
&
float_format
;
detected
=
detected_float_format
;
}
else
{
PyErr_SetString
(
PyExc_ValueError
,
"__setformat__() argument 1 must "
"be 'double' or 'float'"
);
return
NULL
;
}
if
(
strcmp
(
format
,
"unknown"
)
==
0
)
{
f
=
unknown_format
;
}
else
if
(
strcmp
(
format
,
"IEEE, little-endian"
)
==
0
)
{
f
=
ieee_little_endian_format
;
}
else
if
(
strcmp
(
format
,
"IEEE, big-endian"
)
==
0
)
{
f
=
ieee_big_endian_format
;
}
else
{
PyErr_SetString
(
PyExc_ValueError
,
"__setformat__() argument 2 must be "
"'unknown', 'IEEE, little-endian' or "
"'IEEE, big-endian'"
);
return
NULL
;
}
if
(
f
!=
unknown_format
&&
f
!=
detected
)
{
PyErr_Format
(
PyExc_ValueError
,
"can only set %s format to 'unknown' or the "
"detected platform value"
,
typestr
);
return
NULL
;
}
*
p
=
f
;
Py_RETURN_NONE
;
}
/*----------------------------------------------------------------------------
* _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h.
*/
extern
"C"
int
_PyFloat_Pack4
(
double
x
,
unsigned
char
*
p
,
int
le
)
noexcept
{
if
(
float_format
==
unknown_format
)
{
unsigned
char
sign
;
int
e
;
double
f
;
unsigned
int
fbits
;
int
incr
=
1
;
if
(
le
)
{
p
+=
3
;
incr
=
-
1
;
}
if
(
x
<
0
)
{
sign
=
1
;
x
=
-
x
;
}
else
sign
=
0
;
f
=
frexp
(
x
,
&
e
);
/* Normalize f to be in the range [1.0, 2.0) */
if
(
0.5
<=
f
&&
f
<
1.0
)
{
f
*=
2.0
;
e
--
;
}
else
if
(
f
==
0.0
)
e
=
0
;
else
{
PyErr_SetString
(
PyExc_SystemError
,
"frexp() result out of range"
);
return
-
1
;
}
if
(
e
>=
128
)
goto
Overflow
;
else
if
(
e
<
-
126
)
{
/* Gradual underflow */
f
=
ldexp
(
f
,
126
+
e
);
e
=
0
;
}
else
if
(
!
(
e
==
0
&&
f
==
0.0
))
{
e
+=
127
;
f
-=
1.0
;
/* Get rid of leading 1 */
}
f
*=
8388608.0
;
/* 2**23 */
fbits
=
(
unsigned
int
)(
f
+
0.5
);
/* Round */
assert
(
fbits
<=
8388608
);
if
(
fbits
>>
23
)
{
/* The carry propagated out of a string of 23 1 bits. */
fbits
=
0
;
++
e
;
if
(
e
>=
255
)
goto
Overflow
;
}
/* First byte */
*
p
=
(
sign
<<
7
)
|
(
e
>>
1
);
p
+=
incr
;
/* Second byte */
*
p
=
(
char
)(((
e
&
1
)
<<
7
)
|
(
fbits
>>
16
));
p
+=
incr
;
/* Third byte */
*
p
=
(
fbits
>>
8
)
&
0xFF
;
p
+=
incr
;
/* Fourth byte */
*
p
=
fbits
&
0xFF
;
/* Done */
return
0
;
}
else
{
float
y
=
(
float
)
x
;
const
char
*
s
=
(
char
*
)
&
y
;
int
i
,
incr
=
1
;
if
(
Py_IS_INFINITY
(
y
)
&&
!
Py_IS_INFINITY
(
x
))
goto
Overflow
;
if
((
float_format
==
ieee_little_endian_format
&&
!
le
)
||
(
float_format
==
ieee_big_endian_format
&&
le
))
{
p
+=
3
;
incr
=
-
1
;
}
for
(
i
=
0
;
i
<
4
;
i
++
)
{
*
p
=
*
s
++
;
p
+=
incr
;
}
return
0
;
}
Overflow:
PyErr_SetString
(
PyExc_OverflowError
,
"float too large to pack with f format"
);
return
-
1
;
}
extern
"C"
int
_PyFloat_Pack8
(
double
x
,
unsigned
char
*
p
,
int
le
)
noexcept
{
if
(
double_format
==
unknown_format
)
{
unsigned
char
sign
;
int
e
;
double
f
;
unsigned
int
fhi
,
flo
;
int
incr
=
1
;
if
(
le
)
{
p
+=
7
;
incr
=
-
1
;
}
if
(
x
<
0
)
{
sign
=
1
;
x
=
-
x
;
}
else
sign
=
0
;
f
=
frexp
(
x
,
&
e
);
/* Normalize f to be in the range [1.0, 2.0) */
if
(
0.5
<=
f
&&
f
<
1.0
)
{
f
*=
2.0
;
e
--
;
}
else
if
(
f
==
0.0
)
e
=
0
;
else
{
PyErr_SetString
(
PyExc_SystemError
,
"frexp() result out of range"
);
return
-
1
;
}
if
(
e
>=
1024
)
goto
Overflow
;
else
if
(
e
<
-
1022
)
{
/* Gradual underflow */
f
=
ldexp
(
f
,
1022
+
e
);
e
=
0
;
}
else
if
(
!
(
e
==
0
&&
f
==
0.0
))
{
e
+=
1023
;
f
-=
1.0
;
/* Get rid of leading 1 */
}
/* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */
f
*=
268435456.0
;
/* 2**28 */
fhi
=
(
unsigned
int
)
f
;
/* Truncate */
assert
(
fhi
<
268435456
);
f
-=
(
double
)
fhi
;
f
*=
16777216.0
;
/* 2**24 */
flo
=
(
unsigned
int
)(
f
+
0.5
);
/* Round */
assert
(
flo
<=
16777216
);
if
(
flo
>>
24
)
{
/* The carry propagated out of a string of 24 1 bits. */
flo
=
0
;
++
fhi
;
if
(
fhi
>>
28
)
{
/* And it also progagated out of the next 28 bits. */
fhi
=
0
;
++
e
;
if
(
e
>=
2047
)
goto
Overflow
;
}
}
/* First byte */
*
p
=
(
sign
<<
7
)
|
(
e
>>
4
);
p
+=
incr
;
/* Second byte */
*
p
=
(
unsigned
char
)(((
e
&
0xF
)
<<
4
)
|
(
fhi
>>
24
));
p
+=
incr
;
/* Third byte */
*
p
=
(
fhi
>>
16
)
&
0xFF
;
p
+=
incr
;
/* Fourth byte */
*
p
=
(
fhi
>>
8
)
&
0xFF
;
p
+=
incr
;
/* Fifth byte */
*
p
=
fhi
&
0xFF
;
p
+=
incr
;
/* Sixth byte */
*
p
=
(
flo
>>
16
)
&
0xFF
;
p
+=
incr
;
/* Seventh byte */
*
p
=
(
flo
>>
8
)
&
0xFF
;
p
+=
incr
;
/* Eighth byte */
*
p
=
flo
&
0xFF
;
/* p += incr; Unneeded (for now) */
/* Done */
return
0
;
Overflow:
PyErr_SetString
(
PyExc_OverflowError
,
"float too large to pack with d format"
);
return
-
1
;
}
else
{
const
char
*
s
=
(
char
*
)
&
x
;
int
i
,
incr
=
1
;
if
((
double_format
==
ieee_little_endian_format
&&
!
le
)
||
(
double_format
==
ieee_big_endian_format
&&
le
))
{
p
+=
7
;
incr
=
-
1
;
}
for
(
i
=
0
;
i
<
8
;
i
++
)
{
*
p
=
*
s
++
;
p
+=
incr
;
}
return
0
;
}
}
extern
"C"
double
_PyFloat_Unpack4
(
const
unsigned
char
*
p
,
int
le
)
noexcept
{
if
(
float_format
==
unknown_format
)
{
unsigned
char
sign
;
int
e
;
unsigned
int
f
;
double
x
;
int
incr
=
1
;
if
(
le
)
{
p
+=
3
;
incr
=
-
1
;
}
/* First byte */
sign
=
(
*
p
>>
7
)
&
1
;
e
=
(
*
p
&
0x7F
)
<<
1
;
p
+=
incr
;
/* Second byte */
e
|=
(
*
p
>>
7
)
&
1
;
f
=
(
*
p
&
0x7F
)
<<
16
;
p
+=
incr
;
if
(
e
==
255
)
{
PyErr_SetString
(
PyExc_ValueError
,
"can't unpack IEEE 754 special value "
"on non-IEEE platform"
);
return
-
1
;
}
/* Third byte */
f
|=
*
p
<<
8
;
p
+=
incr
;
/* Fourth byte */
f
|=
*
p
;
x
=
(
double
)
f
/
8388608.0
;
/* XXX This sadly ignores Inf/NaN issues */
if
(
e
==
0
)
e
=
-
126
;
else
{
x
+=
1.0
;
e
-=
127
;
}
x
=
ldexp
(
x
,
e
);
if
(
sign
)
x
=
-
x
;
return
x
;
}
else
{
float
x
;
if
((
float_format
==
ieee_little_endian_format
&&
!
le
)
||
(
float_format
==
ieee_big_endian_format
&&
le
))
{
char
buf
[
4
];
char
*
d
=
&
buf
[
3
];
int
i
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
*
d
--
=
*
p
++
;
}
memcpy
(
&
x
,
buf
,
4
);
}
else
{
memcpy
(
&
x
,
p
,
4
);
}
return
x
;
}
}
extern
"C"
double
_PyFloat_Unpack8
(
const
unsigned
char
*
p
,
int
le
)
noexcept
{
if
(
double_format
==
unknown_format
)
{
unsigned
char
sign
;
int
e
;
unsigned
int
fhi
,
flo
;
double
x
;
int
incr
=
1
;
if
(
le
)
{
p
+=
7
;
incr
=
-
1
;
}
/* First byte */
sign
=
(
*
p
>>
7
)
&
1
;
e
=
(
*
p
&
0x7F
)
<<
4
;
p
+=
incr
;
/* Second byte */
e
|=
(
*
p
>>
4
)
&
0xF
;
fhi
=
(
*
p
&
0xF
)
<<
24
;
p
+=
incr
;
if
(
e
==
2047
)
{
PyErr_SetString
(
PyExc_ValueError
,
"can't unpack IEEE 754 special value "
"on non-IEEE platform"
);
return
-
1.0
;
}
/* Third byte */
fhi
|=
*
p
<<
16
;
p
+=
incr
;
/* Fourth byte */
fhi
|=
*
p
<<
8
;
p
+=
incr
;
/* Fifth byte */
fhi
|=
*
p
;
p
+=
incr
;
/* Sixth byte */
flo
=
*
p
<<
16
;
p
+=
incr
;
/* Seventh byte */
flo
|=
*
p
<<
8
;
p
+=
incr
;
/* Eighth byte */
flo
|=
*
p
;
x
=
(
double
)
fhi
+
(
double
)
flo
/
16777216.0
;
/* 2**24 */
x
/=
268435456.0
;
/* 2**28 */
if
(
e
==
0
)
e
=
-
1022
;
else
{
x
+=
1.0
;
e
-=
1023
;
}
x
=
ldexp
(
x
,
e
);
if
(
sign
)
x
=
-
x
;
return
x
;
}
else
{
double
x
;
if
((
double_format
==
ieee_little_endian_format
&&
!
le
)
||
(
double_format
==
ieee_big_endian_format
&&
le
))
{
char
buf
[
8
];
char
*
d
=
&
buf
[
7
];
int
i
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
*
d
--
=
*
p
++
;
}
memcpy
(
&
x
,
buf
,
8
);
}
else
{
memcpy
(
&
x
,
p
,
8
);
}
return
x
;
}
}
#if DBL_MANT_DIG == 53
#define FIVE_POW_LIMIT 22
#else
#error "C doubles do not appear to be IEEE 754 binary64 format"
#endif
extern
"C"
PyObject
*
_Py_double_round
(
double
x
,
int
ndigits
)
noexcept
{
double
rounded
,
m
;
Py_ssize_t
buflen
,
mybuflen
=
100
;
char
*
buf
,
*
buf_end
,
shortbuf
[
100
],
*
mybuf
=
shortbuf
;
int
decpt
,
sign
,
val
,
halfway_case
;
PyObject
*
result
=
NULL
;
_Py_SET_53BIT_PRECISION_HEADER
;
/* Easy path for the common case ndigits == 0. */
if
(
ndigits
==
0
)
{
rounded
=
round
(
x
);
if
(
fabs
(
rounded
-
x
)
==
0.5
)
/* halfway between two integers; use round-away-from-zero */
rounded
=
x
+
(
x
>
0.0
?
0.5
:
-
0.5
);
return
PyFloat_FromDouble
(
rounded
);
}
/* The basic idea is very simple: convert and round the double to a
decimal string using _Py_dg_dtoa, then convert that decimal string
back to a double with _Py_dg_strtod. There's one minor difficulty:
Python 2.x expects round to do round-half-away-from-zero, while
_Py_dg_dtoa does round-half-to-even. So we need some way to detect
and correct the halfway cases.
Detection: a halfway value has the form k * 0.5 * 10**-ndigits for
some odd integer k. Or in other words, a rational number x is
exactly halfway between two multiples of 10**-ndigits if its
2-valuation is exactly -ndigits-1 and its 5-valuation is at least
-ndigits. For ndigits >= 0 the latter condition is automatically
satisfied for a binary float x, since any such float has
nonnegative 5-valuation. For 0 > ndigits >= -22, x needs to be an
integral multiple of 5**-ndigits; we can check this using fmod.
For -22 > ndigits, there are no halfway cases: 5**23 takes 54 bits
to represent exactly, so any odd multiple of 0.5 * 10**n for n >=
23 takes at least 54 bits of precision to represent exactly.
Correction: a simple strategy for dealing with halfway cases is to
(for the halfway cases only) call _Py_dg_dtoa with an argument of
ndigits+1 instead of ndigits (thus doing an exact conversion to
decimal), round the resulting string manually, and then convert
back using _Py_dg_strtod.
*/
/* nans, infinities and zeros should have already been dealt
with by the caller (in this case, builtin_round) */
assert
(
std
::
isfinite
(
x
)
&&
x
!=
0.0
);
/* find 2-valuation val of x */
m
=
frexp
(
x
,
&
val
);
while
(
m
!=
floor
(
m
))
{
m
*=
2.0
;
val
--
;
}
/* determine whether this is a halfway case */
if
(
val
==
-
ndigits
-
1
)
{
if
(
ndigits
>=
0
)
halfway_case
=
1
;
else
if
(
ndigits
>=
-
FIVE_POW_LIMIT
)
{
double
five_pow
=
1.0
;
int
i
;
for
(
i
=
0
;
i
<
-
ndigits
;
i
++
)
five_pow
*=
5.0
;
halfway_case
=
fmod
(
x
,
five_pow
)
==
0.0
;
}
else
halfway_case
=
0
;
}
else
halfway_case
=
0
;
/* round to a decimal string; use an extra place for halfway case */
_Py_SET_53BIT_PRECISION_START
;
buf
=
_Py_dg_dtoa
(
x
,
3
,
ndigits
+
halfway_case
,
&
decpt
,
&
sign
,
&
buf_end
);
_Py_SET_53BIT_PRECISION_END
;
if
(
buf
==
NULL
)
{
PyErr_NoMemory
();
return
NULL
;
}
buflen
=
buf_end
-
buf
;
/* in halfway case, do the round-half-away-from-zero manually */
if
(
halfway_case
)
{
int
i
,
carry
;
/* sanity check: _Py_dg_dtoa should not have stripped
any zeros from the result: there should be exactly
ndigits+1 places following the decimal point, and
the last digit in the buffer should be a '5'.*/
assert
(
buflen
-
decpt
==
ndigits
+
1
);
assert
(
buf
[
buflen
-
1
]
==
'5'
);
/* increment and shift right at the same time. */
decpt
+=
1
;
carry
=
1
;
for
(
i
=
buflen
-
1
;
i
--
>
0
;)
{
carry
+=
buf
[
i
]
-
'0'
;
buf
[
i
+
1
]
=
carry
%
10
+
'0'
;
carry
/=
10
;
}
buf
[
0
]
=
carry
+
'0'
;
}
/* Get new buffer if shortbuf is too small. Space needed <= buf_end -
buf + 8: (1 extra for '0', 1 for sign, 5 for exp, 1 for '\0'). */
if
(
buflen
+
8
>
mybuflen
)
{
mybuflen
=
buflen
+
8
;
mybuf
=
(
char
*
)
PyMem_Malloc
(
mybuflen
);
if
(
mybuf
==
NULL
)
{
PyErr_NoMemory
();
goto
exit
;
}
}
/* copy buf to mybuf, adding exponent, sign and leading 0 */
PyOS_snprintf
(
mybuf
,
mybuflen
,
"%s0%se%d"
,
(
sign
?
"-"
:
""
),
buf
,
decpt
-
(
int
)
buflen
);
/* and convert the resulting string back to a double */
errno
=
0
;
_Py_SET_53BIT_PRECISION_START
;
rounded
=
_Py_dg_strtod
(
mybuf
,
NULL
);
_Py_SET_53BIT_PRECISION_END
;
if
(
errno
==
ERANGE
&&
fabs
(
rounded
)
>=
1.
)
PyErr_SetString
(
PyExc_OverflowError
,
"rounded value too large to represent"
);
else
result
=
PyFloat_FromDouble
(
rounded
);
/* done computing value; now clean up */
if
(
mybuf
!=
shortbuf
)
PyMem_Free
(
mybuf
);
exit:
_Py_dg_freedtoa
(
buf
);
return
result
;
}
void
setupFloat
()
{
_addFunc
(
"__add__"
,
BOXED_FLOAT
,
(
void
*
)
floatAddFloat
,
(
void
*
)
floatAddInt
,
(
void
*
)
floatAdd
);
float_cls
->
giveAttr
(
"__radd__"
,
float_cls
->
getattr
(
"__add__"
));
...
...
src/runtime/generator.cpp
View file @
181d5850
...
...
@@ -86,28 +86,36 @@ Context* getReturnContextForGeneratorFrame(void* frame_addr) {
}
void
generatorEntry
(
BoxedGenerator
*
g
)
{
assert
(
g
->
cls
==
generator_cls
);
assert
(
g
->
function
->
cls
==
function_cls
);
{
STAT_TIMER2
(
t0
,
"us_timer_generator_toplevel"
,
g
->
timer_time
);
threading
::
pushGenerator
(
g
,
g
->
stack_begin
,
g
->
returnContext
);
assert
(
g
->
cls
==
generator_cls
);
assert
(
g
->
function
->
cls
==
function_cls
);
try
{
RegisterHelper
context_registerer
(
g
,
__builtin_frame_address
(
0
));
threading
::
pushGenerator
(
g
,
g
->
stack_begin
,
g
->
returnContext
);
try
{
RegisterHelper
context_registerer
(
g
,
__builtin_frame_address
(
0
));
// call body of the generator
BoxedFunctionBase
*
func
=
g
->
function
;
// call body of the generator
BoxedFunctionBase
*
func
=
g
->
function
;
Box
**
args
=
g
->
args
?
&
g
->
args
->
elts
[
0
]
:
nullptr
;
callCLFunc
(
func
->
f
,
nullptr
,
func
->
f
->
numReceivedArgs
(),
func
->
closure
,
g
,
func
->
globals
,
g
->
arg1
,
g
->
arg2
,
g
->
arg3
,
args
);
}
catch
(
ExcInfo
e
)
{
// unhandled exception: propagate the exception to the caller
g
->
exception
=
e
;
}
Box
**
args
=
g
->
args
?
&
g
->
args
->
elts
[
0
]
:
nullptr
;
callCLFunc
(
func
->
f
,
nullptr
,
func
->
f
->
numReceivedArgs
(),
func
->
closure
,
g
,
func
->
globals
,
g
->
arg1
,
g
->
arg2
,
g
->
arg3
,
args
);
}
catch
(
ExcInfo
e
)
{
// unhandled exception: propagate the exception to the caller
g
->
exception
=
e
;
}
// we returned from the body of the generator. next/send/throw will notify the caller
g
->
entryExited
=
true
;
threading
::
popGenerator
();
// we returned from the body of the generator. next/send/throw will notify the caller
g
->
entryExited
=
true
;
threading
::
popGenerator
();
#if STAT_TIMERS
g
->
timer_time
=
getCPUTicks
();
// store off the timer that our caller (in g->returnContext) will resume at
STAT_TIMER_NAME
(
t0
).
pause
(
g
->
timer_time
);
#endif
}
swapContext
(
&
g
->
context
,
g
->
returnContext
,
0
);
}
...
...
@@ -130,7 +138,21 @@ Box* generatorSend(Box* s, Box* v) {
self
->
returnValue
=
v
;
self
->
running
=
true
;
#if STAT_TIMERS
// store off the time that the generator will use to initialize its toplevel timer
self
->
timer_time
=
getCPUTicks
();
StatTimer
*
current_timers
=
StatTimer
::
swapStack
(
self
->
statTimers
,
self
->
timer_time
);
#endif
swapContext
(
&
self
->
returnContext
,
self
->
context
,
(
intptr_t
)
self
);
#if STAT_TIMERS
// if the generator exited we use the time that generatorEntry stored in self->timer_time (the same time it paused
// its timer at).
self
->
statTimers
=
StatTimer
::
swapStack
(
current_timers
,
self
->
entryExited
?
self
->
timer_time
:
getCPUTicks
());
#endif
self
->
running
=
false
;
// propagate exception to the caller
...
...
src/runtime/import.cpp
View file @
181d5850
...
...
@@ -21,6 +21,7 @@
#include "codegen/irgen/hooks.h"
#include "codegen/parser.h"
#include "codegen/unwinding.h"
#include "runtime/capi.h"
#include "runtime/objmodel.h"
...
...
@@ -267,7 +268,7 @@ static Box* getParent(Box* globals, int level, std::string& buf) {
if
(
globals
==
NULL
||
globals
==
None
||
level
==
0
)
return
None
;
BoxedString
*
pkgname
=
static_cast
<
BoxedString
*>
(
get
attrInternal
(
globals
,
package_str
,
NULL
));
BoxedString
*
pkgname
=
static_cast
<
BoxedString
*>
(
get
FromGlobals
(
globals
,
package_str
));
if
(
pkgname
!=
NULL
&&
pkgname
!=
None
)
{
/* __package__ is set, so use it */
if
(
pkgname
->
cls
!=
str_cls
)
{
...
...
@@ -286,17 +287,11 @@ static Box* getParent(Box* globals, int level, std::string& buf) {
buf
+=
pkgname
->
s
;
}
else
{
/* __package__ not set, so figure it out and set it */
BoxedString
*
modname
=
static_cast
<
BoxedString
*>
(
get
attrInternal
(
globals
,
name_str
,
NULL
));
BoxedString
*
modname
=
static_cast
<
BoxedString
*>
(
get
FromGlobals
(
globals
,
name_str
));
if
(
modname
==
NULL
||
modname
->
cls
!=
str_cls
)
return
None
;
Box
*
modpath
=
NULL
;
try
{
modpath
=
getattrInternal
(
globals
,
path_str
,
NULL
);
}
catch
(
ExcInfo
e
)
{
if
(
!
e
.
matches
(
AttributeError
))
raiseRaw
(
e
);
}
Box
*
modpath
=
getFromGlobals
(
globals
,
path_str
);
if
(
modpath
!=
NULL
)
{
/* __path__ is set, so modname is already the package name */
...
...
@@ -304,7 +299,7 @@ static Box* getParent(Box* globals, int level, std::string& buf) {
raiseExcHelper
(
ValueError
,
"Module name too long"
);
}
buf
+=
modname
->
s
;
globals
->
setattr
(
package_str
,
modname
,
NULL
);
setGlobal
(
globals
,
package_str
,
modname
);
}
else
{
/* Normal module, so work out the package name if any */
size_t
lastdot
=
modname
->
s
.
rfind
(
'.'
);
...
...
@@ -312,7 +307,7 @@ static Box* getParent(Box* globals, int level, std::string& buf) {
raiseExcHelper
(
ValueError
,
"Attempted relative import in non-package"
);
}
if
(
lastdot
==
std
::
string
::
npos
)
{
globals
->
setattr
(
package_str
,
None
,
NULL
);
setGlobal
(
globals
,
package_str
,
None
);
return
None
;
}
if
(
lastdot
>=
PATH_MAX
)
{
...
...
@@ -320,7 +315,7 @@ static Box* getParent(Box* globals, int level, std::string& buf) {
}
buf
=
std
::
string
(
modname
->
s
,
0
,
lastdot
);
globals
->
setattr
(
package_str
,
boxStringPtr
(
&
buf
),
NULL
);
setGlobal
(
globals
,
package_str
,
boxStringPtr
(
&
buf
)
);
}
}
...
...
@@ -471,7 +466,6 @@ static bool loadNext(Box* mod, Box* altmod, std::string& name, std::string& buf,
static
void
ensureFromlist
(
Box
*
module
,
Box
*
fromlist
,
std
::
string
&
buf
,
bool
recursive
);
Box
*
importModuleLevel
(
const
std
::
string
&
name
,
Box
*
globals
,
Box
*
from_imports
,
int
level
)
{
RELEASE_ASSERT
(
!
globals
||
globals
==
None
||
isSubclass
(
globals
->
cls
,
module_cls
),
""
);
bool
return_first
=
from_imports
==
None
;
static
StatCounter
slowpath_import
(
"slowpath_import"
);
...
...
@@ -665,7 +659,7 @@ Box* nullImporterFindModule(Box* self, Box* fullname, Box* path) {
extern
"C"
Box
*
import
(
int
level
,
Box
*
from_imports
,
const
std
::
string
*
module_name
)
{
std
::
string
_module_name
(
*
module_name
);
return
importModuleLevel
(
_module_name
,
get
CurrentModule
(),
from_imports
,
level
);
return
importModuleLevel
(
_module_name
,
get
Globals
(),
from_imports
,
level
);
}
Box
*
impFindModule
(
Box
*
_name
,
BoxedList
*
path
)
{
...
...
src/runtime/int.cpp
View file @
181d5850
...
...
@@ -200,7 +200,7 @@ extern "C" PyObject* PyInt_FromString(const char* s, char** pend, int base) noex
if
(
x
<
0
)
return
PyLong_FromString
(
s
,
pend
,
base
);
}
else
x
=
strto
u
l
(
s
,
&
end
,
base
);
x
=
strtol
(
s
,
&
end
,
base
);
if
(
end
==
s
||
!
isalnum
(
Py_CHARMASK
(
end
[
-
1
])))
goto
bad
;
while
(
*
end
&&
isspace
(
Py_CHARMASK
(
*
end
)))
...
...
@@ -672,8 +672,13 @@ extern "C" Box* intLShiftInt(BoxedInt* lhs, BoxedInt* rhs) {
if
(
rhs
->
n
<
0
)
raiseExcHelper
(
ValueError
,
"negative shift count"
);
// TODO overflow?
return
boxInt
(
lhs
->
n
<<
rhs
->
n
);
bool
undefined
=
rhs
->
n
>=
sizeof
(
rhs
->
n
)
*
8
;
if
(
!
undefined
)
{
int64_t
res
=
lhs
->
n
<<
rhs
->
n
;
if
((
res
>>
rhs
->
n
)
==
lhs
->
n
)
return
boxInt
(
lhs
->
n
<<
rhs
->
n
);
}
return
longLshift
(
boxLong
(
lhs
->
n
),
rhs
);
}
extern
"C"
Box
*
intLShift
(
BoxedInt
*
lhs
,
Box
*
rhs
)
{
...
...
src/runtime/iterobject.cpp
View file @
181d5850
...
...
@@ -109,7 +109,7 @@ Box* seqiterNext(Box* s) {
}
static
void
seqiterGCVisit
(
GCVisitor
*
v
,
Box
*
b
)
{
assert
(
b
->
cls
==
seqiter_cls
);
assert
(
b
->
cls
==
seqiter_cls
||
b
->
cls
==
seqreviter_cls
);
boxGCHandler
(
v
,
b
);
BoxedSeqIter
*
si
=
static_cast
<
BoxedSeqIter
*>
(
b
);
...
...
@@ -182,7 +182,8 @@ void setupIter() {
seqiter_cls
->
freeze
();
seqiter_cls
->
tpp_hasnext
=
seqiterHasnextUnboxed
;
seqreviter_cls
=
BoxedHeapClass
::
create
(
type_cls
,
object_cls
,
NULL
,
0
,
0
,
sizeof
(
BoxedSeqIter
),
false
,
"reversed"
);
seqreviter_cls
=
BoxedHeapClass
::
create
(
type_cls
,
object_cls
,
seqiterGCVisit
,
0
,
0
,
sizeof
(
BoxedSeqIter
),
false
,
"reversed"
);
seqreviter_cls
->
giveAttr
(
"next"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
seqiterNext
,
UNKNOWN
,
1
)));
seqreviter_cls
->
giveAttr
(
"__hasnext__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
seqreviterHasnext
,
BOXED_BOOL
,
1
)));
...
...
src/runtime/list.cpp
View file @
181d5850
...
...
@@ -25,6 +25,7 @@
#include "core/stats.h"
#include "core/types.h"
#include "gc/collector.h"
#include "gc/roots.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
...
...
@@ -423,23 +424,21 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) {
size_t
v_size
;
Box
**
v_elts
;
RootedBox
v_as_seq
((
Box
*
)
nullptr
);
if
(
!
v
)
{
v_size
=
0
;
v_elts
=
NULL
;
}
else
if
(
v
->
cls
==
list_cls
||
isSubclass
(
v
->
cls
,
list_cls
))
{
BoxedList
*
lv
=
static_cast
<
BoxedList
*>
(
v
);
v_size
=
lv
->
size
;
}
else
{
v_as_seq
=
RootedBox
(
PySequence_Fast
(
v
,
"can only assign an iterable"
));
if
(
v_as_seq
==
NULL
)
throwCAPIException
();
v_size
=
PySequence_Fast_GET_SIZE
(
v_as_seq
);
// If lv->size is 0, lv->elts->elts is garbage
if
(
v_size
)
v_elts
=
lv
->
elts
->
elts
;
v_elts
=
PySequence_Fast_ITEMS
(
v_as_seq
)
;
else
v_elts
=
NULL
;
}
else
if
(
v
->
cls
==
tuple_cls
||
isSubclass
(
v
->
cls
,
tuple_cls
))
{
BoxedTuple
*
tv
=
static_cast
<
BoxedTuple
*>
(
v
);
v_size
=
tv
->
size
();
v_elts
=
&
tv
->
elts
[
0
];
}
else
{
RELEASE_ASSERT
(
0
,
"unsupported type for list slice assignment: '%s'"
,
getTypeName
(
v
));
}
// If self->size is 0, self->elts->elts is garbage
...
...
@@ -542,6 +541,8 @@ extern "C" Box* listInsert(BoxedList* self, Box* idx, Box* v) {
}
Box
*
listMul
(
BoxedList
*
self
,
Box
*
rhs
)
{
STAT_TIMER
(
t0
,
"us_timer_listMul"
);
if
(
rhs
->
cls
!=
int_cls
)
{
raiseExcHelper
(
TypeError
,
"can't multiply sequence by non-int of type '%s'"
,
getTypeName
(
rhs
));
}
...
...
@@ -961,7 +962,7 @@ Box* listNe(BoxedList* self, Box* rhs) {
}
Box
*
listLt
(
BoxedList
*
self
,
Box
*
rhs
)
{
if
(
rhs
->
cls
!=
list_cls
)
{
if
(
!
isSubclass
(
rhs
->
cls
,
list_cls
)
)
{
return
NotImplemented
;
}
...
...
@@ -971,7 +972,7 @@ Box* listLt(BoxedList* self, Box* rhs) {
}
Box
*
listLe
(
BoxedList
*
self
,
Box
*
rhs
)
{
if
(
rhs
->
cls
!=
list_cls
)
{
if
(
!
isSubclass
(
rhs
->
cls
,
list_cls
)
)
{
return
NotImplemented
;
}
...
...
@@ -981,7 +982,7 @@ Box* listLe(BoxedList* self, Box* rhs) {
}
Box
*
listGt
(
BoxedList
*
self
,
Box
*
rhs
)
{
if
(
rhs
->
cls
!=
list_cls
)
{
if
(
!
isSubclass
(
rhs
->
cls
,
list_cls
)
)
{
return
NotImplemented
;
}
...
...
@@ -991,7 +992,7 @@ Box* listGt(BoxedList* self, Box* rhs) {
}
Box
*
listGe
(
BoxedList
*
self
,
Box
*
rhs
)
{
if
(
rhs
->
cls
!=
list_cls
)
{
if
(
!
isSubclass
(
rhs
->
cls
,
list_cls
)
)
{
return
NotImplemented
;
}
...
...
src/runtime/long.cpp
View file @
181d5850
...
...
@@ -116,7 +116,48 @@ extern "C" unsigned PY_LONG_LONG PyLong_AsUnsignedLongLongMask(PyObject* vv) noe
}
extern
"C"
PY_LONG_LONG
PyLong_AsLongLong
(
PyObject
*
vv
)
noexcept
{
Py_FatalError
(
"unimplemented"
);
PY_LONG_LONG
bytes
;
int
one
=
1
;
int
res
;
if
(
vv
==
NULL
)
{
PyErr_BadInternalCall
();
return
-
1
;
}
if
(
!
PyLong_Check
(
vv
))
{
PyNumberMethods
*
nb
;
PyObject
*
io
;
if
(
PyInt_Check
(
vv
))
return
(
PY_LONG_LONG
)
PyInt_AsLong
(
vv
);
if
((
nb
=
vv
->
cls
->
tp_as_number
)
==
NULL
||
nb
->
nb_int
==
NULL
)
{
PyErr_SetString
(
PyExc_TypeError
,
"an integer is required"
);
return
-
1
;
}
io
=
(
*
nb
->
nb_int
)(
vv
);
if
(
io
==
NULL
)
return
-
1
;
if
(
PyInt_Check
(
io
))
{
bytes
=
PyInt_AsLong
(
io
);
Py_DECREF
(
io
);
return
bytes
;
}
if
(
PyLong_Check
(
io
))
{
bytes
=
PyLong_AsLongLong
(
io
);
Py_DECREF
(
io
);
return
bytes
;
}
Py_DECREF
(
io
);
PyErr_SetString
(
PyExc_TypeError
,
"integer conversion failed"
);
return
-
1
;
}
res
=
_PyLong_AsByteArray
((
PyLongObject
*
)
vv
,
(
unsigned
char
*
)
&
bytes
,
SIZEOF_LONG_LONG
,
IS_LITTLE_ENDIAN
,
1
);
/* Plan 9 can't handle PY_LONG_LONG in ? : expressions */
if
(
res
<
0
)
return
(
PY_LONG_LONG
)
-
1
;
else
return
bytes
;
}
extern
"C"
PY_LONG_LONG
PyLong_AsLongLongAndOverflow
(
PyObject
*
obj
,
int
*
overflow
)
noexcept
{
...
...
@@ -442,7 +483,12 @@ extern "C" void* PyLong_AsVoidPtr(PyObject* vv) noexcept {
extern
"C"
int
_PyLong_AsByteArray
(
PyLongObject
*
v
,
unsigned
char
*
bytes
,
size_t
n
,
int
little_endian
,
int
is_signed
)
noexcept
{
Py_FatalError
(
"unimplemented"
);
RELEASE_ASSERT
(
little_endian
==
1
,
"not implemented"
);
RELEASE_ASSERT
(
n
==
8
,
"did not yet check if the behaviour is correct for sizes other than 8"
);
size_t
count
=
0
;
mpz_export
(
bytes
,
&
count
,
-
1
,
n
,
0
,
0
,
((
BoxedLong
*
)
v
)
->
n
);
RELEASE_ASSERT
(
count
<=
n
,
"overflow handling is not yet implemented"
);
return
0
;
}
extern
"C"
PyObject
*
_PyLong_FromByteArray
(
const
unsigned
char
*
bytes
,
size_t
n
,
int
little_endian
,
...
...
src/runtime/objmodel.cpp
View file @
181d5850
...
...
@@ -125,6 +125,7 @@ static Box* (*callattrInternal3)(Box*, const std::string*, LookupScope, CallRewr
*
(
*
)(
Box
*
,
const
std
::
string
*
,
LookupScope
,
CallRewriteArgs
*
,
ArgPassSpec
,
Box
*
,
Box
*
,
Box
*
))
callattrInternal
;
size_t
PyHasher
::
operator
()(
Box
*
b
)
const
{
STAT_TIMER
(
t0
,
"us_timer_PyHasher"
);
if
(
b
->
cls
==
str_cls
)
{
StringHash
<
char
>
H
;
auto
s
=
static_cast
<
BoxedString
*>
(
b
);
...
...
@@ -138,6 +139,8 @@ size_t PyHasher::operator()(Box* b) const {
}
bool
PyEq
::
operator
()(
Box
*
lhs
,
Box
*
rhs
)
const
{
STAT_TIMER
(
t0
,
"us_timer_PyEq"
);
if
(
lhs
->
cls
==
rhs
->
cls
)
{
if
(
lhs
->
cls
==
str_cls
)
{
return
static_cast
<
BoxedString
*>
(
lhs
)
->
s
==
static_cast
<
BoxedString
*>
(
rhs
)
->
s
;
...
...
@@ -151,6 +154,8 @@ bool PyEq::operator()(Box* lhs, Box* rhs) const {
}
bool
PyLt
::
operator
()(
Box
*
lhs
,
Box
*
rhs
)
const
{
STAT_TIMER
(
t0
,
"us_timer_PyLt"
);
// TODO fix this
Box
*
cmp
=
compareInternal
(
lhs
,
rhs
,
AST_TYPE
::
Lt
,
NULL
);
assert
(
cmp
->
cls
==
bool_cls
);
...
...
@@ -211,6 +216,7 @@ extern "C" void my_assert(bool b) {
}
extern
"C"
bool
isSubclass
(
BoxedClass
*
child
,
BoxedClass
*
parent
)
{
STAT_TIMER
(
t0
,
"us_timer_isSubclass"
);
return
PyType_IsSubtype
(
child
,
parent
);
}
...
...
@@ -476,6 +482,7 @@ const char* getNameOfClass(BoxedClass* cls) {
}
HiddenClass
*
HiddenClass
::
getOrMakeChild
(
const
std
::
string
&
attr
)
{
STAT_TIMER
(
t0
,
"us_timer_hiddenclass_getOrMakeChild"
);
assert
(
type
==
NORMAL
);
auto
it
=
children
.
find
(
attr
);
...
...
@@ -507,6 +514,8 @@ HiddenClass* HiddenClass::getAttrwrapperChild() {
* del attr from current HiddenClass, maintaining the order of the remaining attrs
*/
HiddenClass
*
HiddenClass
::
delAttrToMakeHC
(
const
std
::
string
&
attr
)
{
STAT_TIMER
(
t0
,
"us_timer_hiddenclass_delAttrToMakeHC"
);
assert
(
type
==
NORMAL
);
int
idx
=
getOffset
(
attr
);
assert
(
idx
>=
0
);
...
...
@@ -655,8 +664,9 @@ Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) {
Box
*
key
=
boxString
(
attr
);
auto
it
=
d
->
d
.
find
(
key
);
if
(
it
==
d
->
d
.
end
())
if
(
it
==
d
->
d
.
end
())
{
return
NULL
;
}
return
it
->
second
;
}
...
...
@@ -1211,6 +1221,8 @@ Box* getattrInternalEx(Box* obj, const std::string& attr, GetattrRewriteArgs* re
if
(
!
cls_only
)
{
BoxedClass
*
cls
=
obj
->
cls
;
if
(
obj
->
cls
->
tp_getattro
&&
obj
->
cls
->
tp_getattro
!=
PyObject_GenericGetAttr
)
{
STAT_TIMER
(
t0
,
"us_timer_tp_getattro"
);
Box
*
r
=
obj
->
cls
->
tp_getattro
(
obj
,
boxString
(
attr
));
if
(
!
r
)
throwCAPIException
();
...
...
@@ -1218,6 +1230,8 @@ Box* getattrInternalEx(Box* obj, const std::string& attr, GetattrRewriteArgs* re
}
if
(
obj
->
cls
->
tp_getattr
)
{
STAT_TIMER
(
t0
,
"us_timer_tp_getattr"
);
Box
*
r
=
obj
->
cls
->
tp_getattr
(
obj
,
const_cast
<
char
*>
(
attr
.
c_str
()));
if
(
!
r
)
throwCAPIException
();
...
...
@@ -1242,6 +1256,8 @@ inline Box* getclsattrInternal(Box* obj, const std::string& attr, GetattrRewrite
}
extern
"C"
Box
*
getclsattr
(
Box
*
obj
,
const
char
*
attr
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_getclsattr"
);
static
StatCounter
slowpath_getclsattr
(
"slowpath_getclsattr"
);
slowpath_getclsattr
.
log
();
...
...
@@ -1312,12 +1328,6 @@ Box* processDescriptor(Box* obj, Box* inst, Box* owner) {
}
static
Box
*
(
*
runtimeCall0
)(
Box
*
,
ArgPassSpec
)
=
(
Box
*
(
*
)(
Box
*
,
ArgPassSpec
))
runtimeCall
;
static
Box
*
(
*
runtimeCall1
)(
Box
*
,
ArgPassSpec
,
Box
*
)
=
(
Box
*
(
*
)(
Box
*
,
ArgPassSpec
,
Box
*
))
runtimeCall
;
static
Box
*
(
*
runtimeCall2
)(
Box
*
,
ArgPassSpec
,
Box
*
,
Box
*
)
=
(
Box
*
(
*
)(
Box
*
,
ArgPassSpec
,
Box
*
,
Box
*
))
runtimeCall
;
static
Box
*
(
*
runtimeCall3
)(
Box
*
,
ArgPassSpec
,
Box
*
,
Box
*
,
Box
*
)
=
(
Box
*
(
*
)(
Box
*
,
ArgPassSpec
,
Box
*
,
Box
*
,
Box
*
))
runtimeCall
;
Box
*
getattrInternalGeneric
(
Box
*
obj
,
const
std
::
string
&
attr
,
GetattrRewriteArgs
*
rewrite_args
,
bool
cls_only
,
bool
for_call
,
Box
**
bind_obj_out
,
RewriterVar
**
r_bind_obj_out
)
{
if
(
for_call
)
{
...
...
@@ -1635,6 +1645,8 @@ Box* getattrInternal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewr
}
extern
"C"
Box
*
getattr
(
Box
*
obj
,
const
char
*
attr
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_getattr"
);
static
StatCounter
slowpath_getattr
(
"slowpath_getattr"
);
slowpath_getattr
.
log
();
...
...
@@ -1845,10 +1857,14 @@ void setattrGeneric(Box* obj, const std::string& attr, Box* val, SetattrRewriteA
}
extern
"C"
void
setattr
(
Box
*
obj
,
const
char
*
attr
,
Box
*
attr_val
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_setsattr"
);
static
StatCounter
slowpath_setattr
(
"slowpath_setattr"
);
slowpath_setattr
.
log
();
if
(
obj
->
cls
->
tp_setattr
)
{
STAT_TIMER
(
t1
,
"us_timer_tp_setattr"
);
int
rtn
=
obj
->
cls
->
tp_setattr
(
obj
,
const_cast
<
char
*>
(
attr
),
attr_val
);
if
(
rtn
)
throwCAPIException
();
...
...
@@ -1923,6 +1939,7 @@ extern "C" void setattr(Box* obj, const char* attr, Box* attr_val) {
setattr
=
processDescriptor
(
setattr
,
obj
,
obj
->
cls
);
runtimeCallInternal
(
setattr
,
NULL
,
ArgPassSpec
(
2
),
boxstr
,
attr_val
,
NULL
,
NULL
,
NULL
);
}
else
{
STAT_TIMER
(
t0
,
"us_timer_tp_setattro"
);
int
r
=
tp_setattro
(
obj
,
boxstr
,
attr_val
);
if
(
r
)
throwCAPIException
();
...
...
@@ -1935,6 +1952,8 @@ bool isUserDefined(BoxedClass* cls) {
}
extern
"C"
bool
nonzero
(
Box
*
obj
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_nonzero"
);
assert
(
gc
::
isValidGCObject
(
obj
));
static
StatCounter
slowpath_nonzero
(
"slowpath_nonzero"
);
...
...
@@ -2009,7 +2028,7 @@ extern "C" bool nonzero(Box* obj) {
return
true
;
}
Box
*
r
=
runtimeCall
0
(
func
,
ArgPassSpec
(
0
)
);
Box
*
r
=
runtimeCall
Internal
(
func
,
NULL
,
ArgPassSpec
(
0
),
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
// I believe this behavior is handled by the slot wrappers in CPython:
if
(
r
->
cls
==
bool_cls
)
{
BoxedBool
*
b
=
static_cast
<
BoxedBool
*>
(
r
);
...
...
@@ -2025,6 +2044,7 @@ extern "C" bool nonzero(Box* obj) {
}
extern
"C"
BoxedString
*
str
(
Box
*
obj
)
{
STAT_TIMER
(
t0
,
"us_timer_str"
);
static
StatCounter
slowpath_str
(
"slowpath_str"
);
slowpath_str
.
log
();
...
...
@@ -2046,6 +2066,7 @@ extern "C" BoxedString* str(Box* obj) {
}
extern
"C"
Box
*
strOrUnicode
(
Box
*
obj
)
{
STAT_TIMER
(
t0
,
"us_timer_strOrUnicode"
);
// Like str, but returns unicode objects unchanged.
if
(
obj
->
cls
==
unicode_cls
)
{
return
obj
;
...
...
@@ -2054,6 +2075,7 @@ extern "C" Box* strOrUnicode(Box* obj) {
}
extern
"C"
BoxedString
*
repr
(
Box
*
obj
)
{
STAT_TIMER
(
t0
,
"us_timer_repr"
);
static
StatCounter
slowpath_repr
(
"slowpath_repr"
);
slowpath_repr
.
log
();
...
...
@@ -2071,6 +2093,7 @@ extern "C" BoxedString* repr(Box* obj) {
}
extern
"C"
BoxedString
*
reprOrNull
(
Box
*
obj
)
{
STAT_TIMER
(
t0
,
"us_timer_reprOrNull"
);
try
{
Box
*
r
=
repr
(
obj
);
assert
(
r
->
cls
==
str_cls
);
// this should be checked by repr()
...
...
@@ -2081,6 +2104,7 @@ extern "C" BoxedString* reprOrNull(Box* obj) {
}
extern
"C"
BoxedString
*
strOrNull
(
Box
*
obj
)
{
STAT_TIMER
(
t0
,
"us_timer_strOrNull"
);
try
{
BoxedString
*
r
=
str
(
obj
);
return
static_cast
<
BoxedString
*>
(
r
);
...
...
@@ -2090,6 +2114,7 @@ extern "C" BoxedString* strOrNull(Box* obj) {
}
extern
"C"
bool
exceptionMatches
(
Box
*
obj
,
Box
*
cls
)
{
STAT_TIMER
(
t0
,
"us_timer_exceptionMatches"
);
int
rtn
=
PyErr_GivenExceptionMatches
(
obj
,
cls
);
RELEASE_ASSERT
(
rtn
>=
0
,
""
);
return
rtn
;
...
...
@@ -2114,7 +2139,7 @@ extern "C" BoxedInt* hash(Box* obj) {
raiseExcHelper
(
TypeError
,
"unhashable type: '%s'"
,
obj
->
cls
->
tp_name
);
}
Box
*
rtn
=
runtimeCall
0
(
hash
,
ArgPassSpec
(
0
)
);
Box
*
rtn
=
runtimeCall
Internal
(
hash
,
NULL
,
ArgPassSpec
(
0
),
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
if
(
rtn
->
cls
!=
int_cls
)
{
raiseExcHelper
(
TypeError
,
"an integer is required"
);
}
...
...
@@ -2167,6 +2192,8 @@ Box* lenCallInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, Arg
}
extern
"C"
BoxedInt
*
len
(
Box
*
obj
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_len"
);
static
StatCounter
slowpath_len
(
"slowpath_len"
);
slowpath_len
.
log
();
...
...
@@ -2174,6 +2201,8 @@ extern "C" BoxedInt* len(Box* obj) {
}
extern
"C"
i64
unboxedLen
(
Box
*
obj
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_unboxedLen"
);
static
StatCounter
slowpath_unboxedlen
(
"slowpath_unboxedlen"
);
slowpath_unboxedlen
.
log
();
...
...
@@ -2515,6 +2544,8 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
extern
"C"
Box
*
callattr
(
Box
*
obj
,
const
std
::
string
*
attr
,
CallattrFlags
flags
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
,
const
std
::
vector
<
const
std
::
string
*>*
keyword_names
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_callattr"
);
ASSERT
(
gc
::
isValidGCObject
(
obj
),
"%p"
,
obj
);
int
npassed_args
=
argspec
.
totalPassed
();
...
...
@@ -2704,6 +2735,9 @@ static StatCounter slowpath_callfunc_slowpath("slowpath_callfunc_slowpath");
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
)
{
#if STAT_TIMERS
StatTimer
::
assertActive
();
#endif
/*
* Procedure:
* - First match up positional arguments; any extra go to varargs. error if too many.
...
...
@@ -3050,12 +3084,26 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
return
res
;
}
static
Box
*
callChosenCF
(
CompiledFunction
*
chosen_cf
,
BoxedClosure
*
closure
,
BoxedGenerator
*
generator
,
Box
*
oarg1
,
Box
*
oarg2
,
Box
*
oarg3
,
Box
**
oargs
)
{
if
(
closure
&&
generator
)
return
chosen_cf
->
closure_generator_call
(
closure
,
generator
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
else
if
(
closure
)
return
chosen_cf
->
closure_call
(
closure
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
else
if
(
generator
)
return
chosen_cf
->
generator_call
(
generator
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
else
return
chosen_cf
->
call
(
oarg1
,
oarg2
,
oarg3
,
oargs
);
}
Box
*
callCLFunc
(
CLFunction
*
f
,
CallRewriteArgs
*
rewrite_args
,
int
num_output_args
,
BoxedClosure
*
closure
,
BoxedGenerator
*
generator
,
Box
*
globals
,
Box
*
oarg1
,
Box
*
oarg2
,
Box
*
oarg3
,
Box
**
oargs
)
{
CompiledFunction
*
chosen_cf
=
pickVersion
(
f
,
num_output_args
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
assert
(
chosen_cf
->
is_interpreted
==
(
chosen_cf
->
code
==
NULL
));
if
(
chosen_cf
->
is_interpreted
)
{
STAT_TIMER
(
t0
,
"us_timer_astInterpretFunction"
);
return
astInterpretFunction
(
chosen_cf
,
num_output_args
,
closure
,
generator
,
globals
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
}
...
...
@@ -3084,18 +3132,21 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
}
Box
*
r
;
if
(
closure
&&
generator
)
r
=
chosen_cf
->
closure_generator_call
(
closure
,
generator
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
else
if
(
closure
)
r
=
chosen_cf
->
closure_call
(
closure
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
else
if
(
generator
)
r
=
chosen_cf
->
generator_call
(
generator
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
else
r
=
chosen_cf
->
call
(
oarg1
,
oarg2
,
oarg3
,
oargs
);
// we duplicate the call to callChosenCf here so we can
// distinguish lexically between calls that target jitted python
// code and calls that target to builtins.
if
(
f
->
source
)
{
STAT_TIMER
(
t0
,
"us_timer_chosen_cf_body_jitted"
);
r
=
callChosenCF
(
chosen_cf
,
closure
,
generator
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
}
else
{
STAT_TIMER
(
t0
,
"us_timer_chosen_cf_body_builtins"
);
r
=
callChosenCF
(
chosen_cf
,
closure
,
generator
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
}
ASSERT
(
chosen_cf
->
spec
->
rtn_type
->
isFitBy
(
r
->
cls
),
"%s (%p) was supposed to return %s, but gave a %s"
,
g
.
func_addr_registry
.
getFuncNameAtAddress
(
chosen_cf
->
code
,
true
,
NULL
).
c_str
(),
chosen_cf
->
code
,
chosen_cf
->
spec
->
rtn_type
->
debugName
().
c_str
(),
r
->
cls
->
tp_name
);
return
r
;
}
...
...
@@ -3225,9 +3276,9 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar
Box
**
new_args
=
(
Box
**
)
alloca
(
sizeof
(
Box
*
)
*
(
npassed_args
+
1
-
3
));
new_args
[
0
]
=
arg3
;
memcpy
(
new_args
+
1
,
args
,
(
npassed_args
-
3
)
*
sizeof
(
Box
*
));
Box
*
rtn
=
runtimeCall
(
im
->
func
,
ArgPassSpec
(
argspec
.
num_args
+
1
,
argspec
.
num_keywords
,
argspec
.
has_starargs
,
argspec
.
has_kwargs
),
im
->
obj
,
arg1
,
arg2
,
new_args
,
keyword_names
);
Box
*
rtn
=
runtimeCall
Internal
(
im
->
func
,
NULL
,
ArgPassSpec
(
argspec
.
num_args
+
1
,
argspec
.
num_keywords
,
argspec
.
has_starargs
,
argspec
.
has_kwargs
),
im
->
obj
,
arg1
,
arg2
,
new_args
,
keyword_names
);
return
rtn
;
}
}
...
...
@@ -3237,6 +3288,8 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar
extern
"C"
Box
*
runtimeCall
(
Box
*
obj
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
,
const
std
::
vector
<
const
std
::
string
*>*
keyword_names
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_runtimecall"
);
int
npassed_args
=
argspec
.
totalPassed
();
static
StatCounter
slowpath_runtimecall
(
"slowpath_runtimecall"
);
...
...
@@ -3394,6 +3447,8 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin
}
extern
"C"
Box
*
binop
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_binop"
);
static
StatCounter
slowpath_binop
(
"slowpath_binop"
);
slowpath_binop
.
log
();
// static StatCounter nopatch_binop("nopatch_binop");
...
...
@@ -3430,11 +3485,13 @@ extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) {
}
extern
"C"
Box
*
augbinop
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
)
{
static
StatCounter
slowpath_binop
(
"slowpath_binop"
);
slowpath_binop
.
log
();
// static StatCounter nopatch_binop("nopatch_binop");
STAT_TIMER
(
t0
,
"us_timer_slowpath_augbinop"
);
// int id = Stats::getStatId("slowpath_binop_" + *getTypeName(lhs) + op_name + *getTypeName(rhs));
static
StatCounter
slowpath_augbinop
(
"slowpath_augbinop"
);
slowpath_augbinop
.
log
();
// static StatCounter nopatch_binop("nopatch_augbinop");
// int id = Stats::getStatId("slowpath_augbinop_" + *getTypeName(lhs) + op_name + *getTypeName(rhs));
// Stats::log(id);
std
::
unique_ptr
<
Rewriter
>
rewriter
((
Rewriter
*
)
NULL
);
...
...
@@ -3597,6 +3654,8 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
}
extern
"C"
Box
*
compare
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_compare"
);
static
StatCounter
slowpath_compare
(
"slowpath_compare"
);
slowpath_compare
.
log
();
static
StatCounter
nopatch_compare
(
"nopatch_compare"
);
...
...
@@ -3622,6 +3681,8 @@ extern "C" Box* compare(Box* lhs, Box* rhs, int op_type) {
}
extern
"C"
Box
*
unaryop
(
Box
*
operand
,
int
op_type
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_unaryop"
);
static
StatCounter
slowpath_unaryop
(
"slowpath_unaryop"
);
slowpath_unaryop
.
log
();
...
...
@@ -3631,11 +3692,13 @@ extern "C" Box* unaryop(Box* operand, int op_type) {
ASSERT
(
attr_func
,
"%s.%s"
,
getTypeName
(
operand
),
op_name
.
c_str
());
Box
*
rtn
=
runtimeCall
0
(
attr_func
,
ArgPassSpec
(
0
)
);
Box
*
rtn
=
runtimeCall
Internal
(
attr_func
,
NULL
,
ArgPassSpec
(
0
),
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
return
rtn
;
}
extern
"C"
Box
*
getitem
(
Box
*
value
,
Box
*
slice
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_getitem"
);
// This possibly could just be represented as a single callattr; the only tricky part
// are the error messages.
// Ex "(1)[1]" and "(1).__getitem__(1)" give different error messages.
...
...
@@ -3679,6 +3742,8 @@ extern "C" Box* getitem(Box* value, Box* slice) {
// target[slice] = value
extern
"C"
void
setitem
(
Box
*
target
,
Box
*
slice
,
Box
*
value
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_setitem"
);
static
StatCounter
slowpath_setitem
(
"slowpath_setitem"
);
slowpath_setitem
.
log
();
...
...
@@ -3711,6 +3776,8 @@ extern "C" void setitem(Box* target, Box* slice, Box* value) {
// del target[start:end:step]
extern
"C"
void
delitem
(
Box
*
target
,
Box
*
slice
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_delitem"
);
static
StatCounter
slowpath_delitem
(
"slowpath_delitem"
);
slowpath_delitem
.
log
();
...
...
@@ -3793,7 +3860,7 @@ extern "C" void delattrGeneric(Box* obj, const std::string& attr, DelattrRewrite
if
(
delAttr
!=
NULL
)
{
Box
*
boxstr
=
boxString
(
attr
);
Box
*
rtn
=
runtimeCall
2
(
delAttr
,
ArgPassSpec
(
2
),
clsAttr
,
obj
);
Box
*
rtn
=
runtimeCall
Internal
(
delAttr
,
NULL
,
ArgPassSpec
(
2
),
clsAttr
,
obj
,
NULL
,
NULL
,
NULL
);
return
;
}
}
...
...
@@ -3841,7 +3908,7 @@ extern "C" void delattrInternal(Box* obj, const std::string& attr, DelattrRewrit
Box
*
delAttr
=
typeLookup
(
obj
->
cls
,
delattr_str
,
NULL
);
if
(
delAttr
!=
NULL
)
{
Box
*
boxstr
=
boxString
(
attr
);
Box
*
rtn
=
runtimeCall
2
(
delAttr
,
ArgPassSpec
(
2
),
obj
,
boxstr
);
Box
*
rtn
=
runtimeCall
Internal
(
delAttr
,
NULL
,
ArgPassSpec
(
2
),
obj
,
boxstr
,
NULL
,
NULL
,
NULL
);
return
;
}
...
...
@@ -3850,6 +3917,8 @@ extern "C" void delattrInternal(Box* obj, const std::string& attr, DelattrRewrit
// del target.attr
extern
"C"
void
delattr
(
Box
*
obj
,
const
char
*
attr
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_delattr"
);
static
StatCounter
slowpath_delattr
(
"slowpath_delattr"
);
slowpath_delattr
.
log
();
...
...
@@ -3869,6 +3938,8 @@ extern "C" Box* createBoxedIterWrapper(Box* o) {
}
extern
"C"
Box
*
createBoxedIterWrapperIfNeeded
(
Box
*
o
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_createBoxedIterWrapperIfNeeded"
);
std
::
unique_ptr
<
Rewriter
>
rewriter
(
Rewriter
::
createRewriter
(
__builtin_extract_return_addr
(
__builtin_return_address
(
0
)),
1
,
"createBoxedIterWrapperIfNeeded"
));
...
...
@@ -3901,6 +3972,8 @@ extern "C" Box* createBoxedIterWrapperIfNeeded(Box* o) {
}
extern
"C"
Box
*
getPystonIter
(
Box
*
o
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_getPystonIter"
);
Box
*
r
=
getiter
(
o
);
// assert((typeLookup(r->cls, hasnext_str, NULL) == NULL) == (r->cls->tpp_hasnext == object_cls->tpp_hasnext));
if
(
r
->
cls
->
tpp_hasnext
==
object_cls
->
tpp_hasnext
)
...
...
@@ -3938,6 +4011,9 @@ static void assertInitNone(Box* obj) {
}
Box
*
typeNew
(
Box
*
_cls
,
Box
*
arg1
,
Box
*
arg2
,
Box
**
_args
)
{
STAT_TIMER
(
t0
,
"us_timer_typeNew"
);
Box
*
arg3
=
_args
[
0
];
if
(
!
isSubclass
(
_cls
->
cls
,
type_cls
))
...
...
@@ -4391,6 +4467,8 @@ extern "C" void delGlobal(Box* globals, const std::string* name) {
}
extern
"C"
Box
*
getGlobal
(
Box
*
globals
,
const
std
::
string
*
name
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_getglobal"
);
static
StatCounter
slowpath_getglobal
(
"slowpath_getglobal"
);
slowpath_getglobal
.
log
();
static
StatCounter
nopatch_getglobal
(
"nopatch_getglobal"
);
...
...
@@ -4484,7 +4562,43 @@ extern "C" Box* getGlobal(Box* globals, const std::string* name) {
raiseExcHelper
(
NameError
,
"global name '%s' is not defined"
,
name
->
c_str
());
}
Box
*
getFromGlobals
(
Box
*
globals
,
llvm
::
StringRef
name
)
{
if
(
globals
->
cls
==
attrwrapper_cls
)
{
globals
=
unwrapAttrWrapper
(
globals
);
RELEASE_ASSERT
(
globals
->
cls
==
module_cls
,
"%s"
,
globals
->
cls
->
tp_name
);
}
if
(
globals
->
cls
==
module_cls
)
{
return
globals
->
getattr
(
name
);
}
else
if
(
globals
->
cls
==
dict_cls
)
{
auto
d
=
static_cast
<
BoxedDict
*>
(
globals
)
->
d
;
auto
name_str
=
boxString
(
name
.
str
());
auto
it
=
d
.
find
(
name_str
);
if
(
it
!=
d
.
end
())
return
it
->
second
;
return
NULL
;
}
else
{
RELEASE_ASSERT
(
0
,
"%s"
,
globals
->
cls
->
tp_name
);
}
}
void
setGlobal
(
Box
*
globals
,
llvm
::
StringRef
name
,
Box
*
value
)
{
if
(
globals
->
cls
==
attrwrapper_cls
)
{
globals
=
unwrapAttrWrapper
(
globals
);
RELEASE_ASSERT
(
globals
->
cls
==
module_cls
,
"%s"
,
globals
->
cls
->
tp_name
);
}
if
(
globals
->
cls
==
module_cls
)
{
setattr
(
static_cast
<
BoxedModule
*>
(
globals
),
name
.
data
(),
value
);
}
else
{
RELEASE_ASSERT
(
globals
->
cls
==
dict_cls
,
"%s"
,
globals
->
cls
->
tp_name
);
static_cast
<
BoxedDict
*>
(
globals
)
->
d
[
boxString
(
name
)]
=
value
;
}
}
extern
"C"
Box
*
importFrom
(
Box
*
_m
,
const
std
::
string
*
name
)
{
STAT_TIMER
(
t0
,
"us_timer_importFrom"
);
Box
*
r
=
getattrInternal
(
_m
,
*
name
,
NULL
);
if
(
r
)
return
r
;
...
...
@@ -4493,6 +4607,8 @@ extern "C" Box* importFrom(Box* _m, const std::string* name) {
}
extern
"C"
Box
*
importStar
(
Box
*
_from_module
,
BoxedModule
*
to_module
)
{
STAT_TIMER
(
t0
,
"us_timer_importStar"
);
// TODO(kmod): it doesn't seem too bad to update this to take custom globals;
// it looks like mostly a matter of changing the getattr calls to getitem.
RELEASE_ASSERT
(
getGlobals
()
==
to_module
,
"importStar doesn't support custom globals yet"
);
...
...
src/runtime/objmodel.h
View file @
181d5850
...
...
@@ -183,7 +183,13 @@ inline std::tuple<Box*, Box*, Box*, Box**> getTupleFromArgsArray(Box** args, int
// The `globals` argument can be either a BoxedModule or a BoxedDict
// Corresponds to a name lookup with GLOBAL scope. Checks the passed globals object, then the builtins,
// and if not found raises an exception.
extern
"C"
Box
*
getGlobal
(
Box
*
globals
,
const
std
::
string
*
name
);
// Checks for the name just in the passed globals object, and returns NULL if it is not found.
// This includes if the globals object defined a custom __getattr__ method that threw an AttributeError.
Box
*
getFromGlobals
(
Box
*
globals
,
llvm
::
StringRef
name
);
void
setGlobal
(
Box
*
globals
,
llvm
::
StringRef
name
,
Box
*
value
);
extern
"C"
void
delGlobal
(
Box
*
globals
,
const
std
::
string
*
name
);
extern
"C"
void
boxedLocalsSet
(
Box
*
boxedLocals
,
const
char
*
attr
,
Box
*
val
);
...
...
src/runtime/stacktrace.cpp
View file @
181d5850
...
...
@@ -96,6 +96,7 @@ void unwindExc(Box* exc_obj) {
void
raiseRaw
(
const
ExcInfo
&
e
)
__attribute__
((
__noreturn__
));
void
raiseRaw
(
const
ExcInfo
&
e
)
{
STAT_TIMER
(
t0
,
"us_timer_raiseraw"
);
// Should set these to None before getting here:
assert
(
e
.
type
);
assert
(
e
.
value
);
...
...
@@ -197,6 +198,7 @@ extern "C" void abort() {
__builtin_unreachable
();
}
#if 0
extern "C" void exit(int code) {
static void (*libc_exit)(int) = (void (*)(int))dlsym(RTLD_NEXT, "exit");
...
...
@@ -218,6 +220,7 @@ extern "C" void exit(int code) {
libc_exit(code);
__builtin_unreachable();
}
#endif
extern
"C"
void
raise0
()
{
ExcInfo
*
exc_info
=
getFrameExcInfo
();
...
...
src/runtime/str.cpp
View file @
181d5850
...
...
@@ -1112,6 +1112,7 @@ extern "C" Box* strMod(BoxedString* lhs, Box* rhs) {
}
extern
"C"
Box
*
strMul
(
BoxedString
*
lhs
,
Box
*
rhs
)
{
STAT_TIMER
(
t0
,
"us_timer_strMul"
);
assert
(
isSubclass
(
lhs
->
cls
,
str_cls
));
int
n
;
...
...
@@ -1514,6 +1515,7 @@ failed:
}
extern
"C"
size_t
unicodeHashUnboxed
(
PyUnicodeObject
*
self
)
{
STAT_TIMER
(
t0
,
"us_timer_unicodeHashUnboxed"
);
if
(
self
->
hash
!=
-
1
)
return
self
->
hash
;
...
...
@@ -1524,6 +1526,7 @@ extern "C" size_t unicodeHashUnboxed(PyUnicodeObject* self) {
}
extern
"C"
Box
*
strHash
(
BoxedString
*
self
)
{
STAT_TIMER
(
t0
,
"us_timer_strHash"
);
assert
(
isSubclass
(
self
->
cls
,
str_cls
));
StringHash
<
char
>
H
;
...
...
@@ -2302,8 +2305,17 @@ extern "C" PyObject* PyString_FromStringAndSize(const char* s, ssize_t n) noexce
return
boxStrConstantSize
(
s
,
n
);
}
static
/*const*/
char
*
string_getbuffer
(
register
PyObject
*
op
)
noexcept
{
char
*
s
;
Py_ssize_t
len
;
if
(
PyString_AsStringAndSize
(
op
,
&
s
,
&
len
))
return
NULL
;
return
s
;
}
extern
"C"
char
*
PyString_AsString
(
PyObject
*
o
)
noexcept
{
RELEASE_ASSERT
(
isSubclass
(
o
->
cls
,
str_cls
),
""
);
if
(
!
PyString_Check
(
o
))
return
string_getbuffer
(
o
);
BoxedString
*
s
=
static_cast
<
BoxedString
*>
(
o
);
return
getWriteableStringContents
(
s
);
...
...
src/runtime/tuple.cpp
View file @
181d5850
...
...
@@ -168,6 +168,7 @@ Box* tupleAdd(BoxedTuple* self, Box* rhs) {
}
Box
*
tupleMul
(
BoxedTuple
*
self
,
Box
*
rhs
)
{
STAT_TIMER
(
t0
,
"us_timer_tupleMul"
);
if
(
rhs
->
cls
!=
int_cls
)
{
raiseExcHelper
(
TypeError
,
"can't multiply sequence by non-int of type '%s'"
,
getTypeName
(
rhs
));
}
...
...
@@ -337,6 +338,7 @@ Box* tupleIndex(BoxedTuple* self, Box* elt) {
}
Box
*
tupleHash
(
BoxedTuple
*
self
)
{
STAT_TIMER
(
t0
,
"us_timer_tupleHash"
);
assert
(
isSubclass
(
self
->
cls
,
tuple_cls
));
int64_t
rtn
=
3527539
;
...
...
src/runtime/types.cpp
View file @
181d5850
...
...
@@ -978,7 +978,39 @@ Box* sliceRepr(BoxedSlice* self) {
extern
"C"
int
PySlice_GetIndices
(
PySliceObject
*
r
,
Py_ssize_t
length
,
Py_ssize_t
*
start
,
Py_ssize_t
*
stop
,
Py_ssize_t
*
step
)
noexcept
{
Py_FatalError
(
"unimplemented"
);
/* XXX support long ints */
if
(
r
->
step
==
Py_None
)
{
*
step
=
1
;
}
else
{
if
(
!
PyInt_Check
(
r
->
step
)
&&
!
PyLong_Check
(
r
->
step
))
return
-
1
;
*
step
=
PyInt_AsSsize_t
(
r
->
step
);
}
if
(
r
->
start
==
Py_None
)
{
*
start
=
*
step
<
0
?
length
-
1
:
0
;
}
else
{
if
(
!
PyInt_Check
(
r
->
start
)
&&
!
PyLong_Check
(
r
->
step
))
return
-
1
;
*
start
=
PyInt_AsSsize_t
(
r
->
start
);
if
(
*
start
<
0
)
*
start
+=
length
;
}
if
(
r
->
stop
==
Py_None
)
{
*
stop
=
*
step
<
0
?
-
1
:
length
;
}
else
{
if
(
!
PyInt_Check
(
r
->
stop
)
&&
!
PyLong_Check
(
r
->
step
))
return
-
1
;
*
stop
=
PyInt_AsSsize_t
(
r
->
stop
);
if
(
*
stop
<
0
)
*
stop
+=
length
;
}
if
(
*
stop
>
length
)
return
-
1
;
if
(
*
start
>=
length
)
return
-
1
;
if
(
*
step
==
0
)
return
-
1
;
return
0
;
}
extern
"C"
int
PySlice_GetIndicesEx
(
PySliceObject
*
_r
,
Py_ssize_t
length
,
Py_ssize_t
*
start
,
Py_ssize_t
*
stop
,
...
...
@@ -1238,6 +1270,8 @@ public:
}
static
Box
*
setitem
(
Box
*
_self
,
Box
*
_key
,
Box
*
value
)
{
STAT_TIMER
(
t0
,
"us_timer_AttrWrapper_setitem"
);
RELEASE_ASSERT
(
_self
->
cls
==
attrwrapper_cls
,
""
);
AttrWrapper
*
self
=
static_cast
<
AttrWrapper
*>
(
_self
);
...
...
@@ -1250,6 +1284,7 @@ public:
}
static
Box
*
setdefault
(
Box
*
_self
,
Box
*
_key
,
Box
*
value
)
{
STAT_TIMER
(
t0
,
"us_timer_AttrWrapper_setdefault"
);
RELEASE_ASSERT
(
_self
->
cls
==
attrwrapper_cls
,
""
);
AttrWrapper
*
self
=
static_cast
<
AttrWrapper
*>
(
_self
);
...
...
@@ -1265,6 +1300,7 @@ public:
}
static
Box
*
get
(
Box
*
_self
,
Box
*
_key
,
Box
*
def
)
{
STAT_TIMER
(
t0
,
"us_timer_AttrWrapper_get"
);
RELEASE_ASSERT
(
_self
->
cls
==
attrwrapper_cls
,
""
);
AttrWrapper
*
self
=
static_cast
<
AttrWrapper
*>
(
_self
);
...
...
@@ -1279,6 +1315,7 @@ public:
}
static
Box
*
getitem
(
Box
*
_self
,
Box
*
_key
)
{
STAT_TIMER
(
t0
,
"us_timer_AttrWrapper_getitem"
);
RELEASE_ASSERT
(
_self
->
cls
==
attrwrapper_cls
,
""
);
AttrWrapper
*
self
=
static_cast
<
AttrWrapper
*>
(
_self
);
...
...
@@ -1312,6 +1349,7 @@ public:
}
static
Box
*
delitem
(
Box
*
_self
,
Box
*
_key
)
{
STAT_TIMER
(
t0
,
"us_timer_AttrWrapper_delitem"
);
RELEASE_ASSERT
(
_self
->
cls
==
attrwrapper_cls
,
""
);
AttrWrapper
*
self
=
static_cast
<
AttrWrapper
*>
(
_self
);
...
...
@@ -1377,6 +1415,7 @@ public:
}
static
Box
*
values
(
Box
*
_self
)
{
STAT_TIMER
(
t0
,
"us_timer_AttrWrapper_values"
);
RELEASE_ASSERT
(
_self
->
cls
==
attrwrapper_cls
,
""
);
AttrWrapper
*
self
=
static_cast
<
AttrWrapper
*>
(
_self
);
...
...
@@ -1391,6 +1430,7 @@ public:
}
static
Box
*
items
(
Box
*
_self
)
{
STAT_TIMER
(
t0
,
"us_timer_AttrWrapper_items"
);
RELEASE_ASSERT
(
_self
->
cls
==
attrwrapper_cls
,
""
);
AttrWrapper
*
self
=
static_cast
<
AttrWrapper
*>
(
_self
);
...
...
@@ -1429,6 +1469,7 @@ public:
}
static
Box
*
update
(
Box
*
_self
,
Box
*
_container
)
{
STAT_TIMER
(
t0
,
"us_timer_AttrWrapper_update"
);
RELEASE_ASSERT
(
_self
->
cls
==
attrwrapper_cls
,
""
);
AttrWrapper
*
self
=
static_cast
<
AttrWrapper
*>
(
_self
);
...
...
src/runtime/types.h
View file @
181d5850
...
...
@@ -410,12 +410,37 @@ public:
size_t
size
()
{
return
s
.
size
();
}
void
*
operator
new
(
size_t
size
,
size_t
ssize
)
__attribute__
((
visibility
(
"default"
)))
{
#if STAT_ALLOCATIONS
static
StatCounter
alloc_str
(
"alloc.str"
);
static
StatCounter
alloc_str1
(
"alloc.str(1)"
);
static
StatCounter
allocsize_str
(
"allocsize.str"
);
if
(
ssize
==
1
)
alloc_str1
.
log
();
else
alloc_str
.
log
();
allocsize_str
.
log
(
str_cls
->
tp_basicsize
+
ssize
+
1
);
#endif
Box
*
rtn
=
static_cast
<
Box
*>
(
gc_alloc
(
str_cls
->
tp_basicsize
+
ssize
+
1
,
gc
::
GCKind
::
PYTHON
));
rtn
->
cls
=
str_cls
;
return
rtn
;
}
void
*
operator
new
(
size_t
size
,
BoxedClass
*
cls
,
size_t
ssize
)
__attribute__
((
visibility
(
"default"
)))
{
#if STAT_ALLOCATIONS
static
StatCounter
alloc_str
(
"alloc.str"
);
static
StatCounter
alloc_str1
(
"alloc.str(1)"
);
static
StatCounter
allocsize_str
(
"allocsize.str"
);
if
(
ssize
==
1
)
alloc_str1
.
log
();
else
alloc_str
.
log
();
allocsize_str
.
log
(
cls
->
tp_basicsize
+
ssize
+
1
);
#endif
Box
*
rtn
=
static_cast
<
Box
*>
(
cls
->
tp_alloc
(
cls
,
ssize
+
1
));
rtn
->
cls
=
cls
;
return
rtn
;
...
...
@@ -517,12 +542,43 @@ public:
Box
**
elts
;
void
*
operator
new
(
size_t
size
,
size_t
nelts
)
__attribute__
((
visibility
(
"default"
)))
{
#if STAT_ALLOCATIONS
static
StatCounter
alloc_tuple
(
"alloc.tuple"
);
static
StatCounter
alloc_tuple0
(
"alloc.tuple(0)"
);
static
StatCounter
allocsize_tuple
(
"allocsize.tuple"
);
static
StatCounter
allocsize_tuple0
(
"allocsize.tuple(0)"
);
if
(
nelts
==
0
)
{
alloc_tuple0
.
log
();
allocsize_tuple0
.
log
(
_PyObject_VAR_SIZE
(
tuple_cls
,
nelts
+
1
));
}
else
{
alloc_tuple
.
log
();
allocsize_tuple
.
log
(
_PyObject_VAR_SIZE
(
tuple_cls
,
nelts
+
1
));
}
#endif
Box
*
rtn
=
static_cast
<
Box
*>
(
gc_alloc
(
_PyObject_VAR_SIZE
(
tuple_cls
,
nelts
+
1
),
gc
::
GCKind
::
PYTHON
));
rtn
->
cls
=
tuple_cls
;
return
rtn
;
}
void
*
operator
new
(
size_t
size
,
BoxedClass
*
cls
,
size_t
nelts
)
__attribute__
((
visibility
(
"default"
)))
{
#if STAT_ALLOCATIONS
static
StatCounter
alloc_tuple
(
"alloc.tuple"
);
static
StatCounter
alloc_tuple0
(
"alloc.tuple(0)"
);
static
StatCounter
allocsize_tuple
(
"allocsize.tuple"
);
static
StatCounter
allocsize_tuple0
(
"allocsize.tuple(0)"
);
if
(
nelts
==
0
)
{
alloc_tuple0
.
log
();
allocsize_tuple0
.
log
(
_PyObject_VAR_SIZE
(
cls
,
nelts
+
1
));
}
else
{
alloc_tuple
.
log
();
allocsize_tuple
.
log
(
_PyObject_VAR_SIZE
(
cls
,
nelts
+
1
));
}
#endif
Box
*
rtn
=
static_cast
<
Box
*>
(
cls
->
tp_alloc
(
cls
,
nelts
));
rtn
->
cls
=
cls
;
return
rtn
;
...
...
@@ -817,6 +873,11 @@ public:
struct
Context
*
context
,
*
returnContext
;
void
*
stack_begin
;
#if STAT_TIMERS
StatTimer
*
statTimers
;
uint64_t
timer_time
;
#endif
BoxedGenerator
(
BoxedFunctionBase
*
function
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
);
DEFAULT_CLASS
(
generator_cls
);
...
...
test/integration/virtualenv_test.py
View file @
181d5850
...
...
@@ -21,9 +21,10 @@ set -e
set -ux
python -c 'import __future__'
python -c 'import sys; print sys.executable'
pip install bcrypt==1.1.0 python-gflags==2.0
pip install bcrypt==1.1.0 python-gflags==2.0
sqlalchemy==1.0.0
python -c 'import bcrypt; assert bcrypt.__version__ == "1.1.0"; assert bcrypt.hashpw("password1", "$2a$12$0123456789012345678901").endswith("I1hdtg4K"); print "bcrypt seems to work"'
python -c 'import gflags; print "gflags imports"'
python -c 'import sqlalchemy; print "sqlalchemy imports"'
"""
.
strip
()
# print sh_script
...
...
test/tests/builtins.py
View file @
181d5850
...
...
@@ -105,8 +105,8 @@ print callable(lambda: 1)
print
range
(
5L
,
7L
)
print
round
(
-
1.1
),
round
(
-
1.9
)
print
round
(
0.5
),
round
(
-
0.5
)
for
n
in
[
0
,
1
,
2
,
3
,
4
,
5
]:
print
round
(
-
1.1
,
n
),
round
(
-
1.9
,
n
),
round
(
0.5
,
n
),
round
(
-
0.5
,
n
),
round
(
-
0.123456789
,
n
)
print
list
(
iter
(
xrange
(
100
).
__iter__
().
next
,
20
))
...
...
test/tests/import_globals.py
0 → 100644
View file @
181d5850
import
test_package.import_target
import
import_target
print
s
=
"""
import import_target
print import_target.__file__.replace(".pyc", ".py")
"""
def
test
(
g
):
print
"Testing with globals:"
,
"None"
if
g
is
None
else
(
"globals"
if
g
is
globals
()
else
sorted
(
g
.
items
()))
print
__import__
(
"import_target"
,
g
).
__file__
.
replace
(
".pyc"
,
".py"
)
exec
s
in
g
print
"Resulting globals:"
,
"None"
if
g
is
None
else
(
"globals"
if
g
is
globals
()
else
sorted
(
g
.
keys
()))
print
test
(
None
)
test
(
globals
())
test
({
"__package__"
:
"test_package"
})
test
({
"__name__"
:
"test_package.foo"
})
test
({
"__name__"
:
"test_package"
})
test
({
"__name__"
:
"test_package"
,
"__path__"
:
"foo"
})
test/tests/intmethods.py
View file @
181d5850
...
...
@@ -66,6 +66,9 @@ class L(object):
print
type
(
int
(
L
()))
print
int
(
u'123'
)
print
int
(
"9223372036854775808"
,
0
)
print
1
<<
63
,
1
<<
64
,
-
1
<<
63
,
-
1
<<
64
,
2
<<
63
print
type
(
1
<<
63
),
type
(
1
<<
64
),
type
(
-
1
<<
63
),
type
(
-
1
<<
64
),
type
(
2
<<
63
)
for
b
in
range
(
26
):
try
:
...
...
test/tests/list.py
View file @
181d5850
...
...
@@ -124,7 +124,13 @@ for i in xrange(3):
l
[
j
:
k
]
=
[
"added"
]
print
i
,
j
,
k
,
l
def
G
():
yield
"a"
yield
"b"
yield
"c"
l
=
[
0
,
1
,
2
,
3
,
4
,
5
]
l
[
1
:]
=
G
()
print
l
l
=
[
1
,
3
,
5
,
7
,
2
,
4
]
print
l
.
sort
(
key
=
lambda
x
:
x
%
3
)
...
...
test/tests/list_subclassing.py
View file @
181d5850
...
...
@@ -13,5 +13,26 @@ print len(MyList.__new__(MyList))
l
[:]
=
l
[:]
print
l
print
[
1
,
2
,
3
]
==
MyList
((
1
,
2
,
3
))
print
[
1
,
2
,
3
]
!=
MyList
((
1
,
2
,
3
))
print
[
1
,
2
,
3
]
==
MyList
((
1
,
2
,
3
,
4
))
print
[
1
,
2
,
3
]
!=
MyList
((
1
,
2
,
3
,
4
))
print
[
1
,
2
,
3
,
4
]
>
MyList
((
1
,
2
,
3
))
print
[
1
,
2
,
3
,
4
]
<
MyList
((
1
,
2
,
3
))
print
[
1
,
2
,
3
]
>
MyList
((
1
,
2
,
3
,
4
))
print
[
1
,
2
,
3
]
<
MyList
((
1
,
2
,
3
,
4
))
print
[
1
,
2
,
3
]
>=
MyList
((
1
,
2
,
3
))
print
[
1
,
2
,
3
]
<=
MyList
((
1
,
2
,
3
))
print
MyList
((
1
,
2
,
3
))
==
MyList
((
1
,
2
,
3
,
4
))
print
MyList
((
1
,
2
,
3
))
!=
MyList
((
1
,
2
,
3
,
4
))
print
MyList
((
1
,
2
,
3
,
4
))
>
MyList
((
1
,
2
,
3
))
print
MyList
((
1
,
2
,
3
,
4
))
<
MyList
((
1
,
2
,
3
))
print
MyList
((
1
,
2
,
3
))
>
MyList
((
1
,
2
,
3
,
4
))
print
MyList
((
1
,
2
,
3
))
<
MyList
((
1
,
2
,
3
,
4
))
print
MyList
((
1
,
2
,
3
))
>=
MyList
((
1
,
2
,
3
))
print
MyList
((
1
,
2
,
3
))
<=
MyList
((
1
,
2
,
3
))
tools/tester.py
View file @
181d5850
...
...
@@ -157,6 +157,9 @@ def run_test(fn, check_stats, run_memcheck):
code
=
p
.
wait
()
elapsed
=
time
.
time
()
-
start
if
code
>=
128
:
code
-=
256
return
determine_test_result
(
fn
,
opts
,
code
,
out
,
stderr
,
elapsed
)
def
get_test_options
(
fn
,
check_stats
,
run_memcheck
):
...
...
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