Make improvements to locking

This change makes pthread_mutex_lock() as fast as _spinlock() by
default. Thread instability issues on NetBSD have been resolved.
Improvements made to gdtoa thread code. Crash reporting will now
synchronize between threads in a slightly better way.
This commit is contained in:
Justine Tunney 2022-06-19 01:13:03 -07:00
parent 25041b8026
commit d5312b60f7
60 changed files with 890 additions and 629 deletions

View file

@ -36,9 +36,7 @@ EXAMPLES_COMS = \
EXAMPLES_BINS = \ EXAMPLES_BINS = \
$(EXAMPLES_COMS) \ $(EXAMPLES_COMS) \
$(EXAMPLES_COMS:%=%.dbg) \ $(EXAMPLES_COMS:%=%.dbg)
o/$(MODE)/examples/life-nomod.com \
o/$(MODE)/examples/life-classic.com
EXAMPLES_DIRECTDEPS = \ EXAMPLES_DIRECTDEPS = \
DSP_CORE \ DSP_CORE \
@ -166,34 +164,6 @@ o/$(MODE)/usr/share/dict/words: \
@$(MKDIR) $(@D) @$(MKDIR) $(@D)
@o/$(MODE)/tool/build/gzip.com $(ZFLAGS) -cd <$< >$@ @o/$(MODE)/tool/build/gzip.com $(ZFLAGS) -cd <$< >$@
################################################################################
# binaries for execve_test.com
o/$(MODE)/examples/life-nomod.com.zip.o: o/$(MODE)/examples/life-nomod.com
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -B $(OUTPUT_OPTION) $<
o/$(MODE)/examples/life-classic.com.zip.o: o/$(MODE)/examples/life-classic.com
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -B $(OUTPUT_OPTION) $<
o/$(MODE)/examples/pylife/pylife.com.zip.o: o/$(MODE)/examples/pylife/pylife.com
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -B $(OUTPUT_OPTION) $<
o/$(MODE)/examples/life-classic.com.dbg: \
$(EXAMPLES_DEPS) \
o/$(MODE)/examples/life.o \
o/$(MODE)/examples/examples.pkg \
$(CRT) \
$(APE)
@$(APELINK)
o/$(MODE)/examples/life-nomod.com.dbg: \
$(EXAMPLES_DEPS) \
o/$(MODE)/examples/life.o \
o/$(MODE)/examples/examples.pkg \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
################################################################################ ################################################################################
.PHONY: o/$(MODE)/examples .PHONY: o/$(MODE)/examples

View file

@ -16,9 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/calls/struct/timespec.h"
#include "libc/str/str.h"
#include "libc/time/time.h" #include "libc/time/time.h"
/** /**

View file

@ -25,9 +25,11 @@ unsigned __sighandflags[NSIG];
static pthread_mutex_t __sig_lock_obj; static pthread_mutex_t __sig_lock_obj;
void(__sig_lock)(void) { void(__sig_lock)(void) {
__sig_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_lock(&__sig_lock_obj); pthread_mutex_lock(&__sig_lock_obj);
} }
void(__sig_unlock)(void) { void(__sig_unlock)(void) {
__sig_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_unlock(&__sig_lock_obj); pthread_mutex_unlock(&__sig_lock_obj);
} }

View file

@ -18,34 +18,44 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/strace.internal.h" #include "libc/calls/calls.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/intrin/lockcmpxchg.h" #include "libc/intrin/lockcmpxchgp.h"
#include "libc/log/log.h" #include "libc/log/backtrace.internal.h"
#include "libc/log/internal.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
/** /**
* Handles failure of assert() macro. * Handles failure of assert() macro.
*/ */
relegated wontreturn void __assert_fail(const char *expr, const char *file, relegated wontreturn void __assert_fail(const char *expr, const char *file,
int line) { int line) {
int rc; int me, owner;
static bool noreentry; static int sync;
--__strace; --__strace;
--__ftrace; --__ftrace;
kprintf("%s:%d: assert(%s) failed\n", file, line, expr); owner = 0;
if (_lockcmpxchg(&noreentry, false, true)) { me = gettid();
if (weaken(__die)) { kprintf("%s:%d: assert(%s) failed (tid %d)\n", file, line, expr, me);
weaken(__die)(); if (_lockcmpxchgp(&sync, &owner, me)) {
__restore_tty();
if (weaken(ShowBacktrace)) {
weaken(ShowBacktrace)(2, __builtin_frame_address(0));
} else if (weaken(PrintBacktraceUsingSymbols) && weaken(GetSymbolTable)) {
weaken(PrintBacktraceUsingSymbols)(2, __builtin_frame_address(0),
weaken(GetSymbolTable)());
} else { } else {
kprintf("can't backtrace b/c `__die` not linked\n"); kprintf("can't backtrace b/c `ShowCrashReports` not linked\n");
}
rc = 23;
} else {
rc = 24;
} }
__restorewintty(); __restorewintty();
_Exit(rc); _Exit(23);
} else if (owner == me) {
kprintf("assert failed while failing\n");
__restorewintty();
_Exit(24);
} else {
_Exit1(25);
}
} }

View file

@ -31,7 +31,6 @@
* @noreturn * @noreturn
*/ */
privileged wontreturn void _Exit1(int rc) { privileged wontreturn void _Exit1(int rc) {
jmp_buf *jb;
struct WinThread *wt; struct WinThread *wt;
STRACE("_Exit1(%d)", rc); STRACE("_Exit1(%d)", rc);
if (!IsWindows() && !IsMetal()) { if (!IsWindows() && !IsMetal()) {

View file

@ -30,10 +30,12 @@ struct Fds g_fds;
static pthread_mutex_t __fds_lock_obj; static pthread_mutex_t __fds_lock_obj;
void(__fds_lock)(void) { void(__fds_lock)(void) {
__fds_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_lock(&__fds_lock_obj); pthread_mutex_lock(&__fds_lock_obj);
} }
void(__fds_unlock)(void) { void(__fds_unlock)(void) {
__fds_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_unlock(&__fds_lock_obj); pthread_mutex_unlock(&__fds_lock_obj);
} }

View file

@ -22,7 +22,7 @@
STATIC_YOINK("_init__mmi"); STATIC_YOINK("_init__mmi");
struct MemoryIntervals _mmi; struct MemoryIntervals _mmi;
static pthread_mutex_t __mmi_lock_obj; pthread_mutex_t __mmi_lock_obj; // recursive :'(
void(__mmi_lock)(void) { void(__mmi_lock)(void) {
pthread_mutex_lock(&__mmi_lock_obj); pthread_mutex_lock(&__mmi_lock_obj);

View file

@ -16,9 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/intrin/pthread.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
.init.start 200,_init__mmi .init.start 200,_init__mmi
movb $OPEN_MAX,_mmi+8 movb $OPEN_MAX,_mmi+8
movl $_mmi+24,_mmi+16 movl $_mmi+24,_mmi+16
movb $PTHREAD_MUTEX_RECURSIVE,__mmi_lock_obj(%rip)
.init.end 200,_init__mmi .init.end 200,_init__mmi

View file

@ -1,19 +1,21 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_ #ifndef COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_
#define COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_ #define COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_
#include "libc/bits/atomic.h"
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/intrin/kprintf.h" #include "libc/dce.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define PTHREAD_ONCE_INIT 0 #define PTHREAD_ONCE_INIT 0
#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL #define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
#define PTHREAD_MUTEX_RECURSIVE 0 #define PTHREAD_MUTEX_NORMAL 0
#define PTHREAD_MUTEX_NORMAL 1 #define PTHREAD_MUTEX_RECURSIVE 1
#define PTHREAD_MUTEX_ERRORCHECK 2 #define PTHREAD_MUTEX_ERRORCHECK 2
#define PTHREAD_MUTEX_STALLED 0 #define PTHREAD_MUTEX_STALLED 0
#define PTHREAD_MUTEX_ROBUST 1 #define PTHREAD_MUTEX_ROBUST 1
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/* clang-format off */ /* clang-format off */
#define PTHREAD_MUTEX_INITIALIZER {PTHREAD_MUTEX_DEFAULT} #define PTHREAD_MUTEX_INITIALIZER {PTHREAD_MUTEX_DEFAULT}
#define PTHREAD_RWLOCK_INITIALIZER {{{0}}} #define PTHREAD_RWLOCK_INITIALIZER {{{0}}}
@ -66,8 +68,8 @@ typedef struct {
} __u; } __u;
} pthread_rwlock_t; } pthread_rwlock_t;
wontreturn void pthread_exit(void *); void pthread_exit(void *) wontreturn;
pureconst pthread_t pthread_self(void); pthread_t pthread_self(void) pureconst;
int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *), int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *),
void *); void *);
int pthread_yield(void); int pthread_yield(void);
@ -104,6 +106,30 @@ int pthread_rwlock_trywrlock(pthread_rwlock_t *);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *, const struct timespec *); int pthread_rwlock_timedwrlock(pthread_rwlock_t *, const struct timespec *);
int pthread_rwlock_unlock(pthread_rwlock_t *); int pthread_rwlock_unlock(pthread_rwlock_t *);
#define pthread_mutexattr_init(pAttr) ((pAttr)->attr = PTHREAD_MUTEX_DEFAULT, 0)
#define pthread_mutexattr_destroy(pAttr) ((pAttr)->attr = 0)
#define pthread_mutexattr_gettype(pAttr, pType) (*(pType) = (pAttr)->attr, 0)
#define pthread_mutexattr_settype(pAttr, type) ((pAttr)->attr = type, 0)
#ifdef __GNUC__
#define pthread_mutex_lock(mutex) \
(((mutex)->attr == PTHREAD_MUTEX_NORMAL && \
!atomic_load_explicit(&(mutex)->lock, memory_order_relaxed) && \
!atomic_exchange(&(mutex)->lock, 1)) \
? 0 \
: pthread_mutex_lock(mutex))
#define pthread_mutex_unlock(mutex) \
((mutex)->attr == PTHREAD_MUTEX_NORMAL \
? (atomic_store_explicit(&(mutex)->lock, 0, memory_order_relaxed), \
(IsLinux() && \
atomic_load_explicit(&(mutex)->waits, memory_order_relaxed) && \
_pthread_mutex_wake(mutex)), \
0) \
: pthread_mutex_unlock(mutex))
#endif
int _pthread_mutex_wake(pthread_mutex_t *) hidden;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_ */ #endif /* COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_ */

View file

@ -21,16 +21,50 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/intrin/spinlock.h"
#include "libc/linux/futex.h" #include "libc/linux/futex.h"
#include "libc/nexgen32e/threaded.h" #include "libc/nexgen32e/threaded.h"
static int pthread_mutex_lock_spin(pthread_mutex_t *mutex, int tries) {
volatile int i;
if (tries < 7) {
for (i = 0; i != 1 << tries; i++) {
}
tries++;
} else if (IsLinux()) {
atomic_fetch_add(&mutex->waits, 1);
LinuxFutexWait(&mutex->lock, 1, 0);
atomic_fetch_sub(&mutex->waits, 1);
} else {
sched_yield();
}
return tries;
}
/** /**
* Locks mutex. * Locks mutex.
*
* _spinlock() l: 181,570c 58,646ns
* mutex normal l: 297,965c 96,241ns
* mutex recursive l: 1,112,166c 359,223ns
* mutex errorcheck l: 1,449,723c 468,252ns
*
* @return 0 on success, or error number on failure * @return 0 on success, or error number on failure
*/ */
int pthread_mutex_lock(pthread_mutex_t *mutex) { int(pthread_mutex_lock)(pthread_mutex_t *mutex) {
volatile int i;
int me, owner, tries; int me, owner, tries;
switch (mutex->attr) {
case PTHREAD_MUTEX_NORMAL:
for (tries = 0;;) {
if (!atomic_load_explicit(&mutex->lock, memory_order_relaxed) &&
!atomic_exchange_explicit(&mutex->lock, 1, memory_order_acquire)) {
break;
}
tries = pthread_mutex_lock_spin(mutex, tries);
}
return 0;
case PTHREAD_MUTEX_RECURSIVE:
case PTHREAD_MUTEX_ERRORCHECK:
for (tries = 0, me = gettid();;) { for (tries = 0, me = gettid();;) {
owner = atomic_load_explicit(&mutex->lock, memory_order_relaxed); owner = atomic_load_explicit(&mutex->lock, memory_order_relaxed);
if (!owner && atomic_compare_exchange_weak_explicit( if (!owner && atomic_compare_exchange_weak_explicit(
@ -44,18 +78,11 @@ int pthread_mutex_lock(pthread_mutex_t *mutex) {
return EDEADLK; return EDEADLK;
} }
} }
if (tries < 7) { tries = pthread_mutex_lock_spin(mutex, tries);
for (i = 0; i != 1 << tries; i++) {
}
tries++;
} else if (IsLinux()) {
atomic_fetch_add(&mutex->waits, 1);
LinuxFutexWait(&mutex->lock, owner, 0);
atomic_fetch_sub(&mutex->waits, 1);
} else {
sched_yield();
}
} }
++mutex->reent; ++mutex->reent;
return 0; return 0;
default:
return EINVAL;
}
} }

View file

@ -18,28 +18,34 @@
*/ */
#include "libc/bits/atomic.h" #include "libc/bits/atomic.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/linux/futex.h"
#include "libc/nexgen32e/threaded.h"
/** /**
* Releases mutex. * Releases mutex.
* @return 0 on success or error number on failure * @return 0 on success or error number on failure
* @raises EPERM if in error check mode and not owned by caller * @raises EPERM if in error check mode and not owned by caller
*/ */
int pthread_mutex_unlock(pthread_mutex_t *mutex) { int(pthread_mutex_unlock)(pthread_mutex_t *mutex) {
int owner; int me, owner;
if (mutex->attr == PTHREAD_MUTEX_ERRORCHECK && mutex->lock != gettid()) { switch (mutex->attr) {
return EPERM; case PTHREAD_MUTEX_ERRORCHECK:
} me = gettid();
if (!--mutex->reent) { owner = atomic_load_explicit(&mutex->lock, memory_order_relaxed);
if (owner != me) return EPERM;
// fallthrough
case PTHREAD_MUTEX_RECURSIVE:
if (--mutex->reent) return 0;
// fallthrough
case PTHREAD_MUTEX_NORMAL:
atomic_store_explicit(&mutex->lock, 0, memory_order_relaxed); atomic_store_explicit(&mutex->lock, 0, memory_order_relaxed);
if (IsLinux() && if (IsLinux() &&
atomic_load_explicit(&mutex->waits, memory_order_acquire)) { atomic_load_explicit(&mutex->waits, memory_order_relaxed)) {
LinuxFutexWake(&mutex->lock, 1); _pthread_mutex_wake(mutex);
}
} }
return 0; return 0;
default:
return EINVAL;
}
} }

View file

@ -0,0 +1,26 @@
/*-*- 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 2022 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.
*/
#include "libc/bits/atomic.h"
#include "libc/dce.h"
#include "libc/intrin/pthread.h"
#include "libc/linux/futex.h"
int _pthread_mutex_wake(pthread_mutex_t *mutex) {
return LinuxFutexWake(&mutex->lock, 1);
}

View file

@ -17,13 +17,12 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/str/str.h"
/** /**
* Destroys mutex attr. * Destroys mutex attr.
* @return 0 on success, or error number on failure * @return 0 on success, or error number on failure
*/ */
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) { int(pthread_mutexattr_destroy)(pthread_mutexattr_t *attr) {
bzero(attr, sizeof(*attr)); attr->attr = 0;
return 0; return 0;
} }

View file

@ -29,7 +29,7 @@
* - `PTHREAD_MUTEX_ERRORCHECK` * - `PTHREAD_MUTEX_ERRORCHECK`
* @return 0 on success, or error on failure * @return 0 on success, or error on failure
*/ */
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type) { int(pthread_mutexattr_gettype)(const pthread_mutexattr_t *attr, int *type) {
*type = attr->attr; *type = attr->attr;
return 0; return 0;
} }

View file

@ -17,14 +17,12 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/str/str.h"
/** /**
* Initializes mutex attr. * Initializes mutex attr.
* @return 0 on success, or error number on failure * @return 0 on success, or error number on failure
*/ */
int pthread_mutexattr_init(pthread_mutexattr_t *attr) { int(pthread_mutexattr_init)(pthread_mutexattr_t *attr) {
bzero(attr, sizeof(*attr));
attr->attr = PTHREAD_MUTEX_DEFAULT; attr->attr = PTHREAD_MUTEX_DEFAULT;
return 0; return 0;
} }

View file

@ -30,7 +30,7 @@
* @return 0 on success, or error on failure * @return 0 on success, or error on failure
* @raises EINVAL if `type` is invalid * @raises EINVAL if `type` is invalid
*/ */
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) { int(pthread_mutexattr_settype)(pthread_mutexattr_t *attr, int type) {
switch (type) { switch (type) {
case PTHREAD_MUTEX_NORMAL: case PTHREAD_MUTEX_NORMAL:
case PTHREAD_MUTEX_RECURSIVE: case PTHREAD_MUTEX_RECURSIVE:

View file

@ -1,5 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ #ifndef COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
#define COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ #define COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗ /*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § spinlocks cosmopolitan § spinlocks
@ -11,7 +13,7 @@
#define _spinlock(lock) _spinlock_cooperative(lock) #define _spinlock(lock) _spinlock_cooperative(lock)
#endif #endif
#define _spunlock(lock) __atomic_store_n(lock, 0, __ATOMIC_RELAXED) #define _spunlock(lock) (__atomic_store_n(lock, 0, __ATOMIC_RELAXED), 0)
#define _seizelock(lock, value) \ #define _seizelock(lock, value) \
({ \ ({ \
@ -69,6 +71,8 @@
#define _trylock(lock) __atomic_test_and_set(lock, __ATOMIC_SEQ_CST) #define _trylock(lock) __atomic_test_and_set(lock, __ATOMIC_SEQ_CST)
void _spinlock_yield(void); int _spinlock_yield(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ */ #endif /* COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ */

View file

@ -103,12 +103,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
garbage = weaken(__garbage); garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0; gi = garbage ? garbage->i : 0;
for (frame = bp; frame && i < kBacktraceMaxFrames - 1; frame = frame->next) { for (frame = bp; frame && i < kBacktraceMaxFrames - 1; frame = frame->next) {
__mmi_lock();
ok = IsValidStackFramePointer(frame);
__mmi_unlock();
if (!ok) {
return -1;
}
addr = frame->addr; addr = frame->addr;
if (addr == weakaddr("__gc")) { if (addr == weakaddr("__gc")) {
do { do {

View file

@ -57,13 +57,6 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
garbage = weaken(__garbage); garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0; gi = garbage ? garbage->i : 0;
for (i = 0, frame = bp; frame; frame = frame->next) { for (i = 0, frame = bp; frame; frame = frame->next) {
__mmi_lock();
ok = IsValidStackFramePointer(frame);
__mmi_unlock();
if (!ok) {
kprintf("%p corrupt frame pointer\n", frame);
break;
}
if (++i == LIMIT) { if (++i == LIMIT) {
kprintf("<truncated backtrace>\n"); kprintf("<truncated backtrace>\n");
break; break;

View file

@ -16,8 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/lockcmpxchg.h" #include "libc/intrin/kprintf.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/log/backtrace.internal.h" #include "libc/log/backtrace.internal.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
@ -32,18 +34,30 @@
*/ */
relegated wontreturn void __die(void) { relegated wontreturn void __die(void) {
/* asan runtime depends on this function */ /* asan runtime depends on this function */
int rc; int me, owner;
static bool once; static int sync;
if (_lockcmpxchg(&once, false, true)) { owner = 0;
me = gettid();
if (_lockcmpxchgp(&sync, &owner, me)) {
__restore_tty(); __restore_tty();
if (IsDebuggerPresent(false)) { if (IsDebuggerPresent(false)) {
DebugBreak(); DebugBreak();
} }
ShowBacktrace(2, NULL); if (weaken(ShowBacktrace)) {
rc = 77; weaken(ShowBacktrace)(2, __builtin_frame_address(0));
} else if (weaken(PrintBacktraceUsingSymbols) && weaken(GetSymbolTable)) {
weaken(PrintBacktraceUsingSymbols)(2, __builtin_frame_address(0),
weaken(GetSymbolTable)());
} else { } else {
rc = 78; kprintf("can't backtrace b/c `ShowCrashReports` not linked\n");
} }
__restorewintty(); __restorewintty();
_Exit(rc); _Exit(77);
} else if (owner == me) {
kprintf("die failed while dying\n");
__restorewintty();
_Exit(78);
} else {
_Exit1(79);
}
} }

View file

@ -26,6 +26,7 @@
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/intrin/lockcmpxchg.h" #include "libc/intrin/lockcmpxchg.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/log/backtrace.internal.h" #include "libc/log/backtrace.internal.h"
#include "libc/log/gdb.h" #include "libc/log/gdb.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
@ -262,15 +263,22 @@ static wontreturn relegated noinstrument void __minicrash(int sig,
* simply print addresses which may be cross-referenced using objdump. * simply print addresses which may be cross-referenced using objdump.
* *
* This function never returns, except for traps w/ human supervision. * This function never returns, except for traps w/ human supervision.
*
* @threadsafe
* @vforksafe
*/ */
relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) { relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
intptr_t rip; intptr_t rip;
int me, owner;
int gdbpid, err; int gdbpid, err;
static bool noreentry, notpossible; static int sync;
static bool notpossible;
STRACE("__oncrash rip %x", ctx->uc_mcontext.rip); STRACE("__oncrash rip %x", ctx->uc_mcontext.rip);
--__ftrace; --__ftrace;
--__strace; --__strace;
if (_lockcmpxchg(&noreentry, false, true)) { owner = 0;
me = gettid();
if (_lockcmpxchgp(&sync, &owner, me)) {
if (!__vforked) { if (!__vforked) {
rip = ctx ? ctx->uc_mcontext.rip : 0; rip = ctx ? ctx->uc_mcontext.rip : 0;
err = errno; err = errno;
@ -292,20 +300,30 @@ relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
__restorewintty(); __restorewintty();
_Exit(128 + sig); _Exit(128 + sig);
} }
sync = 0;
} else { } else {
sync = 0;
__minicrash(sig, si, ctx, "WHILE VFORKED"); __minicrash(sig, si, ctx, "WHILE VFORKED");
} }
} else if (sig == SIGTRAP) { } else if (sig == SIGTRAP) {
/* chances are IsDebuggerPresent() confused strace w/ gdb */ // chances are IsDebuggerPresent() confused strace w/ gdb
goto ItsATrap; goto ItsATrap;
} else if (_lockcmpxchg(&notpossible, false, true)) { } else if (owner == me) {
// we crashed while generating a crash report
if (_lockcmpxchg(&notpossible, false, true)) {
__minicrash(sig, si, ctx, "WHILE CRASHING"); __minicrash(sig, si, ctx, "WHILE CRASHING");
} else { } else {
// somehow __minicrash() crashed not possible
for (;;) { for (;;) {
asm("ud2"); asm("ud2");
} }
} }
noreentry = false; } else {
// multiple threads have crashed
// kill current thread assuming process dies soon
// TODO(jart): It'd be nice to report on all threads.
_Exit1(8);
}
ItsATrap: ItsATrap:
++__strace; ++__strace;
++__ftrace; ++__ftrace;

View file

@ -30,9 +30,12 @@
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/ss.h" #include "libc/sysv/consts/ss.h"
STATIC_YOINK("__die"); /* for backtracing */ STATIC_YOINK("__die"); // for backtracing
STATIC_YOINK("malloc_inspect_all"); /* for asan memory origin */ STATIC_YOINK("ShowBacktrace"); // for backtracing
STATIC_YOINK("__get_symbol_by_addr"); /* for asan memory origin */ STATIC_YOINK("GetSymbolTable"); // for backtracing
STATIC_YOINK("PrintBacktraceUsingSymbols"); // for backtracing
STATIC_YOINK("malloc_inspect_all"); // for asan memory origin
STATIC_YOINK("__get_symbol_by_addr"); // for asan memory origin
extern const unsigned char __oncrash_thunks[8][11]; extern const unsigned char __oncrash_thunks[8][11];
static struct sigaltstack g_oldsigaltstack; static struct sigaltstack g_oldsigaltstack;

View file

@ -355,16 +355,15 @@ static wontreturn void NetbsdThreadMain(void *arg, int (*func)(void *arg),
static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags, static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags,
void *arg, void *tls, size_t tlssz, int *ctid) { void *arg, void *tls, size_t tlssz, int *ctid) {
// NetBSD has its own clone() and it works, but it's technically a // NetBSD has its own clone() and it works, but it's technically a
// second-class API, intended to help Linux folks migrate to this! // second-class API, intended to help Linux folks migrate to this.
// We put it on the thread's stack, to avoid locking this function
// so its stack doesn't scope. The ucontext struct needs 784 bytes
bool failed; bool failed;
int ax, *tid; int ax, *tid;
intptr_t dx, sp; intptr_t dx, sp;
static bool once; static bool once;
static int broken; static int broken;
struct ucontext_netbsd ctx; struct ucontext_netbsd *ctx;
static struct ucontext_netbsd netbsd_clone_template; static struct ucontext_netbsd netbsd_clone_template;
_Static_assert(sizeof(struct ucontext_netbsd) == 784, "fix assembly");
// memoize arbitrary valid processor state structure // memoize arbitrary valid processor state structure
if (!once) { if (!once) {
@ -382,35 +381,48 @@ static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags,
return -1; return -1;
} }
sp = (intptr_t)(stk + stksz); sp = (intptr_t)(stk + stksz);
// allocate memory for child tid
sp -= sizeof(int); sp -= sizeof(int);
sp = sp & -alignof(int); sp = sp & -alignof(int);
tid = (int *)sp; tid = (int *)sp;
// align the stack
sp = sp & -16; sp = sp & -16;
// simulate call to misalign stack and ensure backtrace looks good
sp -= 8; sp -= 8;
*(intptr_t *)sp = (intptr_t)CloneNetbsd + 1;
// place the giant 784 byte ucontext structure in the red zone!
// it only has to live long enough for the thread to come alive
ctx = (struct ucontext_netbsd *)((sp - sizeof(struct ucontext_netbsd)) &
-alignof(struct ucontext_netbsd));
// pass parameters in process state // pass parameters in process state
memcpy(&ctx, &netbsd_clone_template, sizeof(ctx)); memcpy(ctx, &netbsd_clone_template, sizeof(*ctx));
ctx.uc_link = 0; ctx->uc_link = 0;
ctx.uc_mcontext.rbp = 0; ctx->uc_mcontext.rbp = 0;
ctx.uc_mcontext.rsp = sp; ctx->uc_mcontext.rsp = sp;
ctx.uc_mcontext.rip = (intptr_t)NetbsdThreadMain; ctx->uc_mcontext.rip = (intptr_t)NetbsdThreadMain;
ctx.uc_mcontext.rdi = (intptr_t)arg; ctx->uc_mcontext.rdi = (intptr_t)arg;
ctx.uc_mcontext.rsi = (intptr_t)func; ctx->uc_mcontext.rsi = (intptr_t)func;
ctx.uc_mcontext.rdx = (intptr_t)tid; ctx->uc_mcontext.rdx = (intptr_t)tid;
ctx.uc_mcontext.rcx = (intptr_t)(flags & CLONE_CHILD_SETTID ? ctid : tid); ctx->uc_mcontext.rcx = (intptr_t)(flags & CLONE_CHILD_SETTID ? ctid : tid);
ctx.uc_mcontext.r8 = (intptr_t)(flags & CLONE_CHILD_CLEARTID ? ctid : tid); ctx->uc_mcontext.r8 = (intptr_t)(flags & CLONE_CHILD_CLEARTID ? ctid : tid);
ctx.uc_flags |= _UC_STACK; ctx->uc_flags |= _UC_STACK;
ctx.uc_stack.ss_sp = stk; ctx->uc_stack.ss_sp = stk;
ctx.uc_stack.ss_size = stksz; ctx->uc_stack.ss_size = stksz;
ctx.uc_stack.ss_flags = 0; ctx->uc_stack.ss_flags = 0;
if (flags & CLONE_SETTLS) { if (flags & CLONE_SETTLS) {
ctx.uc_flags |= _UC_TLSBASE; ctx->uc_flags |= _UC_TLSBASE;
ctx.uc_mcontext._mc_tlsbase = (intptr_t)tls; ctx->uc_mcontext._mc_tlsbase = (intptr_t)tls;
} }
// perform the system call // perform the system call
asm volatile(CFLAG_ASM("syscall") asm volatile(CFLAG_ASM("syscall")
: CFLAG_CONSTRAINT(failed), "=a"(ax), "=d"(dx) : CFLAG_CONSTRAINT(failed), "=a"(ax), "=d"(dx)
: "1"(__NR__lwp_create), "D"(&ctx), "S"(LWP_DETACHED), "2"(tid) : "1"(__NR__lwp_create), "D"(ctx), "S"(LWP_DETACHED), "2"(tid)
: "rcx", "r11", "memory"); : "rcx", "r11", "memory");
if (!failed) { if (!failed) {
return *tid; return *tid;

View file

@ -34,10 +34,12 @@
static pthread_mutex_t __fflush_lock_obj; static pthread_mutex_t __fflush_lock_obj;
void(__fflush_lock)(void) { void(__fflush_lock)(void) {
__fflush_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_lock(&__fflush_lock_obj); pthread_mutex_lock(&__fflush_lock_obj);
} }
void(__fflush_unlock)(void) { void(__fflush_unlock)(void) {
__fflush_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_unlock(&__fflush_lock_obj); pthread_mutex_unlock(&__fflush_lock_obj);
} }

View file

@ -22,5 +22,6 @@
* Acquires reentrant lock on stdio object, blocking if needed. * Acquires reentrant lock on stdio object, blocking if needed.
*/ */
void(flockfile)(FILE *f) { void(flockfile)(FILE *f) {
f->lock.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_lock(&f->lock); pthread_mutex_lock(&f->lock);
} }

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/intrin/pthread.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"

View file

@ -22,5 +22,6 @@
* Releases lock on stdio object. * Releases lock on stdio object.
*/ */
void(funlockfile)(FILE *f) { void(funlockfile)(FILE *f) {
f->lock.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_unlock(&f->lock); pthread_mutex_unlock(&f->lock);
} }

View file

@ -31,7 +31,7 @@
mov O_WRONLY,%edx mov O_WRONLY,%edx
mov %edx,4(%rax) # f.iomode mov %edx,4(%rax) # f.iomode
ezlea __stderr_buf,cx ezlea __stderr_buf,cx
mov %rcx,24(%rax) # f.buf mov %rcx,0x18(%rax) # f.buf
movl $BUFSIZ,32(%rax) # f.size movl $BUFSIZ,0x20(%rax) # f.size
mov %rax,stderr(%rip) mov %rax,stderr(%rip)
.init.end 400,_init_stderr,globl,hidden .init.end 400,_init_stderr,globl,hidden

View file

@ -27,7 +27,7 @@
mov O_RDONLY,%edx mov O_RDONLY,%edx
mov %edx,4(%rax) # f.iomode mov %edx,4(%rax) # f.iomode
ezlea __stdin_buf,cx ezlea __stdin_buf,cx
mov %rcx,24(%rax) # f.buf mov %rcx,0x18(%rax) # f.buf
movl $BUFSIZ,32(%rax) # f.size movl $BUFSIZ,0x20(%rax) # f.size
mov %rax,stdin(%rip) mov %rax,stdin(%rip)
.init.end 400,_init_stdin,globl,hidden .init.end 400,_init_stdin,globl,hidden

View file

@ -27,8 +27,8 @@ typedef struct FILE {
uint32_t size; /* 0x20 */ uint32_t size; /* 0x20 */
uint32_t nofree; /* 0x24 */ uint32_t nofree; /* 0x24 */
int pid; /* 0x28 */ int pid; /* 0x28 */
char *getln; char *getln; /* 0x30 */
pthread_mutex_t lock; pthread_mutex_t lock; /* 0x38 */
} FILE; } FILE;
extern FILE *stdin; extern FILE *stdin;

View file

@ -25,11 +25,11 @@
.init.start 400,_init_stdout .init.start 400,_init_stdout
ezlea __stdout,ax ezlea __stdout,ax
push STDOUT_FILENO push STDOUT_FILENO
pop 12(%rax) # f.fd pop 0x0c(%rax) # f.fd
mov O_WRONLY,%edx mov O_WRONLY,%edx
mov %edx,4(%rax) # f.iomode mov %edx,4(%rax) # f.iomode
ezlea __stdout_buf,cx ezlea __stdout_buf,cx
mov %rcx,24(%rax) # f.buf mov %rcx,0x18(%rax) # f.buf
movl $BUFSIZ,32(%rax) # f.size movl $BUFSIZ,0x20(%rax) # f.size
mov %rax,stdout(%rip) mov %rax,stdout(%rip)
.init.end 400,_init_stdout,globl,hidden .init.end 400,_init_stdout,globl,hidden

View file

@ -56,7 +56,7 @@ void SetUp(void) {
ASSERT_SYS(0, 0, mkdir("tmp", 0755)); ASSERT_SYS(0, 0, mkdir("tmp", 0755));
ASSERT_SYS(0, 0, mkdir("bin", 0755)); ASSERT_SYS(0, 0, mkdir("bin", 0755));
Extract("/zip/tiny64.elf", "bin/tiny64.elf", 0755); Extract("/zip/tiny64.elf", "bin/tiny64.elf", 0755);
Extract("/zip/pylife.com", "bin/pylife.com", 0755); // Extract("/zip/pylife.com", "bin/pylife.com", 0755);
Extract("/zip/life-nomod.com", "bin/life-nomod.com", 0755); Extract("/zip/life-nomod.com", "bin/life-nomod.com", 0755);
Extract("/zip/life-classic.com", "bin/life-classic.com", 0755); Extract("/zip/life-classic.com", "bin/life-classic.com", 0755);
setenv("TMPDIR", "tmp", true); setenv("TMPDIR", "tmp", true);
@ -190,6 +190,7 @@ TEST(execve, vfork_apeClassic) {
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#if 0 // not worth depending on THIRD_PARTY_PYTHON for this test
TEST(execve, system_apeNoMod3mb) { TEST(execve, system_apeNoMod3mb) {
if (IsWindows()) return; // todo(jart): wut if (IsWindows()) return; // todo(jart): wut
@ -229,6 +230,7 @@ TEST(execve, vfork_apeNoMod3mb) {
} }
} }
#endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void SystemElf(void) { void SystemElf(void) {

22
test/libc/calls/life.c Normal file
View file

@ -0,0 +1,22 @@
/*-*- 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 2022 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.
*/
int main(int argc, char *argv[]) {
return 42;
}

View file

@ -5,13 +5,15 @@ PKGS += TEST_LIBC_CALLS
TEST_LIBC_CALLS_SRCS := \ TEST_LIBC_CALLS_SRCS := \
$(wildcard test/libc/calls/*.c) $(wildcard test/libc/calls/*.c)
TEST_LIBC_CALLS_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_CALLS_SRCS))
TEST_LIBC_CALLS_SRCS_TEST = \
$(filter %_test.c,$(TEST_LIBC_CALLS_SRCS))
TEST_LIBC_CALLS_OBJS = \ TEST_LIBC_CALLS_OBJS = \
$(TEST_LIBC_CALLS_SRCS:%.c=o/$(MODE)/%.o) $(TEST_LIBC_CALLS_SRCS:%.c=o/$(MODE)/%.o)
TEST_LIBC_CALLS_COMS = \ TEST_LIBC_CALLS_COMS = \
$(TEST_LIBC_CALLS_SRCS:%.c=o/$(MODE)/%.com) $(TEST_LIBC_CALLS_SRCS_TEST:%.c=o/$(MODE)/%.com)
TEST_LIBC_CALLS_BINS = \ TEST_LIBC_CALLS_BINS = \
$(TEST_LIBC_CALLS_COMS) \ $(TEST_LIBC_CALLS_COMS) \
@ -57,9 +59,8 @@ o/$(MODE)/test/libc/calls/calls.pkg: \
o/$(MODE)/test/libc/calls/%.com.dbg: \ o/$(MODE)/test/libc/calls/%.com.dbg: \
$(TEST_LIBC_CALLS_DEPS) \ $(TEST_LIBC_CALLS_DEPS) \
o/$(MODE)/test/libc/calls/%.o \ o/$(MODE)/test/libc/calls/%.o \
o/$(MODE)/examples/life-nomod.com.zip.o \ o/$(MODE)/test/libc/calls/life-nomod.com.zip.o \
o/$(MODE)/examples/life-classic.com.zip.o \ o/$(MODE)/test/libc/calls/life-classic.com.zip.o \
o/$(MODE)/examples/pylife/pylife.com.zip.o \
o/$(MODE)/test/libc/calls/tiny64.elf.zip.o \ o/$(MODE)/test/libc/calls/tiny64.elf.zip.o \
o/$(MODE)/third_party/python/Lib/test/tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt.zip.o \ o/$(MODE)/third_party/python/Lib/test/tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt.zip.o \
o/$(MODE)/test/libc/calls/calls.pkg \ o/$(MODE)/test/libc/calls/calls.pkg \
@ -70,6 +71,26 @@ o/$(MODE)/test/libc/calls/%.com.dbg: \
o/$(MODE)/test/libc/calls/tiny64.elf.zip.o: ZIPOBJ_FLAGS += -B o/$(MODE)/test/libc/calls/tiny64.elf.zip.o: ZIPOBJ_FLAGS += -B
o/$(MODE)/test/libc/calls/life-nomod.com.zip.o: o/$(MODE)/test/libc/calls/life-nomod.com
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -B $(OUTPUT_OPTION) $<
o/$(MODE)/test/libc/calls/life-classic.com.zip.o: o/$(MODE)/test/libc/calls/life-classic.com
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -B $(OUTPUT_OPTION) $<
o/$(MODE)/test/libc/calls/life-classic.com.dbg: \
$(LIBC_RUNTIME) \
o/$(MODE)/test/libc/calls/life.o \
$(CRT) \
$(APE)
@$(APELINK)
o/$(MODE)/test/libc/calls/life-nomod.com.dbg: \
$(LIBC_RUNTIME) \
o/$(MODE)/test/libc/calls/life.o \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
.PHONY: o/$(MODE)/test/libc/calls .PHONY: o/$(MODE)/test/libc/calls
o/$(MODE)/test/libc/calls: \ o/$(MODE)/test/libc/calls: \
$(TEST_LIBC_CALLS_BINS) \ $(TEST_LIBC_CALLS_BINS) \

View file

@ -91,6 +91,7 @@ TEST(memcmp, fuzz) {
int buncmp(const void *, const void *, size_t) asm("bcmp"); int buncmp(const void *, const void *, size_t) asm("bcmp");
int funcmp(const void *, const void *, size_t) asm("memcmp"); int funcmp(const void *, const void *, size_t) asm("memcmp");
#if 0
BENCH(bcmp, bench) { BENCH(bcmp, bench) {
volatile int v; volatile int v;
const char *volatile a; const char *volatile a;
@ -135,7 +136,9 @@ BENCH(bcmp, bench) {
memcpy(b, a, 128 * 1024); memcpy(b, a, 128 * 1024);
EZBENCH_N("bcmp", 131072, v = buncmp(a, b, 131072)); EZBENCH_N("bcmp", 131072, v = buncmp(a, b, 131072));
} }
#endif
#if 0
BENCH(memcmp, bench) { BENCH(memcmp, bench) {
volatile int v; volatile int v;
const char *volatile a; const char *volatile a;
@ -180,7 +183,9 @@ BENCH(memcmp, bench) {
memcpy(b, a, 128 * 1024); memcpy(b, a, 128 * 1024);
EZBENCH_N("memcmp", 131072, v = funcmp(a, b, 131072)); EZBENCH_N("memcmp", 131072, v = funcmp(a, b, 131072));
} }
#endif
#if 0
BENCH(timingsafe_memcmp, bench) { BENCH(timingsafe_memcmp, bench) {
volatile int v; volatile int v;
const char *volatile a; const char *volatile a;
@ -225,7 +230,9 @@ BENCH(timingsafe_memcmp, bench) {
memcpy(b, a, 128 * 1024); memcpy(b, a, 128 * 1024);
EZBENCH_N("timingsafe_memcmp", 131072, v = timingsafe_memcmp(a, b, 131072)); EZBENCH_N("timingsafe_memcmp", 131072, v = timingsafe_memcmp(a, b, 131072));
} }
#endif
#if 0
BENCH(timingsafe_bcmp, bench) { BENCH(timingsafe_bcmp, bench) {
volatile int v; volatile int v;
const char *volatile a; const char *volatile a;
@ -270,7 +277,9 @@ BENCH(timingsafe_bcmp, bench) {
memcpy(b, a, 128 * 1024); memcpy(b, a, 128 * 1024);
EZBENCH_N("timingsafe_bcmp", 131072, v = timingsafe_bcmp(a, b, 131072)); EZBENCH_N("timingsafe_bcmp", 131072, v = timingsafe_bcmp(a, b, 131072));
} }
#endif
#if 0
BENCH(memcasecmp, bench) { BENCH(memcasecmp, bench) {
volatile int v; volatile int v;
const char *volatile a; const char *volatile a;
@ -315,7 +324,9 @@ BENCH(memcasecmp, bench) {
memcpy(b, a, 128 * 1024); memcpy(b, a, 128 * 1024);
EZBENCH_N("memcasecmp", 131072, v = memcasecmp(a, b, 131072)); EZBENCH_N("memcasecmp", 131072, v = memcasecmp(a, b, 131072));
} }
#endif
#if 0
BENCH(timingsafe_memcmp, demonstration) { BENCH(timingsafe_memcmp, demonstration) {
int bcmp_(const void *, const void *, size_t) asm("bcmp"); int bcmp_(const void *, const void *, size_t) asm("bcmp");
int memcmp_(const void *, const void *, size_t) asm("memcmp"); int memcmp_(const void *, const void *, size_t) asm("memcmp");
@ -339,3 +350,4 @@ BENCH(timingsafe_memcmp, demonstration) {
a[0] = b[0]; a[0] = b[0];
EZBENCH_N("timingsafe_memcmp eq", 256, timingsafe_memcmp(a, b, 256)); EZBENCH_N("timingsafe_memcmp eq", 256, timingsafe_memcmp(a, b, 256));
} }
#endif

View file

@ -51,6 +51,7 @@ TEST(pthread_mutex_lock, normal) {
ASSERT_EQ(0, pthread_mutexattr_init(&attr)); ASSERT_EQ(0, pthread_mutexattr_init(&attr));
ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL)); ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL));
ASSERT_EQ(0, pthread_mutex_init(&lock, &attr)); ASSERT_EQ(0, pthread_mutex_init(&lock, &attr));
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
ASSERT_EQ(0, pthread_mutex_init(&lock, 0)); ASSERT_EQ(0, pthread_mutex_init(&lock, 0));
ASSERT_EQ(0, pthread_mutex_lock(&lock)); ASSERT_EQ(0, pthread_mutex_lock(&lock));
ASSERT_EQ(0, pthread_mutex_unlock(&lock)); ASSERT_EQ(0, pthread_mutex_unlock(&lock));
@ -65,6 +66,7 @@ TEST(pthread_mutex_lock, recursive) {
ASSERT_EQ(0, pthread_mutexattr_init(&attr)); ASSERT_EQ(0, pthread_mutexattr_init(&attr));
ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)); ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));
ASSERT_EQ(0, pthread_mutex_init(&lock, &attr)); ASSERT_EQ(0, pthread_mutex_init(&lock, &attr));
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
ASSERT_EQ(0, pthread_mutex_lock(&lock)); ASSERT_EQ(0, pthread_mutex_lock(&lock));
ASSERT_EQ(0, pthread_mutex_lock(&lock)); ASSERT_EQ(0, pthread_mutex_lock(&lock));
ASSERT_EQ(0, pthread_mutex_unlock(&lock)); ASSERT_EQ(0, pthread_mutex_unlock(&lock));
@ -72,7 +74,6 @@ TEST(pthread_mutex_lock, recursive) {
ASSERT_EQ(0, pthread_mutex_unlock(&lock)); ASSERT_EQ(0, pthread_mutex_unlock(&lock));
ASSERT_EQ(0, pthread_mutex_unlock(&lock)); ASSERT_EQ(0, pthread_mutex_unlock(&lock));
ASSERT_EQ(0, pthread_mutex_destroy(&lock)); ASSERT_EQ(0, pthread_mutex_destroy(&lock));
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
} }
TEST(pthread_mutex_lock, errorcheck) { TEST(pthread_mutex_lock, errorcheck) {
@ -81,13 +82,13 @@ TEST(pthread_mutex_lock, errorcheck) {
ASSERT_EQ(0, pthread_mutexattr_init(&attr)); ASSERT_EQ(0, pthread_mutexattr_init(&attr));
ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)); ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK));
ASSERT_EQ(0, pthread_mutex_init(&lock, &attr)); ASSERT_EQ(0, pthread_mutex_init(&lock, &attr));
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
ASSERT_EQ(EPERM, pthread_mutex_unlock(&lock)); ASSERT_EQ(EPERM, pthread_mutex_unlock(&lock));
ASSERT_EQ(0, pthread_mutex_lock(&lock)); ASSERT_EQ(0, pthread_mutex_lock(&lock));
ASSERT_EQ(EDEADLK, pthread_mutex_lock(&lock)); ASSERT_EQ(EDEADLK, pthread_mutex_lock(&lock));
ASSERT_EQ(0, pthread_mutex_unlock(&lock)); ASSERT_EQ(0, pthread_mutex_unlock(&lock));
ASSERT_EQ(EPERM, pthread_mutex_unlock(&lock)); ASSERT_EQ(EPERM, pthread_mutex_unlock(&lock));
ASSERT_EQ(0, pthread_mutex_destroy(&lock)); ASSERT_EQ(0, pthread_mutex_destroy(&lock));
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
} }
int count; int count;
@ -107,6 +108,11 @@ int MutexWorker(void *p) {
TEST(pthread_mutex_lock, contention) { TEST(pthread_mutex_lock, contention) {
int i; int i;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
pthread_mutex_init(&lock, &attr);
pthread_mutexattr_destroy(&attr);
count = 0; count = 0;
for (i = 0; i < THREADS; ++i) { for (i = 0; i < THREADS; ++i) {
clone(MutexWorker, clone(MutexWorker,
@ -125,6 +131,63 @@ TEST(pthread_mutex_lock, contention) {
for (i = 0; i < THREADS; ++i) { for (i = 0; i < THREADS; ++i) {
munmap(stack[i], GetStackSize()); munmap(stack[i], GetStackSize());
} }
pthread_mutex_destroy(&lock);
}
TEST(pthread_mutex_lock, rcontention) {
int i;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&lock, &attr);
pthread_mutexattr_destroy(&attr);
count = 0;
for (i = 0; i < THREADS; ++i) {
clone(MutexWorker,
(stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
MAP_STACK | MAP_ANONYMOUS, -1, 0)),
GetStackSize(),
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS,
0, 0, __initialize_tls(tls[i]), sizeof(tls[i]),
(int *)(tls[i] + 0x38));
}
for (i = 0; i < THREADS; ++i) {
_wait0((int *)(tls[i] + 0x38));
}
ASSERT_EQ(THREADS * ITERATIONS, count);
for (i = 0; i < THREADS; ++i) {
munmap(stack[i], GetStackSize());
}
pthread_mutex_destroy(&lock);
}
TEST(pthread_mutex_lock, econtention) {
int i;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&lock, &attr);
pthread_mutexattr_destroy(&attr);
count = 0;
for (i = 0; i < THREADS; ++i) {
clone(MutexWorker,
(stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
MAP_STACK | MAP_ANONYMOUS, -1, 0)),
GetStackSize(),
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS,
0, 0, __initialize_tls(tls[i]), sizeof(tls[i]),
(int *)(tls[i] + 0x38));
}
for (i = 0; i < THREADS; ++i) {
_wait0((int *)(tls[i] + 0x38));
}
ASSERT_EQ(THREADS * ITERATIONS, count);
for (i = 0; i < THREADS; ++i) {
munmap(stack[i], GetStackSize());
}
pthread_mutex_destroy(&lock);
} }
int SpinlockWorker(void *p) { int SpinlockWorker(void *p) {
@ -165,14 +228,8 @@ TEST(_spinlock, contention) {
BENCH(pthread_mutex_lock, bench) { BENCH(pthread_mutex_lock, bench) {
char schar = 0; char schar = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
EZBENCH2("pthread_mutex_lock", donothing, EZBENCH2("_spinlock", donothing, _spinlock_contention());
(pthread_mutex_lock(&lock), pthread_mutex_unlock(&lock))); EZBENCH2("normal", donothing, pthread_mutex_lock_contention());
EZBENCH2("__fds_lock", donothing, (__fds_lock(), __fds_unlock())); EZBENCH2("recursive", donothing, pthread_mutex_lock_rcontention());
EZBENCH2("_spinlock", donothing, (_spinlock(&schar), _spunlock(&schar))); EZBENCH2("errorcheck", donothing, pthread_mutex_lock_econtention());
EZBENCH2("_spinlock_tiny", donothing,
(_spinlock_tiny(&schar), _spunlock(&schar)));
EZBENCH2("_spinlock_coop", donothing,
(_spinlock_cooperative(&schar), _spunlock(&schar)));
EZBENCH2("content mut", donothing, pthread_mutex_lock_contention());
EZBENCH2("content spin", donothing, _spinlock_contention());
} }

View file

@ -79,6 +79,7 @@ TEST(clone, testNullFunc_raisesEinval) {
int CloneTest1(void *arg) { int CloneTest1(void *arg) {
intptr_t rsp, top, bot; intptr_t rsp, top, bot;
CheckStackIsAligned(); CheckStackIsAligned();
PrintBacktraceUsingSymbols(2, __builtin_frame_address(0), GetSymbolTable());
rsp = (intptr_t)__builtin_frame_address(0); rsp = (intptr_t)__builtin_frame_address(0);
bot = (intptr_t)stack; bot = (intptr_t)stack;
top = bot + GetStackSize(); top = bot + GetStackSize();

View file

@ -30,7 +30,7 @@
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "libc/x/x.h" #include "libc/x/x.h"
#define THREADS 16 #define THREADS 32
#define DUB(i) (union Dub){i}.x #define DUB(i) (union Dub){i}.x
@ -61,10 +61,6 @@ int Worker(void *p) {
} }
TEST(dtoa, test) { TEST(dtoa, test) {
if (IsNetbsd()) {
// TODO(jart): Why does this flake on NetBSD?!
return;
}
int i; int i;
for (i = 0; i < THREADS; ++i) { for (i = 0; i < THREADS; ++i) {
clone(Worker, clone(Worker,

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/runtime/internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/testlib/ezbench.h" #include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
@ -63,11 +64,15 @@ TEST(fgetc, testUnbuffered) {
} }
BENCH(fputc, bench) { BENCH(fputc, bench) {
__enable_tls();
__enable_threads();
FILE *f; FILE *f;
ASSERT_NE(NULL, (f = fopen("/dev/null", "w"))); ASSERT_NE(NULL, (f = fopen("/dev/null", "w")));
EZBENCH2("fputc", donothing, fputc('E', f)); EZBENCH2("fputc", donothing, fputc('E', f));
flockfile(f); flockfile(f);
flockfile(f);
EZBENCH2("fputc_unlocked", donothing, fputc_unlocked('E', f)); EZBENCH2("fputc_unlocked", donothing, fputc_unlocked('E', f));
funlockfile(f); funlockfile(f);
funlockfile(f);
fclose(f); fclose(f);
} }

View file

@ -35,30 +35,30 @@
void void
freedtoa(char *s) freedtoa(char *s)
{ {
ThInfo *TI = 0;
Bigint *b = (Bigint *)((int *)s - 1); Bigint *b = (Bigint *)((int *)s - 1);
b->maxwds = 1 << (b->k = *(int *)b); b->maxwds = 1 << (b->k = *(int *)b);
__gdtoa_Bfree(b); __gdtoa_Bfree(b, &TI);
} }
char * char *
__gdtoa_rv_alloc(int i) __gdtoa_rv_alloc(int i, ThInfo **PTI)
{ {
int j, k, *r; int j, k, *r;
j = sizeof(ULong); j = sizeof(ULong);
for(k = 0; for (k = 0; (int)(sizeof(Bigint) - sizeof(ULong) - sizeof(int)) + j <= i;
(int)(sizeof(Bigint) - sizeof(ULong) - sizeof(int)) + j <= i;
j <<= 1) j <<= 1)
k++; k++;
r = (int*)__gdtoa_Balloc(k); r = (int *)__gdtoa_Balloc(k, PTI);
*r = k; *r = k;
return (char *)(r + 1); return (char *)(r + 1);
} }
char * char *
__gdtoa_nrv_alloc(char *s, char **rve, int n) __gdtoa_nrv_alloc(char *s, char **rve, int n, ThInfo **PTI)
{ {
char *rv, *t; char *rv, *t;
t = rv = __gdtoa_rv_alloc(n); t = rv = __gdtoa_rv_alloc(n, PTI);
while ((*t = *s++) != 0) while ((*t = *s++) != 0)
t++; t++;
if (rve) if (rve)

View file

@ -103,6 +103,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
Sufficient space is allocated to the return value Sufficient space is allocated to the return value
to hold the suppressed trailing zeros. to hold the suppressed trailing zeros.
*/ */
ThInfo *TI = 0;
int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
spec_case, try_quick; spec_case, try_quick;
@ -128,12 +129,12 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
/* Infinity or NaN */ /* Infinity or NaN */
*decpt = 9999; *decpt = 9999;
if (!word1(&d) && !(word0(&d) & 0xfffff)) if (!word1(&d) && !(word0(&d) & 0xfffff))
return __gdtoa_nrv_alloc("Infinity", rve, 8); return __gdtoa_nrv_alloc("Infinity", rve, 8, &TI);
return __gdtoa_nrv_alloc("NaN", rve, 3); return __gdtoa_nrv_alloc("NaN", rve, 3, &TI);
} }
if (!dval(&d)) { if (!dval(&d)) {
*decpt = 1; *decpt = 1;
return __gdtoa_nrv_alloc("0", rve, 1); return __gdtoa_nrv_alloc("0", rve, 1, &TI);
} }
if (Rounding >= 2) { if (Rounding >= 2) {
if (*sign) if (*sign)
@ -142,7 +143,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
if (Rounding != 2) if (Rounding != 2)
Rounding = 0; Rounding = 0;
} }
b = __gdtoa_d2b(dval(&d), &be, &bbits); b = __gdtoa_d2b(dval(&d), &be, &bbits, &TI);
if (( i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) { if (( i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) {
dval(&d2) = dval(&d); dval(&d2) = dval(&d);
word0(&d2) &= Frac_mask1; word0(&d2) &= Frac_mask1;
@ -245,7 +246,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
if (i <= 0) if (i <= 0)
i = 1; i = 1;
} }
s = s0 = __gdtoa_rv_alloc(i); s = s0 = __gdtoa_rv_alloc(i, &TI);
if (mode > 1 && Rounding != 1) if (mode > 1 && Rounding != 1)
leftright = 0; leftright = 0;
if (ilim >= 0 && ilim <= Quick_max && try_quick) { if (ilim >= 0 && ilim <= Quick_max && try_quick) {
@ -409,7 +410,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
i = denorm ? be + (Bias + (P-1) - 1 + 1) : 1 + P - bbits; i = denorm ? be + (Bias + (P-1) - 1 + 1) : 1 + P - bbits;
b2 += i; b2 += i;
s2 += i; s2 += i;
mhi = __gdtoa_i2b(1); mhi = __gdtoa_i2b(1, &TI);
} }
if (m2 > 0 && s2 > 0) { if (m2 > 0 && s2 > 0) {
i = m2 < s2 ? m2 : s2; i = m2 < s2 ? m2 : s2;
@ -420,20 +421,20 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
if (b5 > 0) { if (b5 > 0) {
if (leftright) { if (leftright) {
if (m5 > 0) { if (m5 > 0) {
mhi = __gdtoa_pow5mult(mhi, m5); mhi = __gdtoa_pow5mult(mhi, m5, &TI);
b1 = __gdtoa_mult(mhi, b); b1 = __gdtoa_mult(mhi, b, &TI);
__gdtoa_Bfree(b); __gdtoa_Bfree(b, &TI);
b = b1; b = b1;
} }
if (( j = b5 - m5 )!=0) if (( j = b5 - m5 )!=0)
b = __gdtoa_pow5mult(b, j); b = __gdtoa_pow5mult(b, j, &TI);
} }
else else
b = __gdtoa_pow5mult(b, b5); b = __gdtoa_pow5mult(b, b5, &TI);
} }
S = __gdtoa_i2b(1); S = __gdtoa_i2b(1, &TI);
if (s5 > 0) if (s5 > 0)
S = __gdtoa_pow5mult(S, s5); S = __gdtoa_pow5mult(S, s5, &TI);
/* Check for special case that d is a normalized power of 2. */ /* Check for special case that d is a normalized power of 2. */
spec_case = 0; spec_case = 0;
@ -469,20 +470,20 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
s2 += i; s2 += i;
} }
if (b2 > 0) if (b2 > 0)
b = __gdtoa_lshift(b, b2); b = __gdtoa_lshift(b, b2, &TI);
if (s2 > 0) if (s2 > 0)
S = __gdtoa_lshift(S, s2); S = __gdtoa_lshift(S, s2, &TI);
if (k_check) { if (k_check) {
if (__gdtoa_cmp(b,S) < 0) { if (__gdtoa_cmp(b,S) < 0) {
k--; k--;
b = __gdtoa_multadd(b, 10, 0); /* we botched the k estimate */ b = __gdtoa_multadd(b, 10, 0, &TI); /* we botched the k estimate */
if (leftright) if (leftright)
mhi = __gdtoa_multadd(mhi, 10, 0); mhi = __gdtoa_multadd(mhi, 10, 0, &TI);
ilim = ilim1; ilim = ilim1;
} }
} }
if (ilim <= 0 && (mode == 3 || mode == 5)) { if (ilim <= 0 && (mode == 3 || mode == 5)) {
if (ilim < 0 || __gdtoa_cmp(b,S = __gdtoa_multadd(S,5,0)) <= 0) { if (ilim < 0 || __gdtoa_cmp(b,S = __gdtoa_multadd(S,5,0,&TI)) <= 0) {
/* no digits, fcvt style */ /* no digits, fcvt style */
no_digits: no_digits:
k = -1 - ndigits; k = -1 - ndigits;
@ -495,15 +496,15 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
} }
if (leftright) { if (leftright) {
if (m2 > 0) if (m2 > 0)
mhi = __gdtoa_lshift(mhi, m2); mhi = __gdtoa_lshift(mhi, m2, &TI);
/* Compute mlo -- check for special case /* Compute mlo -- check for special case
* that d is a normalized power of 2. * that d is a normalized power of 2.
*/ */
mlo = mhi; mlo = mhi;
if (spec_case) { if (spec_case) {
mhi = __gdtoa_Balloc(mhi->k); mhi = __gdtoa_Balloc(mhi->k, &TI);
Bcopy(mhi, mlo); Bcopy(mhi, mlo);
mhi = __gdtoa_lshift(mhi, Log2P); mhi = __gdtoa_lshift(mhi, Log2P, &TI);
} }
for(i = 1;;i++) { for(i = 1;;i++) {
dig = __gdtoa_quorem(b,S) + '0'; dig = __gdtoa_quorem(b,S) + '0';
@ -511,9 +512,9 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
* that will round to d? * that will round to d?
*/ */
j = __gdtoa_cmp(b, mlo); j = __gdtoa_cmp(b, mlo);
delta = __gdtoa_diff(S, mhi); delta = __gdtoa_diff(S, mhi, &TI);
j1 = delta->sign ? 1 : __gdtoa_cmp(b, delta); j1 = delta->sign ? 1 : __gdtoa_cmp(b, delta);
__gdtoa_Bfree(delta); __gdtoa_Bfree(delta, &TI);
if (j1 == 0 && mode != 1 && !(word1(&d) & 1) && Rounding >= 1) { if (j1 == 0 && mode != 1 && !(word1(&d) & 1) && Rounding >= 1) {
if (dig == '9') if (dig == '9')
goto round_9_up; goto round_9_up;
@ -533,7 +534,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
case 2: goto keep_dig; case 2: goto keep_dig;
} }
if (j1 > 0) { if (j1 > 0) {
b = __gdtoa_lshift(b, 1); b = __gdtoa_lshift(b, 1, &TI);
j1 = __gdtoa_cmp(b, S); j1 = __gdtoa_cmp(b, S);
if ((j1 > 0 || (j1 == 0 && dig & 1)) if ((j1 > 0 || (j1 == 0 && dig & 1))
&& dig++ == '9') && dig++ == '9')
@ -558,12 +559,12 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
*s++ = dig; *s++ = dig;
if (i == ilim) if (i == ilim)
break; break;
b = __gdtoa_multadd(b, 10, 0); b = __gdtoa_multadd(b, 10, 0, &TI);
if (mlo == mhi) if (mlo == mhi)
mlo = mhi = __gdtoa_multadd(mhi, 10, 0); mlo = mhi = __gdtoa_multadd(mhi, 10, 0, &TI);
else { else {
mlo = __gdtoa_multadd(mlo, 10, 0); mlo = __gdtoa_multadd(mlo, 10, 0, &TI);
mhi = __gdtoa_multadd(mhi, 10, 0); mhi = __gdtoa_multadd(mhi, 10, 0, &TI);
} }
} }
} }
@ -575,7 +576,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
} }
if (i >= ilim) if (i >= ilim)
break; break;
b = __gdtoa_multadd(b, 10, 0); b = __gdtoa_multadd(b, 10, 0, &TI);
} }
} }
@ -584,7 +585,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
case 0: goto trimzeros; case 0: goto trimzeros;
case 2: goto roundoff; case 2: goto roundoff;
} }
b = __gdtoa_lshift(b, 1); b = __gdtoa_lshift(b, 1, &TI);
j = __gdtoa_cmp(b, S); j = __gdtoa_cmp(b, S);
if (j > 0 || (j == 0 && dig & 1)) if (j > 0 || (j == 0 && dig & 1))
{ {
@ -603,17 +604,17 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
s++; s++;
} }
ret: ret:
__gdtoa_Bfree(S); __gdtoa_Bfree(S, &TI);
if (mhi) { if (mhi) {
if (mlo && mlo != mhi) if (mlo && mlo != mhi)
__gdtoa_Bfree(mlo); __gdtoa_Bfree(mlo, &TI);
__gdtoa_Bfree(mhi); __gdtoa_Bfree(mhi, &TI);
} }
retc: retc:
while(s > s0 && s[-1] == '0') while(s > s0 && s[-1] == '0')
--s; --s;
ret1: ret1:
__gdtoa_Bfree(b); __gdtoa_Bfree(b, &TI);
*s = 0; *s = 0;
*decpt = k + 1; *decpt = k + 1;
if (rve) if (rve)

View file

@ -42,6 +42,7 @@ g_ddfmt(char *buf, double *dd0, int ndig, size_t bufsize)
int bx, by, decpt, ex, ey, i, j, mode; int bx, by, decpt, ex, ey, i, j, mode;
Bigint *x, *y, *z; Bigint *x, *y, *z;
U *dd, ddx[2]; U *dd, ddx[2];
ThInfo *TI = 0;
if (bufsize < 10 || bufsize < (size_t)(ndig + 8)) if (bufsize < 10 || bufsize < (size_t)(ndig + 8))
return 0; return 0;
dd = (U*)dd0; dd = (U*)dd0;
@ -84,31 +85,31 @@ g_ddfmt(char *buf, double *dd0, int ndig, size_t bufsize)
dd = ddx; dd = ddx;
L = dd->L; L = dd->L;
} }
z = __gdtoa_d2b(dval(&dd[0]), &ex, &bx); z = __gdtoa_d2b(dval(&dd[0]), &ex, &bx, &TI);
if (dval(&dd[1]) == 0.) if (dval(&dd[1]) == 0.)
goto no_y; goto no_y;
x = z; x = z;
y = __gdtoa_d2b(dval(&dd[1]), &ey, &by); y = __gdtoa_d2b(dval(&dd[1]), &ey, &by, &TI);
if ( (i = ex - ey) !=0) { if ( (i = ex - ey) !=0) {
if (i > 0) { if (i > 0) {
x = __gdtoa_lshift(x, i); x = __gdtoa_lshift(x, i, &TI);
ex = ey; ex = ey;
} }
else else
y = __gdtoa_lshift(y, -i); y = __gdtoa_lshift(y, -i, &TI);
} }
if ((L[1] ^ L[2+1]) & 0x80000000L) { if ((L[1] ^ L[2+1]) & 0x80000000L) {
z = __gdtoa_diff(x, y); z = __gdtoa_diff(x, y, &TI);
if (L[1] & 0x80000000L) if (L[1] & 0x80000000L)
z->sign = 1 - z->sign; z->sign = 1 - z->sign;
} }
else { else {
z = __gdtoa_sum(x, y); z = __gdtoa_sum(x, y, &TI);
if (L[1] & 0x80000000L) if (L[1] & 0x80000000L)
z->sign = 1; z->sign = 1;
} }
__gdtoa_Bfree(x); __gdtoa_Bfree(x, &TI);
__gdtoa_Bfree(y); __gdtoa_Bfree(y, &TI);
no_y: no_y:
bits = zx = z->x; bits = zx = z->x;
for(i = 0; !*zx; zx++) for(i = 0; !*zx; zx++)
@ -132,7 +133,7 @@ no_y:
mode = 2; mode = 2;
if (ndig <= 0) { if (ndig <= 0) {
if (bufsize < (size_t)(fpi.nbits * .301029995664) + 10) { if (bufsize < (size_t)(fpi.nbits * .301029995664) + 10) {
__gdtoa_Bfree(z); __gdtoa_Bfree(z, &TI);
return 0; return 0;
} }
mode = 0; mode = 0;
@ -145,6 +146,6 @@ no_y:
i = STRTOG_Normal; i = STRTOG_Normal;
s = gdtoa(&fpi, ex, bits, &i, mode, ndig, &decpt, &se); s = gdtoa(&fpi, ex, bits, &i, mode, ndig, &decpt, &se);
b = __gdtoa_g__fmt(buf, s, se, decpt, z->sign, bufsize); b = __gdtoa_g__fmt(buf, s, se, decpt, z->sign, bufsize);
__gdtoa_Bfree(z); __gdtoa_Bfree(z, &TI);
return b; return b;
} }

View file

@ -45,6 +45,7 @@ g_ddfmt_p(char *buf, double *dd0, int ndig, size_t bufsize, int nik)
int bx, by, decpt, ex, ey, i, j, mode; int bx, by, decpt, ex, ey, i, j, mode;
Bigint *x, *y, *z; Bigint *x, *y, *z;
U *dd, ddx[2]; U *dd, ddx[2];
ThInfo *TI = 0;
if (bufsize < 10 || bufsize < (size_t)(ndig + 8)) if (bufsize < 10 || bufsize < (size_t)(ndig + 8))
return 0; return 0;
dd = (U*)dd0; dd = (U*)dd0;
@ -105,31 +106,31 @@ g_ddfmt_p(char *buf, double *dd0, int ndig, size_t bufsize, int nik)
dd = ddx; dd = ddx;
L = dd->L; L = dd->L;
} }
z = __gdtoa_d2b(dval(&dd[0]), &ex, &bx); z = __gdtoa_d2b(dval(&dd[0]), &ex, &bx, &TI);
if (dval(&dd[1]) == 0.) if (dval(&dd[1]) == 0.)
goto no_y; goto no_y;
x = z; x = z;
y = __gdtoa_d2b(dval(&dd[1]), &ey, &by); y = __gdtoa_d2b(dval(&dd[1]), &ey, &by, &TI);
if ( (i = ex - ey) !=0) { if ( (i = ex - ey) !=0) {
if (i > 0) { if (i > 0) {
x = __gdtoa_lshift(x, i); x = __gdtoa_lshift(x, i, &TI);
ex = ey; ex = ey;
} }
else else
y = __gdtoa_lshift(y, -i); y = __gdtoa_lshift(y, -i, &TI);
} }
if ((L[1] ^ L[2+1]) & 0x80000000L) { if ((L[1] ^ L[2+1]) & 0x80000000L) {
z = __gdtoa_diff(x, y); z = __gdtoa_diff(x, y, &TI);
if (L[1] & 0x80000000L) if (L[1] & 0x80000000L)
z->sign = 1 - z->sign; z->sign = 1 - z->sign;
} }
else { else {
z = __gdtoa_sum(x, y); z = __gdtoa_sum(x, y, &TI);
if (L[1] & 0x80000000L) if (L[1] & 0x80000000L)
z->sign = 1; z->sign = 1;
} }
__gdtoa_Bfree(x); __gdtoa_Bfree(x, &TI);
__gdtoa_Bfree(y); __gdtoa_Bfree(y, &TI);
no_y: no_y:
bits = zx = z->x; bits = zx = z->x;
for(i = 0; !*zx; zx++) for(i = 0; !*zx; zx++)
@ -153,7 +154,7 @@ no_y:
mode = 2; mode = 2;
if (ndig <= 0) { if (ndig <= 0) {
if (bufsize < (size_t)(fpi.nbits * .301029995664) + 10) { if (bufsize < (size_t)(fpi.nbits * .301029995664) + 10) {
__gdtoa_Bfree(z); __gdtoa_Bfree(z, &TI);
return 0; return 0;
} }
mode = 0; mode = 0;
@ -166,6 +167,6 @@ no_y:
i = STRTOG_Normal; i = STRTOG_Normal;
s = gdtoa(&fpi, ex, bits, &i, mode, ndig, &decpt, &se); s = gdtoa(&fpi, ex, bits, &i, mode, ndig, &decpt, &se);
b = __gdtoa_g__fmt(buf, s, se, decpt, z->sign, bufsize); b = __gdtoa_g__fmt(buf, s, se, decpt, z->sign, bufsize);
__gdtoa_Bfree(z); __gdtoa_Bfree(z, &TI);
return b; return b;
} }

View file

@ -33,7 +33,7 @@
/* clang-format off */ /* clang-format off */
static Bigint * static Bigint *
bitstob(ULong *bits, int nbits, int *bbits) bitstob(ULong *bits, int nbits, int *bbits, ThInfo **PTI)
{ {
int i, k; int i, k;
Bigint *b; Bigint *b;
@ -44,7 +44,7 @@ bitstob(ULong *bits, int nbits, int *bbits)
i <<= 1; i <<= 1;
k++; k++;
} }
b = __gdtoa_Balloc(k); b = __gdtoa_Balloc(k, PTI);
be = bits + ((nbits - 1) >> kshift); be = bits + ((nbits - 1) >> kshift);
x = x0 = b->x; x = x0 = b->x;
do { do {
@ -135,6 +135,7 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
to hold the suppressed trailing zeros. to hold the suppressed trailing zeros.
*/ */
ThInfo *TI = 0;
int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex; int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex;
int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits; int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits;
int rdir, s2, s5, spec_case, try_quick; int rdir, s2, s5, spec_case, try_quick;
@ -153,14 +154,14 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
break; break;
case STRTOG_Infinite: case STRTOG_Infinite:
*decpt = -32768; *decpt = -32768;
return __gdtoa_nrv_alloc("Infinity", rve, 8); return __gdtoa_nrv_alloc("Infinity", rve, 8, &TI);
case STRTOG_NaN: case STRTOG_NaN:
*decpt = -32768; *decpt = -32768;
return __gdtoa_nrv_alloc("NaN", rve, 3); return __gdtoa_nrv_alloc("NaN", rve, 3, &TI);
default: default:
return 0; return 0;
} }
b = bitstob(bits, nbits = fpi->nbits, &bbits); b = bitstob(bits, nbits = fpi->nbits, &bbits, &TI);
be0 = be; be0 = be;
if ( (i = __gdtoa_trailz(b)) !=0) { if ( (i = __gdtoa_trailz(b)) !=0) {
__gdtoa_rshift(b, i); __gdtoa_rshift(b, i);
@ -168,10 +169,10 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
bbits -= i; bbits -= i;
} }
if (!b->wds) { if (!b->wds) {
__gdtoa_Bfree(b); __gdtoa_Bfree(b, &TI);
ret_zero: ret_zero:
*decpt = 1; *decpt = 1;
return __gdtoa_nrv_alloc("0", rve, 1); return __gdtoa_nrv_alloc("0", rve, 1, &TI);
} }
dval(&d) = __gdtoa_b2d(b, &i); dval(&d) = __gdtoa_b2d(b, &i);
i = be + bbits - 1; i = be + bbits - 1;
@ -285,7 +286,7 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
if (i <= 0) if (i <= 0)
i = 1; i = 1;
} }
s = s0 = __gdtoa_rv_alloc(i); s = s0 = __gdtoa_rv_alloc(i, &TI);
if (mode <= 1) if (mode <= 1)
rdir = 0; rdir = 0;
else if ( (rdir = fpi->rounding - 1) !=0) { else if ( (rdir = fpi->rounding - 1) !=0) {
@ -471,7 +472,7 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
} }
b2 += i; b2 += i;
s2 += i; s2 += i;
mhi = __gdtoa_i2b(1); mhi = __gdtoa_i2b(1, &TI);
} }
if (m2 > 0 && s2 > 0) { if (m2 > 0 && s2 > 0) {
i = m2 < s2 ? m2 : s2; i = m2 < s2 ? m2 : s2;
@ -482,20 +483,20 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
if (b5 > 0) { if (b5 > 0) {
if (leftright) { if (leftright) {
if (m5 > 0) { if (m5 > 0) {
mhi = __gdtoa_pow5mult(mhi, m5); mhi = __gdtoa_pow5mult(mhi, m5, &TI);
b1 = __gdtoa_mult(mhi, b); b1 = __gdtoa_mult(mhi, b, &TI);
__gdtoa_Bfree(b); __gdtoa_Bfree(b, &TI);
b = b1; b = b1;
} }
if ( (j = b5 - m5) !=0) if ( (j = b5 - m5) !=0)
b = __gdtoa_pow5mult(b, j); b = __gdtoa_pow5mult(b, j, &TI);
} }
else else
b = __gdtoa_pow5mult(b, b5); b = __gdtoa_pow5mult(b, b5, &TI);
} }
S = __gdtoa_i2b(1); S = __gdtoa_i2b(1, &TI);
if (s5 > 0) if (s5 > 0)
S = __gdtoa_pow5mult(S, s5); S = __gdtoa_pow5mult(S, s5, &TI);
/* Check for special case that d is a normalized power of 2. */ /* Check for special case that d is a normalized power of 2. */
spec_case = 0; spec_case = 0;
if (mode < 2) { if (mode < 2) {
@ -516,20 +517,20 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
i = ((s5 ? hi0bits(S->x[S->wds-1]) : ULbits - 1) - s2 - 4) & kmask; i = ((s5 ? hi0bits(S->x[S->wds-1]) : ULbits - 1) - s2 - 4) & kmask;
m2 += i; m2 += i;
if ((b2 += i) > 0) if ((b2 += i) > 0)
b = __gdtoa_lshift(b, b2); b = __gdtoa_lshift(b, b2, &TI);
if ((s2 += i) > 0) if ((s2 += i) > 0)
S = __gdtoa_lshift(S, s2); S = __gdtoa_lshift(S, s2, &TI);
if (k_check) { if (k_check) {
if (__gdtoa_cmp(b,S) < 0) { if (__gdtoa_cmp(b,S) < 0) {
k--; k--;
b = __gdtoa_multadd(b, 10, 0); /* we botched the k estimate */ b = __gdtoa_multadd(b, 10, 0, &TI); /* we botched the k estimate */
if (leftright) if (leftright)
mhi = __gdtoa_multadd(mhi, 10, 0); mhi = __gdtoa_multadd(mhi, 10, 0, &TI);
ilim = ilim1; ilim = ilim1;
} }
} }
if (ilim <= 0 && mode > 2) { if (ilim <= 0 && mode > 2) {
if (ilim < 0 || __gdtoa_cmp(b,S = __gdtoa_multadd(S,5,0)) <= 0) { if (ilim < 0 || __gdtoa_cmp(b,S = __gdtoa_multadd(S,5,0,&TI)) <= 0) {
/* no digits, fcvt style */ /* no digits, fcvt style */
no_digits: no_digits:
k = -1 - ndigits; k = -1 - ndigits;
@ -544,15 +545,15 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
} }
if (leftright) { if (leftright) {
if (m2 > 0) if (m2 > 0)
mhi = __gdtoa_lshift(mhi, m2); mhi = __gdtoa_lshift(mhi, m2, &TI);
/* Compute mlo -- check for special case /* Compute mlo -- check for special case
* that d is a normalized power of 2. * that d is a normalized power of 2.
*/ */
mlo = mhi; mlo = mhi;
if (spec_case) { if (spec_case) {
mhi = __gdtoa_Balloc(mhi->k); mhi = __gdtoa_Balloc(mhi->k, &TI);
Bcopy(mhi, mlo); Bcopy(mhi, mlo);
mhi = __gdtoa_lshift(mhi, 1); mhi = __gdtoa_lshift(mhi, 1, &TI);
} }
for(i = 1;;i++) { for(i = 1;;i++) {
dig = __gdtoa_quorem(b,S) + '0'; dig = __gdtoa_quorem(b,S) + '0';
@ -560,9 +561,9 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
* that will round to d? * that will round to d?
*/ */
j = __gdtoa_cmp(b, mlo); j = __gdtoa_cmp(b, mlo);
delta = __gdtoa_diff(S, mhi); delta = __gdtoa_diff(S, mhi, &TI);
j1 = delta->sign ? 1 : __gdtoa_cmp(b, delta); j1 = delta->sign ? 1 : __gdtoa_cmp(b, delta);
__gdtoa_Bfree(delta); __gdtoa_Bfree(delta, &TI);
if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) { if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) {
if (dig == '9') if (dig == '9')
goto round_9_up; goto round_9_up;
@ -585,11 +586,11 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
} }
while (__gdtoa_cmp(S,mhi) > 0) { while (__gdtoa_cmp(S,mhi) > 0) {
*s++ = dig; *s++ = dig;
mhi1 = __gdtoa_multadd(mhi, 10, 0); mhi1 = __gdtoa_multadd(mhi, 10, 0, &TI);
if (mlo == mhi) if (mlo == mhi)
mlo = mhi1; mlo = mhi1;
mhi = mhi1; mhi = mhi1;
b = __gdtoa_multadd(b, 10, 0); b = __gdtoa_multadd(b, 10, 0, &TI);
dig = __gdtoa_quorem(b,S) + '0'; dig = __gdtoa_quorem(b,S) + '0';
} }
if (dig++ == '9') if (dig++ == '9')
@ -598,7 +599,7 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
goto accept; goto accept;
} }
if (j1 > 0) { if (j1 > 0) {
b = __gdtoa_lshift(b, 1); b = __gdtoa_lshift(b, 1, &TI);
j1 = __gdtoa_cmp(b, S); j1 = __gdtoa_cmp(b, S);
if ((j1 > 0 || (j1 == 0 && dig & 1)) && dig++ == '9') if ((j1 > 0 || (j1 == 0 && dig & 1)) && dig++ == '9')
goto round_9_up; goto round_9_up;
@ -624,12 +625,12 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
*s++ = dig; *s++ = dig;
if (i == ilim) if (i == ilim)
break; break;
b = __gdtoa_multadd(b, 10, 0); b = __gdtoa_multadd(b, 10, 0, &TI);
if (mlo == mhi) if (mlo == mhi)
mlo = mhi = __gdtoa_multadd(mhi, 10, 0); mlo = mhi = __gdtoa_multadd(mhi, 10, 0, &TI);
else { else {
mlo = __gdtoa_multadd(mlo, 10, 0); mlo = __gdtoa_multadd(mlo, 10, 0, &TI);
mhi = __gdtoa_multadd(mhi, 10, 0); mhi = __gdtoa_multadd(mhi, 10, 0, &TI);
} }
} }
} }
@ -638,7 +639,7 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
*s++ = dig = __gdtoa_quorem(b,S) + '0'; *s++ = dig = __gdtoa_quorem(b,S) + '0';
if (i >= ilim) if (i >= ilim)
break; break;
b = __gdtoa_multadd(b, 10, 0); b = __gdtoa_multadd(b, 10, 0, &TI);
} }
/* Round off last digit */ /* Round off last digit */
if (rdir) { if (rdir) {
@ -646,7 +647,7 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
goto chopzeros; goto chopzeros;
goto roundoff; goto roundoff;
} }
b = __gdtoa_lshift(b, 1); b = __gdtoa_lshift(b, 1, &TI);
j = __gdtoa_cmp(b, S); j = __gdtoa_cmp(b, S);
if (j > 0 || (j == 0 && dig & 1)) if (j > 0 || (j == 0 && dig & 1))
{ {
@ -666,16 +667,16 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
inex = STRTOG_Inexlo; inex = STRTOG_Inexlo;
} }
ret: ret:
__gdtoa_Bfree(S); __gdtoa_Bfree(S, &TI);
if (mhi) { if (mhi) {
if (mlo && mlo != mhi) if (mlo && mlo != mhi)
__gdtoa_Bfree(mlo); __gdtoa_Bfree(mlo, &TI);
__gdtoa_Bfree(mhi); __gdtoa_Bfree(mhi, &TI);
} }
ret1: ret1:
while(s > s0 && s[-1] == '0') while(s > s0 && s[-1] == '0')
--s; --s;
__gdtoa_Bfree(b); __gdtoa_Bfree(b, &TI);
*s = 0; *s = 0;
*decpt = k + 1; *decpt = k + 1;
if (rve) if (rve)

View file

@ -355,35 +355,37 @@ hidden extern const unsigned char __gdtoa_hexdig[];
hidden extern const char *const __gdtoa_InfName[6]; hidden extern const char *const __gdtoa_InfName[6];
hidden extern const char *const __gdtoa_NanName[3]; hidden extern const char *const __gdtoa_NanName[3];
Bigint *__gdtoa_Balloc(int); Bigint *__gdtoa_Balloc(int, ThInfo **);
Bigint *__gdtoa_d2b(double, int *, int *); void __gdtoa_Bfree(Bigint *, ThInfo **);
Bigint *__gdtoa_diff(Bigint *, Bigint *); Bigint *__gdtoa_d2b(double, int *, int *, ThInfo **);
Bigint *__gdtoa_i2b(int); Bigint *__gdtoa_diff(Bigint *, Bigint *, ThInfo **);
Bigint *__gdtoa_increment(Bigint *); int __gdtoa_gethex(const char **, const FPI *, int *, Bigint **, int,
Bigint *__gdtoa_lshift(Bigint *, int); ThInfo **);
Bigint *__gdtoa_mult(Bigint *, Bigint *); Bigint *__gdtoa_i2b(int, ThInfo **);
Bigint *__gdtoa_multadd(Bigint *, int, int); Bigint *__gdtoa_increment(Bigint *, ThInfo **);
Bigint *__gdtoa_s2b(const char *, int, int, ULong, int); Bigint *__gdtoa_lshift(Bigint *, int, ThInfo **);
Bigint *__gdtoa_set_ones(Bigint *, int); Bigint *__gdtoa_mult(Bigint *, Bigint *, ThInfo **);
Bigint *__gdtoa_sum(Bigint *, Bigint *); Bigint *__gdtoa_multadd(Bigint *, int, int, ThInfo **);
Bigint *__gdtoa_pow5mult(Bigint *, int); char *__gdtoa_nrv_alloc(char *, char **, int, ThInfo **);
char *__gdtoa_rv_alloc(int, ThInfo **);
Bigint *__gdtoa_pow5mult(Bigint *, int, ThInfo **);
Bigint *__gdtoa_s2b(const char *, int, int, ULong, int, ThInfo **);
Bigint *__gdtoa_set_ones(Bigint *, int, ThInfo **);
Bigint *__gdtoa_sum(Bigint *, Bigint *, ThInfo **);
ULong __gdtoa_any_on(Bigint *, int); ULong __gdtoa_any_on(Bigint *, int);
char *__gdtoa_add_nanbits(char *, size_t, ULong *, int); char *__gdtoa_add_nanbits(char *, size_t, ULong *, int);
char *__gdtoa_g__fmt(char *, char *, char *, int, ULong, size_t); char *__gdtoa_g__fmt(char *, char *, char *, int, ULong, size_t);
char *__gdtoa_nrv_alloc(char *, char **, int);
char *__gdtoa_rv_alloc(int);
double __gdtoa_b2d(Bigint *, int *); double __gdtoa_b2d(Bigint *, int *);
double __gdtoa_ratio(Bigint *, Bigint *); double __gdtoa_ratio(Bigint *, Bigint *);
double __gdtoa_ulp(U *); double __gdtoa_ulp(U *);
int __gdtoa_cmp(Bigint *, Bigint *); int __gdtoa_cmp(Bigint *, Bigint *);
int __gdtoa_gethex(const char **, const FPI *, Long *, Bigint **, int);
int __gdtoa_hexnan(const char **, const FPI *, ULong *); int __gdtoa_hexnan(const char **, const FPI *, ULong *);
int __gdtoa_match(const char **, char *); int __gdtoa_match(const char **, char *);
int __gdtoa_quorem(Bigint *, Bigint *); int __gdtoa_quorem(Bigint *, Bigint *);
int __gdtoa_strtoIg(const char *, char **, const FPI *, Long *, Bigint **, int __gdtoa_strtoIg(const char *, char **, const FPI *, Long *, Bigint **,
int *); int *);
int __gdtoa_trailz(Bigint *); int __gdtoa_trailz(Bigint *);
void __gdtoa_Bfree(Bigint *);
void __gdtoa_ULtoQ(ULong *, ULong *, Long, int); void __gdtoa_ULtoQ(ULong *, ULong *, Long, int);
void __gdtoa_ULtod(ULong *, ULong *, Long, int); void __gdtoa_ULtod(ULong *, ULong *, Long, int);
void __gdtoa_ULtodd(ULong *, ULong *, Long, int); void __gdtoa_ULtodd(ULong *, ULong *, Long, int);

View file

@ -35,7 +35,7 @@
int int
__gdtoa_gethex(const char **sp, const FPI *fpi, __gdtoa_gethex(const char **sp, const FPI *fpi,
Long *exp, Bigint **bp, int sign) Long *exp, Bigint **bp, int sign, ThInfo **PTI)
{ {
Bigint *b; Bigint *b;
const unsigned char *decpt, *s0, *s, *s1; const unsigned char *decpt, *s0, *s, *s1;
@ -124,7 +124,7 @@ pcheck:
} }
goto retz; goto retz;
ret_tiny: ret_tiny:
b = __gdtoa_Balloc(0); b = __gdtoa_Balloc(0, PTI);
b->wds = 1; b->wds = 1;
b->x[0] = 1; b->x[0] = 1;
goto dret; goto dret;
@ -146,7 +146,7 @@ pcheck:
if (nbits & kmask) if (nbits & kmask)
++n; ++n;
for(j = n, k = 0; j >>= 1; ++k); for(j = n, k = 0; j >>= 1; ++k);
*bp = b = __gdtoa_Balloc(k); *bp = b = __gdtoa_Balloc(k, PTI);
b->wds = n; b->wds = n;
for(j = 0; j < n0; ++j) for(j = 0; j < n0; ++j)
b->x[j] = ALL_ON; b->x[j] = ALL_ON;
@ -158,7 +158,7 @@ pcheck:
n = s1 - s0 - 1; n = s1 - s0 - 1;
for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
k++; k++;
b = __gdtoa_Balloc(k); b = __gdtoa_Balloc(k, PTI);
x = b->x; x = b->x;
n = 0; n = 0;
L = 0; L = 0;
@ -195,13 +195,13 @@ pcheck:
} }
else if (n < nbits) { else if (n < nbits) {
n = nbits - n; n = nbits - n;
b = __gdtoa_lshift(b, n); b = __gdtoa_lshift(b, n, PTI);
e -= n; e -= n;
x = b->x; x = b->x;
} }
if (e > fpi->emax) { if (e > fpi->emax) {
ovfl: ovfl:
__gdtoa_Bfree(b); __gdtoa_Bfree(b, PTI);
ovfl1: ovfl1:
errno = ERANGE; errno = ERANGE;
switch (fpi->rounding) { switch (fpi->rounding) {
@ -243,7 +243,7 @@ pcheck:
| STRTOG_Underflow; | STRTOG_Underflow;
} }
} }
__gdtoa_Bfree(b); __gdtoa_Bfree(b, PTI);
retz: retz:
errno = ERANGE; errno = ERANGE;
return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
@ -277,7 +277,7 @@ pcheck:
} }
if (up) { if (up) {
k = b->wds; k = b->wds;
b = __gdtoa_increment(b); b = __gdtoa_increment(b, PTI);
x = b->x; x = b->x;
if (irv == STRTOG_Denormal) { if (irv == STRTOG_Denormal) {
if (nbits == fpi->nbits - 1 if (nbits == fpi->nbits - 1

View file

@ -20,6 +20,7 @@
#include "third_party/gdtoa/lock.h" #include "third_party/gdtoa/lock.h"
static pthread_mutex_t __gdtoa_lock_obj; static pthread_mutex_t __gdtoa_lock_obj;
static pthread_mutex_t __gdtoa_lock1_obj;
int(__gdtoa_lock)(void) { int(__gdtoa_lock)(void) {
return pthread_mutex_lock(&__gdtoa_lock_obj); return pthread_mutex_lock(&__gdtoa_lock_obj);
@ -28,3 +29,11 @@ int(__gdtoa_lock)(void) {
int(__gdtoa_unlock)(void) { int(__gdtoa_unlock)(void) {
return pthread_mutex_unlock(&__gdtoa_lock_obj); return pthread_mutex_unlock(&__gdtoa_lock_obj);
} }
int(__gdtoa_lock1)(void) {
return pthread_mutex_lock(&__gdtoa_lock1_obj);
}
int(__gdtoa_unlock1)(void) {
return pthread_mutex_unlock(&__gdtoa_lock1_obj);
}

View file

@ -7,13 +7,19 @@ COSMOPOLITAN_C_START_
int __gdtoa_lock(void); int __gdtoa_lock(void);
int __gdtoa_unlock(void); int __gdtoa_unlock(void);
int __gdtoa_lock1(void);
int __gdtoa_unlock1(void);
#if defined(__GNUC__) && !defined(__llvm__) && !defined(__STRICT_ANSI__) #if defined(__GNUC__) && !defined(__llvm__) && !defined(__STRICT_ANSI__)
#define __gdtoa_lock() _NOPL0("__threadcalls", __gdtoa_lock) #define __gdtoa_lock() _NOPL0("__threadcalls", __gdtoa_lock)
#define __gdtoa_unlock() _NOPL0("__threadcalls", __gdtoa_unlock) #define __gdtoa_unlock() _NOPL0("__threadcalls", __gdtoa_unlock)
#define __gdtoa_lock1() _NOPL0("__threadcalls", __gdtoa_lock1)
#define __gdtoa_unlock1() _NOPL0("__threadcalls", __gdtoa_unlock1)
#else #else
#define __gdtoa_lock() (__threaded ? __gdtoa_lock() : 0) #define __gdtoa_lock() (__threaded ? __gdtoa_lock() : 0)
#define __gdtoa_unlock() (__threaded ? __gdtoa_unlock() : 0) #define __gdtoa_unlock() (__threaded ? __gdtoa_unlock() : 0)
#define __gdtoa_lock1() (__threaded ? __gdtoa_lock1() : 0)
#define __gdtoa_unlock1() (__threaded ? __gdtoa_unlock1() : 0)
#endif #endif
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_

View file

@ -30,6 +30,7 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "third_party/gdtoa/gdtoa.internal.h" #include "third_party/gdtoa/gdtoa.internal.h"
@ -62,69 +63,80 @@ __attribute__((__constructor__)) static void
__gdtoa_Binit(void) __gdtoa_Binit(void)
{ {
atexit(__gdtoa_Bclear); atexit(__gdtoa_Bclear);
TI0.P5s = __gdtoa_i2b(625); }
TI0.P5s->next = 0;
static ThInfo *
__gdtoa_get_TI(void)
{
return &TI0;
} }
Bigint * Bigint *
__gdtoa_Balloc(int k) __gdtoa_Balloc(int k, ThInfo **PTI)
{ {
int x; int x;
Bigint *rv; Bigint *rv;
assert(k >= 0); unsigned int len;
ThInfo *TI;
if (!(TI = *PTI))
*PTI = TI = __gdtoa_get_TI();
if (TI == &TI0)
__gdtoa_lock(); __gdtoa_lock();
if (k <= Kmax && (rv = TI0.Freelist[k]) != 0) { if (k <= Kmax && (rv = TI->Freelist[k]) != 0) {
TI0.Freelist[k] = rv->next; TI->Freelist[k] = rv->next;
} else { } else {
x = 1 << k; x = 1 << k;
rv = malloc(sizeof(Bigint) + (x-1)*sizeof(ULong)); rv = malloc(sizeof(Bigint) + (x-1)*sizeof(ULong));
rv->k = k; rv->k = k;
rv->maxwds = x; rv->maxwds = x;
} }
rv->sign = 0; if (TI == &TI0)
rv->wds = 0;
__gdtoa_unlock(); __gdtoa_unlock();
rv->sign = rv->wds = 0;
return rv; return rv;
} }
void void
__gdtoa_Bfree(Bigint *v) __gdtoa_Bfree(Bigint *v, ThInfo **PTI)
{ {
ThInfo *TI;
if (v) { if (v) {
if (v->k > Kmax) { if (v->k > Kmax)
free(v); free((void *)v);
} else { else {
assert(v->k >= 0); if (!(TI = *PTI))
*PTI = TI = __gdtoa_get_TI();
if (TI == &TI0)
__gdtoa_lock(); __gdtoa_lock();
v->next = TI0.Freelist[v->k]; v->next = TI->Freelist[v->k];
TI0.Freelist[v->k] = v; TI->Freelist[v->k] = v;
if (TI == &TI0)
__gdtoa_unlock(); __gdtoa_unlock();
} }
} }
} }
Bigint * /* multiply by m and add a */ Bigint *
__gdtoa_multadd(Bigint *b, int m, int a) __gdtoa_multadd(Bigint *b, int m, int a, ThInfo **PTI)
{ {
int i, wds; int i, wds;
ULong *x; ULong *x;
ULLong carry, y; uint64_t carry, y;
Bigint *b1; Bigint *b1;
wds = b->wds; wds = b->wds;
x = b->x; x = b->x;
i = 0; i = 0;
carry = a; carry = a;
do { do {
y = *x * (ULLong)m + carry; y = *x * (uint64_t)m + carry;
carry = y >> 32; carry = y >> 32;
*x++ = y & 0xffffffffUL; *x++ = y & 0xffffffffUL;
} } while (++i < wds);
while(++i < wds);
if (carry) { if (carry) {
if (wds >= b->maxwds) { if (wds >= b->maxwds) {
b1 = __gdtoa_Balloc(b->k+1); b1 = __gdtoa_Balloc(b->k + 1, PTI);
Bcopy(b1, b); memcpy(&b1->sign, &b->sign, b->wds * sizeof(ULong) + 2 * sizeof(int));
__gdtoa_Bfree(b); __gdtoa_Bfree(b, PTI);
b = b1; b = b1;
} }
b->x[wds++] = carry; b->x[wds++] = carry;
@ -134,23 +146,23 @@ __gdtoa_multadd(Bigint *b, int m, int a)
} }
Bigint * Bigint *
__gdtoa_i2b(int i) __gdtoa_i2b(int i, ThInfo **PTI)
{ {
Bigint *b; Bigint *b;
b = __gdtoa_Balloc(1); b = __gdtoa_Balloc(1, PTI);
b->x[0] = i; b->x[0] = i;
b->wds = 1; b->wds = 1;
return b; return b;
} }
Bigint * Bigint *
__gdtoa_mult(Bigint *a, Bigint *b) __gdtoa_mult(Bigint *a, Bigint *b, ThInfo **PTI)
{ {
Bigint *c; Bigint *c;
int k, wa, wb, wc; int k, wa, wb, wc;
ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
ULong y; ULong y;
ULLong carry, z; uint64_t carry, z;
if (a->wds < b->wds) { if (a->wds < b->wds) {
c = a; c = a;
a = b; a = b;
@ -162,7 +174,7 @@ __gdtoa_mult(Bigint *a, Bigint *b)
wc = wa + wb; wc = wa + wb;
if (wc > a->maxwds) if (wc > a->maxwds)
k++; k++;
c = __gdtoa_Balloc(k); c = __gdtoa_Balloc(k, PTI);
for (x = c->x, xa = x + wc; x < xa; x++) for (x = c->x, xa = x + wc; x < xa; x++)
*x = 0; *x = 0;
xa = a->x; xa = a->x;
@ -176,82 +188,101 @@ __gdtoa_mult(Bigint *a, Bigint *b)
xc = xc0; xc = xc0;
carry = 0; carry = 0;
do { do {
z = *x++ * (ULLong)y + *xc + carry; z = *x++ * (uint64_t)y + *xc + carry;
carry = z >> 32; carry = z >> 32;
*xc++ = z & 0xffffffffUL; *xc++ = z & 0xffffffffUL;
} } while (x < xae);
while(x < xae);
*xc = carry; *xc = carry;
} }
} }
for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc)
;
c->wds = wc; c->wds = wc;
return c; return c;
} }
Bigint * Bigint *
__gdtoa_pow5mult(Bigint *b, int k) __gdtoa_pow5mult(Bigint *b, int k, ThInfo **PTI)
{ {
int i;
Bigint *b1, *p5, *p51; Bigint *b1, *p5, *p51;
static const int p05[3] = { 5, 25, 125 }; ThInfo *TI;
if ((i = k & 3)) int i;
b = __gdtoa_multadd(b, p05[i-1], 0); static int p05[3] = {5, 25, 125};
if ((i = k & 3) != 0)
b = __gdtoa_multadd(b, p05[i - 1], 0, PTI);
if (!(k >>= 2)) if (!(k >>= 2))
return b; return b;
__gdtoa_lock(); if (!(TI = *PTI))
p5 = TI0.P5s; *PTI = TI = __gdtoa_get_TI();
if ((p5 = TI->P5s) == 0) {
if (!(TI = *PTI))
*PTI = TI = __gdtoa_get_TI();
if (TI == &TI0)
__gdtoa_lock1();
if (!(p5 = TI->P5s)) {
p5 = TI->P5s = __gdtoa_i2b(625, PTI);
p5->next = 0;
}
if (TI == &TI0)
__gdtoa_unlock1();
}
for (;;) { for (;;) {
if (k & 1) { if (k & 1) {
b1 = __gdtoa_mult(b, p5); b1 = __gdtoa_mult(b, p5, PTI);
__gdtoa_Bfree(b); __gdtoa_Bfree(b, PTI);
b = b1; b = b1;
} }
if (!(k >>= 1)) if (!(k >>= 1))
break; break;
if ((p51 = p5->next) == 0) { if ((p51 = p5->next) == 0) {
p51 = p5->next = __gdtoa_mult(p5,p5); if (!TI && !(TI = *PTI))
*PTI = TI = __gdtoa_get_TI();
if (TI == &TI0)
__gdtoa_lock1();
if (!(p51 = p5->next)) {
p51 = p5->next = __gdtoa_mult(p5, p5, PTI);
p51->next = 0; p51->next = 0;
} }
if (TI == &TI0)
__gdtoa_unlock1();
}
p5 = p51; p5 = p51;
} }
__gdtoa_unlock();
return b; return b;
} }
Bigint * Bigint *
__gdtoa_lshift(Bigint *b, int k) __gdtoa_lshift(Bigint *b, int k, ThInfo **PTI)
{ {
int i, k1, n, n1; int i, k1, n, n1;
Bigint *b1; Bigint *b1;
ULong *x, *x1, *xe, z; ULong *x, *x1, *xe, z;
n = k >> kshift; n = k >> 5;
k1 = b->k; k1 = b->k;
n1 = n + b->wds + 1; n1 = n + b->wds + 1;
for (i = b->maxwds; n1 > i; i <<= 1) for (i = b->maxwds; n1 > i; i <<= 1)
k1++; k1++;
b1 = __gdtoa_Balloc(k1); b1 = __gdtoa_Balloc(k1, PTI);
x1 = b1->x; x1 = b1->x;
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
*x1++ = 0; *x1++ = 0;
x = b->x; x = b->x;
xe = x + b->wds; xe = x + b->wds;
if (k &= kmask) { if (k &= 31) {
k1 = 32 - k; k1 = 32 - k;
z = 0; z = 0;
do { do {
*x1++ = *x << k | z; *x1++ = *x << k | z;
z = *x++ >> k1; z = *x++ >> k1;
} } while (x < xe);
while(x < xe);
if ((*x1 = z) != 0) if ((*x1 = z) != 0)
++n1; ++n1;
} } else
else do do
*x1++ = *x++; *x1++ = *x++;
while (x < xe); while (x < xe);
b1->wds = n1 - 1; b1->wds = n1 - 1;
__gdtoa_Bfree(b); __gdtoa_Bfree(b, PTI);
return b1; return b1;
} }
@ -262,12 +293,6 @@ __gdtoa_cmp(Bigint *a, Bigint *b)
int i, j; int i, j;
i = a->wds; i = a->wds;
j = b->wds; j = b->wds;
#ifdef DEBUG
if (i > 1 && !a->x[i-1])
Bug("__gdtoa_cmp called with a->x[a->wds-1] == 0");
if (j > 1 && !b->x[j-1])
Bug("__gdtoa_cmp called with b->x[b->wds-1] == 0");
#endif
if (i -= j) if (i -= j)
return i; return i;
xa0 = a->x; xa0 = a->x;
@ -284,15 +309,15 @@ __gdtoa_cmp(Bigint *a, Bigint *b)
} }
Bigint * Bigint *
__gdtoa_diff(Bigint *a, Bigint *b) __gdtoa_diff(Bigint *a, Bigint *b, ThInfo **PTI)
{ {
Bigint *c; Bigint *c;
int i, wa, wb; int i, wa, wb;
ULong *xa, *xae, *xb, *xbe, *xc; ULong *xa, *xae, *xb, *xbe, *xc;
ULLong borrow, y; uint64_t borrow, y;
i = __gdtoa_cmp(a, b); i = __gdtoa_cmp(a, b);
if (!i) { if (!i) {
c = __gdtoa_Balloc(0); c = __gdtoa_Balloc(0, PTI);
c->wds = 1; c->wds = 1;
c->x[0] = 0; c->x[0] = 0;
return c; return c;
@ -302,10 +327,9 @@ __gdtoa_diff(Bigint *a, Bigint *b)
a = b; a = b;
b = c; b = c;
i = 1; i = 1;
} } else
else
i = 0; i = 0;
c = __gdtoa_Balloc(a->k); c = __gdtoa_Balloc(a->k, PTI);
c->sign = i; c->sign = i;
wa = a->wds; wa = a->wds;
xa = a->x; xa = a->x;
@ -316,11 +340,10 @@ __gdtoa_diff(Bigint *a, Bigint *b)
xc = c->x; xc = c->x;
borrow = 0; borrow = 0;
do { do {
y = (ULLong)*xa++ - *xb++ - borrow; y = (uint64_t)*xa++ - *xb++ - borrow;
borrow = y >> 32 & 1UL; borrow = y >> 32 & 1UL;
*xc++ = y & 0xffffffffUL; *xc++ = y & 0xffffffffUL;
} } while (xb < xbe);
while(xb < xbe);
while (xa < xae) { while (xa < xae) {
y = *xa++ - borrow; y = *xa++ - borrow;
borrow = y >> 32 & 1UL; borrow = y >> 32 & 1UL;
@ -341,33 +364,29 @@ __gdtoa_b2d(Bigint *a, int *e)
xa0 = a->x; xa0 = a->x;
xa = xa0 + a->wds; xa = xa0 + a->wds;
y = *--xa; y = *--xa;
#ifdef DEBUG k = hi0bits((ULong)(y));
if (!y) Bug("zero y in __gdtoa_b2d");
#endif
k = hi0bits(y);
*e = 32 - k; *e = 32 - k;
if (k < Ebits) { if (k < 11) {
word0(&d) = Exp_1 | y >> (Ebits - k); (&d)->L[1] = 0x3ff00000 | y >> (11 - k);
w = xa > xa0 ? *--xa : 0; w = xa > xa0 ? *--xa : 0;
word1(&d) = y << ((32-Ebits) + k) | w >> (Ebits - k); (&d)->L[0] = y << ((32 - 11) + k) | w >> (11 - k);
goto ret_d; goto ret_d;
} }
z = xa > xa0 ? *--xa : 0; z = xa > xa0 ? *--xa : 0;
if (k -= Ebits) { if (k -= 11) {
word0(&d) = Exp_1 | y << k | z >> (32 - k); (&d)->L[1] = 0x3ff00000 | y << k | z >> (32 - k);
y = xa > xa0 ? *--xa : 0; y = xa > xa0 ? *--xa : 0;
word1(&d) = z << k | y >> (32 - k); (&d)->L[0] = z << k | y >> (32 - k);
} } else {
else { (&d)->L[1] = 0x3ff00000 | y;
word0(&d) = Exp_1 | y; (&d)->L[0] = z;
word1(&d) = z;
} }
ret_d: ret_d:
return dval(&d); return (&d)->d;
} }
Bigint * Bigint *
__gdtoa_d2b(double dd, int *e, int *bits) __gdtoa_d2b(double dd, int *e, int *bits, ThInfo **PTI)
{ {
Bigint *b; Bigint *b;
U d; U d;
@ -375,47 +394,37 @@ __gdtoa_d2b(double dd, int *e, int *bits)
int de, k; int de, k;
ULong *x, y, z; ULong *x, y, z;
d.d = dd; d.d = dd;
b = __gdtoa_Balloc(1); b = __gdtoa_Balloc(1, PTI);
x = b->x; x = b->x;
z = word0(&d) & Frac_mask; z = (&d)->L[1] & 0xfffff;
word0(&d) &= 0x7fffffff; /* clear sign bit, which we ignore */ (&d)->L[1] &= 0x7fffffff;
if ( (de = (int)(word0(&d) >> Exp_shift)) !=0) if ((de = (int)((&d)->L[1] >> 20)) != 0)
z |= Exp_msk1; z |= 0x100000;
if ( (y = word1(&d)) !=0) { if ((y = (&d)->L[0]) != 0) {
if ((k = lo0bits(&y)) != 0) { if ((k = lo0bits(&y)) != 0) {
x[0] = y | z << (32 - k); x[0] = y | z << (32 - k);
z >>= k; z >>= k;
} } else
else
x[0] = y; x[0] = y;
i = b->wds = (x[1] = z) != 0 ? 2 : 1; i = b->wds = (x[1] = z) != 0 ? 2 : 1;
} } else {
else {
k = lo0bits(&z); k = lo0bits(&z);
x[0] = z; x[0] = z;
i = b->wds = 1; i = b->wds = 1;
k += 32; k += 32;
} }
if (de) { if (de) {
*e = de - Bias - (P-1) + k; *e = de - 1023 - (53 - 1) + k;
*bits = P - k; *bits = 53 - k;
} } else {
else { *e = de - 1023 - (53 - 1) + 1 + k;
*e = de - Bias - (P-1) + 1 + k; *bits = 32 * i - hi0bits((ULong)(x[i - 1]));
*bits = 32*i - hi0bits(x[i-1]);
} }
return b; return b;
} }
const double const double __gdtoa_bigtens[] = {1e16, 1e32, 1e64, 1e128, 1e256};
__gdtoa_bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; const double __gdtoa_tinytens[] = {1e-16, 1e-32, 1e-64, 1e-128, 1e-256};
const double __gdtoa_tens[] = {1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
const double 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
__gdtoa_tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 }; 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
const double
__gdtoa_tens[] = {
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22
};

View file

@ -33,27 +33,27 @@
/* clang-format off */ /* clang-format off */
Bigint * Bigint *
__gdtoa_s2b(const char *s, int nd0, int nd, ULong y9, int dplen) __gdtoa_s2b(const char *s, int nd0, int nd, ULong y9, int dplen, ThInfo **PTI)
{ {
Bigint *b; Bigint *b;
int i, k; int i, k;
Long x, y; Long x, y;
x = (nd + 8) / 9; x = (nd + 8) / 9;
for(k = 0, y = 1; x > y; y <<= 1, k++) ; for(k = 0, y = 1; x > y; y <<= 1, k++) ;
b = __gdtoa_Balloc(k); b = __gdtoa_Balloc(k, PTI);
b->x[0] = y9; b->x[0] = y9;
b->wds = 1; b->wds = 1;
i = 9; i = 9;
if (9 < nd0) { if (9 < nd0) {
s += 9; s += 9;
do b = __gdtoa_multadd(b, 10, *s++ - '0'); do b = __gdtoa_multadd(b, 10, *s++ - '0', PTI);
while(++i < nd0); while(++i < nd0);
s += dplen; s += dplen;
} }
else else
s += dplen + 9; s += dplen + 9;
for(; i < nd; i++) for(; i < nd; i++)
b = __gdtoa_multadd(b, 10, *s++ - '0'); b = __gdtoa_multadd(b, 10, *s++ - '0', PTI);
return b; return b;
} }

View file

@ -39,14 +39,15 @@ strtoId(const char *s, char **sp, double *f0, double *f1)
Long exp[2]; Long exp[2];
Bigint *B[2]; Bigint *B[2];
int k, rv[2]; int k, rv[2];
B[0] = __gdtoa_Balloc(1); ThInfo *TI = 0;
B[0] = __gdtoa_Balloc(1, &TI);
B[0]->wds = 2; B[0]->wds = 2;
k = __gdtoa_strtoIg(s, sp, &fpi, exp, B, rv); k = __gdtoa_strtoIg(s, sp, &fpi, exp, B, rv);
__gdtoa_ULtod((ULong*)f0, B[0]->x, exp[0], rv[0]); __gdtoa_ULtod((ULong*)f0, B[0]->x, exp[0], rv[0]);
__gdtoa_Bfree(B[0]); __gdtoa_Bfree(B[0], &TI);
if (B[1]) { if (B[1]) {
__gdtoa_ULtod((ULong*)f1, B[1]->x, exp[1], rv[1]); __gdtoa_ULtod((ULong*)f1, B[1]->x, exp[1], rv[1]);
__gdtoa_Bfree(B[1]); __gdtoa_Bfree(B[1], &TI);
} }
else { else {
((ULong*)f1)[0] = ((ULong*)f0)[0]; ((ULong*)f1)[0] = ((ULong*)f0)[0];

View file

@ -39,14 +39,15 @@ strtoIdd(const char *s, char **sp, double *f0, double *f1)
Long exp[2]; Long exp[2];
Bigint *B[2]; Bigint *B[2];
int k, rv[2]; int k, rv[2];
B[0] = __gdtoa_Balloc(2); ThInfo *TI = 0;
B[0] = __gdtoa_Balloc(2, &TI);
B[0]->wds = 4; B[0]->wds = 4;
k = __gdtoa_strtoIg(s, sp, &fpi, exp, B, rv); k = __gdtoa_strtoIg(s, sp, &fpi, exp, B, rv);
__gdtoa_ULtodd((ULong*)f0, B[0]->x, exp[0], rv[0]); __gdtoa_ULtodd((ULong*)f0, B[0]->x, exp[0], rv[0]);
__gdtoa_Bfree(B[0]); __gdtoa_Bfree(B[0], &TI);
if (B[1]) { if (B[1]) {
__gdtoa_ULtodd((ULong*)f1, B[1]->x, exp[1], rv[1]); __gdtoa_ULtodd((ULong*)f1, B[1]->x, exp[1], rv[1]);
__gdtoa_Bfree(B[1]); __gdtoa_Bfree(B[1], &TI);
} }
else { else {
((ULong*)f1)[0] = ((ULong*)f0)[0]; ((ULong*)f1)[0] = ((ULong*)f0)[0];

View file

@ -39,14 +39,15 @@ strtoIf(const char *s, char **sp, float *f0, float *f1)
Long exp[2]; Long exp[2];
Bigint *B[2]; Bigint *B[2];
int k, rv[2]; int k, rv[2];
B[0] = __gdtoa_Balloc(0); ThInfo *TI = 0;
B[0] = __gdtoa_Balloc(0, &TI);
B[0]->wds = 1; B[0]->wds = 1;
k = __gdtoa_strtoIg(s, sp, &fpi, exp, B, rv); k = __gdtoa_strtoIg(s, sp, &fpi, exp, B, rv);
__gdtoa_ULtof((ULong*)f0, B[0]->x, exp[0], rv[0]); __gdtoa_ULtof((ULong*)f0, B[0]->x, exp[0], rv[0]);
__gdtoa_Bfree(B[0]); __gdtoa_Bfree(B[0], &TI);
if (B[1]) { if (B[1]) {
__gdtoa_ULtof((ULong*)f1, B[1]->x, exp[1], rv[1]); __gdtoa_ULtof((ULong*)f1, B[1]->x, exp[1], rv[1]);
__gdtoa_Bfree(B[1]); __gdtoa_Bfree(B[1], &TI);
} }
else else
*(ULong*)f1 = *(ULong*)f0; *(ULong*)f1 = *(ULong*)f0;

View file

@ -39,6 +39,7 @@ __gdtoa_strtoIg(const char *s00, char **se, const FPI *fpi, Long *exp, Bigint **
int i, nb, nw, nw1, rv, rv1, swap; int i, nb, nw, nw1, rv, rv1, swap;
unsigned int nb1, nb11; unsigned int nb1, nb11;
Long e1; Long e1;
ThInfo *TI = 0;
b = *B; b = *B;
rv = strtodg(s00, se, fpi, exp, b->x); rv = strtodg(s00, se, fpi, exp, b->x);
if (!(rv & STRTOG_Inexact)) { if (!(rv & STRTOG_Inexact)) {
@ -47,7 +48,7 @@ __gdtoa_strtoIg(const char *s00, char **se, const FPI *fpi, Long *exp, Bigint **
} }
e1 = exp[0]; e1 = exp[0];
rv1 = rv ^ STRTOG_Inexact; rv1 = rv ^ STRTOG_Inexact;
b1 = __gdtoa_Balloc(b->k); b1 = __gdtoa_Balloc(b->k, &TI);
Bcopy(b1, b); Bcopy(b1, b);
nb = fpi->nbits; nb = fpi->nbits;
nb1 = nb & 31; nb1 = nb & 31;
@ -56,7 +57,7 @@ __gdtoa_strtoIg(const char *s00, char **se, const FPI *fpi, Long *exp, Bigint **
nw1 = nw - 1; nw1 = nw - 1;
if (rv & STRTOG_Inexlo) { if (rv & STRTOG_Inexlo) {
swap = 0; swap = 0;
b1 = __gdtoa_increment(b1); b1 = __gdtoa_increment(b1, &TI);
if ((rv & STRTOG_Retmask) == STRTOG_Zero) { if ((rv & STRTOG_Retmask) == STRTOG_Zero) {
if (fpi->sudden_underflow) { if (fpi->sudden_underflow) {
b1->x[0] = 0; b1->x[0] = 0;
@ -85,7 +86,7 @@ __gdtoa_strtoIg(const char *s00, char **se, const FPI *fpi, Long *exp, Bigint **
else { else {
swap = STRTOG_Neg; swap = STRTOG_Neg;
if ((rv & STRTOG_Retmask) == STRTOG_Infinite) { if ((rv & STRTOG_Retmask) == STRTOG_Infinite) {
b1 = __gdtoa_set_ones(b1, nb); b1 = __gdtoa_set_ones(b1, nb, &TI);
e1 = fpi->emax; e1 = fpi->emax;
rv1 = STRTOG_Normal | STRTOG_Inexlo | (rv & STRTOG_Neg); rv1 = STRTOG_Normal | STRTOG_Inexlo | (rv & STRTOG_Neg);
goto swapcheck; goto swapcheck;
@ -108,7 +109,7 @@ __gdtoa_strtoIg(const char *s00, char **se, const FPI *fpi, Long *exp, Bigint **
rv1 |= STRTOG_Underflow; rv1 |= STRTOG_Underflow;
} }
else { else {
b1 = __gdtoa_lshift(b1, 1); b1 = __gdtoa_lshift(b1, 1, &TI);
b1->x[0] |= 1; b1->x[0] |= 1;
--e1; --e1;
} }

View file

@ -39,15 +39,16 @@ strtoIx(const char *s, char **sp, void *a, void *b)
Long exp[2]; Long exp[2];
Bigint *B[2]; Bigint *B[2];
int k, rv[2]; int k, rv[2];
ThInfo *TI = 0;
UShort *L = (UShort *)a, *M = (UShort *)b; UShort *L = (UShort *)a, *M = (UShort *)b;
B[0] = __gdtoa_Balloc(1); B[0] = __gdtoa_Balloc(1, &TI);
B[0]->wds = 2; B[0]->wds = 2;
k = __gdtoa_strtoIg(s, sp, &fpi, exp, B, rv); k = __gdtoa_strtoIg(s, sp, &fpi, exp, B, rv);
__gdtoa_ULtox(L, B[0]->x, exp[0], rv[0]); __gdtoa_ULtox(L, B[0]->x, exp[0], rv[0]);
__gdtoa_Bfree(B[0]); __gdtoa_Bfree(B[0], &TI);
if (B[1]) { if (B[1]) {
__gdtoa_ULtox(M, B[1]->x, exp[1], rv[1]); __gdtoa_ULtox(M, B[1]->x, exp[1], rv[1]);
__gdtoa_Bfree(B[1]); __gdtoa_Bfree(B[1], &TI);
} }
else { else {
M[0] = L[0]; M[0] = L[0];

View file

@ -45,7 +45,7 @@ static const double tiny__gdtoa_tens[] = {
}; };
static double static double
s__gdtoa_ulp(U *x, int scale) __gdtoa_sulp(U *x, int scale)
{ {
U u; U u;
int i; int i;
@ -61,6 +61,7 @@ s__gdtoa_ulp(U *x, int scale)
double double
strtod(const char *s00, char **se) strtod(const char *s00, char **se)
{ {
ThInfo *TI = 0;
int scale; int scale;
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, dsign, int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, dsign,
e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
@ -107,7 +108,7 @@ break2:
{ {
FPI fpi1 = fpi; FPI fpi1 = fpi;
fpi1.rounding = Rounding; fpi1.rounding = Rounding;
switch((i = __gdtoa_gethex(&s, &fpi1, &exp, &bb, sign)) & STRTOG_Retmask) { switch((i = __gdtoa_gethex(&s, &fpi1, &exp, &bb, sign, &TI)) & STRTOG_Retmask) {
case STRTOG_NoNumber: case STRTOG_NoNumber:
s = s00; s = s00;
sign = 0; sign = 0;
@ -116,7 +117,7 @@ break2:
default: default:
if (bb) { if (bb) {
__gdtoa_copybits(bits, fpi.nbits, bb); __gdtoa_copybits(bits, fpi.nbits, bb);
__gdtoa_Bfree(bb); __gdtoa_Bfree(bb, &TI);
} }
__gdtoa_ULtod(((U*)&rv)->L, bits, exp, i); __gdtoa_ULtod(((U*)&rv)->L, bits, exp, i);
}} }}
@ -328,11 +329,11 @@ dig_done:
} }
range_err: range_err:
if (bd0) { if (bd0) {
__gdtoa_Bfree(bb); __gdtoa_Bfree(bb, &TI);
__gdtoa_Bfree(bd); __gdtoa_Bfree(bd, &TI);
__gdtoa_Bfree(bs); __gdtoa_Bfree(bs, &TI);
__gdtoa_Bfree(bd0); __gdtoa_Bfree(bd0, &TI);
__gdtoa_Bfree(delta); __gdtoa_Bfree(delta, &TI);
} }
errno = ERANGE; errno = ERANGE;
goto ret; goto ret;
@ -393,12 +394,12 @@ dig_done:
} }
/* Now the hard part -- adjusting rv to the correct value.*/ /* Now the hard part -- adjusting rv to the correct value.*/
/* Put digits into bd: true value = bd * 10^e */ /* Put digits into bd: true value = bd * 10^e */
bd0 = __gdtoa_s2b(s0, nd0, nd, y, dplen); bd0 = __gdtoa_s2b(s0, nd0, nd, y, dplen, &TI);
for(;;) { for(;;) {
bd = __gdtoa_Balloc(bd0->k); bd = __gdtoa_Balloc(bd0->k, &TI);
Bcopy(bd, bd0); Bcopy(bd, bd0);
bb = __gdtoa_d2b(dval(&rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ bb = __gdtoa_d2b(dval(&rv), &bbe, &bbbits, &TI); /* rv = bb * 2^bbe */
bs = __gdtoa_i2b(1); bs = __gdtoa_i2b(1, &TI);
if (e >= 0) { if (e >= 0) {
bb2 = bb5 = 0; bb2 = bb5 = 0;
bd2 = bd5 = e; bd2 = bd5 = e;
@ -439,20 +440,20 @@ dig_done:
bs2 -= i; bs2 -= i;
} }
if (bb5 > 0) { if (bb5 > 0) {
bs = __gdtoa_pow5mult(bs, bb5); bs = __gdtoa_pow5mult(bs, bb5, &TI);
bb1 = __gdtoa_mult(bs, bb); bb1 = __gdtoa_mult(bs, bb, &TI);
__gdtoa_Bfree(bb); __gdtoa_Bfree(bb, &TI);
bb = bb1; bb = bb1;
} }
if (bb2 > 0) if (bb2 > 0)
bb = __gdtoa_lshift(bb, bb2); bb = __gdtoa_lshift(bb, bb2, &TI);
if (bd5 > 0) if (bd5 > 0)
bd = __gdtoa_pow5mult(bd, bd5); bd = __gdtoa_pow5mult(bd, bd5, &TI);
if (bd2 > 0) if (bd2 > 0)
bd = __gdtoa_lshift(bd, bd2); bd = __gdtoa_lshift(bd, bd2, &TI);
if (bs2 > 0) if (bs2 > 0)
bs = __gdtoa_lshift(bs, bs2); bs = __gdtoa_lshift(bs, bs2, &TI);
delta = __gdtoa_diff(bb, bd); delta = __gdtoa_diff(bb, bd, &TI);
dsign = delta->sign; dsign = delta->sign;
delta->sign = 0; delta->sign = 0;
i = __gdtoa_cmp(delta, bs); i = __gdtoa_cmp(delta, bs);
@ -476,7 +477,7 @@ dig_done:
y = word0(&rv) & Exp_mask; y = word0(&rv) & Exp_mask;
if (!scale || y > 2*P*Exp_msk1) if (!scale || y > 2*P*Exp_msk1)
{ {
delta = __gdtoa_lshift(delta,Log2P); delta = __gdtoa_lshift(delta,Log2P,&TI);
if (__gdtoa_cmp(delta, bs) <= 0) if (__gdtoa_cmp(delta, bs) <= 0)
dval(&adj) = -0.5; dval(&adj) = -0.5;
} }
@ -525,7 +526,7 @@ dig_done:
/* exact result */ /* exact result */
break; break;
} }
delta = __gdtoa_lshift(delta,Log2P); delta = __gdtoa_lshift(delta,Log2P,&TI);
if (__gdtoa_cmp(delta, bs) > 0) if (__gdtoa_cmp(delta, bs) > 0)
goto drop_down; goto drop_down;
break; break;
@ -575,9 +576,9 @@ dig_done:
else if (!(word1(&rv) & Lsb)) else if (!(word1(&rv) & Lsb))
break; break;
if (dsign) if (dsign)
dval(&rv) += s__gdtoa_ulp(&rv, scale); dval(&rv) += __gdtoa_sulp(&rv, scale);
else { else {
dval(&rv) -= s__gdtoa_ulp(&rv, scale); dval(&rv) -= __gdtoa_sulp(&rv, scale);
if (!dval(&rv)) if (!dval(&rv))
goto undfl; goto undfl;
} }
@ -661,16 +662,16 @@ dig_done:
break; break;
} }
cont: cont:
__gdtoa_Bfree(bb); __gdtoa_Bfree(bb, &TI);
__gdtoa_Bfree(bd); __gdtoa_Bfree(bd, &TI);
__gdtoa_Bfree(bs); __gdtoa_Bfree(bs, &TI);
__gdtoa_Bfree(delta); __gdtoa_Bfree(delta, &TI);
} }
__gdtoa_Bfree(bb); __gdtoa_Bfree(bb, &TI);
__gdtoa_Bfree(bd); __gdtoa_Bfree(bd, &TI);
__gdtoa_Bfree(bs); __gdtoa_Bfree(bs, &TI);
__gdtoa_Bfree(bd0); __gdtoa_Bfree(bd0, &TI);
__gdtoa_Bfree(delta); __gdtoa_Bfree(delta, &TI);
if (scale) { if (scale) {
word0(&rv0) = Exp_1 - 2*P*Exp_msk1; word0(&rv0) = Exp_1 - 2*P*Exp_msk1;
word1(&rv0) = 0; word1(&rv0) = 0;

View file

@ -39,7 +39,7 @@ fivesbits[] = { 0, 3, 5, 7, 10, 12, 14, 17, 19, 21,
47, 49, 52 }; 47, 49, 52 };
Bigint * Bigint *
__gdtoa_increment(Bigint *b) __gdtoa_increment(Bigint *b, ThInfo **PTI)
{ {
ULong *x, *xe; ULong *x, *xe;
Bigint *b1; Bigint *b1;
@ -54,9 +54,9 @@ __gdtoa_increment(Bigint *b)
} while(x < xe); } while(x < xe);
{ {
if (b->wds >= b->maxwds) { if (b->wds >= b->maxwds) {
b1 = __gdtoa_Balloc(b->k+1); b1 = __gdtoa_Balloc(b->k+1, PTI);
Bcopy(b1,b); Bcopy(b1,b);
__gdtoa_Bfree(b); __gdtoa_Bfree(b, PTI);
b = b1; b = b1;
} }
b->x[b->wds++] = 1; b->x[b->wds++] = 1;
@ -95,14 +95,14 @@ all_on(Bigint *b, int n)
} }
Bigint * Bigint *
__gdtoa_set_ones(Bigint *b, int n) __gdtoa_set_ones(Bigint *b, int n, ThInfo **PTI)
{ {
int k; int k;
ULong *x, *xe; ULong *x, *xe;
k = (n + ((1 << kshift) - 1)) >> kshift; k = (n + ((1 << kshift) - 1)) >> kshift;
if (b->k < k) { if (b->k < k) {
__gdtoa_Bfree(b); __gdtoa_Bfree(b, PTI);
b = __gdtoa_Balloc(k); b = __gdtoa_Balloc(k, PTI);
} }
k = n >> kshift; k = n >> kshift;
if (n &= kmask) if (n &= kmask)
@ -118,13 +118,13 @@ __gdtoa_set_ones(Bigint *b, int n)
} }
static int static int
rvOK(U *d, const FPI *fpi, Long *exp, ULong *bits, int exact, int rd, int *irv) rvOK(U *d, const FPI *fpi, Long *exp, ULong *bits, int exact, int rd, int *irv, ThInfo **PTI)
{ {
Bigint *b; Bigint *b;
ULong carry, inex, lostbits; ULong carry, inex, lostbits;
int bdif, e, j, k, k1, nb, rv; int bdif, e, j, k, k1, nb, rv;
carry = rv = 0; carry = rv = 0;
b = __gdtoa_d2b(dval(d), &e, &bdif); b = __gdtoa_d2b(dval(d), &e, &bdif, PTI);
bdif -= nb = fpi->nbits; bdif -= nb = fpi->nbits;
e += bdif; e += bdif;
if (bdif <= 0) { if (bdif <= 0) {
@ -166,7 +166,7 @@ trunc:
__gdtoa_rshift(b, bdif); __gdtoa_rshift(b, bdif);
if (carry) { if (carry) {
inex = STRTOG_Inexhi; inex = STRTOG_Inexhi;
b = __gdtoa_increment(b); b = __gdtoa_increment(b, PTI);
if ( (j = nb & kmask) !=0) if ( (j = nb & kmask) !=0)
j = ULbits - j; j = ULbits - j;
if (hi0bits(b->x[b->wds - 1]) != j) { if (hi0bits(b->x[b->wds - 1]) != j) {
@ -178,7 +178,7 @@ trunc:
} }
} }
else if (bdif < 0) else if (bdif < 0)
b = __gdtoa_lshift(b, -bdif); b = __gdtoa_lshift(b, -bdif, PTI);
if (e < fpi->emin) { if (e < fpi->emin) {
k = fpi->emin - e; k = fpi->emin - e;
e = fpi->emin; e = fpi->emin;
@ -197,7 +197,7 @@ trunc:
__gdtoa_rshift(b, k); __gdtoa_rshift(b, k);
*irv = STRTOG_Denormal; *irv = STRTOG_Denormal;
if (carry) { if (carry) {
b = __gdtoa_increment(b); b = __gdtoa_increment(b, PTI);
inex = STRTOG_Inexhi | STRTOG_Underflow; inex = STRTOG_Inexhi | STRTOG_Underflow;
} }
else if (lostbits) else if (lostbits)
@ -215,7 +215,7 @@ trunc:
*irv |= inex; *irv |= inex;
rv = 1; rv = 1;
ret: ret:
__gdtoa_Bfree(b); __gdtoa_Bfree(b, PTI);
return rv; return rv;
} }
@ -243,6 +243,7 @@ strtodg(const char *s00, char **se, const FPI *fpi, Long *exp, ULong *bits)
U adj, rv; U adj, rv;
ULong *b, *be, y, z; ULong *b, *be, y, z;
Bigint *ab, *bb, *bb1, *bd, *bd0, *bs, *delta, *rvb, *rvb0; Bigint *ab, *bb, *bb1, *bd, *bd0, *bs, *delta, *rvb, *rvb0;
ThInfo *TI = 0;
irv = STRTOG_Zero; irv = STRTOG_Zero;
denorm = sign = nz0 = nz = 0; denorm = sign = nz0 = nz = 0;
dval(&rv) = 0.; dval(&rv) = 0.;
@ -276,7 +277,7 @@ break2:
switch(s[1]) { switch(s[1]) {
case 'x': case 'x':
case 'X': case 'X':
irv = __gdtoa_gethex(&s, fpi, exp, &rvb, sign); irv = __gdtoa_gethex(&s, fpi, exp, &rvb, sign, &TI);
if (irv == STRTOG_NoNumber) { if (irv == STRTOG_NoNumber) {
s = s00; s = s00;
sign = 0; sign = 0;
@ -425,14 +426,14 @@ dig_done:
bd0 = 0; bd0 = 0;
if (nbits <= P && nd <= DBL_DIG) { if (nbits <= P && nd <= DBL_DIG) {
if (!e) { if (!e) {
if (rvOK(&rv, fpi, exp, bits, 1, rd, &irv)) if (rvOK(&rv, fpi, exp, bits, 1, rd, &irv, &TI))
goto ret; goto ret;
} }
else if (e > 0) { else if (e > 0) {
if (e <= Ten_pmax) { if (e <= Ten_pmax) {
i = fivesbits[e] + mantbits(&rv) <= P; i = fivesbits[e] + mantbits(&rv) <= P;
/* rv = */ rounded_product(dval(&rv), __gdtoa_tens[e]); /* rv = */ rounded_product(dval(&rv), __gdtoa_tens[e]);
if (rvOK(&rv, fpi, exp, bits, i, rd, &irv)) if (rvOK(&rv, fpi, exp, bits, i, rd, &irv, &TI))
goto ret; goto ret;
e1 -= e; e1 -= e;
goto rv_notOK; goto rv_notOK;
@ -446,14 +447,14 @@ dig_done:
e1 -= i; e1 -= i;
dval(&rv) *= __gdtoa_tens[i]; dval(&rv) *= __gdtoa_tens[i];
/* rv = */ rounded_product(dval(&rv), __gdtoa_tens[e2]); /* rv = */ rounded_product(dval(&rv), __gdtoa_tens[e2]);
if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv)) if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv, &TI))
goto ret; goto ret;
e1 -= e2; e1 -= e2;
} }
} }
else if (e >= -Ten_pmax) { else if (e >= -Ten_pmax) {
/* rv = */ rounded_quotient(dval(&rv), __gdtoa_tens[-e]); /* rv = */ rounded_quotient(dval(&rv), __gdtoa_tens[-e]);
if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv)) if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv, &TI))
goto ret; goto ret;
e1 -= e; e1 -= e;
} }
@ -505,7 +506,7 @@ rv_notOK:
dval(&rv) *= __gdtoa_tinytens[j]; dval(&rv) *= __gdtoa_tinytens[j];
} }
} }
rvb = __gdtoa_d2b(dval(&rv), &rve, &rvbits); /* rv = rvb * 2^rve */ rvb = __gdtoa_d2b(dval(&rv), &rve, &rvbits, &TI); /* rv = rvb * 2^rve */
rve += e2; rve += e2;
if ((j = rvbits - nbits) > 0) { if ((j = rvbits - nbits) > 0) {
__gdtoa_rshift(rvb, j); __gdtoa_rshift(rvb, j);
@ -521,7 +522,7 @@ rv_notOK:
denorm = 1; denorm = 1;
j = rve - emin; j = rve - emin;
if (j > 0) { if (j > 0) {
rvb = __gdtoa_lshift(rvb, j); rvb = __gdtoa_lshift(rvb, j, &TI);
rvbits += j; rvbits += j;
} }
else if (j < 0) { else if (j < 0) {
@ -557,15 +558,15 @@ rv_notOK:
} }
/* Now the hard part -- adjusting rv to the correct value.*/ /* Now the hard part -- adjusting rv to the correct value.*/
/* Put digits into bd: true value = bd * 10^e */ /* Put digits into bd: true value = bd * 10^e */
bd0 = __gdtoa_s2b(s0, nd0, nd, y, 1); bd0 = __gdtoa_s2b(s0, nd0, nd, y, 1, &TI);
for(;;) { for(;;) {
bd = __gdtoa_Balloc(bd0->k); bd = __gdtoa_Balloc(bd0->k, &TI);
Bcopy(bd, bd0); Bcopy(bd, bd0);
bb = __gdtoa_Balloc(rvb->k); bb = __gdtoa_Balloc(rvb->k, &TI);
Bcopy(bb, rvb); Bcopy(bb, rvb);
bbbits = rvbits - bb0; bbbits = rvbits - bb0;
bbe = rve + bb0; bbe = rve + bb0;
bs = __gdtoa_i2b(1); bs = __gdtoa_i2b(1, &TI);
if (e >= 0) { if (e >= 0) {
bb2 = bb5 = 0; bb2 = bb5 = 0;
bd2 = bd5 = e; bd2 = bd5 = e;
@ -594,25 +595,25 @@ rv_notOK:
bs2 -= i; bs2 -= i;
} }
if (bb5 > 0) { if (bb5 > 0) {
bs = __gdtoa_pow5mult(bs, bb5); bs = __gdtoa_pow5mult(bs, bb5, &TI);
bb1 = __gdtoa_mult(bs, bb); bb1 = __gdtoa_mult(bs, bb, &TI);
__gdtoa_Bfree(bb); __gdtoa_Bfree(bb, &TI);
bb = bb1; bb = bb1;
} }
bb2 -= bb0; bb2 -= bb0;
if (bb2 > 0) if (bb2 > 0)
bb = __gdtoa_lshift(bb, bb2); bb = __gdtoa_lshift(bb, bb2, &TI);
else if (bb2 < 0) else if (bb2 < 0)
__gdtoa_rshift(bb, -bb2); __gdtoa_rshift(bb, -bb2);
if (bd5 > 0) if (bd5 > 0)
bd = __gdtoa_pow5mult(bd, bd5); bd = __gdtoa_pow5mult(bd, bd5, &TI);
if (bd2 > 0) if (bd2 > 0)
bd = __gdtoa_lshift(bd, bd2); bd = __gdtoa_lshift(bd, bd2, &TI);
if (bs2 > 0) if (bs2 > 0)
bs = __gdtoa_lshift(bs, bs2); bs = __gdtoa_lshift(bs, bs2, &TI);
asub = 1; asub = 1;
inex = STRTOG_Inexhi; inex = STRTOG_Inexhi;
delta = __gdtoa_diff(bb, bd); delta = __gdtoa_diff(bb, bd, &TI);
if (delta->wds <= 1 && !delta->x[0]) if (delta->wds <= 1 && !delta->x[0])
break; break;
dsign = delta->sign; dsign = delta->sign;
@ -637,7 +638,7 @@ rv_notOK:
if (j > 1 && lo0bits(rvb->x + i) < j - 1) if (j > 1 && lo0bits(rvb->x + i) < j - 1)
goto adj1; goto adj1;
rve = rve1 - 1; rve = rve1 - 1;
rvb = __gdtoa_set_ones(rvb, rvbits = nbits); rvb = __gdtoa_set_ones(rvb, rvbits = nbits, &TI);
break; break;
} }
irv |= dsign ? STRTOG_Inexlo : STRTOG_Inexhi; irv |= dsign ? STRTOG_Inexlo : STRTOG_Inexhi;
@ -652,7 +653,7 @@ rv_notOK:
: STRTOG_Normal | STRTOG_Inexhi; : STRTOG_Normal | STRTOG_Inexhi;
if (dsign || bbbits > 1 || denorm || rve1 == emin) if (dsign || bbbits > 1 || denorm || rve1 == emin)
break; break;
delta = __gdtoa_lshift(delta,1); delta = __gdtoa_lshift(delta,1,&TI);
if (__gdtoa_cmp(delta, bs) > 0) { if (__gdtoa_cmp(delta, bs) > 0) {
irv = STRTOG_Normal | STRTOG_Inexlo; irv = STRTOG_Normal | STRTOG_Inexlo;
goto drop_down; goto drop_down;
@ -684,7 +685,7 @@ rv_notOK:
break; break;
} }
rve -= nbits; rve -= nbits;
rvb = __gdtoa_set_ones(rvb, rvbits = nbits); rvb = __gdtoa_set_ones(rvb, rvbits = nbits, &TI);
break; break;
} }
else else
@ -692,7 +693,7 @@ rv_notOK:
if ((bbbits < nbits && !denorm) || !(rvb->x[0] & 1)) if ((bbbits < nbits && !denorm) || !(rvb->x[0] & 1))
break; break;
if (dsign) { if (dsign) {
rvb = __gdtoa_increment(rvb); rvb = __gdtoa_increment(rvb, &TI);
j = kmask & (ULbits - (rvbits & kmask)); j = kmask & (ULbits - (rvbits & kmask));
if (hi0bits(rvb->x[rvb->wds - 1]) != j) if (hi0bits(rvb->x[rvb->wds - 1]) != j)
rvbits++; rvbits++;
@ -759,20 +760,20 @@ rv_notOK:
/* adj *= __gdtoa_ulp(dval(&rv)); */ /* adj *= __gdtoa_ulp(dval(&rv)); */
/* if (asub) rv -= adj; else rv += adj; */ /* if (asub) rv -= adj; else rv += adj; */
if (!denorm && rvbits < nbits) { if (!denorm && rvbits < nbits) {
rvb = __gdtoa_lshift(rvb, j = nbits - rvbits); rvb = __gdtoa_lshift(rvb, j = nbits - rvbits, &TI);
rve -= j; rve -= j;
rvbits = nbits; rvbits = nbits;
} }
ab = __gdtoa_d2b(dval(&adj), &abe, &abits); ab = __gdtoa_d2b(dval(&adj), &abe, &abits, &TI);
if (abe < 0) if (abe < 0)
__gdtoa_rshift(ab, -abe); __gdtoa_rshift(ab, -abe);
else if (abe > 0) else if (abe > 0)
ab = __gdtoa_lshift(ab, abe); ab = __gdtoa_lshift(ab, abe, &TI);
rvb0 = rvb; rvb0 = rvb;
if (asub) { if (asub) {
/* rv -= adj; */ /* rv -= adj; */
j = hi0bits(rvb->x[rvb->wds-1]); j = hi0bits(rvb->x[rvb->wds-1]);
rvb = __gdtoa_diff(rvb, ab); rvb = __gdtoa_diff(rvb, ab, &TI);
k = rvb0->wds - 1; k = rvb0->wds - 1;
if (denorm) if (denorm)
/* do nothing */; /* do nothing */;
@ -785,7 +786,7 @@ rv_notOK:
denorm = 1; denorm = 1;
} }
else { else {
rvb = __gdtoa_lshift(rvb, 1); rvb = __gdtoa_lshift(rvb, 1, &TI);
--rve; --rve;
--rve1; --rve1;
L = finished = 0; L = finished = 0;
@ -793,7 +794,7 @@ rv_notOK:
} }
} }
else { else {
rvb = __gdtoa_sum(rvb, ab); rvb = __gdtoa_sum(rvb, ab, &TI);
k = rvb->wds - 1; k = rvb->wds - 1;
if (k >= rvb0->wds if (k >= rvb0->wds
|| hi0bits(rvb->x[k]) < hi0bits(rvb0->x[k])) { || hi0bits(rvb->x[k]) < hi0bits(rvb0->x[k])) {
@ -809,8 +810,8 @@ rv_notOK:
} }
} }
} }
__gdtoa_Bfree(ab); __gdtoa_Bfree(ab, &TI);
__gdtoa_Bfree(rvb0); __gdtoa_Bfree(rvb0, &TI);
if (finished) if (finished)
break; break;
z = rve + rvbits; z = rve + rvbits;
@ -830,27 +831,27 @@ rv_notOK:
} }
} }
bb0 = denorm ? 0 : __gdtoa_trailz(rvb); bb0 = denorm ? 0 : __gdtoa_trailz(rvb);
__gdtoa_Bfree(bb); __gdtoa_Bfree(bb, &TI);
__gdtoa_Bfree(bd); __gdtoa_Bfree(bd, &TI);
__gdtoa_Bfree(bs); __gdtoa_Bfree(bs, &TI);
__gdtoa_Bfree(delta); __gdtoa_Bfree(delta, &TI);
} }
if (!denorm && (j = nbits - rvbits)) { if (!denorm && (j = nbits - rvbits)) {
if (j > 0) if (j > 0)
rvb = __gdtoa_lshift(rvb, j); rvb = __gdtoa_lshift(rvb, j, &TI);
else else
__gdtoa_rshift(rvb, -j); __gdtoa_rshift(rvb, -j);
rve -= j; rve -= j;
} }
*exp = rve; *exp = rve;
__gdtoa_Bfree(bb); __gdtoa_Bfree(bb, &TI);
__gdtoa_Bfree(bd); __gdtoa_Bfree(bd, &TI);
__gdtoa_Bfree(bs); __gdtoa_Bfree(bs, &TI);
__gdtoa_Bfree(bd0); __gdtoa_Bfree(bd0, &TI);
__gdtoa_Bfree(delta); __gdtoa_Bfree(delta, &TI);
if (rve > fpi->emax) { if (rve > fpi->emax) {
huge: huge:
__gdtoa_Bfree(rvb); __gdtoa_Bfree(rvb, &TI);
rvb = 0; rvb = 0;
errno = ERANGE; errno = ERANGE;
switch(fpi->rounding & 3) { switch(fpi->rounding & 3) {
@ -904,7 +905,7 @@ ret:
irv |= STRTOG_Neg; irv |= STRTOG_Neg;
if (rvb) { if (rvb) {
__gdtoa_copybits(bits, nbits, rvb); __gdtoa_copybits(bits, nbits, rvb);
__gdtoa_Bfree(rvb); __gdtoa_Bfree(rvb, &TI);
} }
return irv; return irv;
} }

View file

@ -33,7 +33,7 @@
/* clang-format off */ /* clang-format off */
Bigint * Bigint *
__gdtoa_sum(Bigint *a, Bigint *b) __gdtoa_sum(Bigint *a, Bigint *b, ThInfo **PTI)
{ {
Bigint *c; Bigint *c;
ULong carry, *xc, *xa, *xb, *xe, y; ULong carry, *xc, *xa, *xb, *xe, y;
@ -41,7 +41,7 @@ __gdtoa_sum(Bigint *a, Bigint *b)
if (a->wds < b->wds) { if (a->wds < b->wds) {
c = b; b = a; a = c; c = b; b = a; a = c;
} }
c = __gdtoa_Balloc(a->k); c = __gdtoa_Balloc(a->k, PTI);
c->wds = a->wds; c->wds = a->wds;
carry = 0; carry = 0;
xa = a->x; xa = a->x;
@ -66,9 +66,9 @@ __gdtoa_sum(Bigint *a, Bigint *b)
} }
if (carry) { if (carry) {
if (c->wds == c->maxwds) { if (c->wds == c->maxwds) {
b = __gdtoa_Balloc(c->k + 1); b = __gdtoa_Balloc(c->k + 1, PTI);
Bcopy(b, c); Bcopy(b, c);
__gdtoa_Bfree(c); __gdtoa_Bfree(c, PTI);
c = b; c = b;
} }
c->x[c->wds++] = 1; c->x[c->wds++] = 1;

View file

@ -224,6 +224,7 @@ THIRD_PARTY_LUA_LUA_DIRECTDEPS = \
LIBC_INTRIN \ LIBC_INTRIN \
LIBC_NEXGEN32E \ LIBC_NEXGEN32E \
LIBC_STDIO \ LIBC_STDIO \
LIBC_LOG \
LIBC_STR \ LIBC_STR \
LIBC_SYSV \ LIBC_SYSV \
THIRD_PARTY_LINENOISE \ THIRD_PARTY_LINENOISE \