Productionize new APE loader and more

The APE_NO_MODIFY_SELF loader payload has been moved out of the examples
folder and improved so that it works on BSD systems, and permits general
elf program headers. This brings its quality up enough that it should be
acceptable to use by default for many programs, e.g. Python, Lua, SQLite
and Python. It's the responsibility of the user to define an appropriate
TMPDIR if /tmp is considered an adversarial environment. Mac OS shall be
supported by APE_NO_MODIFY_SELF soon.

Fixes and improvements have been made to program_executable_name as it's
now the one true way to get the absolute path of the executing image.

This change fixes a memory leak in linenoise history loading, introduced
by performance optimizations in 51904e2687
This change fixes a longstanding regression with Mach system calls, that
23ae9dfceb back in February which impacted
our sched_yield() implementation, which is why no one noticed until now.

The Blinkenlights PC emulator has been improved. We now fix rendering on
XNU and BSD by not making the assumption that the kernel terminal driver
understands UTF8 since that seems to break its internal modeling of \r\n
which is now being addressed by using \e[𝑦H instead. The paneling is now
more compact in real mode so you won't need to make your font as tiny if
you're only emulating an 8086 program. The CLMUL ISA is now emulated too

This change also makes improvement to time. CLOCK_MONOTONIC now does the
right thing on Windows NT. The nanosecond time module functions added in
Python 3.7 have been backported.

This change doubles the performance of Argon2 password stretching simply
by not using its copy_block and xor_block helper functions, as they were
trivial to inline thus resulting in us needing to iterate over each 1024
byte block four fewer times.

This change makes code size improvements. _PyUnicode_ToNumeric() was 64k
in size and now it's 10k. The CJK codec lookup tables now use lazy delta
zigzag deflate (δzd) encoding which reduces their size from 600k to 200k
plus the code bloat caused by macro abuse in _decimal.c is now addressed
so our fully-loaded statically-linked hermetically-sealed Python virtual
interpreter container is now 9.4 megs in the default build mode and 5.5m
in MODE=tiny which leaves plenty of room for chibicc.

The pydoc web server now accommodates the use case of people who work by
SSH'ing into a different machine w/ python.com -m pydoc -p8080 -h0.0.0.0

Finally Python Capsulae delenda est and won't be supported in the future
This commit is contained in:
Justine Tunney 2021-10-02 08:17:04 -07:00
parent 9cb54218ab
commit 47a53e143b
270 changed files with 214544 additions and 23331 deletions

View file

@ -303,21 +303,18 @@ PyEval_ReleaseThread(PyThreadState *tstate)
* not running in the child process, and clear internal locks which might be
* held by those threads. (This could also be done using pthread_atfork
* mechanism, at least for the pthreads implementation.) */
void
PyEval_ReInitThreads(void)
{
_Py_IDENTIFIER(_after_fork);
PyObject *threading, *result;
PyThreadState *current_tstate = PyThreadState_GET();
if (!gil_created())
return;
recreate_gil();
pending_lock = PyThread_allocate_lock();
take_gil(current_tstate);
main_thread = PyThread_get_thread_ident();
/* Update the threading module with the new state.
*/
threading = PyMapping_GetItemString(current_tstate->interp->modules,
@ -333,7 +330,6 @@ PyEval_ReInitThreads(void)
else
Py_DECREF(result);
Py_DECREF(threading);
/* Destroy all threads except the current one */
_PyThreadState_DeleteExcept(current_tstate);
}
@ -342,7 +338,6 @@ PyEval_ReInitThreads(void)
/* This function is used to signal that async exceptions are waiting to be
raised, therefore it is also useful in non-threaded builds. */
void
_PyEval_SignalAsyncExc(void)
{
@ -352,7 +347,6 @@ _PyEval_SignalAsyncExc(void)
/* Functions save_thread and restore_thread are always defined so
dynamically loaded modules needn't be compiled separately for use
with and without threads: */
PyThreadState *
PyEval_SaveThread(void)
{
@ -387,7 +381,6 @@ PyEval_RestoreThread(PyThreadState *tstate)
PyThreadState_Swap(tstate);
}
/* Mechanism whereby asynchronously executing callbacks (e.g. UNIX
signal handlers or Mac I/O completion routines) can schedule calls
to a function to be called synchronously.
@ -441,7 +434,6 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
{
int i, j, result=0;
PyThread_type_lock lock = pending_lock;
/* try a few times for the lock. Since this mechanism is used
* for signal handling (on the main thread), there is a (slim)
* chance that a signal is delivered on the same thread while we
@ -461,7 +453,6 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
if (i == 100)
return -1;
}
i = pendinglast;
j = (i + 1) % NPENDINGCALLS;
if (j == pendingfirst) {
@ -484,16 +475,13 @@ Py_MakePendingCalls(void)
static int busy = 0;
int i;
int r = 0;
assert(PyGILState_Check());
if (!pending_lock) {
/* initial allocation of the lock */
pending_lock = PyThread_allocate_lock();
if (pending_lock == NULL)
return -1;
}
/* only service pending calls on main thread */
if (main_thread && PyThread_get_thread_ident() != main_thread)
return 0;
@ -504,19 +492,16 @@ Py_MakePendingCalls(void)
/* unsignal before starting to call callbacks, so that any callback
added in-between re-signals */
UNSIGNAL_PENDING_CALLS();
/* Python signal handler doesn't really queue a callback: it only signals
that a signal was received, see _PyEval_SignalReceived(). */
if (PyErr_CheckSignals() < 0) {
goto error;
}
/* perform a bounded number of calls, in case of recursion */
for (i=0; i<NPENDINGCALLS; i++) {
int j;
int (*func)(void *);
void *arg = NULL;
/* pop one item off the queue while holding the lock */
PyThread_acquire_lock(pending_lock, WAIT_LOCK);
j = pendingfirst;
@ -536,10 +521,8 @@ Py_MakePendingCalls(void)
goto error;
}
}
busy = 0;
return r;
error:
busy = 0;
SIGNAL_PENDING_CALLS(); /* We're not done yet */
@ -611,7 +594,6 @@ Py_MakePendingCalls(void)
if (busy)
return 0;
busy = 1;
/* unsignal before starting to call callbacks, so that any callback
added in-between re-signals */
UNSIGNAL_PENDING_CALLS();
@ -620,7 +602,6 @@ Py_MakePendingCalls(void)
if (PyErr_CheckSignals() < 0) {
goto error;
}
for (;;) {
int i;
int (*func)(void *);
@ -637,7 +618,6 @@ Py_MakePendingCalls(void)
}
busy = 0;
return 0;
error:
busy = 0;
SIGNAL_PENDING_CALLS(); /* We're not done yet */
@ -646,7 +626,6 @@ error:
#endif /* WITH_THREAD */
/* The interpreter's recursion limit */
#ifndef Py_DEFAULT_RECURSION_LIMIT
@ -677,7 +656,6 @@ int
_Py_CheckRecursiveCall(const char *where)
{
PyThreadState *tstate = PyThreadState_GET();
#ifdef USE_STACKCHECK
if (PyOS_CheckStack()) {
--tstate->recursion_depth;
@ -3762,7 +3740,6 @@ format_missing(const char *kind, PyCodeObject *co, PyObject *names)
int err;
Py_ssize_t len = PyList_GET_SIZE(names);
PyObject *name_str, *comma, *tail, *tmp;
assert(PyList_CheckExact(names));
assert(len >= 1);
/* Deal with the joys of natural language. */
@ -3827,7 +3804,6 @@ missing_arguments(PyCodeObject *co, Py_ssize_t missing, Py_ssize_t defcount,
int positional = (defcount != -1);
const char *kind = positional ? "positional" : "keyword-only";
PyObject *missing_names;
/* Compute the names of the arguments that are missing. */
missing_names = PyList_New(missing);
if (missing_names == NULL)
@ -3865,7 +3841,6 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount,
Py_ssize_t i;
PyObject *sig, *kwonly_sig;
Py_ssize_t co_argcount = co->co_argcount;
assert((co->co_flags & CO_VARARGS) == 0);
/* Count missing keyword-only args. */
for (i = co_argcount; i < co_argcount + co->co_kwonlyargcount; i++) {
@ -3915,7 +3890,6 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount,
/* This is gonna seem *real weird*, but if you put some other code between
PyEval_EvalFrame() and _PyEval_EvalFrameDefault() you will need to adjust
the test in the if statements in Misc/gdbinit (pystack and pystackv). */
static PyObject *
_PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
PyObject **args, Py_ssize_t argcount,
@ -3934,13 +3908,11 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
Py_ssize_t i, n;
PyObject *kwdict;
if (globals == NULL) {
PyErr_SetString(PyExc_SystemError,
"PyEval_EvalCodeEx: NULL globals");
return NULL;
}
/* Create the frame */
tstate = PyThreadState_GET();
assert(tstate != NULL);
@ -3950,7 +3922,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
}
fastlocals = f->f_localsplus;
freevars = f->f_localsplus + co->co_nlocals;
/* Create a dictionary for keyword parameters (**kwags) */
if (co->co_flags & CO_VARKEYWORDS) {
kwdict = PyDict_New();
@ -3965,7 +3936,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
else {
kwdict = NULL;
}
/* Copy positional arguments into local variables */
if (argcount > co->co_argcount) {
n = co->co_argcount;
@ -3978,7 +3948,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
Py_INCREF(x);
SETLOCAL(i, x);
}
/* Pack other positional arguments into the *args argument */
if (co->co_flags & CO_VARARGS) {
u = PyTuple_New(argcount - n);
@ -3992,7 +3961,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
PyTuple_SET_ITEM(u, i-n, x);
}
}
/* Handle keyword arguments passed as two strided arrays */
kwcount *= kwstep;
for (i = 0; i < kwcount; i += kwstep) {
@ -4000,14 +3968,12 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
PyObject *keyword = kwnames[i];
PyObject *value = kwargs[i];
Py_ssize_t j;
if (keyword == NULL || !PyUnicode_Check(keyword)) {
PyErr_Format(PyExc_TypeError,
"%U() keywords must be strings",
co->co_name);
goto fail;
}
/* Speed hack: do raw pointer compares. As names are
normally interned this should almost always hit. */
co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item;
@ -4017,7 +3983,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
goto kw_found;
}
}
/* Slow fallback, just in case */
for (j = 0; j < total_args; j++) {
PyObject *name = co_varnames[j];
@ -4029,19 +3994,16 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
goto fail;
}
}
if (j >= total_args && kwdict == NULL) {
PyErr_Format(PyExc_TypeError,
"%U() got an unexpected keyword argument '%S'",
co->co_name, keyword);
goto fail;
}
if (PyDict_SetItem(kwdict, keyword, value) == -1) {
goto fail;
}
continue;
kw_found:
if (GETLOCAL(j) != NULL) {
PyErr_Format(PyExc_TypeError,
@ -4052,13 +4014,11 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
Py_INCREF(value);
SETLOCAL(j, value);
}
/* Check the number of positional arguments */
if (argcount > co->co_argcount && !(co->co_flags & CO_VARARGS)) {
too_many_positional(co, argcount, defcount, fastlocals);
goto fail;
}
/* Add missing positional arguments (copy default values from defs) */
if (argcount < co->co_argcount) {
Py_ssize_t m = co->co_argcount - defcount;
@ -4084,7 +4044,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
}
}
}
/* Add missing keyword arguments (copy default values from kwdefs) */
if (co->co_kwonlyargcount > 0) {
Py_ssize_t missing = 0;
@ -4108,7 +4067,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
goto fail;
}
}
/* Allocate and initialize storage for cell vars, and copy free
vars into frame. */
for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) {
@ -4128,20 +4086,17 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
goto fail;
SETLOCAL(co->co_nlocals + i, c);
}
/* Copy closure variables to free variables */
for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) {
PyObject *o = PyTuple_GET_ITEM(closure, i);
Py_INCREF(o);
freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;
}
/* Handle generator/coroutine/asynchronous generator */
if (co->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) {
PyObject *gen;
PyObject *coro_wrapper = tstate->coroutine_wrapper;
int is_coro = co->co_flags & CO_COROUTINE;
if (is_coro && tstate->in_coroutine_wrapper) {
assert(coro_wrapper != NULL);
PyErr_Format(PyExc_RuntimeError,
@ -4151,13 +4106,10 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
co);
goto fail;
}
/* Don't need to keep the reference to f_back, it will be set
* when the generator is resumed. */
Py_CLEAR(f->f_back);
PCALL(PCALL_GENERATOR);
/* Create a new generator that owns the ready to run frame
* and return that as the value. */
if (is_coro) {
@ -4169,7 +4121,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
}
if (gen == NULL)
return NULL;
if (is_coro && coro_wrapper != NULL) {
PyObject *wrapped;
tstate->in_coroutine_wrapper = 1;
@ -4177,14 +4128,10 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
tstate->in_coroutine_wrapper = 0;
return wrapped;
}
return gen;
}
retval = PyEval_EvalFrameEx(f,0);
fail: /* Jump here from prelude on failure */
/* decref'ing the frame can cause __del__ methods to get invoked,
which can call back into Python. While we're done with the
current Python frame (f), the associated C stack is still in use,
@ -4199,8 +4146,8 @@ fail: /* Jump here from prelude on failure */
PyObject *
PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
PyObject **args, int argcount, PyObject **kws, int kwcount,
PyObject **defs, int defcount, PyObject *kwdefs, PyObject *closure)
PyObject **args, int argcount, PyObject **kws, int kwcount,
PyObject **defs, int defcount, PyObject *kwdefs, PyObject *closure)
{
return _PyEval_EvalCodeWithName(_co, globals, locals,
args, argcount,
@ -4223,9 +4170,7 @@ special_lookup(PyObject *o, _Py_Identifier *id)
return res;
}
/* These 3 functions deal with the exception state of generators. */
static void
save_exc_state(PyThreadState *tstate, PyFrameObject *f)
{
@ -4283,7 +4228,6 @@ static noinline int
do_raise(PyObject *exc, PyObject *cause)
{
PyObject *type = NULL, *value = NULL;
if (exc == NULL) {
/* Reraise */
PyThreadState *tstate = PyThreadState_GET();
@ -4302,12 +4246,10 @@ do_raise(PyObject *exc, PyObject *cause)
PyErr_Restore(type, value, tb);
return 1;
}
/* We support the following forms of raise:
raise
raise <instance>
raise <type> */
if (PyExceptionClass_Check(exc)) {
type = exc;
value = PyObject_CallObject(exc, NULL);
@ -4334,7 +4276,6 @@ do_raise(PyObject *exc, PyObject *cause)
"exceptions must derive from BaseException");
goto raise_error;
}
if (cause) {
PyObject *fixed_cause;
if (PyExceptionClass_Check(cause)) {
@ -4358,13 +4299,11 @@ do_raise(PyObject *exc, PyObject *cause)
}
PyException_SetCause(value, fixed_cause);
}
PyErr_SetObject(type, value);
/* PyErr_SetObject incref's its arguments */
Py_XDECREF(value);
Py_XDECREF(type);
return 0;
raise_error:
Py_XDECREF(value);
Py_XDECREF(type);
@ -4373,12 +4312,11 @@ raise_error:
}
/* Iterate v argcnt times and store the results on the stack (via decreasing
sp). Return 1 for success, 0 if error.
If argcntafter == -1, do a simple unpack. If it is >= 0, do an unpack
with a variable target.
*/
* sp). Return 1 for success, 0 if error.
*
* If argcntafter == -1, do a simple unpack. If it is >= 0, do an unpack
* with a variable target.
*/
static int
unpack_iterable(PyObject *v, int argcnt, int argcntafter, PyObject **sp)
{
@ -4387,13 +4325,10 @@ unpack_iterable(PyObject *v, int argcnt, int argcntafter, PyObject **sp)
PyObject *it; /* iter(v) */
PyObject *w;
PyObject *l = NULL; /* variable list */
assert(v != NULL);
it = PyObject_GetIter(v);
if (it == NULL)
goto Error;
for (; i < argcnt; i++) {
w = PyIter_Next(it);
if (w == NULL) {
@ -4415,7 +4350,6 @@ unpack_iterable(PyObject *v, int argcnt, int argcntafter, PyObject **sp)
}
*--sp = w;
}
if (argcntafter == -1) {
/* We better have exhausted the iterator now. */
w = PyIter_Next(it);
@ -4431,13 +4365,11 @@ unpack_iterable(PyObject *v, int argcnt, int argcntafter, PyObject **sp)
argcnt);
goto Error;
}
l = PySequence_List(it);
if (l == NULL)
goto Error;
*--sp = l;
i++;
ll = PyList_GET_SIZE(l);
if (ll < argcntafter) {
PyErr_Format(PyExc_ValueError,
@ -4445,7 +4377,6 @@ unpack_iterable(PyObject *v, int argcnt, int argcntafter, PyObject **sp)
argcnt + argcntafter, argcnt + ll);
goto Error;
}
/* Pop the "after-variable" args off the list. */
for (j = argcntafter; j > 0; j--, i++) {
*--sp = PyList_GET_ITEM(l, ll - j);
@ -4454,7 +4385,6 @@ unpack_iterable(PyObject *v, int argcnt, int argcntafter, PyObject **sp)
Py_SIZE(l) = ll - argcntafter;
Py_DECREF(it);
return 1;
Error:
for (; i > 0; i--, sp++)
Py_DECREF(*sp);
@ -4566,7 +4496,6 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
{
int result = 0;
int line = frame->f_lineno;
/* If the last instruction executed isn't in the current
instruction window, reset the window.
*/
@ -4628,7 +4557,6 @@ void
_PyEval_SetCoroutineWrapper(PyObject *wrapper)
{
PyThreadState *tstate = PyThreadState_GET();
Py_XINCREF(wrapper);
Py_XSETREF(tstate->coroutine_wrapper, wrapper);
}
@ -4644,7 +4572,6 @@ void
_PyEval_SetAsyncGenFirstiter(PyObject *firstiter)
{
PyThreadState *tstate = PyThreadState_GET();
Py_XINCREF(firstiter);
Py_XSETREF(tstate->async_gen_firstiter, firstiter);
}
@ -4660,7 +4587,6 @@ void
_PyEval_SetAsyncGenFinalizer(PyObject *finalizer)
{
PyThreadState *tstate = PyThreadState_GET();
Py_XINCREF(finalizer);
Py_XSETREF(tstate->async_gen_finalizer, finalizer);
}
@ -4704,10 +4630,8 @@ PyEval_GetLocals(void)
PyErr_SetString(PyExc_SystemError, "frame does not exist");
return NULL;
}
if (PyFrame_FastToLocalsWithError(current_frame) < 0)
return NULL;
assert(current_frame->f_locals != NULL);
return current_frame->f_locals;
}
@ -4718,7 +4642,6 @@ PyEval_GetGlobals(void)
PyFrameObject *current_frame = PyEval_GetFrame();
if (current_frame == NULL)
return NULL;
assert(current_frame->f_globals != NULL);
return current_frame->f_globals;
}
@ -4735,7 +4658,6 @@ PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
{
PyFrameObject *current_frame = PyEval_GetFrame();
int result = cf->cf_flags != 0;
if (current_frame != NULL) {
const int codeflags = current_frame->f_code->co_flags;
const int compilerflags = codeflags & PyCF_MASK;
@ -4756,7 +4678,6 @@ PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
/* External interface to call any callable object.
The arg must be a tuple or NULL. The kw must be a dict or NULL. */
PyObject *
PyEval_CallObjectWithKeywords(PyObject *func, PyObject *args, PyObject *kwargs)
{
@ -4766,19 +4687,16 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *args, PyObject *kwargs)
PyTuple_New() fails, and so the original exception is lost. */
assert(!PyErr_Occurred());
#endif
if (args != NULL && !PyTuple_Check(args)) {
PyErr_SetString(PyExc_TypeError,
"argument list must be a tuple");
return NULL;
}
if (kwargs != NULL && !PyDict_Check(kwargs)) {
PyErr_SetString(PyExc_TypeError,
"keyword list must be a dictionary");
return NULL;
}
if (args == NULL) {
return _PyObject_FastCallDict(func, NULL, 0, kwargs);
}
@ -4853,15 +4771,12 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
Py_ssize_t nargs = oparg - nkwargs;
PyObject **stack;
/* Always dispatch PyCFunction first, because these are
presumed to be the most frequent callable object.
*/
if (PyCFunction_Check(func)) {
PyThreadState *tstate = PyThreadState_GET();
PCALL(PCALL_CFUNCTION);
stack = (*pp_stack) - nargs - nkwargs;
C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
}
@ -4880,21 +4795,16 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
else {
Py_INCREF(func);
}
stack = (*pp_stack) - nargs - nkwargs;
if (PyFunction_Check(func)) {
x = fast_function(func, stack, nargs, kwnames);
}
else {
x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
}
Py_DECREF(func);
}
assert((x != NULL) ^ (PyErr_Occurred() != NULL));
/* Clear the stack of the function object. Also removes
the arguments in case they weren't consumed already
(fast_function() and err_args() leave them on the stack).
@ -4904,7 +4814,6 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
Py_DECREF(w);
PCALL(PCALL_POP);
}
return x;
}
@ -4916,7 +4825,6 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
PyEval_EvalCodeEx(), which vastly reduces the checks that must be
done before evaluating the frame.
*/
static PyObject*
_PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,
PyObject *globals)
@ -4926,7 +4834,6 @@ _PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,
PyObject **fastlocals;
Py_ssize_t i;
PyObject *result;
PCALL(PCALL_FASTER_FUNCTION);
assert(globals != NULL);
/* XXX Perhaps we should create a specialized
@ -4938,19 +4845,15 @@ _PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,
if (f == NULL) {
return NULL;
}
fastlocals = f->f_localsplus;
for (i = 0; i < nargs; i++) {
Py_INCREF(*args);
fastlocals[i] = *args++;
}
result = PyEval_EvalFrameEx(f,0);
++tstate->recursion_depth;
Py_DECREF(f);
--tstate->recursion_depth;
return result;
}
@ -4965,17 +4868,14 @@ fast_function(PyObject *func, PyObject **stack,
PyObject **d;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
Py_ssize_t nd;
assert(PyFunction_Check(func));
assert(nargs >= 0);
assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
/* kwnames must only contains str strings, no subclass, and all keys must
be unique */
PCALL(PCALL_FUNCTION);
PCALL(PCALL_FAST_FUNCTION);
if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
{
@ -4990,12 +4890,10 @@ fast_function(PyObject *func, PyObject **stack,
return _PyFunction_FastCall(co, stack, Py_SIZE(argdefs), globals);
}
}
kwdefs = PyFunction_GET_KW_DEFAULTS(func);
closure = PyFunction_GET_CLOSURE(func);
name = ((PyFunctionObject *)func) -> func_name;
qualname = ((PyFunctionObject *)func) -> func_qualname;
if (argdefs != NULL) {
d = &PyTuple_GET_ITEM(argdefs, 0);
nd = Py_SIZE(argdefs);
@ -5032,15 +4930,12 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
PyObject **d;
Py_ssize_t nd, nk;
PyObject *result;
assert(func != NULL);
assert(nargs >= 0);
assert(nargs == 0 || args != NULL);
assert(kwargs == NULL || PyDict_Check(kwargs));
PCALL(PCALL_FUNCTION);
PCALL(PCALL_FAST_FUNCTION);
if (co->co_kwonlyargcount == 0 &&
(kwargs == NULL || PyDict_Size(kwargs) == 0) &&
co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
@ -5057,16 +4952,13 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
return _PyFunction_FastCall(co, args, Py_SIZE(argdefs), globals);
}
}
if (kwargs != NULL) {
Py_ssize_t pos, i;
nk = PyDict_Size(kwargs);
kwtuple = PyTuple_New(2 * nk);
if (kwtuple == NULL) {
return NULL;
}
k = &PyTuple_GET_ITEM(kwtuple, 0);
pos = i = 0;
while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) {
@ -5081,12 +4973,10 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
k = NULL;
nk = 0;
}
kwdefs = PyFunction_GET_KW_DEFAULTS(func);
closure = PyFunction_GET_CLOSURE(func);
name = ((PyFunctionObject *)func) -> func_name;
qualname = ((PyFunctionObject *)func) -> func_qualname;
if (argdefs != NULL) {
d = &PyTuple_GET_ITEM(argdefs, 0);
nd = Py_SIZE(argdefs);
@ -5095,7 +4985,6 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
d = NULL;
nd = 0;
}
result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
args, nargs,
k, k != NULL ? k + 1 : NULL, nk, 2,
@ -5124,7 +5013,6 @@ do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
else
PCALL(PCALL_OTHER);
#endif
if (PyCFunction_Check(func)) {
PyObject *result;
PyThreadState *tstate = PyThreadState_GET();
@ -5244,13 +5132,11 @@ import_name(PyFrameObject *f, PyObject *name, PyObject *fromlist, PyObject *leve
_Py_IDENTIFIER(__import__);
PyObject *import_func, *res;
PyObject* stack[5];
import_func = _PyDict_GetItemId(f->f_builtins, &PyId___import__);
if (import_func == NULL) {
PyErr_SetString(PyExc_ImportError, "__import__ not found");
return NULL;
}
/* Fast path for not overloaded __import__. */
if (import_func == PyThreadState_GET()->interp->import_func) {
int ilevel = _PyLong_AsInt(level);
@ -5265,9 +5151,7 @@ import_name(PyFrameObject *f, PyObject *name, PyObject *fromlist, PyObject *leve
ilevel);
return res;
}
Py_INCREF(import_func);
stack[0] = name;
stack[1] = f->f_globals;
stack[2] = f->f_locals == NULL ? Py_None : f->f_locals;
@ -5412,14 +5296,11 @@ static void
format_exc_check_arg(PyObject *exc, const char *format_str, PyObject *obj)
{
const char *obj_str;
if (!obj)
return;
obj_str = PyUnicode_AsUTF8(obj);
if (!obj_str)
return;
PyErr_Format(exc, format_str, obj_str);
}
@ -5564,7 +5445,6 @@ _PyEval_RequestCodeExtraIndex(freefunc free)
{
__PyCodeExtraState *state = __PyCodeExtraState_Get();
Py_ssize_t new_index;
if (state->co_extra_user_count == MAX_CO_EXTRA_USERS - 1) {
return -1;
}
@ -5579,11 +5459,9 @@ dtrace_function_entry(PyFrameObject *f)
char* filename;
char* funcname;
int lineno;
filename = PyUnicode_AsUTF8(f->f_code->co_filename);
funcname = PyUnicode_AsUTF8(f->f_code->co_name);
lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno);
}
@ -5593,11 +5471,9 @@ dtrace_function_return(PyFrameObject *f)
char* filename;
char* funcname;
int lineno;
filename = PyUnicode_AsUTF8(f->f_code->co_filename);
funcname = PyUnicode_AsUTF8(f->f_code->co_name);
lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
PyDTrace_FUNCTION_RETURN(filename, funcname, lineno);
}
@ -5608,7 +5484,6 @@ maybe_dtrace_line(PyFrameObject *frame,
{
int line = frame->f_lineno;
char *co_filename, *co_name;
/* If the last instruction executed isn't in the current
instruction window, reset the window.
*/

View file

@ -173,28 +173,6 @@ cosmo_decimate(PyObject *self, PyObject *args)
return buf;
}
PyDoc_STRVAR(ild_doc,
"ild($module, bytes)\n\
--\n\n\
Decodes byte-length of first machine instruction in byte sequence.\n\
\n\
This function makes it possible to tokenize raw x86 binary instructions.\n\
Return value is negative on error, where -1 is defined as buffer being\n\
too short, and lower numbers represent other errors.");
static PyObject *
cosmo_ild(PyObject *self, PyObject *args)
{
Py_ssize_t n;
const char *p;
enum XedError e;
struct XedDecodedInst xedd;
if (!PyArg_ParseTuple(args, "y#:ild", &p, &n)) return 0;
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
e = xed_instruction_length_decode(&xedd, p, n);
return PyLong_FromUnsignedLong(e ? -e : xedd.length);
}
PyDoc_STRVAR(popcount_doc,
"popcount($module, bytes)\n\
--\n\n\
@ -216,45 +194,7 @@ cosmo_popcount(PyObject *self, PyObject *args)
return PyLong_FromSize_t(_countbits(p, n));
}
PyDoc_STRVAR(rgb2xterm256_doc,
"rgb2xterm256($module, r, g, b)\n\
--\n\n\
Quantizes RGB to color to XTERM256 ANSI terminal code.\n\
\n\
This helps you print colors in the terminal faster. For example:\n\
\n\
print(\"\\x1b[38;5;%dmhello\\x1b[0m\" % (cosmo.rgb2xterm256(255,0,0)))\n\
\n\
Will print red text to the terminal.");
static PyObject *
cosmo_rgb2xterm256(PyObject *self, PyObject *args)
{
unsigned char r, g, b;
int res, cerr, gerr, ir, ig, ib, gray, grai, cr, cg, cb, gv;
const unsigned char kXtermCube[6] = {0, 0137, 0207, 0257, 0327, 0377};
if (!PyArg_ParseTuple(args, "BBB:rgb2xterm256", &r, &g, &b)) return 0;
gray = round(r * .299 + g * .587 + b * .114);
grai = gray > 238 ? 23 : (gray - 3) / 10;
ir = r < 48 ? 0 : r < 115 ? 1 : (r - 35) / 40;
ig = g < 48 ? 0 : g < 115 ? 1 : (g - 35) / 40;
ib = b < 48 ? 0 : b < 115 ? 1 : (b - 35) / 40;
cr = kXtermCube[ir];
cg = kXtermCube[ig];
cb = kXtermCube[ib];
gv = 8 + 10 * grai;
cerr = (cr-r)*(cr-r) + (cg-g)*(cg-g) + (cb-b)*(cb-b);
gerr = (gv-r)*(gv-r) + (gv-g)*(gv-g) + (gv-b)*(gv-b);
if (cerr <= gerr) {
res = 16 + 36 * ir + 6 * ig + ib;
} else {
res = 232 + grai;
}
return PyLong_FromUnsignedLong(res);
}
static PyMethodDef cosmo_methods[] = {
{"ild", cosmo_ild, METH_VARARGS, ild_doc},
{"rdtsc", cosmo_rdtsc, METH_NOARGS, rdtsc_doc},
{"crc32c", cosmo_crc32c, METH_VARARGS, crc32c_doc},
{"syscount", cosmo_syscount, METH_NOARGS, syscount_doc},
@ -262,7 +202,6 @@ static PyMethodDef cosmo_methods[] = {
{"decimate", cosmo_decimate, METH_VARARGS, decimate_doc},
{"getcpucore", cosmo_getcpucore, METH_NOARGS, getcpucore_doc},
{"getcpunode", cosmo_getcpunode, METH_NOARGS, getcpunode_doc},
{"rgb2xterm256", cosmo_rgb2xterm256, METH_VARARGS, rgb2xterm256_doc},
#ifdef __PG__
{"ftrace", cosmo_ftrace, METH_NOARGS, ftrace_doc},
#endif

View file

@ -13,6 +13,8 @@
#include "third_party/python/Python/importdl.h"
/* clang-format off */
#define SOABI "cpython36m-x86_64-cosmo"
#if (defined(__OpenBSD__) || defined(__NetBSD__)) && !defined(__ELF__)
#define LEAD_UNDERSCORE "_"
#else

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,7 @@
*/
#include "libc/calls/weirdtypes.h"
#include "libc/math.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/clock.h"
#include "libc/time/time.h"
#include "third_party/python/Include/floatobject.h"
@ -47,6 +48,21 @@ error_time_t_overflow(void)
"timestamp out of range for platform time_t");
}
_PyTime_t
_PyTime_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div)
{
_PyTime_t intpart, remaining;
/* Compute (ticks * mul / div) in two parts to prevent integer overflow:
compute integer part, and then the remaining part.
(ticks * mul) / div == (ticks / div) * mul + (ticks % div) * mul / div
The caller must ensure that "(div - 1) * mul" cannot overflow. */
intpart = ticks / div;
ticks %= div;
remaining = ticks * mul;
remaining /= div;
return intpart * mul + remaining;
}
time_t
_PyLong_AsTime_t(PyObject *obj)
{
@ -94,7 +110,6 @@ _PyTime_Round(double x, _PyTime_round_t round)
{
/* volatile avoids optimization changing how numbers are rounded */
volatile double d;
d = x;
if (round == _PyTime_ROUND_HALF_EVEN){
d = _PyTime_RoundHalfEven(d);
@ -119,9 +134,7 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
double intpart;
/* volatile avoids optimization changing how numbers are rounded */
volatile double floatpart;
floatpart = modf(d, &intpart);
floatpart *= denominator;
floatpart = _PyTime_Round(floatpart, round);
if (floatpart >= denominator) {
@ -133,14 +146,12 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
intpart -= 1.0;
}
assert(0.0 <= floatpart && floatpart < denominator);
if (!_Py_InIntegralTypeRange(time_t, intpart)) {
error_time_t_overflow();
return -1;
}
*sec = (time_t)intpart;
*numerator = (long)floatpart;
return 0;
}
@ -149,7 +160,6 @@ _PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator,
double denominator, _PyTime_round_t round)
{
assert(denominator <= (double)LONG_MAX);
if (PyFloat_Check(obj)) {
double d = PyFloat_AsDouble(obj);
if (Py_IS_NAN(d)) {
@ -257,51 +267,51 @@ _PyTime_FromNanoseconds(long long ns)
return t;
}
#ifdef HAVE_CLOCK_GETTIME
static int
_PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts, int raise)
pytime_fromtimespec(_PyTime_t *tp, struct timespec *ts, int raise)
{
_PyTime_t t;
int res = 0;
_PyTime_t t;
Py_BUILD_ASSERT(sizeof(ts->tv_sec) <= sizeof(_PyTime_t));
t = (_PyTime_t)ts->tv_sec;
if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) {
if (__builtin_mul_overflow(t, SEC_TO_NS, &t)) {
if (raise)
_PyTime_overflow();
res = -1;
}
t = t * SEC_TO_NS;
t += ts->tv_nsec;
*tp = t;
return res;
}
#elif !defined(MS_WINDOWS)
static int
_PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv, int raise)
int
_PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts)
{
return pytime_fromtimespec(tp, ts, 1);
}
int
pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise)
{
_PyTime_t t;
int res = 0;
Py_BUILD_ASSERT(sizeof(tv->tv_sec) <= sizeof(_PyTime_t));
t = (_PyTime_t)tv->tv_sec;
if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) {
if (__builtin_mul_overflow(t, SEC_TO_NS, &t)) {
if (raise)
_PyTime_overflow();
res = -1;
}
t = t * SEC_TO_NS;
t += (_PyTime_t)tv->tv_usec * US_TO_NS;
*tp = t;
return res;
}
#endif
int
_PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv)
{
return pytime_fromtimeval(tp, tv, 1);
}
static int
_PyTime_FromFloatObject(_PyTime_t *t, double value, _PyTime_round_t round,
@ -309,12 +319,10 @@ _PyTime_FromFloatObject(_PyTime_t *t, double value, _PyTime_round_t round,
{
/* volatile avoids optimization changing how numbers are rounded */
volatile double d;
/* convert to a number of nanoseconds */
d = value;
d *= (double)unit_to_ns;
d = _PyTime_Round(d, round);
if (!_Py_InIntegralTypeRange(_PyTime_t, d)) {
_PyTime_overflow();
return -1;
@ -339,14 +347,12 @@ _PyTime_FromObject(_PyTime_t *t, PyObject *obj, _PyTime_round_t round,
else {
long long sec;
Py_BUILD_ASSERT(sizeof(long long) <= sizeof(_PyTime_t));
sec = PyLong_AsLongLong(obj);
if (sec == -1 && PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_OverflowError))
_PyTime_overflow();
return -1;
}
if (_PyTime_check_mul_overflow(sec, unit_to_ns)) {
_PyTime_overflow();
return -1;
@ -459,10 +465,8 @@ _PyTime_AsTimeval_impl(_PyTime_t t, _PyTime_t *p_secs, int *p_us,
_PyTime_t secs, ns;
int usec;
int res = 0;
secs = t / SEC_TO_NS;
ns = t % SEC_TO_NS;
usec = (int)_PyTime_Divide(ns, US_TO_NS, round);
if (usec < 0) {
usec += SEC_TO_US;
@ -479,10 +483,8 @@ _PyTime_AsTimeval_impl(_PyTime_t t, _PyTime_t *p_secs, int *p_us,
res = -1;
}
assert(0 <= usec && usec < SEC_TO_US);
*p_secs = secs;
*p_us = usec;
return res;
}
@ -493,16 +495,13 @@ _PyTime_AsTimevalStruct_impl(_PyTime_t t, struct timeval *tv,
_PyTime_t secs, secs2;
int us;
int res;
res = _PyTime_AsTimeval_impl(t, &secs, &us, round);
#ifdef MS_WINDOWS
tv->tv_sec = (long)secs;
#else
tv->tv_sec = secs;
#endif
tv->tv_usec = us;
secs2 = (_PyTime_t)tv->tv_sec;
if (res < 0 || secs2 != secs) {
if (raise)
@ -530,11 +529,8 @@ _PyTime_AsTimevalTime_t(_PyTime_t t, time_t *p_secs, int *us,
{
_PyTime_t secs;
int res;
res = _PyTime_AsTimeval_impl(t, &secs, us, round);
*p_secs = secs;
if (res < 0 || (_PyTime_t)*p_secs != secs) {
error_time_t_overflow();
return -1;
@ -542,13 +538,90 @@ _PyTime_AsTimevalTime_t(_PyTime_t t, time_t *p_secs, int *us,
return 0;
}
static int
win_perf_counter_frequency(int64_t *pfrequency, int raise)
{
int64_t frequency;
if (!QueryPerformanceFrequency(&frequency)) {
if (raise) {
PyErr_SetFromWindowsErr(0);
}
return -1;
}
/* Sanity check: should never occur in practice */
if (frequency < 1) {
if (raise) {
PyErr_SetString(PyExc_RuntimeError,
"invalid QueryPerformanceFrequency");
}
return -1;
}
/* Check that frequency can be casted to _PyTime_t.
*
* Make also sure that (ticks * SEC_TO_NS) cannot overflow in
* _PyTime_MulDiv(), with ticks < frequency.
*
* Known QueryPerformanceFrequency() values:
*
* - 10,000,000 (10 MHz): 100 ns resolution
* - 3,579,545 Hz (3.6 MHz): 279 ns resolution
*
* None of these frequencies can overflow with 64-bit _PyTime_t, but
* check for overflow, just in case.
*/
if (frequency > _PyTime_MAX
|| frequency > (int64_t)_PyTime_MAX / (int64_t)SEC_TO_NS)
{
if (raise) {
PyErr_SetString(PyExc_OverflowError,
"QueryPerformanceFrequency is too large");
}
return -1;
}
*pfrequency = frequency;
return 0;
}
static int
py_get_win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
{
static int64_t frequency;
if (!frequency) {
if (win_perf_counter_frequency(&frequency, raise) < 0) {
return -1;
}
}
if (info) {
info->implementation = "QueryPerformanceCounter()";
info->resolution = 1 / (double)frequency;
info->monotonic = 1;
info->adjustable = 0;
}
int64_t ticksll;
QueryPerformanceCounter(&ticksll);
/* Make sure that casting int64_t to _PyTime_t cannot overflow,
both types are signed */
_PyTime_t ticks;
Py_BUILD_ASSERT(sizeof(ticksll) <= sizeof(ticks));
ticks = (_PyTime_t)ticksll;
*tp = _PyTime_MulDiv(ticks, SEC_TO_NS, (_PyTime_t)frequency);
return 0;
}
int
_PyTime_GetPerfCounterWithInfo(_PyTime_t *t, _Py_clock_info_t *info)
{
if (!IsWindows()) {
return _PyTime_GetMonotonicClockWithInfo(t, info);
} else {
return py_get_win_perf_counter(t, info, 1);
}
}
#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE)
int
_PyTime_AsTimespec(_PyTime_t t, struct timespec *ts)
{
_PyTime_t secs, nsec;
secs = t / SEC_TO_NS;
nsec = t % SEC_TO_NS;
if (nsec < 0) {
@ -558,101 +631,64 @@ _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts)
ts->tv_sec = (time_t)secs;
assert(0 <= nsec && nsec < SEC_TO_NS);
ts->tv_nsec = nsec;
if ((_PyTime_t)ts->tv_sec != secs) {
error_time_t_overflow();
return -1;
}
return 0;
}
#endif
static int
pygettimeofday(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
{
#ifdef MS_WINDOWS
FILETIME system_time;
ULARGE_INTEGER large;
assert(info == NULL || raise);
GetSystemTimeAsFileTime(&system_time);
large.u.LowPart = system_time.dwLowDateTime;
large.u.HighPart = system_time.dwHighDateTime;
/* 11,644,473,600,000,000,000: number of nanoseconds between
the 1st january 1601 and the 1st january 1970 (369 years + 89 leap
days). */
*tp = large.QuadPart * 100 - 11644473600000000000;
if (info) {
DWORD timeAdjustment, timeIncrement;
BOOL isTimeAdjustmentDisabled, ok;
info->implementation = "GetSystemTimeAsFileTime()";
info->monotonic = 0;
ok = GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement,
&isTimeAdjustmentDisabled);
if (!ok) {
PyErr_SetFromWindowsErr(0);
if (IsWindows()) {
uint64_t large;
struct NtFileTime system_time;
assert(info == NULL || raise);
GetSystemTimeAsFileTime(&system_time);
large = system_time.dwHighDateTime;
large <<= 32;
large |= system_time.dwLowDateTime;
/* 11,644,473,600,000,000,000: number of nanoseconds between
the 1st january 1601 and the 1st january 1970 (369 years + 89 leap
days). */
*tp = large * 100 - 11644473600000000000ull;
if (info) {
bool32 isTimeAdjustmentDisabled;
uint32_t timeAdjustment, timeIncrement;
info->implementation = "GetSystemTimeAsFileTime()";
info->monotonic = 0;
if (!GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement,
&isTimeAdjustmentDisabled)) {
PyErr_SetFromWindowsErr(0);
return -1;
}
info->resolution = timeIncrement * 1e-7;
info->adjustable = 1;
}
} else {
int err;
struct timespec ts;
assert(info == NULL || raise);
err = clock_gettime(CLOCK_REALTIME, &ts);
if (err) {
if (raise)
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
info->resolution = timeIncrement * 1e-7;
info->adjustable = 1;
if (pytime_fromtimespec(tp, &ts, raise) < 0)
return -1;
if (info) {
struct timespec res;
info->implementation = "clock_gettime(CLOCK_REALTIME)";
info->monotonic = 0;
info->adjustable = 1;
if (clock_getres(CLOCK_REALTIME, &res) == 0)
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
else
info->resolution = 1e-9;
}
}
#else /* MS_WINDOWS */
int err;
#ifdef HAVE_CLOCK_GETTIME
struct timespec ts;
#else
struct timeval tv;
#endif
assert(info == NULL || raise);
#ifdef HAVE_CLOCK_GETTIME
err = clock_gettime(CLOCK_REALTIME, &ts);
if (err) {
if (raise)
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
if (_PyTime_FromTimespec(tp, &ts, raise) < 0)
return -1;
if (info) {
struct timespec res;
info->implementation = "clock_gettime(CLOCK_REALTIME)";
info->monotonic = 0;
info->adjustable = 1;
if (clock_getres(CLOCK_REALTIME, &res) == 0)
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
else
info->resolution = 1e-9;
}
#else /* HAVE_CLOCK_GETTIME */
/* test gettimeofday() */
#ifdef GETTIMEOFDAY_NO_TZ
err = gettimeofday(&tv);
#else
err = gettimeofday(&tv, (struct timezone *)NULL);
#endif
if (err) {
if (raise)
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
if (_PyTime_FromTimeval(tp, &tv, raise) < 0)
return -1;
if (info) {
info->implementation = "gettimeofday()";
info->resolution = 1e-6;
info->monotonic = 0;
info->adjustable = 1;
}
#endif /* !HAVE_CLOCK_GETTIME */
#endif /* !MS_WINDOWS */
return 0;
}
@ -663,7 +699,6 @@ _PyTime_GetSystemClock(void)
if (pygettimeofday(&t, NULL, 0) < 0) {
/* should not happen, _PyTime_Init() checked the clock at startup */
assert(0);
/* use a fixed value instead of a random value from the stack */
t = 0;
}
@ -679,66 +714,57 @@ _PyTime_GetSystemClockWithInfo(_PyTime_t *t, _Py_clock_info_t *info)
static int
pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
{
#if defined(MS_WINDOWS)
ULONGLONG ticks;
_PyTime_t t;
assert(info == NULL || raise);
ticks = GetTickCount64();
Py_BUILD_ASSERT(sizeof(ticks) <= sizeof(_PyTime_t));
t = (_PyTime_t)ticks;
if (_PyTime_check_mul_overflow(t, MS_TO_NS)) {
if (raise) {
_PyTime_overflow();
return -1;
if (IsWindows()) {
uint64_t ticks;
_PyTime_t t;
assert(info == NULL || raise);
ticks = GetTickCount64();
Py_BUILD_ASSERT(sizeof(ticks) <= sizeof(_PyTime_t));
t = (_PyTime_t)ticks;
if (__builtin_mul_overflow(t, MS_TO_NS, &t)) {
if (raise) {
_PyTime_overflow();
return -1;
}
/* Hello, time traveler! */
assert(0);
}
/* Hello, time traveler! */
assert(0);
}
*tp = t * MS_TO_NS;
if (info) {
DWORD timeAdjustment, timeIncrement;
BOOL isTimeAdjustmentDisabled, ok;
info->implementation = "GetTickCount64()";
info->monotonic = 1;
ok = GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement,
&isTimeAdjustmentDisabled);
if (!ok) {
PyErr_SetFromWindowsErr(0);
return -1;
*tp = t * MS_TO_NS;
if (info) {
uint32_t timeAdjustment, timeIncrement;
bool32 isTimeAdjustmentDisabled, ok;
info->implementation = "GetTickCount64()";
info->monotonic = 1;
ok = GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement,
&isTimeAdjustmentDisabled);
if (!ok) {
PyErr_SetFromWindowsErr(0);
return -1;
}
info->resolution = timeIncrement * 1e-7;
info->adjustable = 0;
}
info->resolution = timeIncrement * 1e-7;
info->adjustable = 0;
return 0;
}
#elif defined(__APPLE__)
#ifdef __APPLE__
static mach_timebase_info_data_t timebase;
uint64_t time;
if (timebase.denom == 0) {
/* According to the Technical Q&A QA1398, mach_timebase_info() cannot
fail: https://developer.apple.com/library/mac/#qa/qa1398/ */
(void)mach_timebase_info(&timebase);
}
time = mach_absolute_time();
/* apply timebase factor */
time *= timebase.numer;
time /= timebase.denom;
*tp = time;
if (info) {
info->implementation = "mach_absolute_time()";
info->resolution = (double)timebase.numer / timebase.denom * 1e-9;
info->monotonic = 1;
info->adjustable = 0;
}
#else
struct timespec ts;
#ifdef CLOCK_HIGHRES
@ -748,9 +774,7 @@ pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
const clockid_t clk_id = CLOCK_MONOTONIC;
const char *implementation = "clock_gettime(CLOCK_MONOTONIC)";
#endif
assert(info == NULL || raise);
if (clock_gettime(clk_id, &ts) != 0) {
if (raise) {
PyErr_SetFromErrno(PyExc_OSError);
@ -758,7 +782,6 @@ pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
}
return -1;
}
if (info) {
struct timespec res;
info->monotonic = 1;
@ -770,7 +793,7 @@ pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
}
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
}
if (_PyTime_FromTimespec(tp, &ts, raise) < 0)
if (pytime_fromtimespec(tp, &ts, raise) < 0)
return -1;
#endif
return 0;
@ -784,7 +807,6 @@ _PyTime_GetMonotonicClock(void)
/* should not happen, _PyTime_Init() checked that monotonic clock at
startup */
assert(0);
/* use a fixed value instead of a random value from the stack */
t = 0;
}
@ -801,15 +823,12 @@ int
_PyTime_Init(void)
{
_PyTime_t t;
/* ensure that the system clock works */
if (_PyTime_GetSystemClockWithInfo(&t, NULL) < 0)
return -1;
/* ensure that the operating system provides a monotonic clock */
if (_PyTime_GetMonotonicClockWithInfo(&t, NULL) < 0)
return -1;
return 0;
}

80
third_party/python/Python/xedmodule.c vendored Normal file
View file

@ -0,0 +1,80 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#define PY_SSIZE_T_CLEAN
#include "third_party/python/Include/import.h"
#include "third_party/python/Include/longobject.h"
#include "third_party/python/Include/modsupport.h"
#include "third_party/python/Include/moduleobject.h"
#include "third_party/python/Include/object.h"
#include "third_party/python/Include/pymacro.h"
#include "third_party/python/Include/yoink.h"
#include "third_party/xed/x86.h"
/* clang-format off */
PYTHON_PROVIDE("xed");
PyDoc_STRVAR(xed_doc, "Xed Module\n\
\n\
This module exposes low-level utilities for x86 encoding.");
PyDoc_STRVAR(ild_doc,
"ild($module, bytes)\n\
--\n\n\
Decodes byte-length of first machine instruction in byte sequence.\n\
\n\
This function makes it possible to tokenize raw x86 binary instructions.\n\
Return value is negative on error, where -1 is defined as buffer being\n\
too short, and lower numbers represent other errors.");
static PyObject *
xed_ild(PyObject *self, PyObject *args)
{
Py_ssize_t n;
const char *p;
enum XedError e;
struct XedDecodedInst xedd;
if (!PyArg_ParseTuple(args, "y#:ild", &p, &n)) return 0;
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
e = xed_instruction_length_decode(&xedd, p, n);
return PyLong_FromUnsignedLong(e ? -e : xedd.length);
}
static PyMethodDef xed_methods[] = {
{"ild", xed_ild, METH_VARARGS, ild_doc},
{0},
};
static struct PyModuleDef xedmodule = {
PyModuleDef_HEAD_INIT,
"xed",
xed_doc,
-1,
xed_methods,
};
PyMODINIT_FUNC
PyInit_xed(void)
{
return PyModule_Create(&xedmodule);
}
_Section(".rodata.pytab.1") const struct _inittab _PyImport_Inittab_xed = {
"xed",
PyInit_xed,
};

94
third_party/python/Python/xtermmodule.c vendored Normal file
View file

@ -0,0 +1,94 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#define PY_SSIZE_T_CLEAN
#include "third_party/python/Include/import.h"
#include "third_party/python/Include/longobject.h"
#include "third_party/python/Include/modsupport.h"
#include "third_party/python/Include/moduleobject.h"
#include "third_party/python/Include/object.h"
#include "third_party/python/Include/pymacro.h"
#include "third_party/python/Include/yoink.h"
/* clang-format off */
PYTHON_PROVIDE("xterm");
PyDoc_STRVAR(xterm_doc, "Xterm Module\n\
\n\
This module exposes low-level utilities for xterm ansi encoding.");
PyDoc_STRVAR(rgb2xterm256_doc,
"rgb2xterm256($module, r, g, b)\n\
--\n\n\
Quantizes RGB to color to XTERM256 ANSI terminal code.\n\
\n\
This helps you print colors in the terminal faster. For example:\n\
\n\
print(\"\\x1b[38;5;%dmhello\\x1b[0m\" % (xterm.rgb2xterm256(255,0,0)))\n\
\n\
Will print red text to the terminal.");
static PyObject *
xterm_rgb2xterm256(PyObject *self, PyObject *args)
{
unsigned char r, g, b;
int res, cerr, gerr, ir, ig, ib, gray, grai, cr, cg, cb, gv;
const unsigned char kXtermCube[6] = {0, 0137, 0207, 0257, 0327, 0377};
if (!PyArg_ParseTuple(args, "BBB:rgb2xterm256", &r, &g, &b)) return 0;
gray = round(r * .299 + g * .587 + b * .114);
grai = gray > 238 ? 23 : (gray - 3) / 10;
ir = r < 48 ? 0 : r < 115 ? 1 : (r - 35) / 40;
ig = g < 48 ? 0 : g < 115 ? 1 : (g - 35) / 40;
ib = b < 48 ? 0 : b < 115 ? 1 : (b - 35) / 40;
cr = kXtermCube[ir];
cg = kXtermCube[ig];
cb = kXtermCube[ib];
gv = 8 + 10 * grai;
cerr = (cr-r)*(cr-r) + (cg-g)*(cg-g) + (cb-b)*(cb-b);
gerr = (gv-r)*(gv-r) + (gv-g)*(gv-g) + (gv-b)*(gv-b);
if (cerr <= gerr) {
res = 16 + 36 * ir + 6 * ig + ib;
} else {
res = 232 + grai;
}
return PyLong_FromUnsignedLong(res);
}
static PyMethodDef xterm_methods[] = {
{"rgb2xterm256", xterm_rgb2xterm256, METH_VARARGS, rgb2xterm256_doc},
{0},
};
static struct PyModuleDef xtermmodule = {
PyModuleDef_HEAD_INIT,
"xterm",
xterm_doc,
-1,
xterm_methods,
};
PyMODINIT_FUNC
PyInit_xterm(void)
{
return PyModule_Create(&xtermmodule);
}
_Section(".rodata.pytab.1") const struct _inittab _PyImport_Inittab_xterm = {
"xterm",
PyInit_xterm,
};