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
3a811c26
Commit
3a811c26
authored
Nov 02, 2015
by
Kevin Modzelewski
Committed by
Kevin Modzelewski
Nov 02, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add documentation about some structs/classes
parent
8e2a0949
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
167 additions
and
38 deletions
+167
-38
src/codegen/irgen/hooks.cpp
src/codegen/irgen/hooks.cpp
+2
-2
src/core/stats.h
src/core/stats.h
+31
-0
src/core/threading.h
src/core/threading.h
+1
-0
src/core/types.h
src/core/types.h
+121
-33
src/runtime/types.h
src/runtime/types.h
+12
-3
No files found.
src/codegen/irgen/hooks.cpp
View file @
3a811c26
...
@@ -772,11 +772,11 @@ CompiledFunction::CompiledFunction(llvm::Function* func, FunctionSpecialization*
...
@@ -772,11 +772,11 @@ CompiledFunction::CompiledFunction(llvm::Function* func, FunctionSpecialization*
ExceptionStyle
exception_style
,
const
OSREntryDescriptor
*
entry_descriptor
)
ExceptionStyle
exception_style
,
const
OSREntryDescriptor
*
entry_descriptor
)
:
clfunc
(
NULL
),
:
clfunc
(
NULL
),
func
(
func
),
func
(
func
),
effort
(
effort
),
exception_style
(
exception_style
),
spec
(
spec
),
spec
(
spec
),
entry_descriptor
(
entry_descriptor
),
entry_descriptor
(
entry_descriptor
),
code
(
code
),
code
(
code
),
effort
(
effort
),
exception_style
(
exception_style
),
times_called
(
0
),
times_called
(
0
),
times_speculation_failed
(
0
),
times_speculation_failed
(
0
),
location_map
(
nullptr
)
{
location_map
(
nullptr
)
{
...
...
src/core/stats.h
View file @
3a811c26
...
@@ -26,8 +26,10 @@
...
@@ -26,8 +26,10 @@
namespace
pyston
{
namespace
pyston
{
// Set this to 1 to disable all stats-related operations. Shouldn't usually be necessary.
#define DISABLE_STATS 0
#define DISABLE_STATS 0
// Enable certain expensive stat collections:
#define STAT_ALLOCATIONS (0 && !DISABLE_STATS)
#define STAT_ALLOCATIONS (0 && !DISABLE_STATS)
#define STAT_ALLOCATION_TYPES (0 && !DISABLE_STATS)
#define STAT_ALLOCATION_TYPES (0 && !DISABLE_STATS)
#define STAT_CALLATTR_DESCR_ABORTS (0 && !DISABLE_STATS)
#define STAT_CALLATTR_DESCR_ABORTS (0 && !DISABLE_STATS)
...
@@ -53,6 +55,8 @@ namespace pyston {
...
@@ -53,6 +55,8 @@ namespace pyston {
#define STAT_TIMER_NAME(id) _st##id
#define STAT_TIMER_NAME(id) _st##id
#if !DISABLE_STATS
#if !DISABLE_STATS
// The class that stores and manages stats collection. For normal stats collections purposes,
// you shouldn't have to use this class, and will usually want to use StatCounter instead.
struct
Stats
{
struct
Stats
{
private:
private:
static
std
::
unordered_map
<
uint64_t
*
,
std
::
string
>*
names
;
static
std
::
unordered_map
<
uint64_t
*
,
std
::
string
>*
names
;
...
@@ -75,6 +79,22 @@ public:
...
@@ -75,6 +79,22 @@ public:
static
void
endOfInit
();
static
void
endOfInit
();
};
};
// A helper class for efficient stats collections. Typical usage:
//
// static StatCounter my_stat_counter("my_informative_stat_name");
// void myFunction() {
// my_stat_counter.log();
// }
//
// The current convention for stat names is underscore_case, such as `num_cxa_throw`,
// though at some point we'd like to move to a period-delimited convention.
// (Run `./pyston -s` to see the list of current stats we log.)
// For single stats, usually `num_foo` is a decent name. If there are many stats in a
// single category, you can drop the `num_`.
// If a stat name is a prefix of another, the event it is counting should be a superset.
// For instance, `ic_rewrites` counts a superset of the events that `ic_rewrites_aborted`
// counts, which itself is a superset of the events that `ic_rewrites_aborted_assemblyfail`
// counts.
struct
StatCounter
{
struct
StatCounter
{
private:
private:
uint64_t
*
counter
;
uint64_t
*
counter
;
...
@@ -85,6 +105,11 @@ public:
...
@@ -85,6 +105,11 @@ public:
void
log
(
uint64_t
count
=
1
)
{
*
counter
+=
count
;
}
void
log
(
uint64_t
count
=
1
)
{
*
counter
+=
count
;
}
};
};
// Similar to StatCounter, but should be allocated as:
//
// static thread_local StatPerThreadCounter my_stat_counter("cool_stat_name");
//
// This will automatically add the thread id to the stat name.
struct
StatPerThreadCounter
{
struct
StatPerThreadCounter
{
private:
private:
uint64_t
*
counter
=
0
;
uint64_t
*
counter
=
0
;
...
@@ -117,6 +142,9 @@ struct StatPerThreadCounter {
...
@@ -117,6 +142,9 @@ struct StatPerThreadCounter {
#endif
#endif
#if STAT_TIMERS
#if STAT_TIMERS
// StatTimers are for a specific type of profiling investigation. Until we make this more usable,
// there probably shouldn't be more changes or uses of this class.
class
StatTimer
{
class
StatTimer
{
private:
private:
static
__thread
StatTimer
*
stack
;
static
__thread
StatTimer
*
stack
;
...
@@ -226,6 +254,8 @@ public:
...
@@ -226,6 +254,8 @@ public:
static
void
assertActive
()
{
ASSERT
(
stack
&&
!
stack
->
isPaused
(),
""
);
}
static
void
assertActive
()
{
ASSERT
(
stack
&&
!
stack
->
isPaused
(),
""
);
}
};
};
// Helper class around a StatTimer
class
ScopedStatTimer
{
class
ScopedStatTimer
{
private:
private:
StatTimer
timer
;
StatTimer
timer
;
...
@@ -237,6 +267,7 @@ public:
...
@@ -237,6 +267,7 @@ public:
}
}
~
ScopedStatTimer
()
{
timer
.
popNonTopLevel
();
}
~
ScopedStatTimer
()
{
timer
.
popNonTopLevel
();
}
};
};
#else
#else
struct
StatTimer
{
struct
StatTimer
{
StatTimer
(
uint64_t
*
)
{}
StatTimer
(
uint64_t
*
)
{}
...
...
src/core/threading.h
View file @
3a811c26
...
@@ -138,6 +138,7 @@ void demoteGL();
...
@@ -138,6 +138,7 @@ void demoteGL();
// Helper macro for creating a RAII wrapper around two functions.
#define MAKE_REGION(name, start, end) \
#define MAKE_REGION(name, start, end) \
class name { \
class name { \
public: \
public: \
...
...
src/core/types.h
View file @
3a811c26
...
@@ -41,16 +41,35 @@ namespace pyston {
...
@@ -41,16 +41,35 @@ namespace pyston {
using
gc
::
GCVisitor
;
using
gc
::
GCVisitor
;
// The "effort" which we will put into compiling a Python function. This applies to the LLVM tier,
// where it can affect things such as the amount of type analysis we do, whether or not to run expensive
// LLVM optimization passes, etc.
// Currently (Nov '15) these are mostly unused, and we only use MAXIMAL. There used to be two other levels
// as well but we stopped using them too.
enum
class
EffortLevel
{
enum
class
EffortLevel
{
MODERATE
=
2
,
MODERATE
=
2
,
MAXIMAL
=
3
,
MAXIMAL
=
3
,
};
};
// Pyston supports two ways of implementing Python exceptions: by using return-code-based exceptions ("CAPI"
// style since this is what the CPython C API uses), or our custom C++-based exceptions ("CXX" style). CAPI
// is faster when an exception is thrown, and CXX is faster when an exception is not thrown, so depending on
// the situation it can be beneficial to use one or the other. The JIT will use some light profiling to
// determine when to emit code in one style or the other.
// Many runtime functions support being called in either style, and can get passed one of these enum values
// as a template parameter to switch between them.
enum
ExceptionStyle
{
enum
ExceptionStyle
{
CAPI
,
CAPI
,
CXX
,
CXX
,
};
};
// Much of our runtime supports "rewriting" aka tracing itself. Our tracing JIT requires support from the
// functions to be traced, so our runtime functions will contain checks to see if the tracer is currently
// activated, and then will do additional work.
// When the tracer isn't active, these extra "is the tracer active" checks can become expensive. So when
// the caller knows that the tracer is not active, they can call a special version of the function where
// all of the "is the tracer active" checks are hardcoded to false. This is possible by passing "NOT_REWRITEABLE"
// as a template argument to the called function.
enum
Rewritable
{
enum
Rewritable
{
NOT_REWRITABLE
,
NOT_REWRITABLE
,
REWRITABLE
,
REWRITABLE
,
...
@@ -88,6 +107,8 @@ public:
...
@@ -88,6 +107,8 @@ public:
template
<
ExceptionStyle
S
>
R
call
(
Args
...
args
)
noexcept
(
S
==
CAPI
)
{
return
this
->
template
get
<
S
>()(
args
...);
}
template
<
ExceptionStyle
S
>
R
call
(
Args
...
args
)
noexcept
(
S
==
CAPI
)
{
return
this
->
template
get
<
S
>()(
args
...);
}
};
};
// CompilerType (and a specific kind of CompilerType, the ConcreteCompilerType) are the way that the LLVM JIT represents
// type information. See src/codegen/compvars.h for more information.
class
CompilerType
;
class
CompilerType
;
template
<
class
V
>
class
ValuedCompilerType
;
template
<
class
V
>
class
ValuedCompilerType
;
typedef
ValuedCompilerType
<
llvm
::
Value
*>
ConcreteCompilerType
;
typedef
ValuedCompilerType
<
llvm
::
Value
*>
ConcreteCompilerType
;
...
@@ -98,6 +119,8 @@ extern ConcreteCompilerType* UNBOXED_INT, *BOXED_INT, *LONG, *UNBOXED_FLOAT, *BO
...
@@ -98,6 +119,8 @@ extern ConcreteCompilerType* UNBOXED_INT, *BOXED_INT, *LONG, *UNBOXED_FLOAT, *BO
*
BOXED_COMPLEX
,
*
FRAME_INFO
;
*
BOXED_COMPLEX
,
*
FRAME_INFO
;
extern
CompilerType
*
UNDEF
,
*
INT
,
*
FLOAT
,
*
UNBOXED_SLICE
;
extern
CompilerType
*
UNDEF
,
*
INT
,
*
FLOAT
,
*
UNBOXED_SLICE
;
// CompilerVariables are the way that the LLVM JIT tracks variables, which are a CompilerType combined with some sort
// of value (the type of value depends on the type of CompilerType).
class
CompilerVariable
;
class
CompilerVariable
;
template
<
class
V
>
class
ValuedCompilerVariable
;
template
<
class
V
>
class
ValuedCompilerVariable
;
typedef
ValuedCompilerVariable
<
llvm
::
Value
*>
ConcreteCompilerVariable
;
typedef
ValuedCompilerVariable
<
llvm
::
Value
*>
ConcreteCompilerVariable
;
...
@@ -125,6 +148,10 @@ class ScopingAnalysis;
...
@@ -125,6 +148,10 @@ class ScopingAnalysis;
class
CLFunction
;
class
CLFunction
;
class
OSREntryDescriptor
;
class
OSREntryDescriptor
;
// Pyston's internal calling convention is to pass around arguments in as unprocessed a form as possible,
// which lets the callee decide how they would like to receive their arguments. In addition to the actual
// argument parameters, functions will often receive an ArgPassSpec struct which specifies the meaning of
// the raw pointer values, such as whether they were positional arguments or keyword arguments, etc.
struct
ArgPassSpec
{
struct
ArgPassSpec
{
bool
has_starargs
:
1
;
bool
has_starargs
:
1
;
bool
has_kwargs
:
1
;
bool
has_kwargs
:
1
;
...
@@ -196,7 +223,8 @@ private:
...
@@ -196,7 +223,8 @@ private:
ParamNames
()
:
takes_param_names
(
false
),
vararg_name
(
NULL
),
kwarg_name
(
NULL
)
{}
ParamNames
()
:
takes_param_names
(
false
),
vararg_name
(
NULL
),
kwarg_name
(
NULL
)
{}
};
};
// Probably overkill to copy this from ArgPassSpec
// Similar to ArgPassSpec, this struct is how functions specify what their parameter signature is.
// (Probably overkill to copy this from ArgPassSpec)
struct
ParamReceiveSpec
{
struct
ParamReceiveSpec
{
bool
takes_varargs
:
1
;
bool
takes_varargs
:
1
;
bool
takes_kwargs
:
1
;
bool
takes_kwargs
:
1
;
...
@@ -228,6 +256,14 @@ struct ParamReceiveSpec {
...
@@ -228,6 +256,14 @@ struct ParamReceiveSpec {
int
kwargsIndex
()
{
return
num_args
+
(
takes_varargs
?
1
:
0
);
}
int
kwargsIndex
()
{
return
num_args
+
(
takes_varargs
?
1
:
0
);
}
};
};
// Inline-caches contain fastpath code, and need to know that their fastpath is valid for a particular set
// of arguments. This is usually done with guards: conditional checks that will avoid the fastpath if the
// assumptions failed. This can also be done using invalidation: no checks will be emitted into the generated
// assembly, but instead if the assumption is invalidated, the IC will get erased.
// This is useful for cases where we expect the assumption to overwhelmingly be true, or cases where it
// is not possible to use guards. It is more difficult to use invalidation because it is much easier to
// get it wrong by forgetting to invalidate in all places that are necessary (whereas it is easier to be
// conservative about guarding).
class
ICInvalidator
{
class
ICInvalidator
{
private:
private:
int64_t
cur_version
;
int64_t
cur_version
;
...
@@ -259,17 +295,31 @@ class ICInfo;
...
@@ -259,17 +295,31 @@ class ICInfo;
class
LocationMap
;
class
LocationMap
;
class
JitCodeBlock
;
class
JitCodeBlock
;
// A specific compilation of a CLFunction. Usually these will be created by the LLVM JIT, which will take a CLFunction
// and some compilation settings, and produce a CompiledFunction
// CompiledFunctions can also be created from raw function pointers, using boxRTFunction.
// A single CLFunction can have multiple CompiledFunctions associated with it, if they have different settings.
// Typically, this will happen due to specialization on the argument types (ie we will generate a separate versions
// of a function that are faster but only apply to specific argument types).
struct
CompiledFunction
{
struct
CompiledFunction
{
private:
private:
public:
public:
CLFunction
*
clfunc
;
CLFunction
*
clfunc
;
llvm
::
Function
*
func
;
// the llvm IR object
llvm
::
Function
*
func
;
// the llvm IR object
// Some compilation settings:
EffortLevel
effort
;
ExceptionStyle
exception_style
;
FunctionSpecialization
*
spec
;
FunctionSpecialization
*
spec
;
// If this compilation was due to an OSR, `entry_descriptor` contains metadata about the OSR.
// Otherwise this field is NULL.
const
OSREntryDescriptor
*
entry_descriptor
;
const
OSREntryDescriptor
*
entry_descriptor
;
// Pointers that were written directly into the code, which the GC should be aware of.
// Pointers that were written directly into the code, which the GC should be aware of.
std
::
vector
<
const
void
*>
pointers_in_code
;
std
::
vector
<
const
void
*>
pointers_in_code
;
// The function pointer to the generated code. For convenience, it can be accessed
// as one of many different types.
union
{
union
{
Box
*
(
*
call
)(
Box
*
,
Box
*
,
Box
*
,
Box
**
);
Box
*
(
*
call
)(
Box
*
,
Box
*
,
Box
*
,
Box
**
);
Box
*
(
*
closure_call
)(
BoxedClosure
*
,
Box
*
,
Box
*
,
Box
*
,
Box
**
);
Box
*
(
*
closure_call
)(
BoxedClosure
*
,
Box
*
,
Box
*
,
Box
*
,
Box
**
);
...
@@ -283,14 +333,20 @@ public:
...
@@ -283,14 +333,20 @@ public:
};
};
int
code_size
;
int
code_size
;
EffortLevel
effort
;
// Some simple profiling stats:
ExceptionStyle
exception_style
;
int64_t
times_called
,
times_speculation_failed
;
int64_t
times_called
,
times_speculation_failed
;
// A list of ICs that depend on various properties of this CompiledFunction.
// These will get invalidated in situations such as: we compiled a higher-effort version of
// this function so we want to get old callsites to use the newer and better version, or
// we noticed that we compiled the function with speculations that kept on failing and
// we want to generate a more conservative version.
ICInvalidator
dependent_callsites
;
ICInvalidator
dependent_callsites
;
// Metadata that lets us find local variables from the C stack fram.
LocationMap
*
location_map
;
LocationMap
*
location_map
;
// List of metadata objects for ICs inside this compilation
std
::
vector
<
ICInfo
*>
ics
;
std
::
vector
<
ICInfo
*>
ics
;
CompiledFunction
(
llvm
::
Function
*
func
,
FunctionSpecialization
*
spec
,
void
*
code
,
EffortLevel
effort
,
CompiledFunction
(
llvm
::
Function
*
func
,
FunctionSpecialization
*
spec
,
void
*
code
,
EffortLevel
effort
,
...
@@ -316,9 +372,12 @@ class BoxedModule;
...
@@ -316,9 +372,12 @@ class BoxedModule;
class
ScopeInfo
;
class
ScopeInfo
;
class
InternedStringPool
;
class
InternedStringPool
;
class
LivenessAnalysis
;
class
LivenessAnalysis
;
// Data about a single textual function definition.
class
SourceInfo
{
class
SourceInfo
{
private:
private:
BoxedString
*
fn
;
// equivalent of code.co_filename
BoxedString
*
fn
;
// equivalent of code.co_filename
public:
public:
BoxedModule
*
parent_module
;
BoxedModule
*
parent_module
;
ScopingAnalysis
*
scoping
;
ScopingAnalysis
*
scoping
;
...
@@ -354,16 +413,24 @@ private:
...
@@ -354,16 +413,24 @@ private:
typedef
std
::
vector
<
CompiledFunction
*>
FunctionList
;
typedef
std
::
vector
<
CompiledFunction
*>
FunctionList
;
struct
CallRewriteArgs
;
struct
CallRewriteArgs
;
// A BoxedCode is our implementation of the Python "code" object (such as function.func_code).
// It is implemented as a wrapper around a CLFunction.
class
BoxedCode
;
class
BoxedCode
;
class
CLFunction
{
class
CLFunction
{
private:
// The Python-level "code" object corresponding to this CLFunction. We store it in the CLFunction
// so that multiple attempts to translate from CLFunction->BoxedCode will always return the same
// BoxedCode object.
// Callers should use getCode()
BoxedCode
*
code_obj
;
BoxedCode
*
code_obj
;
public:
public:
int
num_args
;
int
num_args
;
bool
takes_varargs
,
takes_kwargs
;
bool
takes_varargs
,
takes_kwargs
;
//ParamReceiveSpec paramspec;
std
::
unique_ptr
<
SourceInfo
>
source
;
std
::
unique_ptr
<
SourceInfo
>
source
;
// source can be NULL for functions defined in the C/C++ runtime
ParamNames
param_names
;
ParamNames
param_names
;
FunctionList
FunctionList
...
@@ -371,6 +438,7 @@ public:
...
@@ -371,6 +438,7 @@ public:
CompiledFunction
*
always_use_version
;
// if this version is set, always use it (for unboxed cases)
CompiledFunction
*
always_use_version
;
// if this version is set, always use it (for unboxed cases)
std
::
unordered_map
<
const
OSREntryDescriptor
*
,
CompiledFunction
*>
osr_versions
;
std
::
unordered_map
<
const
OSREntryDescriptor
*
,
CompiledFunction
*>
osr_versions
;
// Profiling counter:
int
propagated_cxx_exceptions
=
0
;
int
propagated_cxx_exceptions
=
0
;
// For use by the interpreter/baseline jit:
// For use by the interpreter/baseline jit:
...
@@ -426,6 +494,9 @@ typedef int64_t i64;
...
@@ -426,6 +494,9 @@ typedef int64_t i64;
const
char
*
getNameOfClass
(
BoxedClass
*
cls
);
const
char
*
getNameOfClass
(
BoxedClass
*
cls
);
std
::
string
getFullNameOfClass
(
BoxedClass
*
cls
);
std
::
string
getFullNameOfClass
(
BoxedClass
*
cls
);
std
::
string
getFullTypeName
(
Box
*
o
);
const
char
*
getTypeName
(
Box
*
b
);
class
Rewriter
;
class
Rewriter
;
class
RewriterVar
;
class
RewriterVar
;
...
@@ -491,6 +562,8 @@ inline void internStringMortalInplace(BoxedString*& s) noexcept {
...
@@ -491,6 +562,8 @@ inline void internStringMortalInplace(BoxedString*& s) noexcept {
PyString_InternInPlace
((
PyObject
**
)
&
s
);
PyString_InternInPlace
((
PyObject
**
)
&
s
);
}
}
// The data structure definition for hidden-class-based attributes. Consists of a
// pointer to the hidden class object, and a pointer to a variable-size attributes array.
struct
HCAttrs
{
struct
HCAttrs
{
public:
public:
struct
AttrList
{
struct
AttrList
{
...
@@ -507,12 +580,13 @@ static_assert(sizeof(HCAttrs) == sizeof(struct _hcattrs), "");
...
@@ -507,12 +580,13 @@ static_assert(sizeof(HCAttrs) == sizeof(struct _hcattrs), "");
class
BoxedDict
;
class
BoxedDict
;
class
BoxedString
;
class
BoxedString
;
// In Pyston, this is the same type as CPython's PyObject (they are interchangeable, but we
// "Box" is the base class of any C++ type that implements a Python type. For example,
// use Box in Pyston wherever possible as a convention).
// BoxedString is the data structure that implements Python's str type, and BoxedString
// inherits from Box.
//
//
//
Other types on Pyston inherit from Box (e.g. BoxedString is a Box). Why is this class not
//
This is the same as CPython's PyObject (and they are interchangeable), with the difference
//
polymorphic? Because of C extension support -- having virtual methods would change the layou
t
//
since we are in C++ (whereas CPython is in C) we can use C++ inheritance to implemen
t
//
of the object
.
//
Python inheritance, and avoid the raw pointer casts that CPython needs everywhere
.
class
Box
{
class
Box
{
private:
private:
BoxedDict
**
getDictPtr
();
BoxedDict
**
getDictPtr
();
...
@@ -573,6 +647,12 @@ static_assert(offsetof(Box, cls) == offsetof(struct _object, ob_type), "");
...
@@ -573,6 +647,12 @@ static_assert(offsetof(Box, cls) == offsetof(struct _object, ob_type), "");
// Our default for tp_alloc:
// Our default for tp_alloc:
extern
"C"
PyObject
*
PystonType_GenericAlloc
(
BoxedClass
*
cls
,
Py_ssize_t
nitems
)
noexcept
;
extern
"C"
PyObject
*
PystonType_GenericAlloc
(
BoxedClass
*
cls
,
Py_ssize_t
nitems
)
noexcept
;
// These are some macros for tying the C++ type hiercharchy to the Pyston type hiercharchy.
// Classes that inherit from Box have a special operator new() that takes a class object (as
// a BoxedClass*) since the class is necessary for object allocation.
// To enable expressions such as `new BoxedString()` instead of having to type
// `new (str_cls) BoxedString()` everywhere, we need to tell C++ what the default class is.
// We can do this by putting `DEFAULT_CLASS(str_cls);` anywhere in the definition of BoxedString.
#define DEFAULT_CLASS(default_cls) \
#define DEFAULT_CLASS(default_cls) \
void* operator new(size_t size, BoxedClass * cls) __attribute__((visibility("default"))) { \
void* operator new(size_t size, BoxedClass * cls) __attribute__((visibility("default"))) { \
assert(cls->tp_itemsize == 0); \
assert(cls->tp_itemsize == 0); \
...
@@ -615,6 +695,11 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
...
@@ -615,6 +695,11 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
#endif
#endif
// In the simple cases, we can inline the fast paths of the following methods and improve allocation speed quite a bit:
// - Box::operator new
// - cls->tp_alloc
// - PystonType_GenericAlloc
// - PyObject_Init
// The restrictions on when you can use the SIMPLE (ie fast) variant are encoded as
// The restrictions on when you can use the SIMPLE (ie fast) variant are encoded as
// asserts in the 1-arg operator new function:
// asserts in the 1-arg operator new function:
#define DEFAULT_CLASS_SIMPLE(default_cls) \
#define DEFAULT_CLASS_SIMPLE(default_cls) \
...
@@ -623,12 +708,6 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
...
@@ -623,12 +708,6 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
} \
} \
void* operator new(size_t size) __attribute__((visibility("default"))) { \
void* operator new(size_t size) __attribute__((visibility("default"))) { \
ALLOC_STATS(default_cls); \
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 \
* - PystonType_GenericAlloc \
* - PyObject_Init \
*/
\
assert(default_cls->tp_alloc == PystonType_GenericAlloc); \
assert(default_cls->tp_alloc == PystonType_GenericAlloc); \
assert(default_cls->tp_itemsize == 0); \
assert(default_cls->tp_itemsize == 0); \
assert(default_cls->tp_basicsize == size); \
assert(default_cls->tp_basicsize == size); \
...
@@ -650,6 +729,22 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
...
@@ -650,6 +729,22 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
/* TODO: there should be a way to not have to do this nested inlining by hand */
\
/* TODO: there should be a way to not have to do this nested inlining by hand */
\
}
}
// This corresponds to CPython's PyVarObject, for objects with a variable number of "items" that are stored inline.
// For example, strings and tuples store their data in line in the main object allocation, so are BoxVars. Lists,
// since they have a changeable size, store their elements in a separate array, and their main object is a fixed
// size and so aren't BoxVar.
class
BoxVar
:
public
Box
{
public:
// This field gets initialized in operator new.
Py_ssize_t
ob_size
;
BoxVar
()
{}
void
*
operator
new
(
size_t
size
,
BoxedClass
*
cls
,
size_t
nitems
)
__attribute__
((
visibility
(
"default"
)));
};
static_assert
(
offsetof
(
BoxVar
,
ob_size
)
==
offsetof
(
struct
_varobject
,
ob_size
),
""
);
// This is the variant of DEFAULT_CLASS that applies to BoxVar objects.
#define DEFAULT_CLASS_VAR(default_cls, itemsize) \
#define DEFAULT_CLASS_VAR(default_cls, itemsize) \
static_assert(itemsize > 0, ""); \
static_assert(itemsize > 0, ""); \
/* asserts that the class in question is a subclass of BoxVar */
\
/* asserts that the class in question is a subclass of BoxVar */
\
...
@@ -693,21 +788,6 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
...
@@ -693,21 +788,6 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
return rtn; \
return rtn; \
}
}
// CPython C API compatibility class:
class
BoxVar
:
public
Box
{
public:
// This field gets initialized in operator new.
Py_ssize_t
ob_size
;
BoxVar
()
{}
void
*
operator
new
(
size_t
size
,
BoxedClass
*
cls
,
size_t
nitems
)
__attribute__
((
visibility
(
"default"
)));
};
static_assert
(
offsetof
(
BoxVar
,
ob_size
)
==
offsetof
(
struct
_varobject
,
ob_size
),
""
);
std
::
string
getFullTypeName
(
Box
*
o
);
const
char
*
getTypeName
(
Box
*
b
);
class
BoxedClass
;
class
BoxedClass
;
// TODO these shouldn't be here
// TODO these shouldn't be here
...
@@ -733,6 +813,7 @@ void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringR
...
@@ -733,6 +813,7 @@ void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringR
void
raiseSyntaxErrorHelper
(
llvm
::
StringRef
file
,
llvm
::
StringRef
func
,
AST
*
node_at
,
const
char
*
msg
,
...)
void
raiseSyntaxErrorHelper
(
llvm
::
StringRef
file
,
llvm
::
StringRef
func
,
AST
*
node_at
,
const
char
*
msg
,
...)
__attribute__
((
format
(
printf
,
4
,
5
)));
__attribute__
((
format
(
printf
,
4
,
5
)));
// A data structure used for storing information for tracebacks.
struct
LineInfo
{
struct
LineInfo
{
public:
public:
int
line
,
column
;
int
line
,
column
;
...
@@ -742,6 +823,7 @@ public:
...
@@ -742,6 +823,7 @@ public:
:
line
(
line
),
column
(
column
),
file
(
file
),
func
(
func
)
{}
:
line
(
line
),
column
(
column
),
file
(
file
),
func
(
func
)
{}
};
};
// A data structure to simplify passing around all the data about a thrown exception.
struct
ExcInfo
{
struct
ExcInfo
{
Box
*
type
,
*
value
,
*
traceback
;
Box
*
type
,
*
value
,
*
traceback
;
...
@@ -750,7 +832,10 @@ struct ExcInfo {
...
@@ -750,7 +832,10 @@ struct ExcInfo {
void
printExcAndTraceback
()
const
;
void
printExcAndTraceback
()
const
;
};
};
// Our object that implements Python's "frame" object:
class
BoxedFrame
;
class
BoxedFrame
;
// Our internal data structure for storing certain information about a stack frame.
struct
FrameInfo
{
struct
FrameInfo
{
// Note(kmod): we have a number of fields here that all have independent
// Note(kmod): we have a number of fields here that all have independent
// initialization rules. We could potentially save time on every function-entry
// initialization rules. We could potentially save time on every function-entry
...
@@ -779,6 +864,7 @@ struct FrameInfo {
...
@@ -779,6 +864,7 @@ struct FrameInfo {
void
gcVisit
(
GCVisitor
*
visitor
);
void
gcVisit
(
GCVisitor
*
visitor
);
};
};
// callattr() takes a number of flags and arguments, and for performance we pack them into a single register:
struct
CallattrFlags
{
struct
CallattrFlags
{
bool
cls_only
:
1
;
bool
cls_only
:
1
;
bool
null_on_nonexistent
:
1
;
bool
null_on_nonexistent
:
1
;
...
@@ -788,7 +874,7 @@ struct CallattrFlags {
...
@@ -788,7 +874,7 @@ struct CallattrFlags {
};
};
static_assert
(
sizeof
(
CallattrFlags
)
==
sizeof
(
uint64_t
),
""
);
static_assert
(
sizeof
(
CallattrFlags
)
==
sizeof
(
uint64_t
),
""
);
// A C++-style way of handling a PyArena*
// A C++-style
RAII
way of handling a PyArena*
class
ArenaWrapper
{
class
ArenaWrapper
{
private:
private:
PyArena
*
arena
;
PyArena
*
arena
;
...
@@ -803,6 +889,7 @@ public:
...
@@ -803,6 +889,7 @@ public:
operator
PyArena
*
()
const
{
return
arena
;
}
operator
PyArena
*
()
const
{
return
arena
;
}
};
};
// A C++-style RAII way of handling a FILE*
class
FileHandle
{
class
FileHandle
{
private:
private:
FILE
*
file
;
FILE
*
file
;
...
@@ -841,6 +928,7 @@ int binarySearch(T needle, RandomAccessIterator start, RandomAccessIterator end,
...
@@ -841,6 +928,7 @@ int binarySearch(T needle, RandomAccessIterator start, RandomAccessIterator end,
}
}
}
}
// We need to override these functions so that our GC can know about them.
namespace
std
{
namespace
std
{
template
<
>
std
::
pair
<
pyston
::
Box
**
,
std
::
ptrdiff_t
>
get_temporary_buffer
<
pyston
::
Box
*>
(
std
::
ptrdiff_t
count
)
noexcept
;
template
<
>
std
::
pair
<
pyston
::
Box
**
,
std
::
ptrdiff_t
>
get_temporary_buffer
<
pyston
::
Box
*>
(
std
::
ptrdiff_t
count
)
noexcept
;
template
<
>
void
return_temporary_buffer
<
pyston
::
Box
*>
(
pyston
::
Box
**
p
);
template
<
>
void
return_temporary_buffer
<
pyston
::
Box
*>
(
pyston
::
Box
**
p
);
...
...
src/runtime/types.h
View file @
3a811c26
...
@@ -307,6 +307,10 @@ protected:
...
@@ -307,6 +307,10 @@ protected:
friend
void
setupThread
();
friend
void
setupThread
();
};
};
// Corresponds to PyHeapTypeObject. Very similar to BoxedClass, but allocates some extra space for
// structures that otherwise might get allocated statically. For instance, tp_as_number for builtin
// types will usually point to a `static PyNumberMethods` object, but for a heap-allocated class it
// will point to `this->as_number`.
class
BoxedHeapClass
:
public
BoxedClass
{
class
BoxedHeapClass
:
public
BoxedClass
{
public:
public:
PyNumberMethods
as_number
;
PyNumberMethods
as_number
;
...
@@ -336,6 +340,7 @@ private:
...
@@ -336,6 +340,7 @@ private:
friend
void
setupThread
();
friend
void
setupThread
();
};
};
// Assert that our data structures have the same layout as the C API ones with which they need to be interchangeable.
static_assert
(
sizeof
(
pyston
::
Box
)
==
sizeof
(
struct
_object
),
""
);
static_assert
(
sizeof
(
pyston
::
Box
)
==
sizeof
(
struct
_object
),
""
);
static_assert
(
offsetof
(
pyston
::
Box
,
cls
)
==
offsetof
(
struct
_object
,
ob_type
),
""
);
static_assert
(
offsetof
(
pyston
::
Box
,
cls
)
==
offsetof
(
struct
_object
,
ob_type
),
""
);
...
@@ -675,7 +680,7 @@ public:
...
@@ -675,7 +680,7 @@ public:
// CPython declares ob_item (their version of elts) to have 1 element. We want to
// CPython declares ob_item (their version of elts) to have 1 element. We want to
// copy that behavior so that the sizes of the objects match, but we want to also
// copy that behavior so that the sizes of the objects match, but we want to also
// have a zero-length array in there since we have some extra compiler warnings turned
// have a zero-length array in there since we have some extra compiler warnings turned
// on
.
_elts[1] will throw an error, but elts[1] will not.
// on
:
_elts[1] will throw an error, but elts[1] will not.
union
{
union
{
Box
*
elts
[
0
];
Box
*
elts
[
0
];
Box
*
_elts
[
1
];
Box
*
_elts
[
1
];
...
@@ -687,6 +692,7 @@ static_assert(offsetof(BoxedTuple, elts) == offsetof(PyTupleObject, ob_item), ""
...
@@ -687,6 +692,7 @@ static_assert(offsetof(BoxedTuple, elts) == offsetof(PyTupleObject, ob_item), ""
extern
BoxedString
*
characters
[
UCHAR_MAX
+
1
];
extern
BoxedString
*
characters
[
UCHAR_MAX
+
1
];
// C++ functor objects that implement Python semantics.
struct
PyHasher
{
struct
PyHasher
{
size_t
operator
()(
Box
*
b
)
const
{
size_t
operator
()(
Box
*
b
)
const
{
if
(
b
->
cls
==
str_cls
)
{
if
(
b
->
cls
==
str_cls
)
{
...
@@ -719,8 +725,11 @@ struct PyLt {
...
@@ -719,8 +725,11 @@ struct PyLt {
// llvm::DenseMap doesn't store the original hash values, choosing to instead
// llvm::DenseMap doesn't store the original hash values, choosing to instead
// check for equality more often. This is probably a good tradeoff when the keys
// check for equality more often. This is probably a good tradeoff when the keys
// are pointers and comparison is cheap, but we want to make sure that keys with
// are pointers and comparison is cheap, but when the equality function is user-defined
// different hash values don't get compared.
// it can be much faster to avoid Python function invocations by doing some integer
// comparisons.
// This also has a user-visible behavior difference of how many times the hash function
// and equality functions get called.
struct
BoxAndHash
{
struct
BoxAndHash
{
Box
*
value
;
Box
*
value
;
size_t
hash
;
size_t
hash
;
...
...
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