From noreply at buildbot.pypy.org Sun Feb 1 00:27:14 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Sun, 1 Feb 2015 00:27:14 +0100 (CET)
Subject: [pypy-commit] stmgc hashtable-iter: maybe found a simpler and
better way
Message-ID: <20150131232714.969421C02B3@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: hashtable-iter
Changeset: r1599:274a3dfec8ad
Date: 2015-02-01 00:27 +0100
http://bitbucket.org/pypy/stmgc/changeset/274a3dfec8ad/
Log: maybe found a simpler and better way
diff --git a/c7/stm/hashtable.c b/c7/stm/hashtable.c
--- a/c7/stm/hashtable.c
+++ b/c7/stm/hashtable.c
@@ -25,6 +25,10 @@
transaction rather than the modifying transaction, which is probably
what we want.
+XXX NO: when creating new key/value objects, we should copy the read
+marker from the hashtableobj to the new key/value object. I *think*
+this gives a correct and better result XXX
+
Implementation
--------------
@@ -231,7 +235,16 @@
perturb >>= PERTURB_SHIFT;
}
}
- /* here, we didn't find the 'entry' with the correct index. */
+ /* here, we didn't find the 'entry' with the correct index. Note
+ that even if the same 'table' is modified or resized by other
+ threads concurrently, any new item found from a race condition
+ would anyway contain NULL in the present segment (ensured by
+ the first write_fence() below). If the 'table' grows an entry
+ just after we checked above, then we go ahead and lock the
+ table; but after we get the lock, we will notice the new entry
+ (ensured by the second write_fence() below) and restart the
+ whole process.
+ */
intptr_t rc = VOLATILE_TABLE(table)->resize_counter;
bool rc_must_be_negative = false;
@@ -347,9 +360,25 @@
*/
int j, my_segment = STM_SEGMENT->segment_num;
for (j = 1; j <= NB_SEGMENTS; j++) {
- if (j != my_segment) {
- if (was_read_remote(get_segment_base(j), hashtableobj)) {
- xxxxxxxxxxxx conflict xxxxxxxxxxx;
+ if (j == my_segment)
+ continue;
+ if (was_read_remote(get_segment_base(j), hashtableobj)) {
+ /* conflict! */
+ table->resize_counter = rc; /* unlock */
+ if (write_read_contention_management(j, hashtableobj)) {
+ /* If we reach this point, we didn't abort, but we
+ had to wait for the other thread to commit. If
+ we did, then we have to restart. */
+ return true;
+ ...;
+
+ }
+ /* we aborted the other transaction without waiting, so
+ we can just break out of this loop on
+ modified_old_objects and continue with the next
+ segment */
+
+ xxx;
}
}
}
@@ -458,14 +487,15 @@
static void _stm_compact_hashtable(stm_hashtable_t *hashtable)
{
stm_hashtable_table_t *table = hashtable->table;
- assert(!IS_EVEN(table->resize_counter));
+ intptr_t rc = table->resize_counter;
+ assert(!IS_EVEN(rc));
if ((hashtable->additions >> 8) * 4 > table->mask) {
int segment_num = (hashtable->additions & 0xFF);
if (!segment_num) segment_num = 1;
hashtable->additions = segment_num;
uintptr_t initial_rc = (table->mask + 1) * 4 + 1;
- uintptr_t num_entries_times_6 = initial_rc - table->resize_counter;
+ uintptr_t num_entries_times_6 = initial_rc - (rc < 0 ? -rc : rc);
uintptr_t count = INITIAL_HASHTABLE_SIZE;
while (count * 4 < num_entries_times_6)
count *= 2;
@@ -475,7 +505,7 @@
dprintf(("compact with %ld items:\n", num_entries_times_6 / 6));
_stm_rehash_hashtable(hashtable, count, /*remove_unread=*/segment_num,
- /*rc_must_be_negative=*/false);
+ /*rc_must_be_negative=*/rc < 0);
}
table = hashtable->table;
From noreply at buildbot.pypy.org Sun Feb 1 01:28:54 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Sun, 1 Feb 2015 01:28:54 +0100 (CET)
Subject: [pypy-commit] stmgc hashtable-iter: in-progress,
getting there hopefully
Message-ID: <20150201002854.42BA41C0141@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: hashtable-iter
Changeset: r1600:06c31e9c06f8
Date: 2015-02-01 01:29 +0100
http://bitbucket.org/pypy/stmgc/changeset/06c31e9c06f8/
Log: in-progress, getting there hopefully
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -281,10 +281,9 @@
static stm_thread_local_t *abort_with_mutex_no_longjmp(void);
static void abort_data_structures_from_segment_num(int segment_num);
-static inline bool was_read_local(object_t *obj)
-{
- return ((stm_read_marker_t *)(((uintptr_t)obj) >> 4))->rm ==
- STM_SEGMENT->transaction_read_version;
+static inline struct stm_read_marker_s *get_read_marker(char *base,
+ object_t *obj) {
+ return (struct stm_read_marker_s *)(base + (((uintptr_t)obj) >> 4));
}
static inline bool was_read_remote(char *base, object_t *obj)
@@ -292,8 +291,7 @@
uint8_t other_transaction_read_version =
((struct stm_segment_info_s *)REAL_ADDRESS(base, STM_PSEGMENT))
->transaction_read_version;
- uint8_t rm = ((struct stm_read_marker_s *)
- (base + (((uintptr_t)obj) >> 4)))->rm;
+ uint8_t rm = get_read_marker(base, obj)->rm;
assert(rm <= other_transaction_read_version);
return rm == other_transaction_read_version;
}
diff --git a/c7/stm/hashtable.c b/c7/stm/hashtable.c
--- a/c7/stm/hashtable.c
+++ b/c7/stm/hashtable.c
@@ -12,22 +12,16 @@
collision).
The main operations on a hashtable are reading or writing an object at a
-given index. It also supports iterating its non-NULL entries.
+given index. It also supports fetching the list of non-NULL entries.
There are two markers for every index (a read and a write marker).
This is unlike regular arrays, which have only two markers in total.
Additionally, we use the read marker for the hashtable object itself
-to mean "we are iterating". When a transaction has got this "global"
-read marker and another transaction attempts to create a new key/value
-pair via stm_hashtable_{lookup,read,write}, the call immediately fails
-with a read/write conflict. This gives priority to the iterating
-transaction rather than the modifying transaction, which is probably
-what we want.
-
-XXX NO: when creating new key/value objects, we should copy the read
-marker from the hashtableobj to the new key/value object. I *think*
-this gives a correct and better result XXX
+to mean "we have read the complete list of keys". This plays the role
+of a "global" read marker: when any thread adds a new key/value object
+to the hashtable, this new object's read marker is initialized with a
+copy of the "global" read marker --- in all segments.
Implementation
@@ -66,12 +60,8 @@
The field 'resize_counter' also works as a write lock: changes
go via the intermediate value RESIZING_LOCK (0).
-
- In addition, 'resize_counter' can be the negation of the odd
- number that it would normally be: in this case it is "probably
- write-protected" (see stm_hashtable_next()).
*/
- intptr_t resize_counter;
+ uintptr_t resize_counter;
stm_hashtable_entry_t *items[INITIAL_HASHTABLE_SIZE];
} stm_hashtable_table_t;
@@ -104,7 +94,7 @@
void stm_hashtable_free(stm_hashtable_t *hashtable)
{
- intptr_t rc = hashtable->initial_table.resize_counter;
+ uintptr_t rc = hashtable->initial_table.resize_counter;
free(hashtable);
while (IS_EVEN(rc)) {
assert(rc != RESIZING_LOCK);
@@ -119,9 +109,7 @@
{
long i;
for (i = 1; i <= NB_SEGMENTS; i++) {
- char *remote_base = get_segment_base(i);
- uint8_t remote_version = get_segment(i)->transaction_read_version;
- if (was_read_remote(remote_base, obj, remote_version))
+ if (was_read_remote(get_segment_base(i), obj))
return true;
}
return false;
@@ -155,8 +143,7 @@
static void _stm_rehash_hashtable(stm_hashtable_t *hashtable,
uintptr_t biggercount,
- int remove_unread_from_seg,
- bool rc_must_be_negative)
+ int remove_unread_from_seg)
{
dprintf(("rehash %p to %ld, remove_unread_from_seg=%d\n",
hashtable, biggercount, remove_unread_from_seg));
@@ -167,7 +154,7 @@
assert(biggertable); // XXX
stm_hashtable_table_t *table = hashtable->table;
- table->resize_counter = (intptr_t)biggertable;
+ table->resize_counter = (uintptr_t)biggertable;
/* ^^^ this unlocks the table by writing a non-zero value to
table->resize_counter, but the new value is a pointer to the
new bigger table, so IS_EVEN() is still true */
@@ -176,7 +163,7 @@
init_table(biggertable, biggercount);
uintptr_t j, mask = table->mask;
- intptr_t rc = biggertable->resize_counter;
+ uintptr_t rc = biggertable->resize_counter;
char *segment_base = get_segment_base(remove_unread_from_seg);
for (j = 0; j <= mask; j++) {
stm_hashtable_entry_t *entry = table->items[j];
@@ -191,10 +178,10 @@
}
}
_insert_clean(biggertable, entry);
+ assert(rc > 6);
rc -= 6;
}
- assert(rc > 0);
- biggertable->resize_counter = rc_must_be_negative ? -rc : rc;
+ biggertable->resize_counter = rc;
write_fence(); /* make sure that 'biggertable' is valid here,
and make sure 'table->resize_counter' is updated
@@ -246,8 +233,7 @@
whole process.
*/
- intptr_t rc = VOLATILE_TABLE(table)->resize_counter;
- bool rc_must_be_negative = false;
+ uintptr_t rc = VOLATILE_TABLE(table)->resize_counter;
/* if rc is RESIZING_LOCK (which is 0, so even), a concurrent thread
is writing to the hashtable. Or, if rc is another even number, it is
@@ -279,7 +265,6 @@
/* if rc is greater than 6, there is enough room for a new
item in the current table.
*/
- retry_adding:
if (rc > 6) {
/* we can only enter here once! If we allocate stuff, we may
run the GC, and so 'hashtableobj' might move afterwards. */
@@ -312,12 +297,22 @@
synchronization with other pieces of the code that may
change.
*/
+
+ /* First fetch the read marker of 'hashtableobj' in all
+ segments, before allocate_outside_nursery_large()
+ which might trigger a GC */
+ long j;
+ uint8_t readmarkers[NB_SEGMENTS];
+ for (j = 1; j <= NB_SEGMENTS; j++) {
+ readmarkers[j - 1] = get_read_marker(get_segment_base(j),
+ hashtableobj)->rm;
+ }
+
acquire_privatization_lock();
char *p = allocate_outside_nursery_large(
sizeof(stm_hashtable_entry_t));
entry = (stm_hashtable_entry_t *)(p - stm_object_pages);
- long j;
for (j = 0; j <= NB_SEGMENTS; j++) {
struct stm_hashtable_entry_s *e;
e = (struct stm_hashtable_entry_s *)
@@ -329,16 +324,19 @@
}
hashtable->additions += 0x100;
release_privatization_lock();
+
+ for (j = 1; j <= NB_SEGMENTS; j++) {
+ get_read_marker(get_segment_base(j), (object_t *)entry)->rm =
+ readmarkers[j - 1];
+ }
}
write_fence(); /* make sure 'entry' is fully initialized here */
table->items[i] = entry;
write_fence(); /* make sure 'table->items' is written here */
- rc -= 6;
- VOLATILE_TABLE(table)->resize_counter = (
- rc_must_be_negative ? -rc : rc); /* unlock */
+ VOLATILE_TABLE(table)->resize_counter = rc - 6; /* unlock */
return entry;
}
- else if (rc > 0) {
+ else {
/* if rc is smaller than 6, we must allocate a new bigger table.
*/
uintptr_t biggercount = table->mask + 1;
@@ -346,52 +344,9 @@
biggercount *= 4;
else
biggercount *= 2;
- _stm_rehash_hashtable(hashtable, biggercount, /*remove_unread=*/0,
- rc_must_be_negative);
+ _stm_rehash_hashtable(hashtable, biggercount, /*remove_unread=*/0);
goto restart;
}
- else {
- assert(rc < 0);
- assert(!_is_in_nursery(hashtableobj));
-
- /* if rc is negative, the hashtable is probably write-protected.
- Check if the read marker of the 'hashtableobj' is set in
- another segment.
- */
- int j, my_segment = STM_SEGMENT->segment_num;
- for (j = 1; j <= NB_SEGMENTS; j++) {
- if (j == my_segment)
- continue;
- if (was_read_remote(get_segment_base(j), hashtableobj)) {
- /* conflict! */
- table->resize_counter = rc; /* unlock */
- if (write_read_contention_management(j, hashtableobj)) {
- /* If we reach this point, we didn't abort, but we
- had to wait for the other thread to commit. If
- we did, then we have to restart. */
- return true;
- ...;
-
- }
- /* we aborted the other transaction without waiting, so
- we can just break out of this loop on
- modified_old_objects and continue with the next
- segment */
-
- xxx;
- }
- }
- }
-
- /* if even in this thread's segment it was not read, then there
- is no point in keeping it write-protected. So we set
- 'rc_must_be_negative', i.e. keep it write-protected, iff
- it was read locally.
- */
- rc_must_be_negative = was_read_local(hashtableobj);
- rc = -rc;
- goto retry_adding;
- }
}
object_t *stm_hashtable_read(object_t *hobj, stm_hashtable_t *hashtable,
@@ -413,81 +368,86 @@
e->object = nvalue;
}
-struct stm_hashtable_entry_s *
-stm_hashtable_next(object_t *hobj, stm_hashtable_t *hashtable,
- uintptr_t *pposition, stm_thread_local_t *tl)
+long stm_hashtable_length_upper_bound(stm_hashtable_t *hashtable)
{
- /* this assumes the simple c7 model whereby commits only occur with
- all other transaction paused at a known point. */
+ stm_hashtable_table_t *table;
+ uintptr_t rc;
+
+ restart:
+ table = VOLATILE_HASHTABLE(hashtable)->table;
+ rc = VOLATILE_TABLE(table)->resize_counter;
+ if (IS_EVEN(rc)) {
+ spin_loop();
+ goto restart;
+ }
+
+ uintptr_t initial_rc = (table->mask + 1) * 4 + 1;
+ uintptr_t num_entries_times_6 = initial_rc - rc;
+ return num_entries_times_6 / 6;
+}
+
+long stm_hashtable_list(object_t *hobj, stm_hashtable_t *hashtable,
+ stm_hashtable_entry_t **results)
+{
stm_hashtable_table_t *table;
intptr_t rc;
- /* First set the read marker. It will be left as long as we're running
- the same transaction. Note that this code assumes that nothing else
- can set the read marker! Also, if 'hobj' is still in the nursery,
- it was created by this transaction and there is nothing to do.
+ /* Set the read marker. It will be left as long as we're running
+ the same transaction.
*/
- if (!_is_in_nursery(hobj) && !was_read_local(hobj)) {
+ stm_read(hobj);
- stm_read(hobj);
+ /* Acquire and immediately release the lock. We don't actually
+ need to do anything while we hold the lock, but the point is to
+ wait until the lock is available, and to synchronize other
+ threads with the stm_read() done above.
+ */
+ restart:
+ table = VOLATILE_HASHTABLE(hashtable)->table;
+ rc = VOLATILE_TABLE(table)->resize_counter;
+ if (IS_EVEN(rc)) {
+ spin_loop();
+ goto restart;
+ }
+ if (!__sync_bool_compare_and_swap(&table->resize_counter, rc, rc))
+ goto restart;
- /* Change the 'resize_counter' field to its negative value. This
- must be done after we've set the read marker. */
- restart:
- table = VOLATILE_HASHTABLE(hashtable)->table;
- rc = VOLATILE_TABLE(table)->resize_counter;
- if (IS_EVEN(rc)) {
- spin_loop();
- goto restart;
+ /* Read all entries, check which ones are not NULL, count them,
+ and optionally list them in 'results'.
+ */
+ uintptr_t i, mask = table->mask;
+ stm_hashtable_entry_t *entry;
+ long nresult = 0;
+
+ if (results != NULL) {
+ /* collect the results in the provided list */
+ for (i = 0; i <= mask; i++) {
+ entry = VOLATILE_TABLE(table)->items[i];
+ if (entry != NULL) {
+ stm_read((object_t *)entry);
+ if (entry->object != NULL)
+ results[nresult++] = entry;
+ }
}
- if (!__sync_bool_compare_and_swap(&table->resize_counter, rc,
- rc > 0 ? -rc : rc))
- goto restart;
- /* Note that we did a compare-and-swap even if rc was already
- negative. This is needed for its memory-ordering effect,
- to ensure that from now on the other threads do see our
- read marker set. */
}
else {
- /* Read marker already set. Assume (and assert) that we
- already set a negative value into 'resize_counter'.
- Changes of 'table' or 'resize_counter' under our feet
- should not be possible here.
- */
- table = hashtable->table;
-
- if (!_is_in_nursery(hobj)) {
- assert(!IS_EVEN(table->resize_counter) &&
- table->resize_counter < 0);
+ /* don't collect, just get the exact number of results */
+ for (i = 0; i <= mask; i++) {
+ entry = VOLATILE_TABLE(table)->items[i];
+ if (entry != NULL) {
+ stm_read((object_t *)entry);
+ if (entry->object != NULL)
+ nresult++;
+ }
}
}
-
- /* At this point, the hashtable is write-protected: no other
- thread may add new key/value objects nor grow/replace the
- 'table'. The hashtable will remain write-protected as long as
- this transaction is running. Note that *this* thread is
- allowed to continue modifying the hashtable (unless another
- thread did also set a write protection).
- */
- uintptr_t position = *pposition;
- uintptr_t mask = table->mask;
- stm_hashtable_entry_t *entry;
-
- while (position <= mask) {
- entry = table->items[position++];
- if (entry != NULL) {
- *pposition = position;
- return entry;
- }
- }
- *pposition = (uintptr_t)-1;
- return NULL;
+ return nresult;
}
static void _stm_compact_hashtable(stm_hashtable_t *hashtable)
{
stm_hashtable_table_t *table = hashtable->table;
- intptr_t rc = table->resize_counter;
+ uintptr_t rc = table->resize_counter;
assert(!IS_EVEN(rc));
if ((hashtable->additions >> 8) * 4 > table->mask) {
@@ -495,7 +455,7 @@
if (!segment_num) segment_num = 1;
hashtable->additions = segment_num;
uintptr_t initial_rc = (table->mask + 1) * 4 + 1;
- uintptr_t num_entries_times_6 = initial_rc - (rc < 0 ? -rc : rc);
+ uintptr_t num_entries_times_6 = initial_rc - rc;
uintptr_t count = INITIAL_HASHTABLE_SIZE;
while (count * 4 < num_entries_times_6)
count *= 2;
@@ -504,15 +464,14 @@
assert(count <= table->mask + 1);
dprintf(("compact with %ld items:\n", num_entries_times_6 / 6));
- _stm_rehash_hashtable(hashtable, count, /*remove_unread=*/segment_num,
- /*rc_must_be_negative=*/rc < 0);
+ _stm_rehash_hashtable(hashtable, count, /*remove_unread=*/segment_num);
}
table = hashtable->table;
assert(!IS_EVEN(table->resize_counter));
if (table != &hashtable->initial_table) {
- intptr_t rc = hashtable->initial_table.resize_counter;
+ uintptr_t rc = hashtable->initial_table.resize_counter;
while (1) {
assert(IS_EVEN(rc));
assert(rc != RESIZING_LOCK);
@@ -523,7 +482,7 @@
rc = old_table->resize_counter;
free(old_table);
}
- hashtable->initial_table.resize_counter = (intptr_t)table;
+ hashtable->initial_table.resize_counter = (uintptr_t)table;
assert(IS_EVEN(hashtable->initial_table.resize_counter));
}
}
diff --git a/c7/stm/misc.c b/c7/stm/misc.c
--- a/c7/stm/misc.c
+++ b/c7/stm/misc.c
@@ -31,7 +31,7 @@
bool _stm_was_read(object_t *obj)
{
- return was_read_local(obj);
+ return was_read_remote(STM_SEGMENT->segment_base, obj);
}
bool _stm_was_written(object_t *obj)
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -545,8 +545,9 @@
object_t *stm_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key);
void stm_hashtable_write(object_t *, stm_hashtable_t *, uintptr_t key,
object_t *nvalue, stm_thread_local_t *);
-struct stm_hashtable_entry_s *stm_hashtable_next(
- object_t *, stm_hashtable_t *, uintptr_t *pposition, stm_thread_local_t *);
+long stm_hashtable_length_upper_bound(stm_hashtable_t *);
+long stm_hashtable_list(object_t *, stm_hashtable_t *,
+ stm_hashtable_entry_t **results);
extern uint32_t stm_hashtable_entry_userdata;
void stm_hashtable_tracefn(stm_hashtable_t *, void (object_t **));
From noreply at buildbot.pypy.org Sun Feb 1 10:19:46 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Sun, 1 Feb 2015 10:19:46 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: Do a single lookup in all methods of
hashtable, stmset and stmdict.
Message-ID: <20150201091946.F15921C039A@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75617:982b5fc67ac4
Date: 2015-02-01 10:19 +0100
http://bitbucket.org/pypy/pypy/changeset/982b5fc67ac4/
Log: Do a single lookup in all methods of hashtable, stmset and stmdict.
diff --git a/pypy/module/pypystm/hashtable.py b/pypy/module/pypystm/hashtable.py
--- a/pypy/module/pypystm/hashtable.py
+++ b/pypy/module/pypystm/hashtable.py
@@ -25,15 +25,15 @@
@unwrap_spec(key=int)
def setitem_w(self, key, w_value):
- gcref = cast_instance_to_gcref(w_value)
- self.h.set(key, gcref)
+ entry = self.h.lookup(key)
+ entry.object = cast_instance_to_gcref(w_value)
@unwrap_spec(key=int)
def delitem_w(self, space, key):
- gcref = self.h.get(key)
- if not gcref:
+ entry = self.h.lookup(key)
+ if not entry.object:
space.raise_key_error(space.wrap(key))
- self.h.set(key, rstm.NULL_GCREF)
+ entry.object = rstm.NULL_GCREF
@unwrap_spec(key=int)
def contains_w(self, space, key):
@@ -49,10 +49,10 @@
@unwrap_spec(key=int, w_default=WrappedDefault(None))
def setdefault_w(self, space, key, w_default):
- gcref = self.h.get(key)
+ entry = self.h.lookup(key)
+ gcref = entry.object
if not gcref:
- gcref = cast_instance_to_gcref(w_default)
- self.h.set(key, gcref)
+ entry.object = cast_instance_to_gcref(w_default)
return w_default
return cast_gcref_to_instance(W_Root, gcref)
diff --git a/pypy/module/pypystm/stmdict.py b/pypy/module/pypystm/stmdict.py
--- a/pypy/module/pypystm/stmdict.py
+++ b/pypy/module/pypystm/stmdict.py
@@ -61,8 +61,8 @@
def setitem_w(self, space, w_key, w_value):
hkey = space.hash_w(w_key)
- gcref = self.h.get(hkey)
- array = lltype.cast_opaque_ptr(PARRAY, gcref)
+ entry = self.h.lookup(hkey)
+ array = lltype.cast_opaque_ptr(PARRAY, entry.object)
if array:
i = find_equal_item(space, array, w_key)
if i >= 0:
@@ -77,13 +77,12 @@
L = 0
narray[L] = cast_instance_to_gcref(w_key)
narray[L + 1] = cast_instance_to_gcref(w_value)
- gcref = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
- self.h.set(hkey, gcref)
+ entry.object = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
def delitem_w(self, space, w_key):
hkey = space.hash_w(w_key)
- gcref = self.h.get(hkey)
- array = lltype.cast_opaque_ptr(PARRAY, gcref)
+ entry = self.h.lookup(hkey)
+ array = lltype.cast_opaque_ptr(PARRAY, entry.object)
if array:
i = find_equal_item(space, array, w_key)
if i >= 0:
@@ -95,8 +94,7 @@
narray = lltype.malloc(ARRAY, L)
ll_arraycopy(array, narray, 0, 0, i)
ll_arraycopy(array, narray, i + 2, i, L - i)
- gcref = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
- self.h.set(hkey, gcref)
+ entry.object = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
return
space.raise_key_error(w_key)
@@ -122,8 +120,8 @@
@unwrap_spec(w_default=WrappedDefault(None))
def setdefault_w(self, space, w_key, w_default):
hkey = space.hash_w(w_key)
- gcref = self.h.get(hkey)
- array = lltype.cast_opaque_ptr(PARRAY, gcref)
+ entry = self.h.lookup(hkey)
+ array = lltype.cast_opaque_ptr(PARRAY, entry.object)
if array:
i = find_equal_item(space, array, w_key)
if i >= 0:
@@ -137,8 +135,7 @@
L = 0
narray[L] = cast_instance_to_gcref(w_key)
narray[L + 1] = cast_instance_to_gcref(w_default)
- gcref = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
- self.h.set(hkey, gcref)
+ entry.object = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
return w_default
diff --git a/pypy/module/pypystm/stmset.py b/pypy/module/pypystm/stmset.py
--- a/pypy/module/pypystm/stmset.py
+++ b/pypy/module/pypystm/stmset.py
@@ -53,8 +53,8 @@
def add_w(self, space, w_key):
hkey = space.hash_w(w_key)
- gcref = self.h.get(hkey)
- array = lltype.cast_opaque_ptr(PARRAY, gcref)
+ entry = self.h.lookup(hkey)
+ array = lltype.cast_opaque_ptr(PARRAY, entry.object)
if array:
if find_equal_item(space, array, w_key) >= 0:
return # already there
@@ -65,13 +65,12 @@
narray = lltype.malloc(ARRAY, 1)
L = 0
narray[L] = cast_instance_to_gcref(w_key)
- gcref = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
- self.h.set(hkey, gcref)
+ entry.object = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
def try_remove(self, space, w_key):
hkey = space.hash_w(w_key)
- gcref = self.h.get(hkey)
- array = lltype.cast_opaque_ptr(PARRAY, gcref)
+ entry = self.h.lookup(hkey)
+ array = lltype.cast_opaque_ptr(PARRAY, entry.object)
if not array:
return False
i = find_equal_item(space, array, w_key)
@@ -85,8 +84,7 @@
narray = lltype.malloc(ARRAY, L)
ll_arraycopy(array, narray, 0, 0, i)
ll_arraycopy(array, narray, i + 1, i, L - i)
- gcref = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
- self.h.set(hkey, gcref)
+ entry.object = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
return True
def remove_w(self, space, w_key):
diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py
--- a/rpython/rlib/rstm.py
+++ b/rpython/rlib/rstm.py
@@ -181,6 +181,7 @@
_STM_HASHTABLE_ENTRY = lltype.GcStruct('HASHTABLE_ENTRY',
('index', lltype.Unsigned),
('object', llmemory.GCREF))
+_STM_HASHTABLE_ENTRY_P = lltype.Ptr(_STM_HASHTABLE_ENTRY)
@dont_look_inside
def _ll_hashtable_get(h, key):
@@ -191,11 +192,17 @@
def _ll_hashtable_set(h, key, value):
llop.stm_hashtable_write(lltype.Void, h, h.ll_raw_hashtable, key, value)
+ at dont_look_inside
+def _ll_hashtable_lookup(h, key):
+ return llop.stm_hashtable_lookup(_STM_HASHTABLE_ENTRY_P,
+ h, h.ll_raw_hashtable, key)
+
_HASHTABLE_OBJ = lltype.GcStruct('HASHTABLE_OBJ',
('ll_raw_hashtable', _STM_HASHTABLE_P),
rtti=True,
adtmeths={'get': _ll_hashtable_get,
- 'set': _ll_hashtable_set})
+ 'set': _ll_hashtable_set,
+ 'lookup': _ll_hashtable_lookup})
NULL_HASHTABLE = lltype.nullptr(_HASHTABLE_OBJ)
def _ll_hashtable_trace(gc, obj, callback, arg):
@@ -254,3 +261,19 @@
del self._content[key]
except KeyError:
pass
+
+ def lookup(self, key):
+ assert type(key) is int
+ return EntryObjectForTest(self, key)
+
+class EntryObjectForTest(object):
+ def __init__(self, hashtable, key):
+ self.hashtable = hashtable
+ self.key = key
+
+ def _getobj(self):
+ return self.hashtable.get(self.key)
+ def _setobj(self, nvalue):
+ self.hashtable.set(self.key, nvalue)
+
+ object = property(_getobj, _setobj)
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -464,6 +464,7 @@
'stm_hashtable_free': LLOp(),
'stm_hashtable_read': LLOp(),
'stm_hashtable_write': LLOp(),
+ 'stm_hashtable_lookup': LLOp(),
'stm_hashtable_tracefn': LLOp(),
# __________ address operations __________
diff --git a/rpython/translator/stm/funcgen.py b/rpython/translator/stm/funcgen.py
--- a/rpython/translator/stm/funcgen.py
+++ b/rpython/translator/stm/funcgen.py
@@ -312,6 +312,14 @@
return ('stm_hashtable_write((object_t *)%s, %s, %s, (object_t *)%s, '
'&stm_thread_local);' % (arg0, arg1, arg2, arg3))
+def stm_hashtable_lookup(funcgen, op):
+ arg0 = funcgen.expr(op.args[0])
+ arg1 = funcgen.expr(op.args[1])
+ arg2 = funcgen.expr(op.args[2])
+ result = funcgen.expr(op.result)
+ return '%s = stm_hashtable_lookup((object_t *)%s, %s, %s);' % (
+ result, arg0, arg1, arg2)
+
def stm_hashtable_tracefn(funcgen, op):
arg0 = funcgen.expr(op.args[0])
arg1 = funcgen.expr(op.args[1])
From noreply at buildbot.pypy.org Sun Feb 1 10:50:20 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Sun, 1 Feb 2015 10:50:20 +0100 (CET)
Subject: [pypy-commit] stmgc hashtable-iter: Adding tests for
stm_hashtable_list
Message-ID: <20150201095020.C4CCF1C039A@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: hashtable-iter
Changeset: r1601:5e3761dd15b6
Date: 2015-02-01 10:50 +0100
http://bitbucket.org/pypy/stmgc/changeset/5e3761dd15b6/
Log: Adding tests for stm_hashtable_list
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -167,17 +167,23 @@
void (*stmcb_finalizer)(object_t *);
typedef struct stm_hashtable_s stm_hashtable_t;
+typedef ... stm_hashtable_entry_t;
stm_hashtable_t *stm_hashtable_create(void);
void stm_hashtable_free(stm_hashtable_t *);
bool _check_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key);
object_t *hashtable_read_result;
bool _check_hashtable_write(object_t *, stm_hashtable_t *, uintptr_t key,
object_t *nvalue, stm_thread_local_t *tl);
+long stm_hashtable_length_upper_bound(stm_hashtable_t *);
+long stm_hashtable_list(object_t *, stm_hashtable_t *,
+ stm_hashtable_entry_t **results);
uint32_t stm_hashtable_entry_userdata;
void stm_hashtable_tracefn(stm_hashtable_t *, void (object_t **));
void _set_hashtable(object_t *obj, stm_hashtable_t *h);
stm_hashtable_t *_get_hashtable(object_t *obj);
+uintptr_t _get_entry_index(stm_hashtable_entry_t *entry);
+object_t *_get_entry_object(stm_hashtable_entry_t *entry);
""")
@@ -308,6 +314,18 @@
return *(stm_hashtable_t *TLPREFIX *)field_addr;
}
+uintptr_t _get_entry_index(stm_hashtable_entry_t *entry)
+{
+ stm_read((object_t *)entry);
+ return entry->index;
+}
+
+object_t *_get_entry_object(stm_hashtable_entry_t *entry)
+{
+ stm_read((object_t *)entry);
+ return entry->object;
+}
+
void _set_ptr(object_t *obj, int n, object_t *v)
{
long nrefs = (long)((myobj_t*)obj)->type_id - 421420;
diff --git a/c7/test/test_hashtable.py b/c7/test/test_hashtable.py
--- a/c7/test/test_hashtable.py
+++ b/c7/test/test_hashtable.py
@@ -16,6 +16,19 @@
if res:
raise Conflict
+def ht_length_upper_bound(o):
+ h = get_hashtable(o)
+ return lib.stm_hashtable_length_upper_bound(h)
+
+def htitems(o):
+ h = get_hashtable(o)
+ upper_bound = lib.stm_hashtable_length_upper_bound(h)
+ entries = ffi.new("stm_hashtable_entry_t *[]", upper_bound)
+ count = lib.stm_hashtable_list(o, h, entries)
+ assert count <= upper_bound
+ return [(lib._get_entry_index(entries[i]),
+ lib._get_entry_object(entries[i])) for i in range(count)]
+
class BaseTestHashtable(BaseTest):
@@ -236,6 +249,28 @@
assert htget(h, 11) != ffi.NULL
assert htget(h, 12) != ffi.NULL
+ def test_list_1(self):
+ self.start_transaction()
+ h = self.allocate_hashtable()
+ tl0 = self.tls[self.current_thread]
+ for i in range(32):
+ assert ht_length_upper_bound(h) == i
+ htset(h, 19 ^ i, stm_allocate(32), tl0)
+ assert ht_length_upper_bound(h) == 32
+
+ def test_list_2(self):
+ self.start_transaction()
+ h = self.allocate_hashtable()
+ tl0 = self.tls[self.current_thread]
+ expected = []
+ for i in range(29):
+ lp = stm_allocate(32)
+ htset(h, 19 ^ i, lp, tl0)
+ expected.append((19 ^ i, lp))
+ lst = htitems(h)
+ assert len(lst) == 29
+ assert sorted(lst) == sorted(expected)
+
class TestRandomHashtable(BaseTestHashtable):
From noreply at buildbot.pypy.org Sun Feb 1 10:52:10 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Sun, 1 Feb 2015 10:52:10 +0100 (CET)
Subject: [pypy-commit] stmgc hashtable-iter: test stm_hashtable_list(...,
NULL)
Message-ID: <20150201095210.89EAC1C039A@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: hashtable-iter
Changeset: r1602:de27e8f11e38
Date: 2015-02-01 10:52 +0100
http://bitbucket.org/pypy/stmgc/changeset/de27e8f11e38/
Log: test stm_hashtable_list(..., NULL)
diff --git a/c7/test/test_hashtable.py b/c7/test/test_hashtable.py
--- a/c7/test/test_hashtable.py
+++ b/c7/test/test_hashtable.py
@@ -29,6 +29,11 @@
return [(lib._get_entry_index(entries[i]),
lib._get_entry_object(entries[i])) for i in range(count)]
+def htlen(o):
+ h = get_hashtable(o)
+ count = lib.stm_hashtable_list(o, h, ffi.NULL)
+ return count
+
class BaseTestHashtable(BaseTest):
@@ -271,6 +276,14 @@
assert len(lst) == 29
assert sorted(lst) == sorted(expected)
+ def test_list_3(self):
+ self.start_transaction()
+ h = self.allocate_hashtable()
+ tl0 = self.tls[self.current_thread]
+ for i in range(29):
+ htset(h, 19 ^ i, stm_allocate(32), tl0)
+ assert htlen(h) == 29
+
class TestRandomHashtable(BaseTestHashtable):
From noreply at buildbot.pypy.org Sun Feb 1 11:21:26 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Sun, 1 Feb 2015 11:21:26 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: update to stmgc/de27e8f11e38 (branch
hashtable-iter)
Message-ID: <20150201102126.486171C024F@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75618:bf785d8257b2
Date: 2015-02-01 11:03 +0100
http://bitbucket.org/pypy/pypy/changeset/bf785d8257b2/
Log: update to stmgc/de27e8f11e38 (branch hashtable-iter)
diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision
--- a/rpython/translator/stm/src_stm/revision
+++ b/rpython/translator/stm/src_stm/revision
@@ -1,1 +1,1 @@
-e7a6ff9e9da3
+de27e8f11e38
diff --git a/rpython/translator/stm/src_stm/stm/core.c b/rpython/translator/stm/src_stm/stm/core.c
--- a/rpython/translator/stm/src_stm/stm/core.c
+++ b/rpython/translator/stm/src_stm/stm/core.c
@@ -432,13 +432,12 @@
continue; /* no need to check: is pending immediate abort */
char *remote_base = get_segment_base(i);
- uint8_t remote_version = get_segment(i)->transaction_read_version;
LIST_FOREACH_R(
STM_PSEGMENT->modified_old_objects,
object_t * /*item*/,
({
- if (was_read_remote(remote_base, item, remote_version)) {
+ if (was_read_remote(remote_base, item)) {
/* A write-read conflict! */
dprintf(("write-read conflict on %p, our seg: %d, other: %ld\n",
item, STM_SEGMENT->segment_num, i));
diff --git a/rpython/translator/stm/src_stm/stm/core.h b/rpython/translator/stm/src_stm/stm/core.h
--- a/rpython/translator/stm/src_stm/stm/core.h
+++ b/rpython/translator/stm/src_stm/stm/core.h
@@ -282,11 +282,17 @@
static stm_thread_local_t *abort_with_mutex_no_longjmp(void);
static void abort_data_structures_from_segment_num(int segment_num);
-static inline bool was_read_remote(char *base, object_t *obj,
- uint8_t other_transaction_read_version)
+static inline struct stm_read_marker_s *get_read_marker(char *base,
+ object_t *obj) {
+ return (struct stm_read_marker_s *)(base + (((uintptr_t)obj) >> 4));
+}
+
+static inline bool was_read_remote(char *base, object_t *obj)
{
- uint8_t rm = ((struct stm_read_marker_s *)
- (base + (((uintptr_t)obj) >> 4)))->rm;
+ uint8_t other_transaction_read_version =
+ ((struct stm_segment_info_s *)REAL_ADDRESS(base, STM_PSEGMENT))
+ ->transaction_read_version;
+ uint8_t rm = get_read_marker(base, obj)->rm;
assert(rm <= other_transaction_read_version);
return rm == other_transaction_read_version;
}
diff --git a/rpython/translator/stm/src_stm/stm/hashtable.c b/rpython/translator/stm/src_stm/stm/hashtable.c
--- a/rpython/translator/stm/src_stm/stm/hashtable.c
+++ b/rpython/translator/stm/src_stm/stm/hashtable.c
@@ -13,22 +13,28 @@
collision).
The main operations on a hashtable are reading or writing an object at a
-given index. It might support in the future enumerating the indexes of
-non-NULL objects.
+given index. It also supports fetching the list of non-NULL entries.
There are two markers for every index (a read and a write marker).
This is unlike regular arrays, which have only two markers in total.
+Additionally, we use the read marker for the hashtable object itself
+to mean "we have read the complete list of keys". This plays the role
+of a "global" read marker: when any thread adds a new key/value object
+to the hashtable, this new object's read marker is initialized with a
+copy of the "global" read marker --- in all segments.
+
Implementation
--------------
First idea: have the hashtable in raw memory, pointing to "entry"
-objects. The entry objects themselves point to the user-specified
-objects. The entry objects have the read/write markers. Every entry
-object, once created, stays around. It is only removed by the next
-major GC if it points to NULL and its read/write markers are not set
-in any currently-running transaction.
+objects (which are regular, GC- and STM-managed objects). The entry
+objects themselves point to the user-specified objects. The entry
+objects hold the read/write markers. Every entry object, once
+created, stays around. It is only removed by the next major GC if it
+points to NULL and its read/write markers are not set in any
+currently-running transaction.
References
----------
@@ -104,9 +110,7 @@
{
long i;
for (i = 1; i <= NB_SEGMENTS; i++) {
- char *remote_base = get_segment_base(i);
- uint8_t remote_version = get_segment(i)->transaction_read_version;
- if (was_read_remote(remote_base, obj, remote_version))
+ if (was_read_remote(get_segment_base(i), obj))
return true;
}
return false;
@@ -155,6 +159,7 @@
/* ^^^ this unlocks the table by writing a non-zero value to
table->resize_counter, but the new value is a pointer to the
new bigger table, so IS_EVEN() is still true */
+ assert(IS_EVEN(table->resize_counter));
init_table(biggertable, biggercount);
@@ -174,6 +179,7 @@
}
}
_insert_clean(biggertable, entry);
+ assert(rc > 6);
rc -= 6;
}
biggertable->resize_counter = rc;
@@ -217,7 +223,16 @@
perturb >>= PERTURB_SHIFT;
}
}
- /* here, we didn't find the 'entry' with the correct index. */
+ /* here, we didn't find the 'entry' with the correct index. Note
+ that even if the same 'table' is modified or resized by other
+ threads concurrently, any new item found from a race condition
+ would anyway contain NULL in the present segment (ensured by
+ the first write_fence() below). If the 'table' grows an entry
+ just after we checked above, then we go ahead and lock the
+ table; but after we get the lock, we will notice the new entry
+ (ensured by the second write_fence() below) and restart the
+ whole process.
+ */
uintptr_t rc = VOLATILE_TABLE(table)->resize_counter;
@@ -283,12 +298,22 @@
synchronization with other pieces of the code that may
change.
*/
+
+ /* First fetch the read marker of 'hashtableobj' in all
+ segments, before allocate_outside_nursery_large()
+ which might trigger a GC */
+ long j;
+ uint8_t readmarkers[NB_SEGMENTS];
+ for (j = 1; j <= NB_SEGMENTS; j++) {
+ readmarkers[j - 1] = get_read_marker(get_segment_base(j),
+ hashtableobj)->rm;
+ }
+
acquire_privatization_lock();
char *p = allocate_outside_nursery_large(
sizeof(stm_hashtable_entry_t));
entry = (stm_hashtable_entry_t *)(p - stm_object_pages);
- long j;
for (j = 0; j <= NB_SEGMENTS; j++) {
struct stm_hashtable_entry_s *e;
e = (struct stm_hashtable_entry_s *)
@@ -300,6 +325,11 @@
}
hashtable->additions += 0x100;
release_privatization_lock();
+
+ for (j = 1; j <= NB_SEGMENTS; j++) {
+ get_read_marker(get_segment_base(j), (object_t *)entry)->rm =
+ readmarkers[j - 1];
+ }
}
write_fence(); /* make sure 'entry' is fully initialized here */
table->items[i] = entry;
@@ -339,17 +369,94 @@
e->object = nvalue;
}
+long stm_hashtable_length_upper_bound(stm_hashtable_t *hashtable)
+{
+ stm_hashtable_table_t *table;
+ uintptr_t rc;
+
+ restart:
+ table = VOLATILE_HASHTABLE(hashtable)->table;
+ rc = VOLATILE_TABLE(table)->resize_counter;
+ if (IS_EVEN(rc)) {
+ spin_loop();
+ goto restart;
+ }
+
+ uintptr_t initial_rc = (table->mask + 1) * 4 + 1;
+ uintptr_t num_entries_times_6 = initial_rc - rc;
+ return num_entries_times_6 / 6;
+}
+
+long stm_hashtable_list(object_t *hobj, stm_hashtable_t *hashtable,
+ stm_hashtable_entry_t **results)
+{
+ stm_hashtable_table_t *table;
+ intptr_t rc;
+
+ /* Set the read marker. It will be left as long as we're running
+ the same transaction.
+ */
+ stm_read(hobj);
+
+ /* Acquire and immediately release the lock. We don't actually
+ need to do anything while we hold the lock, but the point is to
+ wait until the lock is available, and to synchronize other
+ threads with the stm_read() done above.
+ */
+ restart:
+ table = VOLATILE_HASHTABLE(hashtable)->table;
+ rc = VOLATILE_TABLE(table)->resize_counter;
+ if (IS_EVEN(rc)) {
+ spin_loop();
+ goto restart;
+ }
+ if (!__sync_bool_compare_and_swap(&table->resize_counter, rc, rc))
+ goto restart;
+
+ /* Read all entries, check which ones are not NULL, count them,
+ and optionally list them in 'results'.
+ */
+ uintptr_t i, mask = table->mask;
+ stm_hashtable_entry_t *entry;
+ long nresult = 0;
+
+ if (results != NULL) {
+ /* collect the results in the provided list */
+ for (i = 0; i <= mask; i++) {
+ entry = VOLATILE_TABLE(table)->items[i];
+ if (entry != NULL) {
+ stm_read((object_t *)entry);
+ if (entry->object != NULL)
+ results[nresult++] = entry;
+ }
+ }
+ }
+ else {
+ /* don't collect, just get the exact number of results */
+ for (i = 0; i <= mask; i++) {
+ entry = VOLATILE_TABLE(table)->items[i];
+ if (entry != NULL) {
+ stm_read((object_t *)entry);
+ if (entry->object != NULL)
+ nresult++;
+ }
+ }
+ }
+ return nresult;
+}
+
static void _stm_compact_hashtable(stm_hashtable_t *hashtable)
{
stm_hashtable_table_t *table = hashtable->table;
- assert(!IS_EVEN(table->resize_counter));
+ uintptr_t rc = table->resize_counter;
+ assert(!IS_EVEN(rc));
if ((hashtable->additions >> 8) * 4 > table->mask) {
int segment_num = (hashtable->additions & 0xFF);
if (!segment_num) segment_num = 1;
hashtable->additions = segment_num;
uintptr_t initial_rc = (table->mask + 1) * 4 + 1;
- uintptr_t num_entries_times_6 = initial_rc - table->resize_counter;
+ uintptr_t num_entries_times_6 = initial_rc - rc;
uintptr_t count = INITIAL_HASHTABLE_SIZE;
while (count * 4 < num_entries_times_6)
count *= 2;
@@ -377,6 +484,7 @@
free(old_table);
}
hashtable->initial_table.resize_counter = (uintptr_t)table;
+ assert(IS_EVEN(hashtable->initial_table.resize_counter));
}
}
diff --git a/rpython/translator/stm/src_stm/stm/misc.c b/rpython/translator/stm/src_stm/stm/misc.c
--- a/rpython/translator/stm/src_stm/stm/misc.c
+++ b/rpython/translator/stm/src_stm/stm/misc.c
@@ -32,8 +32,7 @@
bool _stm_was_read(object_t *obj)
{
- return was_read_remote(STM_SEGMENT->segment_base, obj,
- STM_SEGMENT->transaction_read_version);
+ return was_read_remote(STM_SEGMENT->segment_base, obj);
}
bool _stm_was_written(object_t *obj)
diff --git a/rpython/translator/stm/src_stm/stmgc.h b/rpython/translator/stm/src_stm/stmgc.h
--- a/rpython/translator/stm/src_stm/stmgc.h
+++ b/rpython/translator/stm/src_stm/stmgc.h
@@ -546,6 +546,9 @@
object_t *stm_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key);
void stm_hashtable_write(object_t *, stm_hashtable_t *, uintptr_t key,
object_t *nvalue, stm_thread_local_t *);
+long stm_hashtable_length_upper_bound(stm_hashtable_t *);
+long stm_hashtable_list(object_t *, stm_hashtable_t *,
+ stm_hashtable_entry_t **results);
extern uint32_t stm_hashtable_entry_userdata;
void stm_hashtable_tracefn(stm_hashtable_t *, void (object_t **));
From noreply at buildbot.pypy.org Sun Feb 1 11:21:27 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Sun, 1 Feb 2015 11:21:27 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: _ll_hashtable_len
Message-ID: <20150201102127.771C51C024F@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75619:054d5d592ec4
Date: 2015-02-01 11:10 +0100
http://bitbucket.org/pypy/pypy/changeset/054d5d592ec4/
Log: _ll_hashtable_len
diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py
--- a/rpython/rlib/rstm.py
+++ b/rpython/rlib/rstm.py
@@ -182,6 +182,7 @@
('index', lltype.Unsigned),
('object', llmemory.GCREF))
_STM_HASHTABLE_ENTRY_P = lltype.Ptr(_STM_HASHTABLE_ENTRY)
+_STM_HASHTABLE_ENTRY_ARRAY = rffi.CArray(_STM_HASHTABLE_ENTRY_P)
@dont_look_inside
def _ll_hashtable_get(h, key):
@@ -193,6 +194,11 @@
llop.stm_hashtable_write(lltype.Void, h, h.ll_raw_hashtable, key, value)
@dont_look_inside
+def _ll_hashtable_len(h):
+ return llop.stm_hashtable_list(lltype.Signed, h, h.ll_raw_hashtable,
+ lltype.nullptr(_STM_HASHTABLE_ENTRY_ARRAY))
+
+ at dont_look_inside
def _ll_hashtable_lookup(h, key):
return llop.stm_hashtable_lookup(_STM_HASHTABLE_ENTRY_P,
h, h.ll_raw_hashtable, key)
@@ -202,6 +208,7 @@
rtti=True,
adtmeths={'get': _ll_hashtable_get,
'set': _ll_hashtable_set,
+ 'len': _ll_hashtable_len,
'lookup': _ll_hashtable_lookup})
NULL_HASHTABLE = lltype.nullptr(_HASHTABLE_OBJ)
@@ -262,6 +269,9 @@
except KeyError:
pass
+ def len(self):
+ return len(self._content)
+
def lookup(self, key):
assert type(key) is int
return EntryObjectForTest(self, key)
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -465,6 +465,7 @@
'stm_hashtable_read': LLOp(),
'stm_hashtable_write': LLOp(),
'stm_hashtable_lookup': LLOp(),
+ 'stm_hashtable_list' : LLOp(),
'stm_hashtable_tracefn': LLOp(),
# __________ address operations __________
diff --git a/rpython/translator/stm/funcgen.py b/rpython/translator/stm/funcgen.py
--- a/rpython/translator/stm/funcgen.py
+++ b/rpython/translator/stm/funcgen.py
@@ -320,6 +320,14 @@
return '%s = stm_hashtable_lookup((object_t *)%s, %s, %s);' % (
result, arg0, arg1, arg2)
+def stm_hashtable_list(funcgen, op):
+ arg0 = funcgen.expr(op.args[0])
+ arg1 = funcgen.expr(op.args[1])
+ arg2 = funcgen.expr(op.args[2])
+ result = funcgen.expr(op.result)
+ return '%s = stm_hashtable_list((object_t *)%s, %s, %s);' % (
+ result, arg0, arg1, arg2)
+
def stm_hashtable_tracefn(funcgen, op):
arg0 = funcgen.expr(op.args[0])
arg1 = funcgen.expr(op.args[1])
diff --git a/rpython/translator/stm/test/test_ztranslated.py b/rpython/translator/stm/test/test_ztranslated.py
--- a/rpython/translator/stm/test/test_ztranslated.py
+++ b/rpython/translator/stm/test/test_ztranslated.py
@@ -575,6 +575,14 @@
x2 = cast_gcref_to_instance(X, p2)
assert x2 is x1
#
+ entry = h.lookup(-1234)
+ assert cast_gcref_to_instance(X, entry.object) is x1
+ assert h.len() == 1
+ #
+ entry = h.lookup(4242)
+ assert cast_gcref_to_instance(X, entry.object) is None
+ assert h.len() == 1
+ #
print "ok!"
return 0
From noreply at buildbot.pypy.org Sun Feb 1 11:21:28 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Sun, 1 Feb 2015 11:21:28 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: _ll_hashtable_list
Message-ID: <20150201102128.F26AF1C024F@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75620:dce2ea23c327
Date: 2015-02-01 11:21 +0100
http://bitbucket.org/pypy/pypy/changeset/dce2ea23c327/
Log: _ll_hashtable_list
diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py
--- a/rpython/rlib/rstm.py
+++ b/rpython/rlib/rstm.py
@@ -1,5 +1,6 @@
from rpython.rlib.objectmodel import we_are_translated, specialize
from rpython.rlib.objectmodel import CDefinedIntSymbolic, stm_ignored
+from rpython.rlib.rarithmetic import r_uint
from rpython.rlib.nonconst import NonConstant
from rpython.rlib import rgc
from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory
@@ -199,6 +200,20 @@
lltype.nullptr(_STM_HASHTABLE_ENTRY_ARRAY))
@dont_look_inside
+def _ll_hashtable_list(h):
+ upper_bound = llop.stm_hashtable_length_upper_bound(lltype.Signed,
+ h.ll_raw_hashtable)
+ array = lltype.malloc(_STM_HASHTABLE_ENTRY_ARRAY, upper_bound,
+ flavor='raw')
+ count = llop.stm_hashtable_list(lltype.Signed, h, h.ll_raw_hashtable,
+ array)
+ return (array, count)
+
+ at dont_look_inside
+def _ll_hashtable_freelist(h, array):
+ lltype.free(array, flavor='raw')
+
+ at dont_look_inside
def _ll_hashtable_lookup(h, key):
return llop.stm_hashtable_lookup(_STM_HASHTABLE_ENTRY_P,
h, h.ll_raw_hashtable, key)
@@ -209,6 +224,8 @@
adtmeths={'get': _ll_hashtable_get,
'set': _ll_hashtable_set,
'len': _ll_hashtable_len,
+ 'list': _ll_hashtable_list,
+ 'freelist': _ll_hashtable_freelist,
'lookup': _ll_hashtable_lookup})
NULL_HASHTABLE = lltype.nullptr(_HASHTABLE_OBJ)
@@ -272,6 +289,16 @@
def len(self):
return len(self._content)
+ def list(self):
+ items = [self.lookup(key) for key in self._content]
+ count = len(items)
+ for i in range(3):
+ items.append("additional garbage for testing")
+ return items, count
+
+ def freelist(self, array):
+ pass
+
def lookup(self, key):
assert type(key) is int
return EntryObjectForTest(self, key)
@@ -280,6 +307,7 @@
def __init__(self, hashtable, key):
self.hashtable = hashtable
self.key = key
+ self.index = r_uint(key)
def _getobj(self):
return self.hashtable.get(self.key)
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -465,6 +465,7 @@
'stm_hashtable_read': LLOp(),
'stm_hashtable_write': LLOp(),
'stm_hashtable_lookup': LLOp(),
+ 'stm_hashtable_length_upper_bound': LLOp(),
'stm_hashtable_list' : LLOp(),
'stm_hashtable_tracefn': LLOp(),
diff --git a/rpython/translator/stm/funcgen.py b/rpython/translator/stm/funcgen.py
--- a/rpython/translator/stm/funcgen.py
+++ b/rpython/translator/stm/funcgen.py
@@ -320,6 +320,12 @@
return '%s = stm_hashtable_lookup((object_t *)%s, %s, %s);' % (
result, arg0, arg1, arg2)
+def stm_hashtable_length_upper_bound(funcgen, op):
+ arg0 = funcgen.expr(op.args[0])
+ result = funcgen.expr(op.result)
+ return '%s = stm_hashtable_length_upper_bound(%s);' % (
+ result, arg0)
+
def stm_hashtable_list(funcgen, op):
arg0 = funcgen.expr(op.args[0])
arg1 = funcgen.expr(op.args[1])
diff --git a/rpython/translator/stm/test/test_ztranslated.py b/rpython/translator/stm/test/test_ztranslated.py
--- a/rpython/translator/stm/test/test_ztranslated.py
+++ b/rpython/translator/stm/test/test_ztranslated.py
@@ -1,6 +1,7 @@
import py
from rpython.rlib import rstm, rgc, objectmodel
from rpython.rlib.debug import debug_print
+from rpython.rlib.rarithmetic import intmask
from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rtyper.rclass import OBJECTPTR
@@ -583,6 +584,12 @@
assert cast_gcref_to_instance(X, entry.object) is None
assert h.len() == 1
#
+ array, count = h.list()
+ assert count == 1
+ assert intmask(array[0].index) == -1234
+ assert cast_gcref_to_instance(X, array[0].object) is x1
+ h.freelist(array)
+ #
print "ok!"
return 0
From noreply at buildbot.pypy.org Sun Feb 1 11:39:29 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Sun, 1 Feb 2015 11:39:29 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: hashtable.keys(), values(), items()
Message-ID: <20150201103929.0181B1C039A@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75624:d7857d4bcf41
Date: 2015-02-01 11:39 +0100
http://bitbucket.org/pypy/pypy/changeset/d7857d4bcf41/
Log: hashtable.keys(), values(), items()
diff --git a/pypy/module/pypystm/hashtable.py b/pypy/module/pypystm/hashtable.py
--- a/pypy/module/pypystm/hashtable.py
+++ b/pypy/module/pypystm/hashtable.py
@@ -7,6 +7,7 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
from rpython.rlib import rstm
+from rpython.rlib.rarithmetic import intmask
from rpython.rtyper.annlowlevel import cast_gcref_to_instance
from rpython.rtyper.annlowlevel import cast_instance_to_gcref
@@ -59,6 +60,34 @@
def len_w(self, space):
return space.wrap(self.h.len())
+ def keys_w(self, space):
+ array, count = self.h.list()
+ try:
+ lst = [intmask(array[i].index) for i in range(count)]
+ finally:
+ self.h.freelist(array)
+ return space.newlist_int(lst)
+
+ def values_w(self, space):
+ array, count = self.h.list()
+ try:
+ lst_w = [cast_gcref_to_instance(W_Root, array[i].object)
+ for i in range(count)]
+ finally:
+ self.h.freelist(array)
+ return space.newlist(lst_w)
+
+ def items_w(self, space):
+ array, count = self.h.list()
+ try:
+ lst_w = [space.newtuple([
+ space.wrap(intmask(array[i].index)),
+ cast_gcref_to_instance(W_Root, array[i].object)])
+ for i in range(count)]
+ finally:
+ self.h.freelist(array)
+ return space.newlist(lst_w)
+
def W_Hashtable___new__(space, w_subtype):
r = space.allocate_instance(W_Hashtable, w_subtype)
@@ -76,4 +105,7 @@
setdefault = interp2app(W_Hashtable.setdefault_w),
__len__ = interp2app(W_Hashtable.len_w),
+ keys = interp2app(W_Hashtable.keys_w),
+ values = interp2app(W_Hashtable.values_w),
+ items = interp2app(W_Hashtable.items_w),
)
diff --git a/pypy/module/pypystm/test/test_hashtable.py b/pypy/module/pypystm/test/test_hashtable.py
--- a/pypy/module/pypystm/test/test_hashtable.py
+++ b/pypy/module/pypystm/test/test_hashtable.py
@@ -46,3 +46,12 @@
assert len(h) == 2
del h[42]
assert len(h) == 1
+
+ def test_keys_values_items(self):
+ import pypystm
+ h = pypystm.hashtable()
+ h[42] = "foo"
+ h[43] = "bar"
+ assert sorted(h.keys()) == [42, 43]
+ assert sorted(h.values()) == ["bar", "foo"]
+ assert sorted(h.items()) == [(42, "foo"), (43, "bar")]
From noreply at buildbot.pypy.org Sun Feb 1 12:03:41 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Sun, 1 Feb 2015 12:03:41 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: stmdict.keys() and similar methods
Message-ID: <20150201110341.B44FE1C0507@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75625:707dcfba2317
Date: 2015-02-01 12:03 +0100
http://bitbucket.org/pypy/pypy/changeset/707dcfba2317/
Log: stmdict.keys() and similar methods
diff --git a/pypy/module/pypystm/stmdict.py b/pypy/module/pypystm/stmdict.py
--- a/pypy/module/pypystm/stmdict.py
+++ b/pypy/module/pypystm/stmdict.py
@@ -138,6 +138,69 @@
entry.object = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
return w_default
+ def get_length(self):
+ array, count = self.h.list()
+ try:
+ total_length_times_two = 0
+ for i in range(count):
+ subarray = lltype.cast_opaque_ptr(PARRAY, array[i].object)
+ assert subarray
+ total_length_times_two += len(subarray)
+ finally:
+ self.h.freelist(array)
+ return total_length_times_two >> 1
+
+ def get_keys_values_w(self, offset):
+ array, count = self.h.list()
+ try:
+ result_list_w = []
+ for i in range(count):
+ subarray = lltype.cast_opaque_ptr(PARRAY, array[i].object)
+ assert subarray
+ j = offset
+ limit = len(subarray)
+ while j < limit:
+ w_item = cast_gcref_to_instance(W_Root, subarray[j])
+ result_list_w.append(w_item)
+ j += 2
+ finally:
+ self.h.freelist(array)
+ return result_list_w
+
+ def get_items_w(self, space):
+ array, count = self.h.list()
+ try:
+ result_list_w = []
+ for i in range(count):
+ subarray = lltype.cast_opaque_ptr(PARRAY, array[i].object)
+ assert subarray
+ j = 0
+ limit = len(subarray)
+ while j < limit:
+ w_key = cast_gcref_to_instance(W_Root, subarray[j])
+ w_value = cast_gcref_to_instance(W_Root, subarray[j + 1])
+ result_list_w.append(space.newtuple([w_key, w_value]))
+ j += 2
+ finally:
+ self.h.freelist(array)
+ return result_list_w
+
+ def len_w(self, space):
+ return space.wrap(self.get_length())
+
+ def iter_w(self, space):
+ # not a real lazy iterator!
+ return space.iter(self.keys_w(space))
+
+ def keys_w(self, space):
+ return space.newlist(self.get_keys_values_w(offset=0))
+
+ def values_w(self, space):
+ return space.newlist(self.get_keys_values_w(offset=1))
+
+ def items_w(self, space):
+ return space.newlist(self.get_items_w(space))
+
def W_STMDict___new__(space, w_subtype):
r = space.allocate_instance(W_STMDict, w_subtype)
@@ -153,4 +216,10 @@
__contains__ = interp2app(W_STMDict.contains_w),
get = interp2app(W_STMDict.get_w),
setdefault = interp2app(W_STMDict.setdefault_w),
+
+ __len__ = interp2app(W_STMDict.len_w),
+ __iter__ = interp2app(W_STMDict.iter_w),
+ keys = interp2app(W_STMDict.keys_w),
+ values = interp2app(W_STMDict.values_w),
+ items = interp2app(W_STMDict.items_w),
)
diff --git a/pypy/module/pypystm/stmset.py b/pypy/module/pypystm/stmset.py
--- a/pypy/module/pypystm/stmset.py
+++ b/pypy/module/pypystm/stmset.py
@@ -94,6 +94,39 @@
def discard_w(self, space, w_key):
self.try_remove(space, w_key)
+ def get_length(self):
+ array, count = self.h.list()
+ try:
+ total_length = 0
+ for i in range(count):
+ subarray = lltype.cast_opaque_ptr(PARRAY, array[i].object)
+ assert subarray
+ total_length += len(subarray)
+ finally:
+ self.h.freelist(array)
+ return total_length
+
+ def get_items_w(self):
+ array, count = self.h.list()
+ try:
+ result_list_w = []
+ for i in range(count):
+ subarray = lltype.cast_opaque_ptr(PARRAY, array[i].object)
+ assert subarray
+ for j in range(len(subarray)):
+ w_item = cast_gcref_to_instance(W_Root, subarray[j])
+ result_list_w.append(w_item)
+ finally:
+ self.h.freelist(array)
+ return result_list_w
+
+ def len_w(self, space):
+ return space.wrap(self.get_length())
+
+ def iter_w(self, space):
+ # not a real lazy iterator!
+ return space.iter(space.newlist(self.get_items_w()))
+
def W_STMSet___new__(space, w_subtype):
r = space.allocate_instance(W_STMSet, w_subtype)
@@ -107,4 +140,7 @@
add = interp2app(W_STMSet.add_w),
remove = interp2app(W_STMSet.remove_w),
discard = interp2app(W_STMSet.discard_w),
+
+ __len__ = interp2app(W_STMSet.len_w),
+ __iter__ = interp2app(W_STMSet.iter_w),
)
diff --git a/pypy/module/pypystm/test/test_stmdict.py b/pypy/module/pypystm/test/test_stmdict.py
--- a/pypy/module/pypystm/test/test_stmdict.py
+++ b/pypy/module/pypystm/test/test_stmdict.py
@@ -70,3 +70,34 @@
assert d[42] == "hello"
assert d.get(42L) == "hello"
assert d.get(42.001) is None
+
+ def test_list_from_dict(self):
+ import pypystm
+ d = pypystm.stmdict()
+ assert len(d) == 0
+ assert tuple(d) == ()
+ d[42.5] = "foo"
+ d[42.0] = ["bar"]
+ assert sorted(d) == [42.0, 42.5]
+ assert len(d) == 2
+ del d[42]
+ assert len(d) == 1
+ assert list(d) == [42.5]
+ #
+ class Key(object):
+ def __hash__(self):
+ return hash(42.5)
+ key3 = Key()
+ d[key3] = "other"
+ assert len(d) == 2
+ items = list(d)
+ assert items == [42.5, key3] or items == [key3, 42.5]
+
+ def test_keys_values_items(self):
+ import pypystm
+ d = pypystm.stmdict()
+ d[42.5] = "bar"
+ d[42.0] = "foo"
+ assert sorted(d.keys()) == [42.0, 42.5]
+ assert sorted(d.values()) == ["bar", "foo"]
+ assert sorted(d.items()) == [(42.0, "foo"), (42.5, "bar")]
diff --git a/pypy/module/pypystm/test/test_stmset.py b/pypy/module/pypystm/test/test_stmset.py
--- a/pypy/module/pypystm/test/test_stmset.py
+++ b/pypy/module/pypystm/test/test_stmset.py
@@ -62,3 +62,24 @@
assert 42 in s
assert 42L in s
assert 42.001 not in s
+
+ def test_list_from_set(self):
+ import pypystm
+ s = pypystm.stmset()
+ assert len(s) == 0
+ assert tuple(s) == ()
+ s.add(42.5)
+ s.add(42.0)
+ assert sorted(s) == [42.0, 42.5]
+ assert len(s) == 2
+ s.remove(42.0)
+ assert list(s) == [42.5]
+ #
+ class Key(object):
+ def __hash__(self):
+ return hash(42.5)
+ key3 = Key()
+ s.add(key3)
+ assert len(s) == 2
+ items = list(s)
+ assert items == [42.5, key3] or items == [key3, 42.5]
From noreply at buildbot.pypy.org Sun Feb 1 13:44:52 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Sun, 1 Feb 2015 13:44:52 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: stmdict.pop()
Message-ID: <20150201124452.19D571C02CD@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75626:b4c5f43782f1
Date: 2015-02-01 13:44 +0100
http://bitbucket.org/pypy/pypy/changeset/b4c5f43782f1/
Log: stmdict.pop()
diff --git a/pypy/module/pypystm/stmdict.py b/pypy/module/pypystm/stmdict.py
--- a/pypy/module/pypystm/stmdict.py
+++ b/pypy/module/pypystm/stmdict.py
@@ -43,6 +43,25 @@
for i in range(length):
dest[dest_start + i] = source[source_start + i]
+def pop_from_entry(entry, space, w_key):
+ array = lltype.cast_opaque_ptr(PARRAY, entry.object)
+ if not array:
+ return None
+ i = find_equal_item(space, array, w_key)
+ if i < 0:
+ return None
+ # found
+ w_value = cast_gcref_to_instance(W_Root, array[i + 1])
+ L = len(array) - 2
+ if L == 0:
+ narray = lltype.nullptr(ARRAY)
+ else:
+ narray = lltype.malloc(ARRAY, L)
+ ll_arraycopy(array, narray, 0, 0, i)
+ ll_arraycopy(array, narray, i + 2, i, L - i)
+ entry.object = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
+ return w_value
+
class W_STMDict(W_Root):
@@ -82,21 +101,8 @@
def delitem_w(self, space, w_key):
hkey = space.hash_w(w_key)
entry = self.h.lookup(hkey)
- array = lltype.cast_opaque_ptr(PARRAY, entry.object)
- if array:
- i = find_equal_item(space, array, w_key)
- if i >= 0:
- # found
- L = len(array) - 2
- if L == 0:
- narray = lltype.nullptr(ARRAY)
- else:
- narray = lltype.malloc(ARRAY, L)
- ll_arraycopy(array, narray, 0, 0, i)
- ll_arraycopy(array, narray, i + 2, i, L - i)
- entry.object = lltype.cast_opaque_ptr(llmemory.GCREF, narray)
- return
- space.raise_key_error(w_key)
+ if pop_from_entry(entry, space, w_key) is None:
+ space.raise_key_error(w_key)
def contains_w(self, space, w_key):
hkey = space.hash_w(w_key)
@@ -117,6 +123,17 @@
return cast_gcref_to_instance(W_Root, array[i + 1])
return w_default
+ def pop_w(self, space, w_key, w_default=None):
+ hkey = space.hash_w(w_key)
+ entry = self.h.lookup(hkey)
+ w_value = pop_from_entry(entry, space, w_key)
+ if w_value is not None:
+ return w_value
+ elif w_default is not None:
+ return w_default
+ else:
+ space.raise_key_error(w_key)
+
@unwrap_spec(w_default=WrappedDefault(None))
def setdefault_w(self, space, w_key, w_default):
hkey = space.hash_w(w_key)
@@ -215,6 +232,7 @@
__delitem__ = interp2app(W_STMDict.delitem_w),
__contains__ = interp2app(W_STMDict.contains_w),
get = interp2app(W_STMDict.get_w),
+ pop = interp2app(W_STMDict.pop_w),
setdefault = interp2app(W_STMDict.setdefault_w),
__len__ = interp2app(W_STMDict.len_w),
diff --git a/pypy/module/pypystm/test/test_stmdict.py b/pypy/module/pypystm/test/test_stmdict.py
--- a/pypy/module/pypystm/test/test_stmdict.py
+++ b/pypy/module/pypystm/test/test_stmdict.py
@@ -101,3 +101,18 @@
assert sorted(d.keys()) == [42.0, 42.5]
assert sorted(d.values()) == ["bar", "foo"]
assert sorted(d.items()) == [(42.0, "foo"), (42.5, "bar")]
+
+ def test_pop(self):
+ import pypystm
+ d = pypystm.stmdict()
+ raises(KeyError, d.pop, 42.0)
+ assert d.pop(42.0, "foo") == "foo"
+ raises(KeyError, "d[42.0]")
+ d[42.0] = "bar"
+ res = d.pop(42.0)
+ assert res == "bar"
+ raises(KeyError, "d[42.0]")
+ d[42.0] = "bar"
+ res = d.pop(42.0, "foo")
+ assert res == "bar"
+ raises(KeyError, "d[42.0]")
From noreply at buildbot.pypy.org Sun Feb 1 19:21:08 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Sun, 1 Feb 2015 19:21:08 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: fix
Message-ID: <20150201182108.0FEA81C0507@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75627:4aff38646069
Date: 2015-02-01 19:21 +0100
http://bitbucket.org/pypy/pypy/changeset/4aff38646069/
Log: fix
diff --git a/pypy/module/pypystm/stmdict.py b/pypy/module/pypystm/stmdict.py
--- a/pypy/module/pypystm/stmdict.py
+++ b/pypy/module/pypystm/stmdict.py
@@ -225,7 +225,7 @@
return space.wrap(r)
W_STMDict.typedef = TypeDef(
- 'pypystm.stmset',
+ 'pypystm.stmdict',
__new__ = interp2app(W_STMDict___new__),
__getitem__ = interp2app(W_STMDict.getitem_w),
__setitem__ = interp2app(W_STMDict.setitem_w),
From noreply at buildbot.pypy.org Sun Feb 1 19:34:02 2015
From: noreply at buildbot.pypy.org (amauryfa)
Date: Sun, 1 Feb 2015 19:34:02 +0100 (CET)
Subject: [pypy-commit] pypy stdlib-2.7.9: More fields in decode_certificate.
Message-ID: <20150201183402.D01671C0FDE@cobra.cs.uni-duesseldorf.de>
Author: Amaury Forgeot d'Arc
Branch: stdlib-2.7.9
Changeset: r75628:60293e8655ee
Date: 2015-01-31 19:08 +0100
http://bitbucket.org/pypy/pypy/changeset/60293e8655ee/
Log: More fields in decode_certificate.
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -636,7 +636,7 @@
space.setitem(w_retval, space.wrap("issuer"), w_issuer)
space.setitem(w_retval, space.wrap("version"),
- space.wrap(libssl_X509_get_version(certificate)))
+ space.wrap(libssl_X509_get_version(certificate) + 1))
biobuf = libssl_BIO_new(libssl_BIO_s_mem())
try:
@@ -680,6 +680,11 @@
if w_alt_names is not space.w_None:
space.setitem(w_retval, space.wrap("subjectAltName"), w_alt_names)
+ # CDP (CRL distribution points)
+ w_cdp = _get_crl_dp(space, certificate)
+ if not space.is_none(w_cdp):
+ space.setitem(w_retval, space.wrap("crlDistributionPoints"), w_cdp)
+
return w_retval
@@ -828,6 +833,29 @@
return space.newtuple([w_name, w_value])
+def _get_crl_dp(space, certificate):
+ # Calls x509v3_cache_extensions and sets up crldp
+ libssl_X509_check_ca(certificate)
+ dps = certificate[0].c_crldp
+ if not dps:
+ return None
+
+ cdp_w = []
+ for i in range(libssl_sk_DIST_POINT_num(dps)):
+ dp = libssl_sk_DIST_POINT_value(dps, i)
+ gns = libssl_pypy_DIST_POINT_fullname(dp)
+
+ for j in range(libssl_sk_GENERAL_NAME_num(gns)):
+ name = libssl_sk_GENERAL_NAME_value(gns, j)
+ gntype = intmask(name[0].c_type)
+ if gntype != GEN_URI:
+ continue
+ uri = libssl_pypy_GENERAL_NAME_uri(name)
+ length = intmask(uri.c_length)
+ s_uri = rffi.charpsize2str(uri.c_data, length)
+ cdp_w.append(space.wrap(s_uri))
+ return space.newtuple(cdp_w[:])
+
def checkwait(space, w_sock, writing):
"""If the socket has a timeout, do a select()/poll() on the socket.
The argument writing indicates the direction.
diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py
--- a/pypy/module/_ssl/test/test_ssl.py
+++ b/pypy/module/_ssl/test/test_ssl.py
@@ -340,6 +340,9 @@
assert len(certs) == 1
print(certs)
assert len(certs[0]['issuer']) == 4
+ assert certs[0]['version'] == 3
+ assert certs[0]['crlDistributionPoints'] == (
+ 'https://www.cacert.org/revoke.crl',)
def test_load_dh_params(self):
import _ssl
diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py
--- a/rpython/rlib/ropenssl.py
+++ b/rpython/rlib/ropenssl.py
@@ -38,7 +38,9 @@
# Unnamed structures are not supported by rffi_platform.
# So we replace an attribute access with a macro call.
'#define pypy_GENERAL_NAME_dirn(name) (name->d.dirn)',
+ '#define pypy_GENERAL_NAME_uri(name) (name->d.uniformResourceIdentifier)',
'#define pypy_X509_OBJECT_data_x509(obj) (obj->data.x509)',
+ '#define pypy_DIST_POINT_fullname(obj) (obj->distpoint->name.fullname)',
],
)
@@ -48,12 +50,14 @@
include_dir='inc32', library_dir='out32'),
])
-X509 = rffi.COpaquePtr('X509')
ASN1_STRING = lltype.Ptr(lltype.ForwardReference())
+ASN1_IA5STRING = ASN1_STRING
ASN1_ITEM = rffi.COpaquePtr('ASN1_ITEM')
X509_NAME = rffi.COpaquePtr('X509_NAME')
X509_VERIFY_PARAM = rffi.COpaquePtr('X509_VERIFY_PARAM')
stack_st_X509_OBJECT = rffi.COpaquePtr('struct stack_st_X509_OBJECT')
+DIST_POINT = rffi.COpaquePtr('DIST_POINT')
+stack_st_DIST_POINT = rffi.COpaquePtr('struct stack_st_DIST_POINT')
DH = rffi.COpaquePtr('DH')
class CConfigBootstrap:
@@ -138,6 +142,10 @@
OBJ_NAME_TYPE_MD_METH = rffi_platform.ConstantInteger(
"OBJ_NAME_TYPE_MD_METH")
+ X509_st = rffi_platform.Struct(
+ 'struct x509_st',
+ [('crldp', stack_st_DIST_POINT)])
+
# Some structures, with only the fields used in the _ssl module
X509_name_entry_st = rffi_platform.Struct('struct X509_name_entry_st',
[('set', rffi.INT)])
@@ -193,6 +201,7 @@
SSL_CIPHER = rffi.COpaquePtr('SSL_CIPHER')
SSL = rffi.COpaquePtr('SSL')
BIO = rffi.COpaquePtr('BIO')
+X509 = rffi.CArrayPtr(X509_st)
X509_NAME_ENTRY = rffi.CArrayPtr(X509_name_entry_st)
X509_EXTENSION = rffi.CArrayPtr(X509_extension_st)
X509_STORE = rffi.CArrayPtr(x509_store_st)
@@ -341,10 +350,18 @@
X509_OBJECT, macro=True)
ssl_external('pypy_X509_OBJECT_data_x509', [X509_OBJECT], X509,
macro=True)
+ssl_external('sk_DIST_POINT_num', [stack_st_DIST_POINT], rffi.INT,
+ macro=True)
+ssl_external('sk_DIST_POINT_value', [stack_st_DIST_POINT, rffi.INT], DIST_POINT,
+ macro=True)
+ssl_external('pypy_DIST_POINT_fullname', [DIST_POINT], GENERAL_NAMES,
+ macro=True)
ssl_external('GENERAL_NAME_print', [BIO, GENERAL_NAME], rffi.INT)
ssl_external('pypy_GENERAL_NAME_dirn', [GENERAL_NAME], X509_NAME,
macro=True)
+ssl_external('pypy_GENERAL_NAME_uri', [GENERAL_NAME], ASN1_IA5STRING,
+ macro=True)
ssl_external('SSL_get_current_cipher', [SSL], SSL_CIPHER)
ssl_external('SSL_CIPHER_get_name', [SSL_CIPHER], rffi.CCHARP)
From noreply at buildbot.pypy.org Sun Feb 1 19:34:03 2015
From: noreply at buildbot.pypy.org (amauryfa)
Date: Sun, 1 Feb 2015 19:34:03 +0100 (CET)
Subject: [pypy-commit] pypy stdlib-2.7.9: Fix an issue in cert_store_stats()
Message-ID: <20150201183403.F3E4B1C0FDE@cobra.cs.uni-duesseldorf.de>
Author: Amaury Forgeot d'Arc
Branch: stdlib-2.7.9
Changeset: r75629:1c34bb5d8133
Date: 2015-01-31 23:02 +0100
http://bitbucket.org/pypy/pypy/changeset/1c34bb5d8133/
Log: Fix an issue in cert_store_stats()
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -1353,7 +1353,8 @@
obj = libssl_sk_X509_OBJECT_value(store[0].c_objs, i)
if intmask(obj.c_type) == X509_LU_X509:
counters['x509'] += 1
- if libssl_pypy_X509_OBJECT_data_x509(obj):
+ if libssl_X509_check_ca(
+ libssl_pypy_X509_OBJECT_data_x509(obj)):
counters['x509_ca'] += 1
elif intmask(obj.c_type) == X509_LU_CRL:
counters['crl'] += 1
diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py
--- a/pypy/module/_ssl/test/test_ssl.py
+++ b/pypy/module/_ssl/test/test_ssl.py
@@ -344,6 +344,15 @@
assert certs[0]['crlDistributionPoints'] == (
'https://www.cacert.org/revoke.crl',)
+ def test_cert_store_stats(self):
+ import _ssl
+ ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1)
+ assert ctx.cert_store_stats() == {'x509_ca': 0, 'crl': 0, 'x509': 0}
+ ctx.load_cert_chain(self.keycert)
+ assert ctx.cert_store_stats() == {'x509_ca': 0, 'crl': 0, 'x509': 0}
+ ctx.load_verify_locations(self.keycert)
+ assert ctx.cert_store_stats() == {'x509_ca': 0, 'crl': 0, 'x509': 1}
+
def test_load_dh_params(self):
import _ssl
ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1)
From noreply at buildbot.pypy.org Sun Feb 1 19:34:05 2015
From: noreply at buildbot.pypy.org (amauryfa)
Date: Sun, 1 Feb 2015 19:34:05 +0100 (CET)
Subject: [pypy-commit] pypy stdlib-2.7.9: Implement
SSLContext.set_servername_callback.
Message-ID: <20150201183405.23CEF1C0FDE@cobra.cs.uni-duesseldorf.de>
Author: Amaury Forgeot d'Arc
Branch: stdlib-2.7.9
Changeset: r75630:1db91f1d2dbe
Date: 2015-02-01 19:04 +0100
http://bitbucket.org/pypy/pypy/changeset/1db91f1d2dbe/
Log: Implement SSLContext.set_servername_callback. No test so far.
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -1,9 +1,9 @@
-from rpython.rlib import rpoll, rsocket, rthread
+from rpython.rlib import rpoll, rsocket, rthread, rweakref
from rpython.rlib.rarithmetic import intmask, widen, r_uint
from rpython.rlib.ropenssl import *
from rpython.rlib.rposix import get_errno, set_errno
from rpython.rlib.rweakref import RWeakValueDictionary
-from rpython.rlib.objectmodel import specialize
+from rpython.rlib.objectmodel import specialize, compute_unique_id
from rpython.rtyper.lltypesystem import lltype, rffi
from pypy.interpreter.baseobjspace import W_Root
@@ -244,7 +244,7 @@
self.socket_type = socket_type
self.w_socket = w_sock
- self.w_ssl_sock = None
+ self.ssl_sock_weakref_w = rweakref.ref(w_ssl_sock)
return self
def __del__(self):
@@ -1059,6 +1059,64 @@
buf[i] = c
return rffi.cast(rffi.INT, len(password))
+class ServernameCallback(object):
+ w_ctx = None
+ space = None
+SERVERNAME_CALLBACKS = RWeakValueDictionary(int, ServernameCallback)
+
+def _servername_callback(ssl, ad, arg):
+ struct = SERVERNAME_CALLBACKS.get(rffi.cast(lltype.Signed, arg))
+ w_ctx = struct.w_ctx
+ space = struct.space
+ servername = libssl_SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)
+ if not w_ctx.w_set_hostname:
+ # remove race condition.
+ return SSL_TLSEXT_ERR_OK
+ # The high-level ssl.SSLSocket object
+ w_ssl = libssl_SSL_get_app_data(ssl)
+ assert isinstance(w_ssl, _SSLSocket)
+ if w_ssl.ssl_sock_weakref_w:
+ w_ssl_socket = w_ssl.ssl_sock_weakref_w.get()
+ else:
+ w_ssl_socket = space.w_None
+ if space.is_none(w_ssl_socket):
+ ad[0] = SSL_AD_INTERNAL_ERROR
+ return SSL_TLSEXT_ERR_ALERT_FATAL
+
+ try:
+ if not servername:
+ w_result = space.call_function(w_ctx.w_set_hostname,
+ w_ssl_socket, space.w_None, w_ctx)
+
+ else:
+ try:
+ w_servername = space.wrap_bytes(rffi.charp2str(servername))
+ w_servername_idna = space.call_method(
+ w_servername, 'decode', space.wrap('idna'))
+ except OperationError as e:
+ space.write_unraisable(e, "w_servername")
+ ad[0] = SSL_AD_INTERNAL_ERROR;
+ return SSL_TLSEXT_ERR_ALERT_FATAL
+
+ w_result = space.call_function(w_ctx.w_set_hostname,
+ w_ssl_socket,
+ w_servername_idna, w_ctx)
+ except OperationError as e:
+ space.write_unraisable(e, "ssl_ctx->set_hostname")
+ ad[0] = SSL_AD_HANDSHAKE_FAILURE
+ return SSL_TLSEXT_ERR_ALERT_FATAL
+
+ if space.is_none(w_result):
+ return SSL_TLSEXT_ERR_OK
+ else:
+ try:
+ ad[0] = space.int_w(w_result)
+ except OperationError as e:
+ space.write_unraisable(e, "w_result")
+ ad[0] = SSL_AD_INTERNAL_ERROR
+ return SSL_TLSEXT_ERR_ALERT_FATAL
+
+
class _SSLContext(W_Root):
@staticmethod
@unwrap_spec(protocol=int)
@@ -1402,6 +1460,24 @@
rlist.append(_decode_certificate(space, cert))
return space.newlist(rlist)
+ def set_servername_callback_w(self, space, w_callback):
+ if space.is_none(w_callback):
+ libssl_SSL_CTX_set_tlsext_servername_callback(
+ self.ctx, lltype.nullptr(servername_cb.TO))
+ return
+ if not space.is_true(space.callable(w_callback)):
+ raise oefmt(space.w_TypeError, "not a callable object")
+ self.w_set_hostname = w_callback
+ struct = ServernameCallback()
+ struct.space = space
+ struct.w_ctx = self
+ index = compute_unique_id(self)
+ SERVERNAME_CALLBACKS.set(index, struct)
+ libssl_SSL_CTX_set_tlsext_servername_callback(
+ self.ctx, _servername_callback)
+ libssl_SSL_CTX_set_tlsext_servername_arg(self.ctx,
+ rffi.cast(rffi.VOIDP, index))
+
_SSLContext.typedef = TypeDef(
"_ssl._SSLContext",
__new__=interp2app(_SSLContext.descr_new),
@@ -1414,6 +1490,7 @@
set_default_verify_paths=interp2app(_SSLContext.descr_set_default_verify_paths),
_set_npn_protocols=interp2app(_SSLContext.set_npn_protocols_w),
get_ca_certs=interp2app(_SSLContext.get_ca_certs_w),
+ set_servername_callback=interp2app(_SSLContext.set_servername_callback_w),
options=GetSetProperty(_SSLContext.descr_get_options,
_SSLContext.descr_set_options),
diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py
--- a/rpython/rlib/ropenssl.py
+++ b/rpython/rlib/ropenssl.py
@@ -115,6 +115,12 @@
SSL_MODE_AUTO_RETRY = rffi_platform.ConstantInteger("SSL_MODE_AUTO_RETRY")
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = rffi_platform.ConstantInteger("SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER")
SSL_TLSEXT_ERR_OK = rffi_platform.ConstantInteger("SSL_TLSEXT_ERR_OK")
+ SSL_TLSEXT_ERR_ALERT_FATAL = rffi_platform.ConstantInteger("SSL_TLSEXT_ERR_ALERT_FATAL")
+
+ SSL_AD_INTERNAL_ERROR = rffi_platform.ConstantInteger("SSL_AD_INTERNAL_ERROR")
+ SSL_AD_HANDSHAKE_FAILURE = rffi_platform.ConstantInteger("SSL_AD_HANDSHAKE_FAILURE")
+
+ TLSEXT_NAMETYPE_host_name = rffi_platform.ConstantInteger("TLSEXT_NAMETYPE_host_name")
ERR_LIB_X509 = rffi_platform.ConstantInteger("ERR_LIB_X509")
ERR_LIB_PEM = rffi_platform.ConstantInteger("ERR_LIB_PEM")
@@ -273,6 +279,11 @@
pem_password_cb = lltype.Ptr(lltype.FuncType([rffi.CCHARP, rffi.INT, rffi.INT, rffi.VOIDP], rffi.INT))
ssl_external('SSL_CTX_set_default_passwd_cb', [SSL_CTX, pem_password_cb], lltype.Void)
ssl_external('SSL_CTX_set_default_passwd_cb_userdata', [SSL_CTX, rffi.VOIDP], lltype.Void)
+servername_cb = lltype.Ptr(lltype.FuncType([SSL, rffi.INTP, rffi.VOIDP], rffi.INT))
+ssl_external('SSL_CTX_set_tlsext_servername_callback', [SSL_CTX, servername_cb],
+ lltype.Void, macro=True)
+ssl_external('SSL_CTX_set_tlsext_servername_arg', [SSL_CTX, rffi.VOIDP], lltype.Void)
+
SSL_CTX_STATS_NAMES = """
number connect connect_good connect_renegotiate accept accept_good
accept_renegotiate hits misses timeouts cache_full""".split()
@@ -303,6 +314,8 @@
ssl_external('SSL_get_version', [SSL], rffi.CCHARP)
ssl_external('SSL_get_peer_certificate', [SSL], X509)
+ssl_external('SSL_get_servername', [SSL, rffi.INT], rffi.CCHARP)
+ssl_external('SSL_get_app_data', [SSL], rffi.VOIDP, macro=True)
ssl_external('X509_get_subject_name', [X509], X509_NAME)
ssl_external('X509_get_issuer_name', [X509], X509_NAME)
ssl_external('X509_NAME_oneline', [X509_NAME, rffi.CCHARP, rffi.INT], rffi.CCHARP)
From noreply at buildbot.pypy.org Sun Feb 1 19:34:06 2015
From: noreply at buildbot.pypy.org (amauryfa)
Date: Sun, 1 Feb 2015 19:34:06 +0100 (CET)
Subject: [pypy-commit] pypy stdlib-2.7.9: Fixes
Message-ID: <20150201183406.4E3A21C0FDE@cobra.cs.uni-duesseldorf.de>
Author: Amaury Forgeot d'Arc
Branch: stdlib-2.7.9
Changeset: r75631:adaa2c6b7b13
Date: 2015-02-01 19:32 +0100
http://bitbucket.org/pypy/pypy/changeset/adaa2c6b7b13/
Log: Fixes
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -170,6 +170,8 @@
NPN_STORAGE = RWeakValueDictionary(r_uint, SSLNpnProtocols)
+SOCKET_STORAGE = RWeakValueDictionary(int, W_Root)
+
if HAVE_OPENSSL_RAND:
# helper routines for seeding the SSL PRNG
@@ -222,6 +224,11 @@
sock_fd = space.int_w(space.call_method(w_sock, "fileno"))
self.ssl = libssl_SSL_new(w_ctx.ctx) # new ssl struct
+
+ index = compute_unique_id(self)
+ libssl_SSL_set_app_data(self.ssl, rffi.cast(rffi.VOIDP, index))
+ SOCKET_STORAGE.set(index, self)
+
libssl_SSL_set_fd(self.ssl, sock_fd) # set the socket for SSL
# The ACCEPT_MOVING_WRITE_BUFFER flag is necessary because the address
# of a str object may be changed by the garbage collector.
@@ -1068,21 +1075,22 @@
struct = SERVERNAME_CALLBACKS.get(rffi.cast(lltype.Signed, arg))
w_ctx = struct.w_ctx
space = struct.space
- servername = libssl_SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)
if not w_ctx.w_set_hostname:
- # remove race condition.
+ # Possible race condition.
return SSL_TLSEXT_ERR_OK
# The high-level ssl.SSLSocket object
- w_ssl = libssl_SSL_get_app_data(ssl)
+ index = rffi.cast(lltype.Signed, libssl_SSL_get_app_data(ssl))
+ w_ssl = SOCKET_STORAGE.get(index)
assert isinstance(w_ssl, _SSLSocket)
- if w_ssl.ssl_sock_weakref_w:
- w_ssl_socket = w_ssl.ssl_sock_weakref_w.get()
+ if w_ssl.ssl_sock_weakref_w is not None:
+ w_ssl_socket = w_ssl.ssl_sock_weakref_w()
else:
w_ssl_socket = space.w_None
if space.is_none(w_ssl_socket):
- ad[0] = SSL_AD_INTERNAL_ERROR
+ ad[0] = rffi.cast(rffi.INT, SSL_AD_INTERNAL_ERROR)
return SSL_TLSEXT_ERR_ALERT_FATAL
+ servername = libssl_SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)
try:
if not servername:
w_result = space.call_function(w_ctx.w_set_hostname,
@@ -1090,30 +1098,30 @@
else:
try:
- w_servername = space.wrap_bytes(rffi.charp2str(servername))
+ w_servername = space.wrapbytes(rffi.charp2str(servername))
w_servername_idna = space.call_method(
w_servername, 'decode', space.wrap('idna'))
except OperationError as e:
- space.write_unraisable(e, "w_servername")
- ad[0] = SSL_AD_INTERNAL_ERROR;
+ e.write_unraisable(space, w_ctx)
+ ad[0] = rffi.cast(rffi.INT, SSL_AD_INTERNAL_ERROR)
return SSL_TLSEXT_ERR_ALERT_FATAL
w_result = space.call_function(w_ctx.w_set_hostname,
w_ssl_socket,
w_servername_idna, w_ctx)
except OperationError as e:
- space.write_unraisable(e, "ssl_ctx->set_hostname")
- ad[0] = SSL_AD_HANDSHAKE_FAILURE
+ e.write_unraisable(space, w_ctx.w_set_hostname)
+ ad[0] = rffi.cast(rffi.INT, SSL_AD_HANDSHAKE_FAILURE)
return SSL_TLSEXT_ERR_ALERT_FATAL
if space.is_none(w_result):
return SSL_TLSEXT_ERR_OK
else:
try:
- ad[0] = space.int_w(w_result)
+ ad[0] = rffi.cast(rffi.INT, space.int_w(w_result))
except OperationError as e:
- space.write_unraisable(e, "w_result")
- ad[0] = SSL_AD_INTERNAL_ERROR
+ e.write_unraisable(space, w_result)
+ ad[0] = rffi.cast(rffi.INT, SSL_AD_INTERNAL_ERROR)
return SSL_TLSEXT_ERR_ALERT_FATAL
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -182,6 +182,9 @@
"NOT_RPYTHON"
raise NotImplementedError
+ def wrapbytes(self, x):
+ return w_some_obj()
+
def wrap(self, x):
if not we_are_translated():
if isinstance(x, gateway.interp2app):
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -127,6 +127,9 @@
assert typedef is not None
return self.fromcache(TypeCache).getorbuild(typedef)
+ def wrapbytes(self, x):
+ return wrapstr(self, x)
+
def wrap(self, x):
"Wraps the Python value 'x' into one of the wrapper classes."
# You might notice that this function is rather conspicuously
diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py
--- a/rpython/rlib/ropenssl.py
+++ b/rpython/rlib/ropenssl.py
@@ -316,6 +316,7 @@
ssl_external('SSL_get_peer_certificate', [SSL], X509)
ssl_external('SSL_get_servername', [SSL, rffi.INT], rffi.CCHARP)
ssl_external('SSL_get_app_data', [SSL], rffi.VOIDP, macro=True)
+ssl_external('SSL_set_app_data', [SSL, rffi.VOIDP], lltype.Void, macro=True)
ssl_external('X509_get_subject_name', [X509], X509_NAME)
ssl_external('X509_get_issuer_name', [X509], X509_NAME)
ssl_external('X509_NAME_oneline', [X509_NAME, rffi.CCHARP, rffi.INT], rffi.CCHARP)
From noreply at buildbot.pypy.org Sun Feb 1 20:38:04 2015
From: noreply at buildbot.pypy.org (amauryfa)
Date: Sun, 1 Feb 2015 20:38:04 +0100 (CET)
Subject: [pypy-commit] pypy stdlib-2.7.9: Translation fix
Message-ID: <20150201193804.945591C0FDD@cobra.cs.uni-duesseldorf.de>
Author: Amaury Forgeot d'Arc
Branch: stdlib-2.7.9
Changeset: r75632:4c44fb30552f
Date: 2015-02-01 20:37 +0100
http://bitbucket.org/pypy/pypy/changeset/4c44fb30552f/
Log: Translation fix
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -251,6 +251,7 @@
self.socket_type = socket_type
self.w_socket = w_sock
+ assert w_ssl_sock is not None
self.ssl_sock_weakref_w = rweakref.ref(w_ssl_sock)
return self
From noreply at buildbot.pypy.org Sun Feb 1 21:43:57 2015
From: noreply at buildbot.pypy.org (amauryfa)
Date: Sun, 1 Feb 2015 21:43:57 +0100 (CET)
Subject: [pypy-commit] pypy stdlib-2.7.9: Note to self: always run tests.
Message-ID: <20150201204357.45E2C1C02CD@cobra.cs.uni-duesseldorf.de>
Author: Amaury Forgeot d'Arc
Branch: stdlib-2.7.9
Changeset: r75634:6a56bba1899b
Date: 2015-02-01 21:43 +0100
http://bitbucket.org/pypy/pypy/changeset/6a56bba1899b/
Log: Note to self: always run tests.
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -382,5 +382,8 @@
return "" % (
self.co_name, self.co_filename, self.co_firstlineno)
+ def __repr__(self):
+ return self.get_repr()
+
def repr(self, space):
return space.wrap(self.get_repr())
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -80,6 +80,12 @@
self.initialize_frame_scopes(outer_func, code)
self.f_lineno = code.co_firstlineno
+ def __repr__(self):
+ # NOT_RPYTHON: useful in tracebacks
+ return "<%s.%s executing %s at line %s" % (
+ self.__class__.__module__, self.__class__.__name__,
+ self.pycode, self.get_last_lineno())
+
def mark_as_escaped(self):
"""
Must be called on frames that are exposed to applevel, e.g. by
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -251,8 +251,10 @@
self.socket_type = socket_type
self.w_socket = w_sock
- assert w_ssl_sock is not None
- self.ssl_sock_weakref_w = rweakref.ref(w_ssl_sock)
+ if w_ssl_sock:
+ self.ssl_sock_weakref_w = rweakref.ref(w_ssl_sock)
+ else:
+ self.ssl_sock_weakref_w = None
return self
def __del__(self):
From noreply at buildbot.pypy.org Sun Feb 1 23:44:30 2015
From: noreply at buildbot.pypy.org (amauryfa)
Date: Sun, 1 Feb 2015 23:44:30 +0100 (CET)
Subject: [pypy-commit] pypy stdlib-2.7.9: Fixes for test_sni_callback
Message-ID: <20150201224430.10E111C0507@cobra.cs.uni-duesseldorf.de>
Author: Amaury Forgeot d'Arc
Branch: stdlib-2.7.9
Changeset: r75635:7834e24c3b41
Date: 2015-02-01 23:44 +0100
http://bitbucket.org/pypy/pypy/changeset/7834e24c3b41/
Log: Fixes for test_sni_callback
diff --git a/pypy/bin/pyinteractive.py b/pypy/bin/pyinteractive.py
--- a/pypy/bin/pyinteractive.py
+++ b/pypy/bin/pyinteractive.py
@@ -10,7 +10,8 @@
import sys
import time
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
+pypy_path = os.path.join(os.path.dirname(__file__), '..', '..')
+sys.path.insert(0, os.path.abspath(pypy_path))
from pypy.tool import option
from pypy.interpreter import main, interactive, error, gateway
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1506,6 +1506,8 @@
def str_w(self, w_obj):
return w_obj.str_w(self)
+ bytes_w = str_w # Python2
+
def str0_w(self, w_obj):
"Like str_w, but rejects strings with NUL bytes."
from rpython.rlib import rstring
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -213,7 +213,8 @@
class _SSLSocket(W_Root):
@staticmethod
- def descr_new(space, w_ctx, w_sock, socket_type, hostname, w_ssl_sock):
+ def descr_new(space, w_ctx, w_sock, socket_type,
+ w_hostname=None, w_ssl_sock=None):
self = _SSLSocket()
self.space = space
@@ -235,6 +236,13 @@
libssl_SSL_set_mode(
self.ssl, SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)
+ if not space.is_none(w_hostname):
+ if space.isinstance_w(w_hostname, space.w_unicode):
+ w_hostname = space.call_method(w_hostname, "encode",
+ space.wrap("idna"))
+ libssl_SSL_set_tlsext_host_name(
+ self.ssl, space.bytes_w(w_hostname))
+
# If the socket is in non-blocking mode or timeout mode, set the BIO
# to non-blocking mode (blocking is the default)
w_timeout = space.call_method(w_sock, "gettimeout")
@@ -1078,9 +1086,10 @@
struct = SERVERNAME_CALLBACKS.get(rffi.cast(lltype.Signed, arg))
w_ctx = struct.w_ctx
space = struct.space
- if not w_ctx.w_set_hostname:
+ w_callback = struct.w_set_hostname
+ if not w_ctx.servername_callback:
# Possible race condition.
- return SSL_TLSEXT_ERR_OK
+ return rffi.cast(rffi.INT, SSL_TLSEXT_ERR_OK)
# The high-level ssl.SSLSocket object
index = rffi.cast(lltype.Signed, libssl_SSL_get_app_data(ssl))
w_ssl = SOCKET_STORAGE.get(index)
@@ -1091,12 +1100,12 @@
w_ssl_socket = space.w_None
if space.is_none(w_ssl_socket):
ad[0] = rffi.cast(rffi.INT, SSL_AD_INTERNAL_ERROR)
- return SSL_TLSEXT_ERR_ALERT_FATAL
+ return rffi.cast(rffi.INT, SSL_TLSEXT_ERR_ALERT_FATAL)
servername = libssl_SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)
try:
if not servername:
- w_result = space.call_function(w_ctx.w_set_hostname,
+ w_result = space.call_function(w_callback,
w_ssl_socket, space.w_None, w_ctx)
else:
@@ -1107,25 +1116,25 @@
except OperationError as e:
e.write_unraisable(space, "undecodable server name")
ad[0] = rffi.cast(rffi.INT, SSL_AD_INTERNAL_ERROR)
- return SSL_TLSEXT_ERR_ALERT_FATAL
+ return rffi.cast(rffi.INT, SSL_TLSEXT_ERR_ALERT_FATAL)
- w_result = space.call_function(w_ctx.w_set_hostname,
+ w_result = space.call_function(w_callback,
w_ssl_socket,
w_servername_idna, w_ctx)
except OperationError as e:
e.write_unraisable(space, "in servername callback")
ad[0] = rffi.cast(rffi.INT, SSL_AD_HANDSHAKE_FAILURE)
- return SSL_TLSEXT_ERR_ALERT_FATAL
+ return rffi.cast(rffi.INT, SSL_TLSEXT_ERR_ALERT_FATAL)
if space.is_none(w_result):
- return SSL_TLSEXT_ERR_OK
+ return rffi.cast(rffi.INT, SSL_TLSEXT_ERR_OK)
else:
try:
ad[0] = rffi.cast(rffi.INT, space.int_w(w_result))
except OperationError as e:
- e.write_unraisable(space, "bad result in servername callback")
+ e.write_unraisable(space, "servername callback result")
ad[0] = rffi.cast(rffi.INT, SSL_AD_INTERNAL_ERROR)
- return SSL_TLSEXT_ERR_ALERT_FATAL
+ return rffi.cast(rffi.INT, SSL_TLSEXT_ERR_ALERT_FATAL)
class _SSLContext(W_Root):
@@ -1475,15 +1484,17 @@
if space.is_none(w_callback):
libssl_SSL_CTX_set_tlsext_servername_callback(
self.ctx, lltype.nullptr(servername_cb.TO))
+ self.servername_callback = None
return
if not space.is_true(space.callable(w_callback)):
raise oefmt(space.w_TypeError, "not a callable object")
- self.w_set_hostname = w_callback
- struct = ServernameCallback()
- struct.space = space
- struct.w_ctx = self
+ callback_struct = ServernameCallback()
+ callback_struct.space = space
+ callback_struct.w_ctx = self
+ callback_struct.w_set_hostname = w_callback
+ self.servername_callback = callback_struct
index = compute_unique_id(self)
- SERVERNAME_CALLBACKS.set(index, struct)
+ SERVERNAME_CALLBACKS.set(index, callback_struct)
libssl_SSL_CTX_set_tlsext_servername_callback(
self.ctx, _servername_callback)
libssl_SSL_CTX_set_tlsext_servername_arg(self.ctx,
diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py
--- a/rpython/rlib/ropenssl.py
+++ b/rpython/rlib/ropenssl.py
@@ -282,7 +282,7 @@
servername_cb = lltype.Ptr(lltype.FuncType([SSL, rffi.INTP, rffi.VOIDP], rffi.INT))
ssl_external('SSL_CTX_set_tlsext_servername_callback', [SSL_CTX, servername_cb],
lltype.Void, macro=True)
-ssl_external('SSL_CTX_set_tlsext_servername_arg', [SSL_CTX, rffi.VOIDP], lltype.Void)
+ssl_external('SSL_CTX_set_tlsext_servername_arg', [SSL_CTX, rffi.VOIDP], lltype.Void, macro=True)
SSL_CTX_STATS_NAMES = """
number connect connect_good connect_renegotiate accept accept_good
From noreply at buildbot.pypy.org Mon Feb 2 08:22:56 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Mon, 2 Feb 2015 08:22:56 +0100 (CET)
Subject: [pypy-commit] pypy default: handle the easiest ravel('K') case -
is_c_contiguous and no negative strides
Message-ID: <20150202072256.D87E51C102E@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch:
Changeset: r75636:4d999c098b39
Date: 2015-02-02 00:33 +0200
http://bitbucket.org/pypy/pypy/changeset/4d999c098b39/
Log: handle the easiest ravel('K') case - is_c_contiguous and no negative
strides
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -430,9 +430,15 @@
order = 'C'
else:
order = space.str_w(w_order)
+ if order == 'K' and is_c_contiguous(self.implementation):
+ for s in self.implementation.get_strides():
+ if s < 0:
+ break
+ else:
+ order = 'C'
if order != 'C':
raise OperationError(space.w_NotImplementedError, space.wrap(
- "order not implemented"))
+ "order != 'C' only partially implemented"))
return self.reshape(space, space.wrap(-1))
@unwrap_spec(w_axis=WrappedDefault(None),
diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -2994,6 +2994,7 @@
assert (arange(3).ravel() == arange(3)).all()
assert (arange(6).reshape(2, 3).ravel() == arange(6)).all()
assert (arange(6).reshape(2, 3).T.ravel() == [0, 3, 1, 4, 2, 5]).all()
+ assert (arange(3).ravel('K') == arange(3)).all()
def test_nonzero(self):
from numpy import array
From noreply at buildbot.pypy.org Mon Feb 2 08:22:58 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Mon, 2 Feb 2015 08:22:58 +0100 (CET)
Subject: [pypy-commit] pypy default: imporove error message for missing
dtype casting
Message-ID: <20150202072258.1515B1C102E@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch:
Changeset: r75637:f7072390ff5d
Date: 2015-02-02 00:51 +0200
http://bitbucket.org/pypy/pypy/changeset/f7072390ff5d/
Log: imporove error message for missing dtype casting
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -7,6 +7,7 @@
from pypy.module.micronumpy.concrete import VoidBoxStorage
from pypy.interpreter.gateway import interp2app
from pypy.conftest import option
+from pypy.interpreter.error import OperationError
class TestUfuncCoercion(object):
@@ -129,7 +130,10 @@
'', ufunc.dtypes)
assert index == 0
assert dtypes == [f32_dtype, c64_dtype]
-
+ raises(OperationError, ufunc.type_resolver, space, [f32_array], [None],
+ 'u->u', ufunc.dtypes)
+ exc = raises(OperationError, ufunc.type_resolver, space, [f32_array], [None],
+ 'i->i', ufunc.dtypes)
class AppTestUfuncs(BaseNumpyAppTest):
def test_constants(self):
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -733,20 +733,24 @@
nop = len(inargs) + len(outargs)
dtypes = []
if isinstance(type_tup, str) and len(type_tup) > 0:
- if len(type_tup) == 1:
- dtypes = [get_dtype_cache(space).dtypes_by_name[type_tup]] * self.nargs
- elif len(type_tup) == self.nargs + 2:
- for i in range(self.nin):
- dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[i]])
- #skip the '->' in the signature
- for i in range(self.nout):
- j = i + self.nin + 2
- dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[j]])
- else:
- raise oefmt(space.w_TypeError, "a type-string for %s " \
- "requires 1 typecode or %d typecode(s) before and %d" \
- " after the -> sign, not '%s'", self.name, self.nin,
- self.nout, type_tup)
+ try:
+ if len(type_tup) == 1:
+ dtypes = [get_dtype_cache(space).dtypes_by_name[type_tup]] * self.nargs
+ elif len(type_tup) == self.nargs + 2:
+ for i in range(self.nin):
+ dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[i]])
+ #skip the '->' in the signature
+ for i in range(self.nout):
+ j = i + self.nin + 2
+ dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[j]])
+ else:
+ raise oefmt(space.w_TypeError, "a type-string for %s " \
+ "requires 1 typecode or %d typecode(s) before and %d" \
+ " after the -> sign, not '%s'", self.name, self.nin,
+ self.nout, type_tup)
+ except KeyError:
+ raise oefmt(space.w_ValueError, "unknown typecode in" \
+ " call to %s with type-string '%s'", self.name, type_tup)
else:
# XXX why does the next line not pass translation?
# dtypes = [i.get_dtype() for i in inargs]
@@ -770,9 +774,13 @@
break
else:
if len(self.funcs) > 1:
+ dtypesstr = ','.join(['%s%s%s' % (d.byteorder, d.kind, d.elsize) \
+ for d in dtypes])
+ _dtypesstr = ','.join(['%s%s%s' % (d.byteorder, d.kind, d.elsize) \
+ for d in _dtypes])
raise oefmt(space.w_TypeError,
- 'input dtype did not match any known dtypes',
- )
+ "input dtype [%s] did not match any known dtypes [%s] ",
+ dtypesstr,_dtypesstr)
i = 0
# Fill in empty dtypes
for j in range(self.nargs):
From noreply at buildbot.pypy.org Mon Feb 2 08:22:59 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Mon, 2 Feb 2015 08:22:59 +0100 (CET)
Subject: [pypy-commit] pypy default: test,
fix and start to optimize a=np.array(b) where b is a ndarray subtype
Message-ID: <20150202072259.4493F1C102E@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch:
Changeset: r75638:a0d3e64efd8b
Date: 2015-02-02 09:23 +0200
http://bitbucket.org/pypy/pypy/changeset/a0d3e64efd8b/
Log: test, fix and start to optimize a=np.array(b) where b is a ndarray
subtype
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -82,9 +82,18 @@
return w_object.descr_copy(space, w_order)
elif not copy and (subok or type(w_object) is W_NDimArray):
return w_object
-
- # not an array or incorrect dtype
- shape, elems_w = strides.find_shape_and_elems(space, w_object, dtype)
+ if isinstance(w_object, W_NDimArray) and copy and not subok:
+ # TODO do the loop.assign without copying elems_w
+ shape = w_object.get_shape()
+ _elems_w = w_object.reshape(space, space.wrap(-1))
+ elems_w = [None] * w_object.get_size()
+ for i in range(len(elems_w)):
+ elems_w[i] = _elems_w.descr_getitem(space, space.wrap(i))
+ if space.is_none(w_dtype):
+ dtype = w_object.get_dtype()
+ else:
+ # not an array
+ shape, elems_w = strides.find_shape_and_elems(space, w_object, dtype)
if dtype is None or (dtype.is_str_or_unicode() and dtype.elsize < 1):
dtype = strides.find_dtype_for_seq(space, elems_w, dtype)
if dtype is None:
diff --git a/pypy/module/micronumpy/test/test_subtype.py b/pypy/module/micronumpy/test/test_subtype.py
--- a/pypy/module/micronumpy/test/test_subtype.py
+++ b/pypy/module/micronumpy/test/test_subtype.py
@@ -304,10 +304,13 @@
out.shape = (sh, 1)
else:
out.shape = (1, sh)
- print 'out, shape was',old_shape,'now',out.shape
+ #print 'out, shape was',old_shape,'now',out.shape,'out',out
return out
- a = matrix([[1., 2.]])
+ a = matrix([[1., 2.], [3., 4.]])
b = N.array([a])
+ assert (b == a).all()
+ b = N.array(a)
+ assert len(b.shape) == 2
def test_setstate_no_version(self):
# Some subclasses of ndarray, like MaskedArray, do not use
From noreply at buildbot.pypy.org Mon Feb 2 08:30:01 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Mon, 2 Feb 2015 08:30:01 +0100 (CET)
Subject: [pypy-commit] pypy release-2.5.x: merge default into branch
Message-ID: <20150202073001.147481C102E@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch: release-2.5.x
Changeset: r75639:7abc5b13f7f0
Date: 2015-02-02 09:26 +0200
http://bitbucket.org/pypy/pypy/changeset/7abc5b13f7f0/
Log: merge default into branch
diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -197,6 +197,55 @@
(now-dead) object are still true about the new object.
+
+Would type annotations help PyPy's performance?
+-----------------------------------------------
+
+Two examples of type annotations that are being proposed for improved
+performance are `Cython types`__ and `PEP 484 - Type Hints`__.
+
+.. __: http://docs.cython.org/src/reference/language_basics.html#declaring-data-types
+.. __: https://www.python.org/dev/peps/pep-0484/
+
+**Cython types** are, by construction, similar to C declarations. For
+example, a local variable or an instance attribute can be declared
+``"cdef int"`` to force a machine word to be used. This changes the
+usual Python semantics (e.g. no overflow checks, and errors when
+trying to write other types of objects there). It gives some extra
+performance, but the exact benefits are unclear: right now
+(January 2015) for example we are investigating a technique that would
+store machine-word integers directly on instances, giving part of the
+benefits without the user-supplied ``"cdef int"``.
+
+**PEP 484 - Type Hints,** on the other hand, is almost entirely
+useless if you're looking at performance. First, as the name implies,
+they are *hints:* they must still be checked at runtime, like PEP 484
+says. Or maybe you're fine with a mode in which you get very obscure
+crashes when the type annotations are wrong; but even in that case the
+speed benefits would be extremely minor.
+
+There are several reasons for why. One of them is that annotations
+are at the wrong level (e.g. a PEP 484 "int" corresponds to Python 3's
+int type, which does not necessarily fits inside one machine word;
+even worse, an "int" annotation allows arbitrary int subclasses).
+Another is that a lot more information is needed to produce good code
+(e.g. "this ``f()`` called here really means this function there, and
+will never be monkey-patched" -- same with ``len()`` or ``list()``,
+btw). The third reason is that some "guards" in PyPy's JIT traces
+don't really have an obvious corresponding type (e.g. "this dict is so
+far using keys which don't override ``__hash__`` so a more efficient
+implementation was used"). Many guards don't even have any correspondence
+with types at all ("this class attribute was not modified"; "the loop
+counter did not reach zero so we don't need to release the GIL"; and
+so on).
+
+As PyPy works right now, it is able to derive far more useful
+information than can ever be given by PEP 484, and it works
+automatically. As far as we know, this is true even if we would add
+other techniques to PyPy, like a fast first-pass JIT.
+
+
+
.. _`prolog and javascript`:
Can I use PyPy's translation toolchain for other languages besides Python?
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1017,6 +1017,9 @@
def newlist_unicode(self, list_u):
return self.newlist([self.wrap(u) for u in list_u])
+ def newlist_int(self, list_i):
+ return self.newlist([self.wrap(i) for i in list_i])
+
def newlist_hint(self, sizehint):
from pypy.objspace.std.listobject import make_empty_list_with_size
return make_empty_list_with_size(self, sizehint)
diff --git a/pypy/module/cpyext/ndarrayobject.py b/pypy/module/cpyext/ndarrayobject.py
--- a/pypy/module/cpyext/ndarrayobject.py
+++ b/pypy/module/cpyext/ndarrayobject.py
@@ -291,6 +291,6 @@
Py_ssize_t, Py_ssize_t, rffi.CCHARP, rffi.CCHARP, Py_ssize_t], PyObject)
def PyUFunc_FromFuncAndData(space, funcs, data, types, ntypes,
nin, nout, identity, name, doc, check_return):
- w_signature = ""
+ w_signature = ','.join(['()'] * nin) + '->' + ','.join(['()'] * nout)
return do_ufunc(space, funcs, data, types, ntypes, nin, nout, identity,
name, doc, check_return, w_signature)
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -82,9 +82,18 @@
return w_object.descr_copy(space, w_order)
elif not copy and (subok or type(w_object) is W_NDimArray):
return w_object
-
- # not an array or incorrect dtype
- shape, elems_w = strides.find_shape_and_elems(space, w_object, dtype)
+ if isinstance(w_object, W_NDimArray) and copy and not subok:
+ # TODO do the loop.assign without copying elems_w
+ shape = w_object.get_shape()
+ _elems_w = w_object.reshape(space, space.wrap(-1))
+ elems_w = [None] * w_object.get_size()
+ for i in range(len(elems_w)):
+ elems_w[i] = _elems_w.descr_getitem(space, space.wrap(i))
+ if space.is_none(w_dtype):
+ dtype = w_object.get_dtype()
+ else:
+ # not an array
+ shape, elems_w = strides.find_shape_and_elems(space, w_object, dtype)
if dtype is None or (dtype.is_str_or_unicode() and dtype.elsize < 1):
dtype = strides.find_dtype_for_seq(space, elems_w, dtype)
if dtype is None:
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -430,9 +430,15 @@
order = 'C'
else:
order = space.str_w(w_order)
+ if order == 'K' and is_c_contiguous(self.implementation):
+ for s in self.implementation.get_strides():
+ if s < 0:
+ break
+ else:
+ order = 'C'
if order != 'C':
raise OperationError(space.w_NotImplementedError, space.wrap(
- "order not implemented"))
+ "order != 'C' only partially implemented"))
return self.reshape(space, space.wrap(-1))
@unwrap_spec(w_axis=WrappedDefault(None),
diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -2994,6 +2994,7 @@
assert (arange(3).ravel() == arange(3)).all()
assert (arange(6).reshape(2, 3).ravel() == arange(6)).all()
assert (arange(6).reshape(2, 3).T.ravel() == [0, 3, 1, 4, 2, 5]).all()
+ assert (arange(3).ravel('K') == arange(3)).all()
def test_nonzero(self):
from numpy import array
diff --git a/pypy/module/micronumpy/test/test_subtype.py b/pypy/module/micronumpy/test/test_subtype.py
--- a/pypy/module/micronumpy/test/test_subtype.py
+++ b/pypy/module/micronumpy/test/test_subtype.py
@@ -304,10 +304,13 @@
out.shape = (sh, 1)
else:
out.shape = (1, sh)
- print 'out, shape was',old_shape,'now',out.shape
+ #print 'out, shape was',old_shape,'now',out.shape,'out',out
return out
- a = matrix([[1., 2.]])
+ a = matrix([[1., 2.], [3., 4.]])
b = N.array([a])
+ assert (b == a).all()
+ b = N.array(a)
+ assert len(b.shape) == 2
def test_setstate_no_version(self):
# Some subclasses of ndarray, like MaskedArray, do not use
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -7,6 +7,7 @@
from pypy.module.micronumpy.concrete import VoidBoxStorage
from pypy.interpreter.gateway import interp2app
from pypy.conftest import option
+from pypy.interpreter.error import OperationError
class TestUfuncCoercion(object):
@@ -129,7 +130,10 @@
'', ufunc.dtypes)
assert index == 0
assert dtypes == [f32_dtype, c64_dtype]
-
+ raises(OperationError, ufunc.type_resolver, space, [f32_array], [None],
+ 'u->u', ufunc.dtypes)
+ exc = raises(OperationError, ufunc.type_resolver, space, [f32_array], [None],
+ 'i->i', ufunc.dtypes)
class AppTestUfuncs(BaseNumpyAppTest):
def test_constants(self):
@@ -169,8 +173,7 @@
dtypes=[int, int, int, float, float, float])
int_func22 = frompyfunc([int, int], 2, 2, signature='(i),(i)->(i),(i)',
dtypes=['match'])
- int_func12 = frompyfunc([int], 1, 2, signature='(i)->(i),(i)',
- dtypes=['match'])
+ int_func12 = frompyfunc([int], 1, 2, dtypes=['match'])
retype = dtype(int)
a = arange(10)
assert isinstance(adder_ufunc1, ufunc)
@@ -223,6 +226,7 @@
assert len(in_array.shape) == 2
assert in_array.shape == out_array.shape
out_array[:] = in_array * 2
+
from numpy import frompyfunc, dtype, arange
ufunc = frompyfunc([times_2], 1, 1,
signature='(m,n)->(n,m)',
@@ -233,6 +237,7 @@
ai3 = ufunc(ai[0,:,:])
ai2 = ufunc(ai)
assert (ai2 == ai * 2).all()
+
ufunc = frompyfunc([times_2], 1, 1,
signature='(m,m)->(m,m)',
dtypes=[dtype(int), dtype(int)],
@@ -245,6 +250,21 @@
ai2 = ufunc(ai)
assert (ai2 == ai * 2).all()
+ def test_frompyfunc_needs_nditer(self):
+ def summer(in0):
+ print 'in summer, in0=',in0,'in0.shape=',in0.shape
+ return in0.sum()
+
+ from numpy import frompyfunc, dtype, arange
+ ufunc = frompyfunc([summer], 1, 1,
+ signature='(m,m)->()',
+ dtypes=[dtype(int), dtype(int)],
+ stack_inputs=False,
+ )
+ ai = arange(12, dtype=int).reshape(3, 2, 2)
+ ao = ufunc(ai)
+ assert ao.size == 3
+
def test_frompyfunc_sig_broadcast(self):
def sum_along_0(in_array, out_array):
out_array[...] = in_array.sum(axis=0)
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -520,7 +520,9 @@
'''
_immutable_fields_ = ["funcs", "dtypes", "data", "match_dtypes"]
- def __init__(self, space, funcs, name, identity, nin, nout, dtypes, signature, match_dtypes=False, stack_inputs=False):
+ def __init__(self, space, funcs, name, identity, nin, nout, dtypes,
+ signature, match_dtypes=False, stack_inputs=False,
+ external_loop=False):
# XXX make sure funcs, signature, dtypes, nin, nout are consistent
# These don't matter, we use the signature and dtypes for determining
@@ -549,6 +551,7 @@
self.core_num_dims = [0] * self.nargs # number of core dimensions of each nargs
self.core_offsets = [0] * self.nargs
self.core_dim_ixs = [] # indices into unique shapes for each arg
+ self.external_loop = external_loop
def reduce(self, space, w_obj, w_axis, keepdims=False, out=None, dtype=None,
cumulative=False):
@@ -586,29 +589,21 @@
_dtypes.append(_dtypes[0])
index, dtypes = self.type_resolver(space, inargs, outargs, sig, _dtypes)
func = self.funcs[index]
- if not self.core_enabled:
- # func is going to do all the work, it must accept W_NDimArray args
- inargs0 = inargs[0]
- assert isinstance(inargs0, W_NDimArray)
- arg_shapes = [inargs0.get_shape()] * self.nargs
- inargs, outargs, need_to_cast = self.alloc_args(space, inargs, outargs,
- dtypes, arg_shapes)
- for tf in need_to_cast:
- if tf:
- raise oefmt(space.w_NotImplementedError, "casting not supported yet")
- if self.stack_inputs:
- arglist = space.newlist(list(inargs + outargs))
- space.call_args(func, Arguments.frompacked(space, arglist))
- else:
- arglist = space.newlist(inargs)
- outargs = space.call_args(func, Arguments.frompacked(space, arglist))
- return outargs
- if len(outargs) < 2:
- return outargs[0]
- return space.newtuple(outargs)
iter_shape, arg_shapes, matched_dims = self.verify_args(space, inargs, outargs)
inargs, outargs, need_to_cast = self.alloc_args(space, inargs, outargs, dtypes,
arg_shapes)
+ if not self.external_loop:
+ inargs0 = inargs[0]
+ outargs0 = outargs[0]
+ assert isinstance(inargs0, W_NDimArray)
+ assert isinstance(outargs0, W_NDimArray)
+ res_dtype = outargs0.get_dtype()
+ new_shape = inargs0.get_shape()
+ if len(outargs) < 2:
+ return loop.call_many_to_one(space, new_shape, func,
+ res_dtype, inargs, outargs[0])
+ return loop.call_many_to_many(space, new_shape, func,
+ res_dtype, inargs, outargs)
for tf in need_to_cast:
if tf:
raise oefmt(space.w_NotImplementedError, "casting not supported yet")
@@ -619,44 +614,44 @@
w_casting = space.w_None
w_op_axes = space.w_None
+ #print '\nsignature', sig
+ #print [(d, getattr(self,d)) for d in dir(self) if 'core' in d or 'broad' in d]
+ #print [(d, locals()[d]) for d in locals() if 'core' in d or 'broad' in d]
+ #print 'shapes',[d.get_shape() for d in inargs + outargs]
+ #print 'steps',[d.implementation.strides for d in inargs + outargs]
+ if isinstance(func, W_GenericUFuncCaller):
+ # Use GeneralizeUfunc interface with signature
+ # Unlike numpy, we will not broadcast dims before
+ # the core_ndims rather we use nditer iteration
+ # so dims[0] == 1
+ dims = [1] + matched_dims
+ steps = []
+ allargs = inargs + outargs
+ for i in range(len(allargs)):
+ steps.append(0)
+ for i in range(len(allargs)):
+ _arg = allargs[i]
+ assert isinstance(_arg, W_NDimArray)
+ start_dim = len(iter_shape)
+ steps += _arg.implementation.strides[start_dim:]
+ func.set_dims_and_steps(space, dims, steps)
+ else:
+ # it is a function, ready to be called by the iterator,
+ # from frompyfunc
+ pass
+ # mimic NpyIter_AdvancedNew with a nditer
+ w_itershape = space.newlist([space.wrap(i) for i in iter_shape])
+ nd_it = W_NDIter(space, space.newlist(inargs + outargs), w_flags,
+ w_op_flags, w_op_dtypes, w_casting, w_op_axes,
+ w_itershape)
+ # coalesce each iterators, according to inner_dimensions
+ for i in range(len(inargs) + len(outargs)):
+ for j in range(self.core_num_dims[i]):
+ new_iter = coalesce_iter(nd_it.iters[i][0], nd_it.op_flags[i],
+ nd_it, nd_it.order, flat=False)
+ nd_it.iters[i] = (new_iter, new_iter.reset())
+ # do the iteration
if self.stack_inputs:
- #print '\nsignature', sig
- #print [(d, getattr(self,d)) for d in dir(self) if 'core' in d or 'broad' in d]
- #print [(d, locals()[d]) for d in locals() if 'core' in d or 'broad' in d]
- #print 'shapes',[d.get_shape() for d in inargs + outargs]
- #print 'steps',[d.implementation.strides for d in inargs + outargs]
- if isinstance(func, W_GenericUFuncCaller):
- # Use GeneralizeUfunc interface with signature
- # Unlike numpy, we will not broadcast dims before
- # the core_ndims rather we use nditer iteration
- # so dims[0] == 1
- dims = [1] + matched_dims
- steps = []
- allargs = inargs + outargs
- for i in range(len(allargs)):
- steps.append(0)
- for i in range(len(allargs)):
- _arg = allargs[i]
- assert isinstance(_arg, W_NDimArray)
- start_dim = len(iter_shape)
- steps += _arg.implementation.strides[start_dim:]
- func.set_dims_and_steps(space, dims, steps)
- else:
- # it is a function, ready to be called by the iterator,
- # from frompyfunc
- pass
- # mimic NpyIter_AdvancedNew with a nditer
- w_itershape = space.newlist([space.wrap(i) for i in iter_shape])
- nd_it = W_NDIter(space, space.newlist(inargs + outargs), w_flags,
- w_op_flags, w_op_dtypes, w_casting, w_op_axes,
- w_itershape)
- # coalesce each iterators, according to inner_dimensions
- for i in range(len(inargs) + len(outargs)):
- for j in range(self.core_num_dims[i]):
- new_iter = coalesce_iter(nd_it.iters[i][0], nd_it.op_flags[i],
- nd_it, nd_it.order, flat=False)
- nd_it.iters[i] = (new_iter, new_iter.reset())
- # do the iteration
while not nd_it.done:
# XXX jit me
for it, st in nd_it.iters:
@@ -670,20 +665,35 @@
args.append(nd_it.getitem(it, st))
nd_it.iters[i] = (it, it.next(st))
space.call_args(func, Arguments.frompacked(space, space.newlist(args)))
- if len(outargs) > 1:
- return space.newtuple([convert_to_array(space, o) for o in outargs])
- return outargs[0]
- inargs0 = inargs[0]
- outargs0 = outargs[0]
- assert isinstance(inargs0, W_NDimArray)
- assert isinstance(outargs0, W_NDimArray)
- res_dtype = outargs0.get_dtype()
- new_shape = inargs0.get_shape()
- if len(outargs) < 2:
- return loop.call_many_to_one(space, new_shape, func,
- res_dtype, inargs, outargs[0])
- return loop.call_many_to_many(space, new_shape, func,
- res_dtype, inargs, outargs)
+ else:
+ # do the iteration
+ while not nd_it.done:
+ # XXX jit me
+ for it, st in nd_it.iters:
+ if not it.done(st):
+ break
+ else:
+ nd_it.done = True
+ break
+ initers = []
+ outiters = []
+ nin = len(inargs)
+ for i, (it, st) in enumerate(nd_it.iters[:nin]):
+ initers.append(nd_it.getitem(it, st))
+ nd_it.iters[i] = (it, it.next(st))
+ for i, (it, st) in enumerate(nd_it.iters[nin:]):
+ outiters.append(nd_it.getitem(it, st))
+ nd_it.iters[i + nin] = (it, it.next(st))
+ outs = space.call_args(func, Arguments.frompacked(space, space.newlist(initers)))
+ if len(outiters) < 2:
+ outiters[0].descr_setitem(space, space.w_Ellipsis, outs)
+ else:
+ for i in range(self.nout):
+ w_val = space.getitem(outs, space.wrap(i))
+ outiters[i].descr_setitem(space, space.w_Ellipsis, w_val)
+ if len(outargs) > 1:
+ return space.newtuple([convert_to_array(space, o) for o in outargs])
+ return outargs[0]
def parse_kwargs(self, space, kwargs_w):
w_subok, w_out, casting, sig, extobj = \
@@ -723,20 +733,24 @@
nop = len(inargs) + len(outargs)
dtypes = []
if isinstance(type_tup, str) and len(type_tup) > 0:
- if len(type_tup) == 1:
- dtypes = [get_dtype_cache(space).dtypes_by_name[type_tup]] * self.nargs
- elif len(type_tup) == self.nargs + 2:
- for i in range(self.nin):
- dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[i]])
- #skip the '->' in the signature
- for i in range(self.nout):
- j = i + self.nin + 2
- dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[j]])
- else:
- raise oefmt(space.w_TypeError, "a type-string for %s " \
- "requires 1 typecode or %d typecode(s) before and %d" \
- " after the -> sign, not '%s'", self.name, self.nin,
- self.nout, type_tup)
+ try:
+ if len(type_tup) == 1:
+ dtypes = [get_dtype_cache(space).dtypes_by_name[type_tup]] * self.nargs
+ elif len(type_tup) == self.nargs + 2:
+ for i in range(self.nin):
+ dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[i]])
+ #skip the '->' in the signature
+ for i in range(self.nout):
+ j = i + self.nin + 2
+ dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[j]])
+ else:
+ raise oefmt(space.w_TypeError, "a type-string for %s " \
+ "requires 1 typecode or %d typecode(s) before and %d" \
+ " after the -> sign, not '%s'", self.name, self.nin,
+ self.nout, type_tup)
+ except KeyError:
+ raise oefmt(space.w_ValueError, "unknown typecode in" \
+ " call to %s with type-string '%s'", self.name, type_tup)
else:
# XXX why does the next line not pass translation?
# dtypes = [i.get_dtype() for i in inargs]
@@ -760,9 +774,13 @@
break
else:
if len(self.funcs) > 1:
+ dtypesstr = ','.join(['%s%s%s' % (d.byteorder, d.kind, d.elsize) \
+ for d in dtypes])
+ _dtypesstr = ','.join(['%s%s%s' % (d.byteorder, d.kind, d.elsize) \
+ for d in _dtypes])
raise oefmt(space.w_TypeError,
- 'input dtype did not match any known dtypes',
- )
+ "input dtype [%s] did not match any known dtypes [%s] ",
+ dtypesstr,_dtypesstr)
i = 0
# Fill in empty dtypes
for j in range(self.nargs):
@@ -1235,7 +1253,8 @@
w_identity=None, name='', doc='', stack_inputs=False):
''' frompyfunc(func, nin, nout) #cpython numpy compatible
frompyfunc(func, nin, nout, dtypes=None, signature='',
- identity=None, name='', doc='', stack_inputs=False)
+ identity=None, name='', doc='',
+ stack_inputs=False)
Takes an arbitrary Python function and returns a ufunc.
@@ -1251,10 +1270,12 @@
nout : int
The number of arrays returned by `func`.
dtypes: None or [dtype, ...] of the input, output args for each function,
- or 'match' to force output to exactly match input dtype
+ or 'match' to force output to exactly match input dtype
+ Note that 'match' is a pypy-only extension to allow non-object
+ return dtypes
signature*: str, default=''
The mapping of input args to output args, defining the
- inner-loop indexing
+ inner-loop indexing. If it is empty, the func operates on scalars
identity*: None (default) or int
For reduce-type ufuncs, the default value
name: str, default=''
@@ -1273,7 +1294,7 @@
Notes
-----
- If the signature and out_dtype are both missing, the returned ufunc
+ If the signature and dtype are both missing, the returned ufunc
always returns PyObject arrays (cpython numpy compatability).
Input arguments marked with a * are pypy-only extensions
@@ -1329,16 +1350,15 @@
'identity must be None or an int')
if len(signature) == 0:
- # cpython compatability, func is of the form (),()->()
- signature = ','.join(['()'] * nin) + '->' + ','.join(['()'] * nout)
+ external_loop=False
else:
- #stack_inputs = True
- pass
+ external_loop=True
w_ret = W_UfuncGeneric(space, func, name, identity, nin, nout, dtypes,
signature, match_dtypes=match_dtypes,
- stack_inputs=stack_inputs)
- _parse_signature(space, w_ret, w_ret.signature)
+ stack_inputs=stack_inputs, external_loop=external_loop)
+ if w_ret.external_loop:
+ _parse_signature(space, w_ret, w_ret.signature)
if doc:
w_ret.w_doc = space.wrap(doc)
return w_ret
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -173,7 +173,7 @@
exiting (blackhole) steps, but just not from the final assembler.
Note that the return value of the callable is ignored, because
-there is no reasonable way to guess what it sound be in case the
+there is no reasonable way to guess what it should be in case the
function is not called.
This is meant to be used notably in sys.settrace() for coverage-
diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -1173,8 +1173,8 @@
def wrapkey(space, key):
return space.wrap(key)
- # XXX there is no space.newlist_int yet to implement w_keys more
- # efficiently
+ def w_keys(self, w_dict):
+ return self.space.newlist_int(self.listview_int(w_dict))
create_iterator_classes(IntDictStrategy)
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -176,6 +176,12 @@
storage = strategy.erase(list_u)
return W_ListObject.from_storage_and_strategy(space, storage, strategy)
+ @staticmethod
+ def newlist_int(space, list_i):
+ strategy = space.fromcache(IntegerListStrategy)
+ storage = strategy.erase(list_i)
+ return W_ListObject.from_storage_and_strategy(space, storage, strategy)
+
def __repr__(self):
""" representation for debugging purposes """
return "%s(%s, %s)" % (self.__class__.__name__, self.strategy,
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -288,6 +288,9 @@
def newlist_unicode(self, list_u):
return W_ListObject.newlist_unicode(self, list_u)
+ def newlist_int(self, list_i):
+ return W_ListObject.newlist_int(self, list_i)
+
def newdict(self, module=False, instance=False, kwargs=False,
strdict=False):
return W_DictMultiObject.allocate_and_init_instance(
diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py
--- a/rpython/rtyper/rclass.py
+++ b/rpython/rtyper/rclass.py
@@ -711,8 +711,15 @@
continue
value = self.classdef.classdesc.read_attribute(fldname, None)
if value is not None:
- cvalue = inputconst(r.lowleveltype,
- r.convert_desc_or_const(value))
+ ll_value = r.convert_desc_or_const(value)
+ # don't write NULL GC pointers: we know that the malloc
+ # done above initialized at least the GC Ptr fields to
+ # NULL already, and that's true for all our GCs
+ if (isinstance(r.lowleveltype, Ptr) and
+ r.lowleveltype.TO._gckind == 'gc' and
+ not ll_value):
+ continue
+ cvalue = inputconst(r.lowleveltype, ll_value)
self.setfield(vptr, fldname, cvalue, llops,
flags={'access_directly': True})
return vptr
diff --git a/rpython/translator/backendopt/test/test_malloc.py b/rpython/translator/backendopt/test/test_malloc.py
--- a/rpython/translator/backendopt/test/test_malloc.py
+++ b/rpython/translator/backendopt/test/test_malloc.py
@@ -340,3 +340,15 @@
u[0].s.x = x
return u[0].s.x
graph = self.check(f, [int], [42], 42)
+
+ def test_two_paths_one_with_constant(self):
+ py.test.skip("XXX implement me?")
+ def fn(n):
+ if n > 100:
+ tup = (0,)
+ else:
+ tup = (n,)
+ (n,) # <- flowspace
+ return tup[0]
+
+ self.check(fn, [int], [42], 42)
diff --git a/rpython/translator/c/test/test_standalone.py b/rpython/translator/c/test/test_standalone.py
--- a/rpython/translator/c/test/test_standalone.py
+++ b/rpython/translator/c/test/test_standalone.py
@@ -808,12 +808,7 @@
t, cbuilder = self.compile(entry_point, shared=True)
assert cbuilder.shared_library_name is not None
assert cbuilder.shared_library_name != cbuilder.executable_name
- if os.name == 'posix':
- library_path = cbuilder.shared_library_name.dirpath()
- if sys.platform == 'darwin':
- monkeypatch.setenv('DYLD_LIBRARY_PATH', library_path)
- else:
- monkeypatch.setenv('LD_LIBRARY_PATH', library_path)
+ #Do not set LD_LIBRARY_PATH, make sure $ORIGIN flag is working
out, err = cbuilder.cmdexec("a b")
assert out == "3"
diff --git a/rpython/translator/platform/freebsd.py b/rpython/translator/platform/freebsd.py
--- a/rpython/translator/platform/freebsd.py
+++ b/rpython/translator/platform/freebsd.py
@@ -12,6 +12,7 @@
cflags = tuple(
['-O3', '-pthread', '-fomit-frame-pointer'] +
os.environ.get('CFLAGS', '').split())
+ rpath_flags = ['-Wl,-rpath=\'$$ORIGIN/\'', '-Wl,-z,origin']
class Freebsd_64(Freebsd):
shared_only = ('-fPIC',)
diff --git a/rpython/translator/platform/posix.py b/rpython/translator/platform/posix.py
--- a/rpython/translator/platform/posix.py
+++ b/rpython/translator/platform/posix.py
@@ -112,9 +112,9 @@
target_name = exe_name.basename
if shared:
- cflags = self.cflags + self.get_shared_only_compile_flags()
+ cflags = tuple(self.cflags) + self.get_shared_only_compile_flags()
else:
- cflags = self.cflags + self.standalone_only
+ cflags = tuple(self.cflags) + tuple(self.standalone_only)
m = GnuMakefile(path)
m.exe_name = path.join(exe_name.basename)
From noreply at buildbot.pypy.org Mon Feb 2 08:30:02 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Mon, 2 Feb 2015 08:30:02 +0100 (CET)
Subject: [pypy-commit] pypy release-2.5.x: update version info to release
Message-ID: <20150202073002.685EC1C102E@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch: release-2.5.x
Changeset: r75640:75dd29f10ef3
Date: 2015-02-02 09:29 +0200
http://bitbucket.org/pypy/pypy/changeset/75dd29f10ef3/
Log: update version info to release
diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h
--- a/pypy/module/cpyext/include/patchlevel.h
+++ b/pypy/module/cpyext/include/patchlevel.h
@@ -29,7 +29,7 @@
#define PY_VERSION "2.7.8"
/* PyPy version as a string */
-#define PYPY_VERSION "2.5.0-beta0"
+#define PYPY_VERSION "2.5.0-final0"
/* Subversion Revision number of this file (not of the repository).
* Empty since Mercurial migration. */
diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py
--- a/pypy/module/sys/version.py
+++ b/pypy/module/sys/version.py
@@ -10,7 +10,7 @@
#XXX # sync CPYTHON_VERSION with patchlevel.h, package.py
CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h
-PYPY_VERSION = (2, 5, 0, "beta", 0) #XXX # sync patchlevel.h
+PYPY_VERSION = (2, 5, 0, "final", 0) #XXX # sync patchlevel.h
if platform.name == 'msvc':
COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600)
From noreply at buildbot.pypy.org Mon Feb 2 09:26:33 2015
From: noreply at buildbot.pypy.org (amauryfa)
Date: Mon, 2 Feb 2015 09:26:33 +0100 (CET)
Subject: [pypy-commit] pypy stdlib-2.7.9: Add SSLContext.session_stats()
Message-ID: <20150202082633.28A711C1032@cobra.cs.uni-duesseldorf.de>
Author: Amaury Forgeot d'Arc
Branch: stdlib-2.7.9
Changeset: r75641:d48d4991869d
Date: 2015-02-02 08:43 +0100
http://bitbucket.org/pypy/pypy/changeset/d48d4991869d/
Log: Add SSLContext.session_stats()
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -1175,6 +1175,13 @@
libssl_ERR_clear_error()
raise ssl_error(space, "No cipher can be selected.")
+ def session_stats_w(self, space):
+ w_stats = space.newdict()
+ for name, ssl_func in SSL_CTX_STATS:
+ w_value = space.wrap(ssl_func(self.ctx))
+ space.setitem_str(w_stats, name, w_value)
+ return w_stats
+
def descr_set_default_verify_paths(self, space):
if not libssl_SSL_CTX_set_default_verify_paths(self.ctx):
raise ssl_error(space, "")
@@ -1509,6 +1516,7 @@
load_cert_chain=interp2app(_SSLContext.load_cert_chain_w),
load_dh_params=interp2app(_SSLContext.load_dh_params_w),
load_verify_locations=interp2app(_SSLContext.load_verify_locations_w),
+ session_stats = interp2app(_SSLContext.session_stats_w),
set_default_verify_paths=interp2app(_SSLContext.descr_set_default_verify_paths),
_set_npn_protocols=interp2app(_SSLContext.set_npn_protocols_w),
get_ca_certs=interp2app(_SSLContext.get_ca_certs_w),
From noreply at buildbot.pypy.org Mon Feb 2 09:26:34 2015
From: noreply at buildbot.pypy.org (amauryfa)
Date: Mon, 2 Feb 2015 09:26:34 +0100 (CET)
Subject: [pypy-commit] pypy stdlib-2.7.9: ssl: Pass last ssl error code to
the exception.
Message-ID: <20150202082634.663631C1032@cobra.cs.uni-duesseldorf.de>
Author: Amaury Forgeot d'Arc
Branch: stdlib-2.7.9
Changeset: r75642:19337a71252a
Date: 2015-02-02 09:17 +0100
http://bitbucket.org/pypy/pypy/changeset/19337a71252a/
Log: ssl: Pass last ssl error code to the exception.
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -932,9 +932,10 @@
def _ssl_seterror(space, ss, ret):
assert ret <= 0
+ errcode = libssl_ERR_peek_last_error()
+
if ss is None:
- errval = libssl_ERR_peek_last_error()
- return ssl_error(space, None, errcode=errval)
+ return ssl_error(space, None, errcode=errcode)
elif ss.ssl:
err = libssl_SSL_get_error(ss.ssl, ret)
else:
@@ -979,17 +980,17 @@
errstr = rffi.charp2str(libssl_ERR_error_string(e, None))
errval = PY_SSL_ERROR_SYSCALL
elif err == SSL_ERROR_SSL:
- e = libssl_ERR_get_error()
errval = PY_SSL_ERROR_SSL
- if e != 0:
- errstr = rffi.charp2str(libssl_ERR_error_string(e, None))
+ if errcode != 0:
+ errstr = rffi.charp2str(libssl_ERR_error_string(errcode, None))
else:
errstr = "A failure in the SSL library occurred"
else:
errstr = "Invalid error code"
errval = PY_SSL_ERROR_INVALID_ERROR_CODE
- return ssl_error(space, errstr, errval, w_errtype=w_errtype)
+ return ssl_error(space, errstr, errval, w_errtype=w_errtype,
+ errcode=errcode)
def SSLError_descr_str(space, w_exc):
w_strerror = space.getattr(w_exc, space.wrap("strerror"))
From noreply at buildbot.pypy.org Mon Feb 2 09:55:04 2015
From: noreply at buildbot.pypy.org (fijal)
Date: Mon, 2 Feb 2015 09:55:04 +0100 (CET)
Subject: [pypy-commit] extradoc extradoc: fix my dates and add sebastian
Message-ID: <20150202085504.61D071C026B@cobra.cs.uni-duesseldorf.de>
Author: Maciej Fijalkowski
Branch: extradoc
Changeset: r5496:0ade475b25d2
Date: 2015-02-02 10:55 +0200
http://bitbucket.org/pypy/extradoc/changeset/0ade475b25d2/
Log: fix my dates and add sebastian
diff --git a/sprintinfo/leysin-winter-2015/people.txt b/sprintinfo/leysin-winter-2015/people.txt
--- a/sprintinfo/leysin-winter-2015/people.txt
+++ b/sprintinfo/leysin-winter-2015/people.txt
@@ -11,8 +11,9 @@
Name Arrive/Depart Accomodation
==================== ============== =======================
Armin Rigo private
-Maciej Fijalkowski 20-28 Ermina
+Maciej Fijalkowski 21-28 Ermina
Remi Meier 21-28 Ermina
+Sebastian Pawlus 21-27 Ermina
==================== ============== =======================
From noreply at buildbot.pypy.org Mon Feb 2 15:44:21 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 15:44:21 +0100 (CET)
Subject: [pypy-commit] stmgc default: finalizer bug: found a test
Message-ID: <20150202144421.1C6091C02CD@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch:
Changeset: r1603:f8215ea24895
Date: 2015-02-02 15:44 +0100
http://bitbucket.org/pypy/stmgc/changeset/f8215ea24895/
Log: finalizer bug: found a test
diff --git a/c7/test/test_finalizer.py b/c7/test/test_finalizer.py
--- a/c7/test/test_finalizer.py
+++ b/c7/test/test_finalizer.py
@@ -176,12 +176,14 @@
def test_finalizer_in_major_collection(self):
self.start_transaction()
- lp1 = stm_allocate_with_finalizer(48)
- lp2 = stm_allocate_with_finalizer(48)
- lp3 = stm_allocate_with_finalizer(48)
- print lp1, lp2, lp3
- stm_major_collect()
- self.expect_finalized([lp1, lp2, lp3])
+ for repeat in range(2):
+ lp1 = stm_allocate_with_finalizer(48)
+ lp2 = stm_allocate_with_finalizer(48)
+ lp3 = stm_allocate_with_finalizer(48)
+ print repeat, lp1, lp2, lp3
+ self.expect_finalized([])
+ stm_major_collect()
+ self.expect_finalized([lp1, lp2, lp3])
def test_finalizer_from_other_thread(self):
self.start_transaction()
From noreply at buildbot.pypy.org Mon Feb 2 15:48:51 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 15:48:51 +0100 (CET)
Subject: [pypy-commit] stmgc default: fix
Message-ID: <20150202144851.13C2B1C02D4@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch:
Changeset: r1604:97f88816858e
Date: 2015-02-02 15:49 +0100
http://bitbucket.org/pypy/stmgc/changeset/97f88816858e/
Log: fix
diff --git a/c7/stm/finalizer.c b/c7/stm/finalizer.c
--- a/c7/stm/finalizer.c
+++ b/c7/stm/finalizer.c
@@ -138,6 +138,8 @@
init_finalizers(f);
STM_PSEGMENT->finalizers = f;
}
+ assert(STM_PSEGMENT->finalizers->count_non_young
+ <= list_count(STM_PSEGMENT->finalizers->objects_with_finalizers));
LIST_APPEND(STM_PSEGMENT->finalizers->objects_with_finalizers, obj);
return obj;
}
@@ -289,6 +291,8 @@
struct list_s *lst = f->objects_with_finalizers;
long i, count = list_count(lst);
lst->count = 0;
+ f->count_non_young = 0;
+
for (i = 0; i < count; i++) {
object_t *x = (object_t *)list_item(lst, i);
From noreply at buildbot.pypy.org Mon Feb 2 15:49:09 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 15:49:09 +0100 (CET)
Subject: [pypy-commit] stmgc hashtable-iter: hg merge default
Message-ID: <20150202144909.8C1611C02D4@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: hashtable-iter
Changeset: r1605:88492dc56aa8
Date: 2015-02-02 15:49 +0100
http://bitbucket.org/pypy/stmgc/changeset/88492dc56aa8/
Log: hg merge default
diff --git a/c7/stm/finalizer.c b/c7/stm/finalizer.c
--- a/c7/stm/finalizer.c
+++ b/c7/stm/finalizer.c
@@ -138,6 +138,8 @@
init_finalizers(f);
STM_PSEGMENT->finalizers = f;
}
+ assert(STM_PSEGMENT->finalizers->count_non_young
+ <= list_count(STM_PSEGMENT->finalizers->objects_with_finalizers));
LIST_APPEND(STM_PSEGMENT->finalizers->objects_with_finalizers, obj);
return obj;
}
@@ -289,6 +291,8 @@
struct list_s *lst = f->objects_with_finalizers;
long i, count = list_count(lst);
lst->count = 0;
+ f->count_non_young = 0;
+
for (i = 0; i < count; i++) {
object_t *x = (object_t *)list_item(lst, i);
diff --git a/c7/test/test_finalizer.py b/c7/test/test_finalizer.py
--- a/c7/test/test_finalizer.py
+++ b/c7/test/test_finalizer.py
@@ -176,12 +176,14 @@
def test_finalizer_in_major_collection(self):
self.start_transaction()
- lp1 = stm_allocate_with_finalizer(48)
- lp2 = stm_allocate_with_finalizer(48)
- lp3 = stm_allocate_with_finalizer(48)
- print lp1, lp2, lp3
- stm_major_collect()
- self.expect_finalized([lp1, lp2, lp3])
+ for repeat in range(2):
+ lp1 = stm_allocate_with_finalizer(48)
+ lp2 = stm_allocate_with_finalizer(48)
+ lp3 = stm_allocate_with_finalizer(48)
+ print repeat, lp1, lp2, lp3
+ self.expect_finalized([])
+ stm_major_collect()
+ self.expect_finalized([lp1, lp2, lp3])
def test_finalizer_from_other_thread(self):
self.start_transaction()
From noreply at buildbot.pypy.org Mon Feb 2 15:53:28 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 15:53:28 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: update to stmgc/88492dc56aa8 (branch
hashtable-iter)
Message-ID: <20150202145328.0529D1C02CD@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75644:55be055e388a
Date: 2015-02-02 15:51 +0100
http://bitbucket.org/pypy/pypy/changeset/55be055e388a/
Log: update to stmgc/88492dc56aa8 (branch hashtable-iter)
diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision
--- a/rpython/translator/stm/src_stm/revision
+++ b/rpython/translator/stm/src_stm/revision
@@ -1,1 +1,1 @@
-de27e8f11e38
+88492dc56aa8
diff --git a/rpython/translator/stm/src_stm/stm/finalizer.c b/rpython/translator/stm/src_stm/stm/finalizer.c
--- a/rpython/translator/stm/src_stm/stm/finalizer.c
+++ b/rpython/translator/stm/src_stm/stm/finalizer.c
@@ -139,6 +139,8 @@
init_finalizers(f);
STM_PSEGMENT->finalizers = f;
}
+ assert(STM_PSEGMENT->finalizers->count_non_young
+ <= list_count(STM_PSEGMENT->finalizers->objects_with_finalizers));
LIST_APPEND(STM_PSEGMENT->finalizers->objects_with_finalizers, obj);
return obj;
}
@@ -290,6 +292,8 @@
struct list_s *lst = f->objects_with_finalizers;
long i, count = list_count(lst);
lst->count = 0;
+ f->count_non_young = 0;
+
for (i = 0; i < count; i++) {
object_t *x = (object_t *)list_item(lst, i);
From noreply at buildbot.pypy.org Mon Feb 2 16:15:14 2015
From: noreply at buildbot.pypy.org (mjacob)
Date: Mon, 2 Feb 2015 16:15:14 +0100 (CET)
Subject: [pypy-commit] extradoc extradoc: Add myself to the Leysin sprint.
Message-ID: <20150202151514.DD5F71C02CD@cobra.cs.uni-duesseldorf.de>
Author: Manuel Jacob
Branch: extradoc
Changeset: r5498:ac5668253cbc
Date: 2015-02-02 16:14 +0100
http://bitbucket.org/pypy/extradoc/changeset/ac5668253cbc/
Log: Add myself to the Leysin sprint.
diff --git a/sprintinfo/leysin-winter-2015/people.txt b/sprintinfo/leysin-winter-2015/people.txt
--- a/sprintinfo/leysin-winter-2015/people.txt
+++ b/sprintinfo/leysin-winter-2015/people.txt
@@ -14,6 +14,7 @@
Maciej Fijalkowski 21-28 Ermina
Remi Meier 21-28 Ermina
Sebastian Pawlus 21-27 Ermina
+Manuel Jacob 21-28 Ermina
==================== ============== =======================
From noreply at buildbot.pypy.org Mon Feb 2 17:08:00 2015
From: noreply at buildbot.pypy.org (alex_gaynor)
Date: Mon, 2 Feb 2015 17:08:00 +0100 (CET)
Subject: [pypy-commit] pypy default: Fixed #1968 -- bump the version for
greenlet.py to the latest
Message-ID: <20150202160800.AA14A1C02CD@cobra.cs.uni-duesseldorf.de>
Author: Alex Gaynor
Branch:
Changeset: r75647:0def3207e879
Date: 2015-02-02 08:07 -0800
http://bitbucket.org/pypy/pypy/changeset/0def3207e879/
Log: Fixed #1968 -- bump the version for greenlet.py to the latest
diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info
--- a/lib_pypy/greenlet.egg-info
+++ b/lib_pypy/greenlet.egg-info
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: greenlet
-Version: 0.4.0
+Version: 0.4.5
Summary: Lightweight in-process concurrent programming
Home-page: https://github.com/python-greenlet/greenlet
Author: Ralf Schmitt (for CPython), PyPy team
diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py
--- a/lib_pypy/greenlet.py
+++ b/lib_pypy/greenlet.py
@@ -1,7 +1,7 @@
import sys
import _continuation
-__version__ = "0.4.0"
+__version__ = "0.4.5"
# ____________________________________________________________
# Exceptions
From noreply at buildbot.pypy.org Mon Feb 2 18:16:34 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 18:16:34 +0100 (CET)
Subject: [pypy-commit] pypy default: Support for "with open(...) as f" in
RPython.
Message-ID: <20150202171634.959091C02D4@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch:
Changeset: r75649:6657cb5a838d
Date: 2015-02-02 18:15 +0100
http://bitbucket.org/pypy/pypy/changeset/6657cb5a838d/
Log: Support for "with open(...) as f" in RPython.
diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -535,3 +535,9 @@
def isatty(self):
self._check_closed()
return os.isatty(c_fileno(self._ll_file))
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.close()
diff --git a/rpython/rlib/test/test_rfile.py b/rpython/rlib/test/test_rfile.py
--- a/rpython/rlib/test/test_rfile.py
+++ b/rpython/rlib/test/test_rfile.py
@@ -395,6 +395,25 @@
os.unlink(fname)
self.interpret(f, [])
+ def test_with_statement(self):
+ fname = str(self.tmpdir.join('file_6'))
+
+ def f():
+ with open(fname, "w") as f:
+ f.write("dupa")
+ try:
+ f.write("dupb")
+ except ValueError:
+ pass
+ else:
+ assert False
+
+ f()
+ assert open(fname, "r").read() == "dupa"
+ os.unlink(fname)
+ self.interpret(f, [])
+ assert open(fname, "r").read() == "dupa"
+
class TestDirect:
def setup_class(cls):
From noreply at buildbot.pypy.org Mon Feb 2 18:16:33 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 18:16:33 +0100 (CET)
Subject: [pypy-commit] pypy default: Improve the tests to actually check
that the file is created by the
Message-ID: <20150202171633.77D321C02D4@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch:
Changeset: r75648:aaf45cb3d1a5
Date: 2015-02-02 18:14 +0100
http://bitbucket.org/pypy/pypy/changeset/aaf45cb3d1a5/
Log: Improve the tests to actually check that the file is created by the
interpret() version. They could pass by simply having the same file
already created by the direct f() version first.
diff --git a/rpython/rlib/test/test_rfile.py b/rpython/rlib/test/test_rfile.py
--- a/rpython/rlib/test/test_rfile.py
+++ b/rpython/rlib/test/test_rfile.py
@@ -26,6 +26,7 @@
f()
assert open(fname, "r").read() == "dupa"
+ os.unlink(fname)
self.interpret(f, [])
assert open(fname, "r").read() == "dupa"
@@ -102,6 +103,7 @@
f2.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
@py.test.mark.skipif("sys.platform == 'win32'")
@@ -121,6 +123,7 @@
f2.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
def test_open_buffering_full(self):
@@ -138,6 +141,7 @@
f2.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
def test_fdopen_buffering_full(self):
@@ -157,6 +161,7 @@
f2.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
def test_read_write(self):
@@ -203,6 +208,7 @@
f2.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
def test_read_sequentially(self):
@@ -277,6 +283,7 @@
f.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
def test_tempfile(self):
@@ -309,6 +316,7 @@
f()
assert open(fname).read() == "xxx"
+ os.unlink(fname)
self.interpret(f, [])
assert open(fname).read() == "xxx"
@@ -325,6 +333,7 @@
res = f()
assert res > 2
+ os.unlink(fname)
res = self.interpret(f, [])
assert res > 2
@@ -341,6 +350,7 @@
res = f()
assert res == 3
+ os.unlink(fname)
res = self.interpret(f, [])
assert res == 3
@@ -357,6 +367,7 @@
f.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
def test_truncate(self):
@@ -381,6 +392,7 @@
f.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
From noreply at buildbot.pypy.org Mon Feb 2 18:51:31 2015
From: noreply at buildbot.pypy.org (cfbolz)
Date: Mon, 2 Feb 2015 18:51:31 +0100 (CET)
Subject: [pypy-commit] pypy typed-cells: merge default
Message-ID: <20150202175131.16C8F1C026B@cobra.cs.uni-duesseldorf.de>
Author: Carl Friedrich Bolz
Branch: typed-cells
Changeset: r75650:2ac6556197f9
Date: 2015-02-02 16:30 +0100
http://bitbucket.org/pypy/pypy/changeset/2ac6556197f9/
Log: merge default
diff --git a/lib-python/2.7/ctypes/test/test_frombuffer.py b/lib-python/2.7/ctypes/test/test_frombuffer.py
--- a/lib-python/2.7/ctypes/test/test_frombuffer.py
+++ b/lib-python/2.7/ctypes/test/test_frombuffer.py
@@ -2,7 +2,6 @@
import array
import gc
import unittest
-from ctypes.test import xfail
class X(Structure):
_fields_ = [("c_int", c_int)]
@@ -11,7 +10,6 @@
self._init_called = True
class Test(unittest.TestCase):
- @xfail
def test_fom_buffer(self):
a = array.array("i", range(16))
x = (c_int * 16).from_buffer(a)
@@ -34,10 +32,9 @@
del a; gc.collect(); gc.collect(); gc.collect()
self.assertEqual(x[:], expected)
- self.assertRaises(TypeError,
+ self.assertRaises((TypeError, ValueError),
(c_char * 16).from_buffer, "a" * 16)
- @xfail
def test_fom_buffer_with_offset(self):
a = array.array("i", range(16))
x = (c_int * 15).from_buffer(a, sizeof(c_int))
@@ -46,7 +43,6 @@
self.assertRaises(ValueError, lambda: (c_int * 16).from_buffer(a, sizeof(c_int)))
self.assertRaises(ValueError, lambda: (c_int * 1).from_buffer(a, 16 * sizeof(c_int)))
- @xfail
def test_from_buffer_copy(self):
a = array.array("i", range(16))
x = (c_int * 16).from_buffer_copy(a)
@@ -71,7 +67,6 @@
x = (c_char * 16).from_buffer_copy("a" * 16)
self.assertEqual(x[:], "a" * 16)
- @xfail
def test_fom_buffer_copy_with_offset(self):
a = array.array("i", range(16))
x = (c_int * 15).from_buffer_copy(a, sizeof(c_int))
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -83,6 +83,37 @@
def in_dll(self, dll, name):
return self.from_address(dll._handle.getaddressindll(name))
+ def from_buffer(self, obj, offset=0):
+ size = self._sizeofinstances()
+ buf = buffer(obj, offset, size)
+ if len(buf) < size:
+ raise ValueError(
+ "Buffer size too small (%d instead of at least %d bytes)"
+ % (len(buf) + offset, size + offset))
+ raw_addr = buf._pypy_raw_address()
+ result = self.from_address(raw_addr)
+ result._ensure_objects()['ffffffff'] = obj
+ return result
+
+ def from_buffer_copy(self, obj, offset=0):
+ size = self._sizeofinstances()
+ buf = buffer(obj, offset, size)
+ if len(buf) < size:
+ raise ValueError(
+ "Buffer size too small (%d instead of at least %d bytes)"
+ % (len(buf) + offset, size + offset))
+ result = self()
+ dest = result._buffer.buffer
+ try:
+ raw_addr = buf._pypy_raw_address()
+ except ValueError:
+ _rawffi.rawstring2charp(dest, buf)
+ else:
+ from ctypes import memmove
+ memmove(dest, raw_addr, size)
+ return result
+
+
class CArgObject(object):
""" simple wrapper around buffer, just for the case of freeing
it afterwards
diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py
--- a/lib_pypy/_ctypes/structure.py
+++ b/lib_pypy/_ctypes/structure.py
@@ -1,3 +1,4 @@
+import sys
import _rawffi
from _ctypes.basics import _CData, _CDataMeta, keepalive_key,\
store_reference, ensure_objects, CArgObject
@@ -178,6 +179,8 @@
instance = StructOrUnion.__new__(self)
if isinstance(address, _rawffi.StructureInstance):
address = address.buffer
+ # fix the address: turn it into as unsigned, in case it is negative
+ address = address & (sys.maxint * 2 + 1)
instance.__dict__['_buffer'] = self._ffistruct.fromaddress(address)
return instance
diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -3,6 +3,13 @@
.. contents::
+See also: `Frequently ask questions about RPython.`__
+
+.. __: http://rpython.readthedocs.org/en/latest/faq.html
+
+---------------------------
+
+
What is PyPy?
-------------
diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst
--- a/pypy/doc/project-ideas.rst
+++ b/pypy/doc/project-ideas.rst
@@ -1,14 +1,23 @@
Potential project list
======================
-===========================
-Simple tasks for newcomers:
-===========================
+==========================
+Simple tasks for newcomers
+==========================
-Optimize random
----------------
+* Tkinter module missing support for threads:
+ https://bitbucket.org/pypy/pypy/issue/1929/tkinter-broken-for-threaded-python-on-both
-https://bitbucket.org/pypy/pypy/issue/1901/try-using-a-different-implementation-of
+* Optimize random:
+ https://bitbucket.org/pypy/pypy/issue/1901/try-using-a-different-implementation-of
+
+* Implement AF_XXX packet types of sockets:
+ https://bitbucket.org/pypy/pypy/issue/1942/support-for-af_xxx-sockets
+
+
+==================
+Mid-to-large tasks
+==================
Below is a list of projects that are interesting for potential contributors
who are seriously interested in the PyPy project. They mostly share common
@@ -33,15 +42,8 @@
------------------------
PyPy's bytearray type is very inefficient. It would be an interesting
-task to look into possible optimizations on this.
-
-Implement AF_XXX packet types for PyPy
---------------------------------------
-
-PyPy is missing AF_XXX types of sockets. Implementing it is easy-to-medium
-task. `bug report`_
-
-.. _`bug report`: https://bitbucket.org/pypy/pypy/issue/1942/support-for-af_xxx-sockets#more
+task to look into possible optimizations on this. (XXX current status
+unknown; ask on #pypy for updates on this.)
Implement copy-on-write list slicing
------------------------------------
@@ -106,6 +108,8 @@
Translation Toolchain
---------------------
+(XXX this is unlikely to be feasible.)
+
* Incremental or distributed translation.
* Allow separate compilation of extension modules.
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -439,7 +439,10 @@
f_back = space.interp_w(PyFrame, w_f_back, can_be_None=True)
new_frame.f_backref = jit.non_virtual_ref(f_back)
- new_frame.builtin = space.interp_w(Module, w_builtin)
+ if space.config.objspace.honor__builtins__:
+ new_frame.builtin = space.interp_w(Module, w_builtin)
+ else:
+ assert space.interp_w(Module, w_builtin) is space.builtin
new_frame.set_blocklist([unpickle_block(space, w_blk)
for w_blk in space.unpackiterable(w_blockstack)])
values_w = maker.slp_from_tuple_with_nulls(space, w_valuestack)
@@ -524,9 +527,10 @@
# cellvars are values exported to inner scopes
# freevars are values coming from outer scopes
- freevarnames = list(self.pycode.co_cellvars)
+ # (see locals2fast for why CO_OPTIMIZED)
+ freevarnames = self.pycode.co_cellvars
if self.pycode.co_flags & consts.CO_OPTIMIZED:
- freevarnames.extend(self.pycode.co_freevars)
+ freevarnames = freevarnames + self.pycode.co_freevars
for i in range(len(freevarnames)):
name = freevarnames[i]
cell = self.cells[i]
@@ -555,7 +559,16 @@
self.setfastscope(new_fastlocals_w)
- freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
+ freevarnames = self.pycode.co_cellvars
+ if self.pycode.co_flags & consts.CO_OPTIMIZED:
+ freevarnames = freevarnames + self.pycode.co_freevars
+ # If the namespace is unoptimized, then one of the
+ # following cases applies:
+ # 1. It does not contain free variables, because it
+ # uses import * or is a top-level namespace.
+ # 2. It is a class namespace.
+ # We don't want to accidentally copy free variables
+ # into the locals dict used by the class.
for i in range(len(freevarnames)):
name = freevarnames[i]
cell = self.cells[i]
diff --git a/pypy/interpreter/test/test_pyframe.py b/pypy/interpreter/test/test_pyframe.py
--- a/pypy/interpreter/test/test_pyframe.py
+++ b/pypy/interpreter/test/test_pyframe.py
@@ -516,3 +516,21 @@
assert seen == [(1, f, firstline + 6, 'line', None),
(1, f, firstline + 7, 'line', None),
(1, f, firstline + 8, 'line', None)]
+
+ def test_locals2fast_freevar_bug(self):
+ import sys
+ def f(n):
+ class A(object):
+ def g(self):
+ return n
+ n = 42
+ return A()
+ res = f(10).g()
+ assert res == 10
+ #
+ def trace(*args):
+ return trace
+ sys.settrace(trace)
+ res = f(10).g()
+ sys.settrace(None)
+ assert res == 10
diff --git a/rpython/doc/faq.rst b/rpython/doc/faq.rst
--- a/rpython/doc/faq.rst
+++ b/rpython/doc/faq.rst
@@ -3,6 +3,12 @@
.. contents::
+See also: `Frequently ask questions about PyPy.`__
+
+.. __: http://pypy.readthedocs.org/en/latest/faq.html
+
+--------------------------
+
What is RPython?
----------------
diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -1298,5 +1298,6 @@
self.load_reg(self.mc, res_loc, r.sp, ofs)
scale = get_scale(size_loc.value)
signed = (sign_loc.value != 0)
- self._load_from_mem(res_loc, res_loc, ofs_loc, scale, signed, fcond)
+ self._load_from_mem(res_loc, res_loc, ofs_loc, imm(scale), signed,
+ fcond)
return fcond
diff --git a/rpython/jit/backend/x86/valgrind.py b/rpython/jit/backend/x86/valgrind.py
--- a/rpython/jit/backend/x86/valgrind.py
+++ b/rpython/jit/backend/x86/valgrind.py
@@ -6,6 +6,7 @@
from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.rlib.objectmodel import we_are_translated
+from rpython.jit.backend.x86.arch import WORD
eci = ExternalCompilationInfo(includes = ['valgrind/valgrind.h'])
@@ -13,9 +14,91 @@
try:
rffi_platform.verify_eci(eci)
except rffi_platform.CompilationError:
- VALGRIND_DISCARD_TRANSLATIONS = None
-else:
- VALGRIND_DISCARD_TRANSLATIONS = rffi.llexternal(
+ # Can't open 'valgrind/valgrind.h'. It is a bad idea to just go
+ # ahead and not compile the valgrind-specific hacks. Instead,
+ # we'll include manually the few needed macros from a hopefully
+ # standard valgrind.h file.
+ eci = ExternalCompilationInfo(post_include_bits = [r"""
+/************ Valgrind support: only with GCC/clang for now ***********/
+/** This code is inserted only if valgrind/valgrind.h is not found **/
+/**********************************************************************/
+#ifdef __GNUC__
+
+#if ${WORD} == 4 /* if 32-bit x86 */
+
+#define VG__SPECIAL_INSTRUCTION_PREAMBLE \
+ "roll $3, %%edi ; roll $13, %%edi\n\t" \
+ "roll $29, %%edi ; roll $19, %%edi\n\t"
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ __extension__ \
+ ({volatile unsigned int _zzq_args[6]; \
+ volatile unsigned int _zzq_result; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ __asm__ volatile(VG__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %EDX = client_request ( %EAX ) */ \
+ "xchgl %%ebx,%%ebx" \
+ : "=d" (_zzq_result) \
+ : "a" (&_zzq_args[0]), "0" (_zzq_default) \
+ : "cc", "memory" \
+ ); \
+ _zzq_result; \
+ })
+
+#else /* 64-bit x86-64 */
+
+#define VG__SPECIAL_INSTRUCTION_PREAMBLE \
+ "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \
+ "rolq $61, %%rdi ; rolq $51, %%rdi\n\t"
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ __extension__ \
+ ({ volatile unsigned long long int _zzq_args[6]; \
+ volatile unsigned long long int _zzq_result; \
+ _zzq_args[0] = (unsigned long long int)(_zzq_request); \
+ _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \
+ __asm__ volatile(VG__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %RDX = client_request ( %RAX ) */ \
+ "xchgq %%rbx,%%rbx" \
+ : "=d" (_zzq_result) \
+ : "a" (&_zzq_args[0]), "0" (_zzq_default) \
+ : "cc", "memory" \
+ ); \
+ _zzq_result; \
+ })
+#endif
+
+#define VALGRIND_DO_CLIENT_REQUEST_STMT(_zzq_request, _zzq_arg1, \
+ _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ do { (void) VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
+ (_zzq_request), (_zzq_arg1), (_zzq_arg2), \
+ (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0)
+
+#define VG_USERREQ__DISCARD_TRANSLATIONS 0x1002
+#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DISCARD_TRANSLATIONS, \
+ _qzz_addr, _qzz_len, 0, 0, 0)
+
+/**********************************************************************/
+#else /* if !__GNUC__ */
+#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) do { } while(0)
+#endif
+/**********************************************************************/
+""".replace("${WORD}", str(WORD))])
+
+
+VALGRIND_DISCARD_TRANSLATIONS = rffi.llexternal(
"VALGRIND_DISCARD_TRANSLATIONS",
[llmemory.Address, lltype.Signed],
lltype.Void,
@@ -26,5 +109,5 @@
# ____________________________________________________________
def discard_translations(data, size):
- if we_are_translated() and VALGRIND_DISCARD_TRANSLATIONS is not None:
+ if we_are_translated():
VALGRIND_DISCARD_TRANSLATIONS(llmemory.cast_int_to_adr(data), size)
diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -477,8 +477,7 @@
@enforceargs(None, str)
def write(self, value):
self._check_closed()
- ll_value, is_pinned, is_raw = rffi.get_nonmovingbuffer(value)
- try:
+ with rffi.scoped_nonmovingbuffer(value) as ll_value:
# note that since we got a nonmoving buffer, it is either raw
# or already cannot move, so the arithmetics below are fine
length = len(value)
@@ -487,8 +486,6 @@
errno = rposix.get_saved_errno()
c_clearerr(self._ll_file)
raise IOError(errno, os.strerror(errno))
- finally:
- rffi.free_nonmovingbuffer(value, ll_value, is_pinned, is_raw)
def flush(self):
self._check_closed()
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -684,7 +684,7 @@
class RegisterGcTraceEntry(ExtRegistryEntry):
_about_ = register_custom_trace_hook
- def compute_result_annotation(self, *args_s):
+ def compute_result_annotation(self, s_tp, s_lambda_func):
pass
def specialize_call(self, hop):
@@ -692,3 +692,26 @@
lambda_func = hop.args_s[1].const
hop.exception_cannot_occur()
hop.rtyper.custom_trace_funcs.append((TP, lambda_func()))
+
+def register_custom_light_finalizer(TP, lambda_func):
+ """ This function does not do anything, but called from any annotated
+ place, will tell that "func" is used as a lightweight finalizer for TP.
+ The func must be specified as "lambda: func" in this call, for internal
+ reasons.
+ """
+
+class RegisterCustomLightFinalizer(ExtRegistryEntry):
+ _about_ = register_custom_light_finalizer
+
+ def compute_result_annotation(self, s_tp, s_lambda_func):
+ pass
+
+ def specialize_call(self, hop):
+ from rpython.rtyper.llannotation import SomePtr
+ TP = hop.args_s[0].const
+ lambda_func = hop.args_s[1].const
+ ll_func = lambda_func()
+ args_s = [SomePtr(lltype.Ptr(TP))]
+ funcptr = hop.rtyper.annotate_helper_fn(ll_func, args_s)
+ hop.exception_cannot_occur()
+ lltype.attachRuntimeTypeInfo(TP, destrptr=funcptr)
diff --git a/rpython/translator/c/src/asm_msvc.h b/rpython/translator/c/src/asm_msvc.h
--- a/rpython/translator/c/src/asm_msvc.h
+++ b/rpython/translator/c/src/asm_msvc.h
@@ -2,3 +2,14 @@
#define PYPY_X86_CHECK_SSE2_DEFINED
RPY_EXTERN void pypy_x86_check_sse2(void);
#endif
+
+
+/* Provides the same access to RDTSC as used by the JIT backend. This
+ is needed (at least if the JIT is enabled) because otherwise the
+ JIT-produced assembler would use RDTSC while the non-jitted code
+ would use QueryPerformanceCounter(), giving different incompatible
+ results. See issue #900.
+*/
+#include
+#pragma intrinsic(__rdtsc)
+#define READ_TIMESTAMP(val) do { val = (long long)__rdtsc(); } while (0)
diff --git a/rpython/translator/c/test/test_newgc.py b/rpython/translator/c/test/test_newgc.py
--- a/rpython/translator/c/test/test_newgc.py
+++ b/rpython/translator/c/test/test_newgc.py
@@ -473,6 +473,31 @@
res = self.run('custom_trace', 0)
assert res == 10000
+ def define_custom_light_finalizer(cls):
+ from rpython.rtyper.annlowlevel import llhelper
+ #
+ T = lltype.Struct('T', ('count', lltype.Signed))
+ t = lltype.malloc(T, zero=True, immortal=True, flavor='raw')
+ #
+ S = lltype.GcStruct('S', rtti=True)
+ def customlightfinlz(addr):
+ t.count += 1
+ lambda_customlightfinlz = lambda: customlightfinlz
+ #
+ def setup():
+ rgc.register_custom_light_finalizer(S, lambda_customlightfinlz)
+ for i in range(10000):
+ lltype.malloc(S)
+ def f(n):
+ setup()
+ llop.gc__collect(lltype.Void)
+ return t.count
+ return f
+
+ def test_custom_light_finalizer(self):
+ res = self.run('custom_light_finalizer', 0)
+ assert res == 10000
+
def define_weakref(cls):
import weakref
diff --git a/rpython/translator/tool/cbuild.py b/rpython/translator/tool/cbuild.py
--- a/rpython/translator/tool/cbuild.py
+++ b/rpython/translator/tool/cbuild.py
@@ -59,7 +59,11 @@
separately and linked later on. (If an .h file is needed for
other .c files to access this, it can be put in includes.)
- (export_symbols: killed, replaced by @rlib.entrypoint.export_symbol)
+ (export_symbols: killed; you need, depending on the case, to
+ add the RPY_EXTERN or RPY_EXPORTED macro just before the
+ declaration of each function in the C header file, as explained
+ in translator/c/src/precommondefs.h; or you need the decorator
+ @rlib.entrypoint.export_symbol)
compile_extra: list of parameters which will be directly passed to
the compiler
From noreply at buildbot.pypy.org Mon Feb 2 18:51:33 2015
From: noreply at buildbot.pypy.org (cfbolz)
Date: Mon, 2 Feb 2015 18:51:33 +0100 (CET)
Subject: [pypy-commit] pypy typed-cells: merge default
Message-ID: <20150202175133.1F23E1C026B@cobra.cs.uni-duesseldorf.de>
Author: Carl Friedrich Bolz
Branch: typed-cells
Changeset: r75651:153478e63e23
Date: 2015-02-02 16:31 +0100
http://bitbucket.org/pypy/pypy/changeset/153478e63e23/
Log: merge default
diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -197,6 +197,55 @@
(now-dead) object are still true about the new object.
+
+Would type annotations help PyPy's performance?
+-----------------------------------------------
+
+Two examples of type annotations that are being proposed for improved
+performance are `Cython types`__ and `PEP 484 - Type Hints`__.
+
+.. __: http://docs.cython.org/src/reference/language_basics.html#declaring-data-types
+.. __: https://www.python.org/dev/peps/pep-0484/
+
+**Cython types** are, by construction, similar to C declarations. For
+example, a local variable or an instance attribute can be declared
+``"cdef int"`` to force a machine word to be used. This changes the
+usual Python semantics (e.g. no overflow checks, and errors when
+trying to write other types of objects there). It gives some extra
+performance, but the exact benefits are unclear: right now
+(January 2015) for example we are investigating a technique that would
+store machine-word integers directly on instances, giving part of the
+benefits without the user-supplied ``"cdef int"``.
+
+**PEP 484 - Type Hints,** on the other hand, is almost entirely
+useless if you're looking at performance. First, as the name implies,
+they are *hints:* they must still be checked at runtime, like PEP 484
+says. Or maybe you're fine with a mode in which you get very obscure
+crashes when the type annotations are wrong; but even in that case the
+speed benefits would be extremely minor.
+
+There are several reasons for why. One of them is that annotations
+are at the wrong level (e.g. a PEP 484 "int" corresponds to Python 3's
+int type, which does not necessarily fits inside one machine word;
+even worse, an "int" annotation allows arbitrary int subclasses).
+Another is that a lot more information is needed to produce good code
+(e.g. "this ``f()`` called here really means this function there, and
+will never be monkey-patched" -- same with ``len()`` or ``list()``,
+btw). The third reason is that some "guards" in PyPy's JIT traces
+don't really have an obvious corresponding type (e.g. "this dict is so
+far using keys which don't override ``__hash__`` so a more efficient
+implementation was used"). Many guards don't even have any correspondence
+with types at all ("this class attribute was not modified"; "the loop
+counter did not reach zero so we don't need to release the GIL"; and
+so on).
+
+As PyPy works right now, it is able to derive far more useful
+information than can ever be given by PEP 484, and it works
+automatically. As far as we know, this is true even if we would add
+other techniques to PyPy, like a fast first-pass JIT.
+
+
+
.. _`prolog and javascript`:
Can I use PyPy's translation toolchain for other languages besides Python?
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1017,6 +1017,9 @@
def newlist_unicode(self, list_u):
return self.newlist([self.wrap(u) for u in list_u])
+ def newlist_int(self, list_i):
+ return self.newlist([self.wrap(i) for i in list_i])
+
def newlist_hint(self, sizehint):
from pypy.objspace.std.listobject import make_empty_list_with_size
return make_empty_list_with_size(self, sizehint)
diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h
--- a/pypy/module/cpyext/include/patchlevel.h
+++ b/pypy/module/cpyext/include/patchlevel.h
@@ -29,7 +29,7 @@
#define PY_VERSION "2.7.8"
/* PyPy version as a string */
-#define PYPY_VERSION "2.5.0-alpha0"
+#define PYPY_VERSION "2.6.0-alpha0"
/* Subversion Revision number of this file (not of the repository).
* Empty since Mercurial migration. */
diff --git a/pypy/module/cpyext/ndarrayobject.py b/pypy/module/cpyext/ndarrayobject.py
--- a/pypy/module/cpyext/ndarrayobject.py
+++ b/pypy/module/cpyext/ndarrayobject.py
@@ -291,6 +291,6 @@
Py_ssize_t, Py_ssize_t, rffi.CCHARP, rffi.CCHARP, Py_ssize_t], PyObject)
def PyUFunc_FromFuncAndData(space, funcs, data, types, ntypes,
nin, nout, identity, name, doc, check_return):
- w_signature = ""
+ w_signature = ','.join(['()'] * nin) + '->' + ','.join(['()'] * nout)
return do_ufunc(space, funcs, data, types, ntypes, nin, nout, identity,
name, doc, check_return, w_signature)
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -82,9 +82,18 @@
return w_object.descr_copy(space, w_order)
elif not copy and (subok or type(w_object) is W_NDimArray):
return w_object
-
- # not an array or incorrect dtype
- shape, elems_w = strides.find_shape_and_elems(space, w_object, dtype)
+ if isinstance(w_object, W_NDimArray) and copy and not subok:
+ # TODO do the loop.assign without copying elems_w
+ shape = w_object.get_shape()
+ _elems_w = w_object.reshape(space, space.wrap(-1))
+ elems_w = [None] * w_object.get_size()
+ for i in range(len(elems_w)):
+ elems_w[i] = _elems_w.descr_getitem(space, space.wrap(i))
+ if space.is_none(w_dtype):
+ dtype = w_object.get_dtype()
+ else:
+ # not an array
+ shape, elems_w = strides.find_shape_and_elems(space, w_object, dtype)
if dtype is None or (dtype.is_str_or_unicode() and dtype.elsize < 1):
dtype = strides.find_dtype_for_seq(space, elems_w, dtype)
if dtype is None:
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -430,9 +430,15 @@
order = 'C'
else:
order = space.str_w(w_order)
+ if order == 'K' and is_c_contiguous(self.implementation):
+ for s in self.implementation.get_strides():
+ if s < 0:
+ break
+ else:
+ order = 'C'
if order != 'C':
raise OperationError(space.w_NotImplementedError, space.wrap(
- "order not implemented"))
+ "order != 'C' only partially implemented"))
return self.reshape(space, space.wrap(-1))
@unwrap_spec(w_axis=WrappedDefault(None),
diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py
--- a/pypy/module/micronumpy/nditer.py
+++ b/pypy/module/micronumpy/nditer.py
@@ -252,10 +252,6 @@
# Copy logic from npyiter_coalesce_axes, used in ufunc iterators
# and in nditer's with 'external_loop' flag
can_coalesce = True
- if it.order == 'F':
- fastest = 0
- else:
- fastest = -1
for idim in range(it.ndim - 1):
for op_it, _ in it.iters:
if op_it is None:
@@ -275,7 +271,7 @@
if can_coalesce:
for i in range(len(it.iters)):
new_iter = coalesce_iter(it.iters[i][0], it.op_flags[i], it,
- it.order, fastest)
+ it.order)
it.iters[i] = (new_iter, new_iter.reset())
if len(it.shape) > 1:
if it.order == 'F':
@@ -289,7 +285,7 @@
break
# Always coalesce at least one
for i in range(len(it.iters)):
- new_iter = coalesce_iter(it.iters[i][0], it.op_flags[i], it, 'C', -1)
+ new_iter = coalesce_iter(it.iters[i][0], it.op_flags[i], it, 'C')
it.iters[i] = (new_iter, new_iter.reset())
if len(it.shape) > 1:
if it.order == 'F':
@@ -300,12 +296,11 @@
it.shape = [1]
-def coalesce_iter(old_iter, op_flags, it, order, fastest=-1, flat=True):
+def coalesce_iter(old_iter, op_flags, it, order, flat=True):
'''
We usually iterate through an array one value at a time.
But after coalesce(), getoperand() will return a slice by removing
- the fastest varying dimension from the beginning or end of the shape.
- XXX - what happens on swapaxis arrays?
+ the fastest varying dimension(s) from the beginning or end of the shape.
If flat is true, then the slice will be 1d, otherwise stack up the shape of
the fastest varying dimension in the slice, so an iterator of a 'C' array
of shape (2,4,3) after two calls to coalesce will iterate 2 times over a slice
@@ -319,6 +314,9 @@
new_strides = strides[1:]
new_backstrides = backstrides[1:]
_stride = old_iter.slice_stride + [strides[0]]
+ _shape = old_iter.slice_shape + [shape[0]]
+ _backstride = old_iter.slice_backstride + [strides[0] * (shape[0] - 1)]
+ fastest = shape[0]
else:
new_shape = shape[:-1]
new_strides = strides[:-1]
@@ -326,14 +324,15 @@
# use the operand's iterator's rightmost stride,
# even if it is not the fastest (for 'F' or swapped axis)
_stride = [strides[-1]] + old_iter.slice_stride
- _shape = [shape[fastest]] + old_iter.slice_shape
- _backstride = [(_shape[fastest] - 1) * _stride[0]] + old_iter.slice_backstride
+ _shape = [shape[-1]] + old_iter.slice_shape
+ _backstride = [(shape[-1] - 1) * strides[-1]] + old_iter.slice_backstride
+ fastest = shape[-1]
if flat:
_shape = [support.product(_shape)]
if len(_stride) > 1:
_stride = [min(_stride[0], _stride[1])]
_backstride = [(shape[0] - 1) * _stride[0]]
- return SliceIter(old_iter.array, old_iter.size / shape[fastest],
+ return SliceIter(old_iter.array, old_iter.size / fastest,
new_shape, new_strides, new_backstrides,
_shape, _stride, _backstride, op_flags, it)
diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -2994,6 +2994,7 @@
assert (arange(3).ravel() == arange(3)).all()
assert (arange(6).reshape(2, 3).ravel() == arange(6)).all()
assert (arange(6).reshape(2, 3).T.ravel() == [0, 3, 1, 4, 2, 5]).all()
+ assert (arange(3).ravel('K') == arange(3)).all()
def test_nonzero(self):
from numpy import array
diff --git a/pypy/module/micronumpy/test/test_subtype.py b/pypy/module/micronumpy/test/test_subtype.py
--- a/pypy/module/micronumpy/test/test_subtype.py
+++ b/pypy/module/micronumpy/test/test_subtype.py
@@ -304,10 +304,13 @@
out.shape = (sh, 1)
else:
out.shape = (1, sh)
- print 'out, shape was',old_shape,'now',out.shape
+ #print 'out, shape was',old_shape,'now',out.shape,'out',out
return out
- a = matrix([[1., 2.]])
+ a = matrix([[1., 2.], [3., 4.]])
b = N.array([a])
+ assert (b == a).all()
+ b = N.array(a)
+ assert len(b.shape) == 2
def test_setstate_no_version(self):
# Some subclasses of ndarray, like MaskedArray, do not use
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -7,6 +7,7 @@
from pypy.module.micronumpy.concrete import VoidBoxStorage
from pypy.interpreter.gateway import interp2app
from pypy.conftest import option
+from pypy.interpreter.error import OperationError
class TestUfuncCoercion(object):
@@ -129,7 +130,10 @@
'', ufunc.dtypes)
assert index == 0
assert dtypes == [f32_dtype, c64_dtype]
-
+ raises(OperationError, ufunc.type_resolver, space, [f32_array], [None],
+ 'u->u', ufunc.dtypes)
+ exc = raises(OperationError, ufunc.type_resolver, space, [f32_array], [None],
+ 'i->i', ufunc.dtypes)
class AppTestUfuncs(BaseNumpyAppTest):
def test_constants(self):
@@ -169,8 +173,7 @@
dtypes=[int, int, int, float, float, float])
int_func22 = frompyfunc([int, int], 2, 2, signature='(i),(i)->(i),(i)',
dtypes=['match'])
- int_func12 = frompyfunc([int], 1, 2, signature='(i)->(i),(i)',
- dtypes=['match'])
+ int_func12 = frompyfunc([int], 1, 2, dtypes=['match'])
retype = dtype(int)
a = arange(10)
assert isinstance(adder_ufunc1, ufunc)
@@ -223,6 +226,7 @@
assert len(in_array.shape) == 2
assert in_array.shape == out_array.shape
out_array[:] = in_array * 2
+
from numpy import frompyfunc, dtype, arange
ufunc = frompyfunc([times_2], 1, 1,
signature='(m,n)->(n,m)',
@@ -233,6 +237,7 @@
ai3 = ufunc(ai[0,:,:])
ai2 = ufunc(ai)
assert (ai2 == ai * 2).all()
+
ufunc = frompyfunc([times_2], 1, 1,
signature='(m,m)->(m,m)',
dtypes=[dtype(int), dtype(int)],
@@ -245,6 +250,21 @@
ai2 = ufunc(ai)
assert (ai2 == ai * 2).all()
+ def test_frompyfunc_needs_nditer(self):
+ def summer(in0):
+ print 'in summer, in0=',in0,'in0.shape=',in0.shape
+ return in0.sum()
+
+ from numpy import frompyfunc, dtype, arange
+ ufunc = frompyfunc([summer], 1, 1,
+ signature='(m,m)->()',
+ dtypes=[dtype(int), dtype(int)],
+ stack_inputs=False,
+ )
+ ai = arange(12, dtype=int).reshape(3, 2, 2)
+ ao = ufunc(ai)
+ assert ao.size == 3
+
def test_frompyfunc_sig_broadcast(self):
def sum_along_0(in_array, out_array):
out_array[...] = in_array.sum(axis=0)
@@ -269,6 +289,26 @@
aout = ufunc_sum(ai)
assert aout.shape == (3, 3)
+ def test_frompyfunc_fortran(self):
+ import numpy as np
+ def tofrom_fortran(in0, out0):
+ out0[:] = in0.T
+
+ def lapack_like_times2(in0, out0):
+ a = np.empty(in0.T.shape, in0.dtype)
+ tofrom_fortran(in0, a)
+ a *= 2
+ tofrom_fortran(a, out0)
+
+ times2 = np.frompyfunc([lapack_like_times2], 1, 1,
+ signature='(m,n)->(m,n)',
+ dtypes=[np.dtype(float), np.dtype(float)],
+ stack_inputs=True,
+ )
+ in0 = np.arange(3300, dtype=float).reshape(100, 33)
+ out0 = times2(in0)
+ assert out0.shape == in0.shape
+ assert (out0 == in0 * 2).all()
def test_ufunc_kwargs(self):
from numpy import ufunc, frompyfunc, arange, dtype
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -520,7 +520,9 @@
'''
_immutable_fields_ = ["funcs", "dtypes", "data", "match_dtypes"]
- def __init__(self, space, funcs, name, identity, nin, nout, dtypes, signature, match_dtypes=False, stack_inputs=False):
+ def __init__(self, space, funcs, name, identity, nin, nout, dtypes,
+ signature, match_dtypes=False, stack_inputs=False,
+ external_loop=False):
# XXX make sure funcs, signature, dtypes, nin, nout are consistent
# These don't matter, we use the signature and dtypes for determining
@@ -549,6 +551,7 @@
self.core_num_dims = [0] * self.nargs # number of core dimensions of each nargs
self.core_offsets = [0] * self.nargs
self.core_dim_ixs = [] # indices into unique shapes for each arg
+ self.external_loop = external_loop
def reduce(self, space, w_obj, w_axis, keepdims=False, out=None, dtype=None,
cumulative=False):
@@ -586,29 +589,21 @@
_dtypes.append(_dtypes[0])
index, dtypes = self.type_resolver(space, inargs, outargs, sig, _dtypes)
func = self.funcs[index]
- if not self.core_enabled:
- # func is going to do all the work, it must accept W_NDimArray args
- inargs0 = inargs[0]
- assert isinstance(inargs0, W_NDimArray)
- arg_shapes = [inargs0.get_shape()] * self.nargs
- inargs, outargs, need_to_cast = self.alloc_args(space, inargs, outargs,
- dtypes, arg_shapes)
- for tf in need_to_cast:
- if tf:
- raise oefmt(space.w_NotImplementedError, "casting not supported yet")
- if self.stack_inputs:
- arglist = space.newlist(list(inargs + outargs))
- space.call_args(func, Arguments.frompacked(space, arglist))
- else:
- arglist = space.newlist(inargs)
- outargs = space.call_args(func, Arguments.frompacked(space, arglist))
- return outargs
- if len(outargs) < 2:
- return outargs[0]
- return space.newtuple(outargs)
iter_shape, arg_shapes, matched_dims = self.verify_args(space, inargs, outargs)
inargs, outargs, need_to_cast = self.alloc_args(space, inargs, outargs, dtypes,
arg_shapes)
+ if not self.external_loop:
+ inargs0 = inargs[0]
+ outargs0 = outargs[0]
+ assert isinstance(inargs0, W_NDimArray)
+ assert isinstance(outargs0, W_NDimArray)
+ res_dtype = outargs0.get_dtype()
+ new_shape = inargs0.get_shape()
+ if len(outargs) < 2:
+ return loop.call_many_to_one(space, new_shape, func,
+ res_dtype, inargs, outargs[0])
+ return loop.call_many_to_many(space, new_shape, func,
+ res_dtype, inargs, outargs)
for tf in need_to_cast:
if tf:
raise oefmt(space.w_NotImplementedError, "casting not supported yet")
@@ -619,48 +614,44 @@
w_casting = space.w_None
w_op_axes = space.w_None
+ #print '\nsignature', sig
+ #print [(d, getattr(self,d)) for d in dir(self) if 'core' in d or 'broad' in d]
+ #print [(d, locals()[d]) for d in locals() if 'core' in d or 'broad' in d]
+ #print 'shapes',[d.get_shape() for d in inargs + outargs]
+ #print 'steps',[d.implementation.strides for d in inargs + outargs]
+ if isinstance(func, W_GenericUFuncCaller):
+ # Use GeneralizeUfunc interface with signature
+ # Unlike numpy, we will not broadcast dims before
+ # the core_ndims rather we use nditer iteration
+ # so dims[0] == 1
+ dims = [1] + matched_dims
+ steps = []
+ allargs = inargs + outargs
+ for i in range(len(allargs)):
+ steps.append(0)
+ for i in range(len(allargs)):
+ _arg = allargs[i]
+ assert isinstance(_arg, W_NDimArray)
+ start_dim = len(iter_shape)
+ steps += _arg.implementation.strides[start_dim:]
+ func.set_dims_and_steps(space, dims, steps)
+ else:
+ # it is a function, ready to be called by the iterator,
+ # from frompyfunc
+ pass
+ # mimic NpyIter_AdvancedNew with a nditer
+ w_itershape = space.newlist([space.wrap(i) for i in iter_shape])
+ nd_it = W_NDIter(space, space.newlist(inargs + outargs), w_flags,
+ w_op_flags, w_op_dtypes, w_casting, w_op_axes,
+ w_itershape)
+ # coalesce each iterators, according to inner_dimensions
+ for i in range(len(inargs) + len(outargs)):
+ for j in range(self.core_num_dims[i]):
+ new_iter = coalesce_iter(nd_it.iters[i][0], nd_it.op_flags[i],
+ nd_it, nd_it.order, flat=False)
+ nd_it.iters[i] = (new_iter, new_iter.reset())
+ # do the iteration
if self.stack_inputs:
- #print '\nsignature', sig
- #print [(d, getattr(self,d)) for d in dir(self) if 'core' in d or 'broad' in d]
- #print [(d, locals()[d]) for d in locals() if 'core' in d or 'broad' in d]
- #print 'shapes',[d.get_shape() for d in inargs + outargs]
- #print 'steps',[d.implementation.strides for d in inargs + outargs]
- if isinstance(func, W_GenericUFuncCaller):
- # Use GeneralizeUfunc interface with signature
- # Unlike numpy, we will not broadcast dims before
- # the core_ndims rather we use nditer iteration
- # so dims[0] == 1
- dims = [1] + matched_dims
- steps = []
- allargs = inargs + outargs
- for i in range(len(allargs)):
- steps.append(0)
- for i in range(len(allargs)):
- _arg = allargs[i]
- assert isinstance(_arg, W_NDimArray)
- start_dim = len(iter_shape)
- steps += _arg.implementation.strides[start_dim:]
- func.set_dims_and_steps(space, dims, steps)
- else:
- # it is a function, ready to be called by the iterator,
- # from frompyfunc
- pass
- # mimic NpyIter_AdvancedNew with a nditer
- w_itershape = space.newlist([space.wrap(i) for i in iter_shape])
- nd_it = W_NDIter(space, space.newlist(inargs + outargs), w_flags,
- w_op_flags, w_op_dtypes, w_casting, w_op_axes,
- w_itershape)
- # coalesce each iterators, according to inner_dimensions
- if nd_it.order == 'F':
- fastest = 0
- else:
- fastest = -1
- for i in range(len(inargs) + len(outargs)):
- for j in range(self.core_num_dims[i]):
- new_iter = coalesce_iter(nd_it.iters[i][0], nd_it.op_flags[i],
- nd_it, nd_it.order, fastest, flat=False)
- nd_it.iters[i] = (new_iter, new_iter.reset())
- # do the iteration
while not nd_it.done:
# XXX jit me
for it, st in nd_it.iters:
@@ -674,20 +665,35 @@
args.append(nd_it.getitem(it, st))
nd_it.iters[i] = (it, it.next(st))
space.call_args(func, Arguments.frompacked(space, space.newlist(args)))
- if len(outargs) > 1:
- return space.newtuple([convert_to_array(space, o) for o in outargs])
- return outargs[0]
- inargs0 = inargs[0]
- outargs0 = outargs[0]
- assert isinstance(inargs0, W_NDimArray)
- assert isinstance(outargs0, W_NDimArray)
- res_dtype = outargs0.get_dtype()
- new_shape = inargs0.get_shape()
- if len(outargs) < 2:
- return loop.call_many_to_one(space, new_shape, func,
- res_dtype, inargs, outargs[0])
- return loop.call_many_to_many(space, new_shape, func,
- res_dtype, inargs, outargs)
+ else:
+ # do the iteration
+ while not nd_it.done:
+ # XXX jit me
+ for it, st in nd_it.iters:
+ if not it.done(st):
+ break
+ else:
+ nd_it.done = True
+ break
+ initers = []
+ outiters = []
+ nin = len(inargs)
+ for i, (it, st) in enumerate(nd_it.iters[:nin]):
+ initers.append(nd_it.getitem(it, st))
+ nd_it.iters[i] = (it, it.next(st))
+ for i, (it, st) in enumerate(nd_it.iters[nin:]):
+ outiters.append(nd_it.getitem(it, st))
+ nd_it.iters[i + nin] = (it, it.next(st))
+ outs = space.call_args(func, Arguments.frompacked(space, space.newlist(initers)))
+ if len(outiters) < 2:
+ outiters[0].descr_setitem(space, space.w_Ellipsis, outs)
+ else:
+ for i in range(self.nout):
+ w_val = space.getitem(outs, space.wrap(i))
+ outiters[i].descr_setitem(space, space.w_Ellipsis, w_val)
+ if len(outargs) > 1:
+ return space.newtuple([convert_to_array(space, o) for o in outargs])
+ return outargs[0]
def parse_kwargs(self, space, kwargs_w):
w_subok, w_out, casting, sig, extobj = \
@@ -727,20 +733,24 @@
nop = len(inargs) + len(outargs)
dtypes = []
if isinstance(type_tup, str) and len(type_tup) > 0:
- if len(type_tup) == 1:
- dtypes = [get_dtype_cache(space).dtypes_by_name[type_tup]] * self.nargs
- elif len(type_tup) == self.nargs + 2:
- for i in range(self.nin):
- dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[i]])
- #skip the '->' in the signature
- for i in range(self.nout):
- j = i + self.nin + 2
- dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[j]])
- else:
- raise oefmt(space.w_TypeError, "a type-string for %s " \
- "requires 1 typecode or %d typecode(s) before and %d" \
- " after the -> sign, not '%s'", self.name, self.nin,
- self.nout, type_tup)
+ try:
+ if len(type_tup) == 1:
+ dtypes = [get_dtype_cache(space).dtypes_by_name[type_tup]] * self.nargs
+ elif len(type_tup) == self.nargs + 2:
+ for i in range(self.nin):
+ dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[i]])
+ #skip the '->' in the signature
+ for i in range(self.nout):
+ j = i + self.nin + 2
+ dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[j]])
+ else:
+ raise oefmt(space.w_TypeError, "a type-string for %s " \
+ "requires 1 typecode or %d typecode(s) before and %d" \
+ " after the -> sign, not '%s'", self.name, self.nin,
+ self.nout, type_tup)
+ except KeyError:
+ raise oefmt(space.w_ValueError, "unknown typecode in" \
+ " call to %s with type-string '%s'", self.name, type_tup)
else:
# XXX why does the next line not pass translation?
# dtypes = [i.get_dtype() for i in inargs]
@@ -764,9 +774,13 @@
break
else:
if len(self.funcs) > 1:
+ dtypesstr = ','.join(['%s%s%s' % (d.byteorder, d.kind, d.elsize) \
+ for d in dtypes])
+ _dtypesstr = ','.join(['%s%s%s' % (d.byteorder, d.kind, d.elsize) \
+ for d in _dtypes])
raise oefmt(space.w_TypeError,
- 'input dtype did not match any known dtypes',
- )
+ "input dtype [%s] did not match any known dtypes [%s] ",
+ dtypesstr,_dtypesstr)
i = 0
# Fill in empty dtypes
for j in range(self.nargs):
@@ -1239,7 +1253,8 @@
w_identity=None, name='', doc='', stack_inputs=False):
''' frompyfunc(func, nin, nout) #cpython numpy compatible
frompyfunc(func, nin, nout, dtypes=None, signature='',
- identity=None, name='', doc='', stack_inputs=False)
+ identity=None, name='', doc='',
+ stack_inputs=False)
Takes an arbitrary Python function and returns a ufunc.
@@ -1255,10 +1270,12 @@
nout : int
The number of arrays returned by `func`.
dtypes: None or [dtype, ...] of the input, output args for each function,
- or 'match' to force output to exactly match input dtype
+ or 'match' to force output to exactly match input dtype
+ Note that 'match' is a pypy-only extension to allow non-object
+ return dtypes
signature*: str, default=''
The mapping of input args to output args, defining the
- inner-loop indexing
+ inner-loop indexing. If it is empty, the func operates on scalars
identity*: None (default) or int
For reduce-type ufuncs, the default value
name: str, default=''
@@ -1277,7 +1294,7 @@
Notes
-----
- If the signature and out_dtype are both missing, the returned ufunc
+ If the signature and dtype are both missing, the returned ufunc
always returns PyObject arrays (cpython numpy compatability).
Input arguments marked with a * are pypy-only extensions
@@ -1333,16 +1350,15 @@
'identity must be None or an int')
if len(signature) == 0:
- # cpython compatability, func is of the form (),()->()
- signature = ','.join(['()'] * nin) + '->' + ','.join(['()'] * nout)
+ external_loop=False
else:
- #stack_inputs = True
- pass
+ external_loop=True
w_ret = W_UfuncGeneric(space, func, name, identity, nin, nout, dtypes,
signature, match_dtypes=match_dtypes,
- stack_inputs=stack_inputs)
- _parse_signature(space, w_ret, w_ret.signature)
+ stack_inputs=stack_inputs, external_loop=external_loop)
+ if w_ret.external_loop:
+ _parse_signature(space, w_ret, w_ret.signature)
if doc:
w_ret.w_doc = space.wrap(doc)
return w_ret
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -173,7 +173,7 @@
exiting (blackhole) steps, but just not from the final assembler.
Note that the return value of the callable is ignored, because
-there is no reasonable way to guess what it sound be in case the
+there is no reasonable way to guess what it should be in case the
function is not called.
This is meant to be used notably in sys.settrace() for coverage-
diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py
--- a/pypy/module/sys/version.py
+++ b/pypy/module/sys/version.py
@@ -10,7 +10,7 @@
#XXX # sync CPYTHON_VERSION with patchlevel.h, package.py
CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h
-PYPY_VERSION = (2, 5, 0, "alpha", 0) #XXX # sync patchlevel.h
+PYPY_VERSION = (2, 6, 0, "alpha", 0) #XXX # sync patchlevel.h
if platform.name == 'msvc':
COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600)
diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -1173,8 +1173,8 @@
def wrapkey(space, key):
return space.wrap(key)
- # XXX there is no space.newlist_int yet to implement w_keys more
- # efficiently
+ def w_keys(self, w_dict):
+ return self.space.newlist_int(self.listview_int(w_dict))
create_iterator_classes(IntDictStrategy)
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -176,6 +176,12 @@
storage = strategy.erase(list_u)
return W_ListObject.from_storage_and_strategy(space, storage, strategy)
+ @staticmethod
+ def newlist_int(space, list_i):
+ strategy = space.fromcache(IntegerListStrategy)
+ storage = strategy.erase(list_i)
+ return W_ListObject.from_storage_and_strategy(space, storage, strategy)
+
def __repr__(self):
""" representation for debugging purposes """
return "%s(%s, %s)" % (self.__class__.__name__, self.strategy,
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -288,6 +288,9 @@
def newlist_unicode(self, list_u):
return W_ListObject.newlist_unicode(self, list_u)
+ def newlist_int(self, list_i):
+ return W_ListObject.newlist_int(self, list_i)
+
def newdict(self, module=False, instance=False, kwargs=False,
strdict=False):
return W_DictMultiObject.allocate_and_init_instance(
diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py
--- a/rpython/rtyper/rclass.py
+++ b/rpython/rtyper/rclass.py
@@ -711,8 +711,15 @@
continue
value = self.classdef.classdesc.read_attribute(fldname, None)
if value is not None:
- cvalue = inputconst(r.lowleveltype,
- r.convert_desc_or_const(value))
+ ll_value = r.convert_desc_or_const(value)
+ # don't write NULL GC pointers: we know that the malloc
+ # done above initialized at least the GC Ptr fields to
+ # NULL already, and that's true for all our GCs
+ if (isinstance(r.lowleveltype, Ptr) and
+ r.lowleveltype.TO._gckind == 'gc' and
+ not ll_value):
+ continue
+ cvalue = inputconst(r.lowleveltype, ll_value)
self.setfield(vptr, fldname, cvalue, llops,
flags={'access_directly': True})
return vptr
diff --git a/rpython/translator/backendopt/test/test_malloc.py b/rpython/translator/backendopt/test/test_malloc.py
--- a/rpython/translator/backendopt/test/test_malloc.py
+++ b/rpython/translator/backendopt/test/test_malloc.py
@@ -340,3 +340,15 @@
u[0].s.x = x
return u[0].s.x
graph = self.check(f, [int], [42], 42)
+
+ def test_two_paths_one_with_constant(self):
+ py.test.skip("XXX implement me?")
+ def fn(n):
+ if n > 100:
+ tup = (0,)
+ else:
+ tup = (n,)
+ (n,) # <- flowspace
+ return tup[0]
+
+ self.check(fn, [int], [42], 42)
diff --git a/rpython/translator/c/test/test_standalone.py b/rpython/translator/c/test/test_standalone.py
--- a/rpython/translator/c/test/test_standalone.py
+++ b/rpython/translator/c/test/test_standalone.py
@@ -808,12 +808,7 @@
t, cbuilder = self.compile(entry_point, shared=True)
assert cbuilder.shared_library_name is not None
assert cbuilder.shared_library_name != cbuilder.executable_name
- if os.name == 'posix':
- library_path = cbuilder.shared_library_name.dirpath()
- if sys.platform == 'darwin':
- monkeypatch.setenv('DYLD_LIBRARY_PATH', library_path)
- else:
- monkeypatch.setenv('LD_LIBRARY_PATH', library_path)
+ #Do not set LD_LIBRARY_PATH, make sure $ORIGIN flag is working
out, err = cbuilder.cmdexec("a b")
assert out == "3"
diff --git a/rpython/translator/platform/freebsd.py b/rpython/translator/platform/freebsd.py
--- a/rpython/translator/platform/freebsd.py
+++ b/rpython/translator/platform/freebsd.py
@@ -12,6 +12,7 @@
cflags = tuple(
['-O3', '-pthread', '-fomit-frame-pointer'] +
os.environ.get('CFLAGS', '').split())
+ rpath_flags = ['-Wl,-rpath=\'$$ORIGIN/\'', '-Wl,-z,origin']
class Freebsd_64(Freebsd):
shared_only = ('-fPIC',)
diff --git a/rpython/translator/platform/posix.py b/rpython/translator/platform/posix.py
--- a/rpython/translator/platform/posix.py
+++ b/rpython/translator/platform/posix.py
@@ -112,9 +112,9 @@
target_name = exe_name.basename
if shared:
- cflags = self.cflags + self.get_shared_only_compile_flags()
+ cflags = tuple(self.cflags) + self.get_shared_only_compile_flags()
else:
- cflags = self.cflags + self.standalone_only
+ cflags = tuple(self.cflags) + tuple(self.standalone_only)
m = GnuMakefile(path)
m.exe_name = path.join(exe_name.basename)
From noreply at buildbot.pypy.org Mon Feb 2 18:51:34 2015
From: noreply at buildbot.pypy.org (cfbolz)
Date: Mon, 2 Feb 2015 18:51:34 +0100 (CET)
Subject: [pypy-commit] pypy typed-cells: also unwrap floats
Message-ID: <20150202175134.5F63E1C026B@cobra.cs.uni-duesseldorf.de>
Author: Carl Friedrich Bolz
Branch: typed-cells
Changeset: r75652:b193ed03acc0
Date: 2015-02-02 18:51 +0100
http://bitbucket.org/pypy/pypy/changeset/b193ed03acc0/
Log: also unwrap floats
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -9,7 +9,8 @@
BaseValueIterator, BaseItemIterator, _never_equal_to_string
)
from pypy.objspace.std.typeobject import (
- MutableCell, IntMutableCell, ObjectMutableCell, unwrap_cell)
+ MutableCell, IntMutableCell, FloatMutableCell, ObjectMutableCell,
+ unwrap_cell)
# ____________________________________________________________
# attribute shapes
@@ -303,15 +304,24 @@
def _write_cell(self, w_cell, w_value):
from pypy.objspace.std.intobject import W_IntObject
+ from pypy.objspace.std.floatobject import W_FloatObject
assert not isinstance(w_cell, ObjectMutableCell)
if isinstance(w_cell, IntMutableCell) and type(w_value) is W_IntObject:
w_cell.intvalue = w_value.intval
return None
+ if isinstance(w_cell, FloatMutableCell) and type(w_value) is W_FloatObject:
+ w_cell.floatvalue = w_value.floatval
+ return None
if type(w_value) is W_IntObject:
if not self.can_contain_mutable_cell:
self.can_contain_mutable_cell = True
if self.ever_mutated:
return IntMutableCell(w_value.intval)
+ if type(w_value) is W_FloatObject:
+ if not self.can_contain_mutable_cell:
+ self.can_contain_mutable_cell = True
+ if self.ever_mutated:
+ return FloatMutableCell(w_value.floatval)
return w_value
def _copy_attr(self, obj, new_obj):
diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py
--- a/pypy/objspace/std/test/test_mapdict.py
+++ b/pypy/objspace/std/test/test_mapdict.py
@@ -182,6 +182,35 @@
assert mutcell2.intvalue == 7
assert mutcell2 is mutcell1
+
+def test_mutcell_not_immutable_float():
+ from pypy.objspace.std.floatobject import W_FloatObject
+ cls = Class()
+ obj = cls.instantiate()
+ # make sure the attribute counts as mutable
+ obj.setdictvalue(space, "a", W_FloatObject(4.43))
+ obj.setdictvalue(space, "a", W_FloatObject(5.43))
+ assert obj.map.ever_mutated
+
+ obj = cls.instantiate()
+ obj.setdictvalue(space, "a", W_FloatObject(5.43))
+ assert obj.getdictvalue(space, "a") == 5.43
+ mutcell = obj._mapdict_read_storage(0)
+ assert mutcell.floatvalue == 5.43
+
+ obj.setdictvalue(space, "a", W_FloatObject(6.43))
+ assert obj.getdictvalue(space, "a") == 6.43
+ mutcell1 = obj._mapdict_read_storage(0)
+ assert mutcell1.floatvalue == 6.43
+ assert mutcell is mutcell1
+
+ obj.setdictvalue(space, "a", W_FloatObject(7.43))
+ assert obj.getdictvalue(space, "a") == 7.43
+ mutcell2 = obj._mapdict_read_storage(0)
+ assert mutcell2.floatvalue == 7.43
+ assert mutcell2 is mutcell1
+
+
def test_no_mutcell_if_immutable():
# don't introduce an immutable cell if the attribute seems immutable
from pypy.objspace.std.intobject import W_IntObject
diff --git a/pypy/objspace/std/test/test_versionedtype.py b/pypy/objspace/std/test/test_versionedtype.py
--- a/pypy/objspace/std/test/test_versionedtype.py
+++ b/pypy/objspace/std/test/test_versionedtype.py
@@ -259,6 +259,43 @@
cell = w_A._getdictvalue_no_unwrapping(space, "x")
assert space.float_w(cell.w_value) == 2.2
+ def test_float_cells(self):
+ space = self.space
+ w_x = space.wrap("x")
+ w_A, w_B, w_C = self.get_three_classes()
+ atag = w_A.version_tag()
+ space.setattr(w_A, w_x, space.newfloat(1.1))
+ assert w_A.version_tag() is not atag
+ assert space.float_w(space.getattr(w_A, w_x)) == 1.1
+
+ atag = w_A.version_tag()
+ space.setattr(w_A, w_x, space.newfloat(2.1))
+ assert w_A.version_tag() is not atag
+ assert space.float_w(space.getattr(w_A, w_x)) == 2.1
+ cell = w_A._getdictvalue_no_unwrapping(space, "x")
+ assert cell.floatvalue == 2.1
+
+ atag = w_A.version_tag()
+ space.setattr(w_A, w_x, space.newfloat(3.1))
+ assert w_A.version_tag() is atag
+ assert space.float_w(space.getattr(w_A, w_x)) == 3.1
+ assert cell.floatvalue == 3.1
+
+ space.setattr(w_A, w_x, space.newfloat(4.1))
+ assert w_A.version_tag() is atag
+ assert space.float_w(space.getattr(w_A, w_x)) == 4.1
+ assert cell.floatvalue == 4.1
+
+ def test_float_cell_turns_into_cell(self):
+ space = self.space
+ w_x = space.wrap("x")
+ w_A, w_B, w_C = self.get_three_classes()
+ atag = w_A.version_tag()
+ space.setattr(w_A, w_x, space.newfloat(1.1))
+ space.setattr(w_A, w_x, space.newfloat(2.1))
+ space.setattr(w_A, w_x, space.wrap("abc"))
+ cell = w_A._getdictvalue_no_unwrapping(space, "x")
+ assert space.str_w(cell.w_value) == "abc"
class AppTestVersionedType(test_typeobject.AppTestTypeObject):
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -36,6 +36,17 @@
def __repr__(self):
return "" % (self.intvalue, )
+class FloatMutableCell(MutableCell):
+ def __init__(self, floatvalue):
+ self.floatvalue = floatvalue
+
+ def unwrap_cell(self, space):
+ return space.wrap(self.floatvalue)
+
+ def __repr__(self):
+ return "" % (self.floatvalue, )
+
+
def unwrap_cell(space, w_value):
if isinstance(w_value, MutableCell):
return w_value.unwrap_cell(space)
@@ -49,6 +60,7 @@
def write_cell(space, w_cell, w_value):
from pypy.objspace.std.intobject import W_IntObject
+ from pypy.objspace.std.floatobject import W_FloatObject
if w_cell is None:
# attribute does not exist at all, write it without a cell first
return w_value
@@ -58,14 +70,19 @@
elif isinstance(w_cell, IntMutableCell) and type(w_value) is W_IntObject:
w_cell.intvalue = w_value.intval
return None
+ elif isinstance(w_cell, FloatMutableCell) and type(w_value) is W_FloatObject:
+ w_cell.floatvalue = w_value.floatval
+ return None
elif space.is_w(w_cell, w_value):
# If the new value and the current value are the same, don't
# create a level of indirection, or mutate the version.
return None
- if type(w_value) is W_IntObject:
- return IntMutableCell(w_value.intval)
- else:
- return ObjectMutableCell(w_value)
+ if not isinstance(w_cell, MutableCell):
+ if type(w_value) is W_IntObject:
+ return IntMutableCell(w_value.intval)
+ if type(w_value) is W_FloatObject:
+ return FloatMutableCell(w_value.floatval)
+ return ObjectMutableCell(w_value)
class VersionTag(object):
pass
From noreply at buildbot.pypy.org Mon Feb 2 21:15:51 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 21:15:51 +0100 (CET)
Subject: [pypy-commit] stmgc hashtable-iter: ready for merge
Message-ID: <20150202201551.9971E1C026B@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: hashtable-iter
Changeset: r1606:ddb0b264ee12
Date: 2015-02-02 19:57 +0100
http://bitbucket.org/pypy/stmgc/changeset/ddb0b264ee12/
Log: ready for merge
From noreply at buildbot.pypy.org Mon Feb 2 21:15:53 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 21:15:53 +0100 (CET)
Subject: [pypy-commit] stmgc default: hg merge hashtable-iter
Message-ID: <20150202201553.178961C026B@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch:
Changeset: r1607:ee68afa62c2c
Date: 2015-02-02 19:58 +0100
http://bitbucket.org/pypy/stmgc/changeset/ee68afa62c2c/
Log: hg merge hashtable-iter
Add methods like .items(), .keys() and so on. Unlike the name of
the branch suggests, we *don't* support the lazy iterators.
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -431,13 +431,12 @@
continue; /* no need to check: is pending immediate abort */
char *remote_base = get_segment_base(i);
- uint8_t remote_version = get_segment(i)->transaction_read_version;
LIST_FOREACH_R(
STM_PSEGMENT->modified_old_objects,
object_t * /*item*/,
({
- if (was_read_remote(remote_base, item, remote_version)) {
+ if (was_read_remote(remote_base, item)) {
/* A write-read conflict! */
dprintf(("write-read conflict on %p, our seg: %d, other: %ld\n",
item, STM_SEGMENT->segment_num, i));
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -281,11 +281,17 @@
static stm_thread_local_t *abort_with_mutex_no_longjmp(void);
static void abort_data_structures_from_segment_num(int segment_num);
-static inline bool was_read_remote(char *base, object_t *obj,
- uint8_t other_transaction_read_version)
+static inline struct stm_read_marker_s *get_read_marker(char *base,
+ object_t *obj) {
+ return (struct stm_read_marker_s *)(base + (((uintptr_t)obj) >> 4));
+}
+
+static inline bool was_read_remote(char *base, object_t *obj)
{
- uint8_t rm = ((struct stm_read_marker_s *)
- (base + (((uintptr_t)obj) >> 4)))->rm;
+ uint8_t other_transaction_read_version =
+ ((struct stm_segment_info_s *)REAL_ADDRESS(base, STM_PSEGMENT))
+ ->transaction_read_version;
+ uint8_t rm = get_read_marker(base, obj)->rm;
assert(rm <= other_transaction_read_version);
return rm == other_transaction_read_version;
}
diff --git a/c7/stm/hashtable.c b/c7/stm/hashtable.c
--- a/c7/stm/hashtable.c
+++ b/c7/stm/hashtable.c
@@ -12,22 +12,28 @@
collision).
The main operations on a hashtable are reading or writing an object at a
-given index. It might support in the future enumerating the indexes of
-non-NULL objects.
+given index. It also supports fetching the list of non-NULL entries.
There are two markers for every index (a read and a write marker).
This is unlike regular arrays, which have only two markers in total.
+Additionally, we use the read marker for the hashtable object itself
+to mean "we have read the complete list of keys". This plays the role
+of a "global" read marker: when any thread adds a new key/value object
+to the hashtable, this new object's read marker is initialized with a
+copy of the "global" read marker --- in all segments.
+
Implementation
--------------
First idea: have the hashtable in raw memory, pointing to "entry"
-objects. The entry objects themselves point to the user-specified
-objects. The entry objects have the read/write markers. Every entry
-object, once created, stays around. It is only removed by the next
-major GC if it points to NULL and its read/write markers are not set
-in any currently-running transaction.
+objects (which are regular, GC- and STM-managed objects). The entry
+objects themselves point to the user-specified objects. The entry
+objects hold the read/write markers. Every entry object, once
+created, stays around. It is only removed by the next major GC if it
+points to NULL and its read/write markers are not set in any
+currently-running transaction.
References
----------
@@ -103,9 +109,7 @@
{
long i;
for (i = 1; i <= NB_SEGMENTS; i++) {
- char *remote_base = get_segment_base(i);
- uint8_t remote_version = get_segment(i)->transaction_read_version;
- if (was_read_remote(remote_base, obj, remote_version))
+ if (was_read_remote(get_segment_base(i), obj))
return true;
}
return false;
@@ -154,6 +158,7 @@
/* ^^^ this unlocks the table by writing a non-zero value to
table->resize_counter, but the new value is a pointer to the
new bigger table, so IS_EVEN() is still true */
+ assert(IS_EVEN(table->resize_counter));
init_table(biggertable, biggercount);
@@ -173,6 +178,7 @@
}
}
_insert_clean(biggertable, entry);
+ assert(rc > 6);
rc -= 6;
}
biggertable->resize_counter = rc;
@@ -216,7 +222,16 @@
perturb >>= PERTURB_SHIFT;
}
}
- /* here, we didn't find the 'entry' with the correct index. */
+ /* here, we didn't find the 'entry' with the correct index. Note
+ that even if the same 'table' is modified or resized by other
+ threads concurrently, any new item found from a race condition
+ would anyway contain NULL in the present segment (ensured by
+ the first write_fence() below). If the 'table' grows an entry
+ just after we checked above, then we go ahead and lock the
+ table; but after we get the lock, we will notice the new entry
+ (ensured by the second write_fence() below) and restart the
+ whole process.
+ */
uintptr_t rc = VOLATILE_TABLE(table)->resize_counter;
@@ -282,12 +297,22 @@
synchronization with other pieces of the code that may
change.
*/
+
+ /* First fetch the read marker of 'hashtableobj' in all
+ segments, before allocate_outside_nursery_large()
+ which might trigger a GC */
+ long j;
+ uint8_t readmarkers[NB_SEGMENTS];
+ for (j = 1; j <= NB_SEGMENTS; j++) {
+ readmarkers[j - 1] = get_read_marker(get_segment_base(j),
+ hashtableobj)->rm;
+ }
+
acquire_privatization_lock();
char *p = allocate_outside_nursery_large(
sizeof(stm_hashtable_entry_t));
entry = (stm_hashtable_entry_t *)(p - stm_object_pages);
- long j;
for (j = 0; j <= NB_SEGMENTS; j++) {
struct stm_hashtable_entry_s *e;
e = (struct stm_hashtable_entry_s *)
@@ -299,6 +324,11 @@
}
hashtable->additions += 0x100;
release_privatization_lock();
+
+ for (j = 1; j <= NB_SEGMENTS; j++) {
+ get_read_marker(get_segment_base(j), (object_t *)entry)->rm =
+ readmarkers[j - 1];
+ }
}
write_fence(); /* make sure 'entry' is fully initialized here */
table->items[i] = entry;
@@ -338,17 +368,94 @@
e->object = nvalue;
}
+long stm_hashtable_length_upper_bound(stm_hashtable_t *hashtable)
+{
+ stm_hashtable_table_t *table;
+ uintptr_t rc;
+
+ restart:
+ table = VOLATILE_HASHTABLE(hashtable)->table;
+ rc = VOLATILE_TABLE(table)->resize_counter;
+ if (IS_EVEN(rc)) {
+ spin_loop();
+ goto restart;
+ }
+
+ uintptr_t initial_rc = (table->mask + 1) * 4 + 1;
+ uintptr_t num_entries_times_6 = initial_rc - rc;
+ return num_entries_times_6 / 6;
+}
+
+long stm_hashtable_list(object_t *hobj, stm_hashtable_t *hashtable,
+ stm_hashtable_entry_t **results)
+{
+ stm_hashtable_table_t *table;
+ intptr_t rc;
+
+ /* Set the read marker. It will be left as long as we're running
+ the same transaction.
+ */
+ stm_read(hobj);
+
+ /* Acquire and immediately release the lock. We don't actually
+ need to do anything while we hold the lock, but the point is to
+ wait until the lock is available, and to synchronize other
+ threads with the stm_read() done above.
+ */
+ restart:
+ table = VOLATILE_HASHTABLE(hashtable)->table;
+ rc = VOLATILE_TABLE(table)->resize_counter;
+ if (IS_EVEN(rc)) {
+ spin_loop();
+ goto restart;
+ }
+ if (!__sync_bool_compare_and_swap(&table->resize_counter, rc, rc))
+ goto restart;
+
+ /* Read all entries, check which ones are not NULL, count them,
+ and optionally list them in 'results'.
+ */
+ uintptr_t i, mask = table->mask;
+ stm_hashtable_entry_t *entry;
+ long nresult = 0;
+
+ if (results != NULL) {
+ /* collect the results in the provided list */
+ for (i = 0; i <= mask; i++) {
+ entry = VOLATILE_TABLE(table)->items[i];
+ if (entry != NULL) {
+ stm_read((object_t *)entry);
+ if (entry->object != NULL)
+ results[nresult++] = entry;
+ }
+ }
+ }
+ else {
+ /* don't collect, just get the exact number of results */
+ for (i = 0; i <= mask; i++) {
+ entry = VOLATILE_TABLE(table)->items[i];
+ if (entry != NULL) {
+ stm_read((object_t *)entry);
+ if (entry->object != NULL)
+ nresult++;
+ }
+ }
+ }
+ return nresult;
+}
+
static void _stm_compact_hashtable(stm_hashtable_t *hashtable)
{
stm_hashtable_table_t *table = hashtable->table;
- assert(!IS_EVEN(table->resize_counter));
+ uintptr_t rc = table->resize_counter;
+ assert(!IS_EVEN(rc));
if ((hashtable->additions >> 8) * 4 > table->mask) {
int segment_num = (hashtable->additions & 0xFF);
if (!segment_num) segment_num = 1;
hashtable->additions = segment_num;
uintptr_t initial_rc = (table->mask + 1) * 4 + 1;
- uintptr_t num_entries_times_6 = initial_rc - table->resize_counter;
+ uintptr_t num_entries_times_6 = initial_rc - rc;
uintptr_t count = INITIAL_HASHTABLE_SIZE;
while (count * 4 < num_entries_times_6)
count *= 2;
@@ -376,6 +483,7 @@
free(old_table);
}
hashtable->initial_table.resize_counter = (uintptr_t)table;
+ assert(IS_EVEN(hashtable->initial_table.resize_counter));
}
}
diff --git a/c7/stm/misc.c b/c7/stm/misc.c
--- a/c7/stm/misc.c
+++ b/c7/stm/misc.c
@@ -31,8 +31,7 @@
bool _stm_was_read(object_t *obj)
{
- return was_read_remote(STM_SEGMENT->segment_base, obj,
- STM_SEGMENT->transaction_read_version);
+ return was_read_remote(STM_SEGMENT->segment_base, obj);
}
bool _stm_was_written(object_t *obj)
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -545,6 +545,9 @@
object_t *stm_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key);
void stm_hashtable_write(object_t *, stm_hashtable_t *, uintptr_t key,
object_t *nvalue, stm_thread_local_t *);
+long stm_hashtable_length_upper_bound(stm_hashtable_t *);
+long stm_hashtable_list(object_t *, stm_hashtable_t *,
+ stm_hashtable_entry_t **results);
extern uint32_t stm_hashtable_entry_userdata;
void stm_hashtable_tracefn(stm_hashtable_t *, void (object_t **));
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -167,17 +167,23 @@
void (*stmcb_finalizer)(object_t *);
typedef struct stm_hashtable_s stm_hashtable_t;
+typedef ... stm_hashtable_entry_t;
stm_hashtable_t *stm_hashtable_create(void);
void stm_hashtable_free(stm_hashtable_t *);
bool _check_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key);
object_t *hashtable_read_result;
bool _check_hashtable_write(object_t *, stm_hashtable_t *, uintptr_t key,
object_t *nvalue, stm_thread_local_t *tl);
+long stm_hashtable_length_upper_bound(stm_hashtable_t *);
+long stm_hashtable_list(object_t *, stm_hashtable_t *,
+ stm_hashtable_entry_t **results);
uint32_t stm_hashtable_entry_userdata;
void stm_hashtable_tracefn(stm_hashtable_t *, void (object_t **));
void _set_hashtable(object_t *obj, stm_hashtable_t *h);
stm_hashtable_t *_get_hashtable(object_t *obj);
+uintptr_t _get_entry_index(stm_hashtable_entry_t *entry);
+object_t *_get_entry_object(stm_hashtable_entry_t *entry);
""")
@@ -308,6 +314,18 @@
return *(stm_hashtable_t *TLPREFIX *)field_addr;
}
+uintptr_t _get_entry_index(stm_hashtable_entry_t *entry)
+{
+ stm_read((object_t *)entry);
+ return entry->index;
+}
+
+object_t *_get_entry_object(stm_hashtable_entry_t *entry)
+{
+ stm_read((object_t *)entry);
+ return entry->object;
+}
+
void _set_ptr(object_t *obj, int n, object_t *v)
{
long nrefs = (long)((myobj_t*)obj)->type_id - 421420;
diff --git a/c7/test/test_hashtable.py b/c7/test/test_hashtable.py
--- a/c7/test/test_hashtable.py
+++ b/c7/test/test_hashtable.py
@@ -16,6 +16,24 @@
if res:
raise Conflict
+def ht_length_upper_bound(o):
+ h = get_hashtable(o)
+ return lib.stm_hashtable_length_upper_bound(h)
+
+def htitems(o):
+ h = get_hashtable(o)
+ upper_bound = lib.stm_hashtable_length_upper_bound(h)
+ entries = ffi.new("stm_hashtable_entry_t *[]", upper_bound)
+ count = lib.stm_hashtable_list(o, h, entries)
+ assert count <= upper_bound
+ return [(lib._get_entry_index(entries[i]),
+ lib._get_entry_object(entries[i])) for i in range(count)]
+
+def htlen(o):
+ h = get_hashtable(o)
+ count = lib.stm_hashtable_list(o, h, ffi.NULL)
+ return count
+
class BaseTestHashtable(BaseTest):
@@ -236,6 +254,36 @@
assert htget(h, 11) != ffi.NULL
assert htget(h, 12) != ffi.NULL
+ def test_list_1(self):
+ self.start_transaction()
+ h = self.allocate_hashtable()
+ tl0 = self.tls[self.current_thread]
+ for i in range(32):
+ assert ht_length_upper_bound(h) == i
+ htset(h, 19 ^ i, stm_allocate(32), tl0)
+ assert ht_length_upper_bound(h) == 32
+
+ def test_list_2(self):
+ self.start_transaction()
+ h = self.allocate_hashtable()
+ tl0 = self.tls[self.current_thread]
+ expected = []
+ for i in range(29):
+ lp = stm_allocate(32)
+ htset(h, 19 ^ i, lp, tl0)
+ expected.append((19 ^ i, lp))
+ lst = htitems(h)
+ assert len(lst) == 29
+ assert sorted(lst) == sorted(expected)
+
+ def test_list_3(self):
+ self.start_transaction()
+ h = self.allocate_hashtable()
+ tl0 = self.tls[self.current_thread]
+ for i in range(29):
+ htset(h, 19 ^ i, stm_allocate(32), tl0)
+ assert htlen(h) == 29
+
class TestRandomHashtable(BaseTestHashtable):
From noreply at buildbot.pypy.org Mon Feb 2 21:15:54 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 21:15:54 +0100 (CET)
Subject: [pypy-commit] stmgc default: One very probable bug fix,
and one more theoretical
Message-ID: <20150202201554.1CA931C026B@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch:
Changeset: r1608:10c636ae449e
Date: 2015-02-02 21:15 +0100
http://bitbucket.org/pypy/stmgc/changeset/10c636ae449e/
Log: One very probable bug fix, and one more theoretical
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -1111,6 +1111,8 @@
dprintf(("become_inevitable: %s\n", msg));
timing_fetch_inev();
+ write_fence(); /* make sure others see a correct 'marker_inev'
+ if they see TS_INEVITABLE */
wait_for_end_of_inevitable_transaction();
STM_PSEGMENT->transaction_state = TS_INEVITABLE;
stm_rewind_jmp_forget(STM_SEGMENT->running_thread);
diff --git a/c7/stm/prof.c b/c7/stm/prof.c
--- a/c7/stm/prof.c
+++ b/c7/stm/prof.c
@@ -32,12 +32,27 @@
int len0 = 0;
int len1 = 0;
if (markers != NULL) {
+ /* Obscure. In rare cases we see an uninitialized object
+ at 'markers[1]->segment_base + object'. I *think* it
+ is related to the other thread busy privatizing the
+ page. We thus need to acquire the privatization_lock
+ here (any will do).
+
+ Note that we have to read the object from the foreign
+ segment. We can't assume the code object to be already
+ committed at all; maybe it was created during the remote
+ transaction.
+ */
+ acquire_privatization_lock();
+
if (markers[1].tl != NULL)
buf.other_thread_num = markers[1].tl->thread_local_counter;
if (markers[0].odd_number != 0)
len0 = profiling_expand_marker(&markers[0], buf.extra, 128);
if (markers[1].odd_number != 0)
len1 = profiling_expand_marker(&markers[1], buf.extra + len0, 128);
+
+ release_privatization_lock();
}
buf.marker_length[0] = len0;
buf.marker_length[1] = len1;
From noreply at buildbot.pypy.org Mon Feb 2 21:23:51 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 21:23:51 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: import stmgc/10c636ae449e
Message-ID: <20150202202351.B268B1C026B@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75654:79d715e680ed
Date: 2015-02-02 21:23 +0100
http://bitbucket.org/pypy/pypy/changeset/79d715e680ed/
Log: import stmgc/10c636ae449e
diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision
--- a/rpython/translator/stm/src_stm/revision
+++ b/rpython/translator/stm/src_stm/revision
@@ -1,1 +1,1 @@
-88492dc56aa8
+10c636ae449e
diff --git a/rpython/translator/stm/src_stm/stm/core.c b/rpython/translator/stm/src_stm/stm/core.c
--- a/rpython/translator/stm/src_stm/stm/core.c
+++ b/rpython/translator/stm/src_stm/stm/core.c
@@ -1112,6 +1112,8 @@
dprintf(("become_inevitable: %s\n", msg));
timing_fetch_inev();
+ write_fence(); /* make sure others see a correct 'marker_inev'
+ if they see TS_INEVITABLE */
wait_for_end_of_inevitable_transaction();
STM_PSEGMENT->transaction_state = TS_INEVITABLE;
stm_rewind_jmp_forget(STM_SEGMENT->running_thread);
diff --git a/rpython/translator/stm/src_stm/stm/prof.c b/rpython/translator/stm/src_stm/stm/prof.c
--- a/rpython/translator/stm/src_stm/stm/prof.c
+++ b/rpython/translator/stm/src_stm/stm/prof.c
@@ -33,12 +33,27 @@
int len0 = 0;
int len1 = 0;
if (markers != NULL) {
+ /* Obscure. In rare cases we see an uninitialized object
+ at 'markers[1]->segment_base + object'. I *think* it
+ is related to the other thread busy privatizing the
+ page. We thus need to acquire the privatization_lock
+ here (any will do).
+
+ Note that we have to read the object from the foreign
+ segment. We can't assume the code object to be already
+ committed at all; maybe it was created during the remote
+ transaction.
+ */
+ acquire_privatization_lock();
+
if (markers[1].tl != NULL)
buf.other_thread_num = markers[1].tl->thread_local_counter;
if (markers[0].odd_number != 0)
len0 = profiling_expand_marker(&markers[0], buf.extra, 128);
if (markers[1].odd_number != 0)
len1 = profiling_expand_marker(&markers[1], buf.extra + len0, 128);
+
+ release_privatization_lock();
}
buf.marker_length[0] = len0;
buf.marker_length[1] = len1;
From noreply at buildbot.pypy.org Mon Feb 2 21:52:26 2015
From: noreply at buildbot.pypy.org (amauryfa)
Date: Mon, 2 Feb 2015 21:52:26 +0100 (CET)
Subject: [pypy-commit] pypy stdlib-2.7.9: ssl: Add ALERT_DESCRIPTION_*
constants
Message-ID: <20150202205226.EE6041C02D4@cobra.cs.uni-duesseldorf.de>
Author: Amaury Forgeot d'Arc
Branch: stdlib-2.7.9
Changeset: r75656:5be3e3aef9b7
Date: 2015-02-02 21:20 +0100
http://bitbucket.org/pypy/pypy/changeset/5be3e3aef9b7/
Log: ssl: Add ALERT_DESCRIPTION_* constants
diff --git a/pypy/module/_ssl/__init__.py b/pypy/module/_ssl/__init__.py
--- a/pypy/module/_ssl/__init__.py
+++ b/pypy/module/_ssl/__init__.py
@@ -1,4 +1,5 @@
from pypy.interpreter.mixedmodule import MixedModule
+from pypy.module._ssl import ssl_data
class Module(MixedModule):
"""Implementation module for SSL socket operations.
@@ -36,6 +37,9 @@
Module.interpleveldefs['RAND_status'] = "interp_ssl.RAND_status"
Module.interpleveldefs['RAND_egd'] = "interp_ssl.RAND_egd"
+ for name, value in ssl_data.ALERT_DESCRIPTION_CODES.items():
+ Module.interpleveldefs[name] = "space.wrap(%r)" % value
+
super(Module, cls).buildloaders()
def startup(self, space):
diff --git a/pypy/module/_ssl/ssl_data.py b/pypy/module/_ssl/ssl_data.py
--- a/pypy/module/_ssl/ssl_data.py
+++ b/pypy/module/_ssl/ssl_data.py
@@ -347,6 +347,21 @@
setattr(CConfig, code, rffi_platform.DefinedConstantInteger(
'%s_R_%s' % (lib, code)))
+# Constants for ALERT_DESCRIPTION_ error codes
+AD_NAMES = """
+ CLOSE_NOTIFY UNEXPECTED_MESSAGE BAD_RECORD_MAC RECORD_OVERFLOW
+ DECOMPRESSION_FAILURE HANDSHAKE_FAILURE BAD_CERTIFICATE
+ UNSUPPORTED_CERTIFICATE CERTIFICATE_REVOKED CERTIFICATE_EXPIRED
+ CERTIFICATE_UNKNOWN ILLEGAL_PARAMETER UNKNOWN_CA ACCESS_DENIED
+ DECODE_ERROR DECRYPT_ERROR PROTOCOL_VERSION INSUFFICIENT_SECURITY
+ INTERNAL_ERROR USER_CANCELLED NO_RENEGOTIATION UNSUPPORTED_EXTENSION
+ CERTIFICATE_UNOBTAINABLE UNRECOGNIZED_NAME BAD_CERTIFICATE_STATUS_RESPONSE
+ BAD_CERTIFICATE_HASH_VALUE UNKNOWN_PSK_IDENTITY
+ """.split()
+for name in AD_NAMES:
+ setattr(CConfig, name, rffi_platform.DefinedConstantInteger(
+ 'SSL_AD_%s' % name))
+
cconfig = rffi_platform.configure(CConfig)
LIBRARY_CODES_TO_NAMES = {}
@@ -356,3 +371,8 @@
for lib, code in error_codes:
ERROR_CODES_TO_NAMES[cconfig[lib], cconfig[code]] = code
+ALERT_DESCRIPTION_CODES = {}
+for name in AD_NAMES:
+ value = cconfig[name]
+ if value is not None:
+ ALERT_DESCRIPTION_CODES['ALERT_DESCRIPTION_%s' % name] = value
diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py
--- a/pypy/module/_ssl/test/test_ssl.py
+++ b/pypy/module/_ssl/test/test_ssl.py
@@ -38,6 +38,8 @@
assert isinstance(_ssl.OPENSSL_VERSION, str)
assert 'openssl' in _ssl.OPENSSL_VERSION.lower()
+ assert isinstance(_ssl.ALERT_DESCRIPTION_ACCESS_DENIED, int)
+
def test_RAND_add(self):
import _ssl
if not hasattr(_ssl, "RAND_add"):
From noreply at buildbot.pypy.org Mon Feb 2 21:52:28 2015
From: noreply at buildbot.pypy.org (amauryfa)
Date: Mon, 2 Feb 2015 21:52:28 +0100 (CET)
Subject: [pypy-commit] pypy stdlib-2.7.9: Fix test, checked with CPython
Message-ID: <20150202205228.1B3691C02D4@cobra.cs.uni-duesseldorf.de>
Author: Amaury Forgeot d'Arc
Branch: stdlib-2.7.9
Changeset: r75657:22cbcc2a0bd4
Date: 2015-02-02 21:38 +0100
http://bitbucket.org/pypy/pypy/changeset/22cbcc2a0bd4/
Log: Fix test, checked with CPython
diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py
--- a/pypy/module/_ssl/test/test_ssl.py
+++ b/pypy/module/_ssl/test/test_ssl.py
@@ -330,7 +330,7 @@
with open(self.keycert) as f:
cacert_pem = f.read().decode('ascii')
ctx.load_verify_locations(cadata=cacert_pem)
- assert ctx.cert_store_stats()["x509_ca"]
+ assert ctx.cert_store_stats()["x509_ca"] == 0
def test_get_ca_certs(self):
import _ssl
From noreply at buildbot.pypy.org Mon Feb 2 21:52:29 2015
From: noreply at buildbot.pypy.org (amauryfa)
Date: Mon, 2 Feb 2015 21:52:29 +0100 (CET)
Subject: [pypy-commit] pypy stdlib-2.7.9: ssl.get_default_verify_paths()
Message-ID: <20150202205229.46E4D1C02D4@cobra.cs.uni-duesseldorf.de>
Author: Amaury Forgeot d'Arc
Branch: stdlib-2.7.9
Changeset: r75658:447c4c3f1931
Date: 2015-02-02 21:51 +0100
http://bitbucket.org/pypy/pypy/changeset/447c4c3f1931/
Log: ssl.get_default_verify_paths()
diff --git a/pypy/module/_ssl/__init__.py b/pypy/module/_ssl/__init__.py
--- a/pypy/module/_ssl/__init__.py
+++ b/pypy/module/_ssl/__init__.py
@@ -9,6 +9,7 @@
'_test_decode_cert': 'interp_ssl._test_decode_cert',
'txt2obj': 'interp_ssl.txt2obj',
'nid2obj': 'interp_ssl.nid2obj',
+ 'get_default_verify_paths': 'interp_ssl.get_default_verify_paths',
'SSLError': "interp_ssl.get_exception_class(space, 'w_sslerror')",
'SSLZeroReturnError': "interp_ssl.get_exception_class(space, 'w_sslzeroreturnerror')",
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -1563,3 +1563,18 @@
@unwrap_spec(nid=int)
def nid2obj(space, nid):
return space.newtuple([])
+
+
+def w_convert_path(space, path):
+ if not path:
+ return space.w_None
+ else:
+ return space.wrapbytes(rffi.charp2str(path))
+
+def get_default_verify_paths(space):
+ return space.newtuple([
+ w_convert_path(space, libssl_X509_get_default_cert_file_env()),
+ w_convert_path(space, libssl_X509_get_default_cert_file()),
+ w_convert_path(space, libssl_X509_get_default_cert_dir_env()),
+ w_convert_path(space, libssl_X509_get_default_cert_dir()),
+ ])
diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py
--- a/pypy/module/_ssl/test/test_ssl.py
+++ b/pypy/module/_ssl/test/test_ssl.py
@@ -363,6 +363,14 @@
raises(TypeError, ctx.load_dh_params, None)
raises(_ssl.SSLError, ctx.load_dh_params, self.keycert)
+ def test_get_default_verify_paths(self):
+ import _ssl
+ paths = _ssl.get_default_verify_paths()
+ assert paths[0] == 'SSL_CERT_FILE'
+ assert paths[2] == 'SSL_CERT_DIR'
+ assert paths[1].endswith('cert.pem')
+ assert paths[3].endswith('certs')
+
class AppTestSSLError:
spaceconfig = dict(usemodules=('_ssl', '_socket', 'thread'))
diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py
--- a/rpython/rlib/ropenssl.py
+++ b/rpython/rlib/ropenssl.py
@@ -338,6 +338,11 @@
ssl_external('X509_VERIFY_PARAM_get_flags', [X509_VERIFY_PARAM], rffi.ULONG)
ssl_external('X509_STORE_add_cert', [X509_STORE, X509], rffi.INT)
+ssl_external('X509_get_default_cert_file_env', [], rffi.CCHARP)
+ssl_external('X509_get_default_cert_file', [], rffi.CCHARP)
+ssl_external('X509_get_default_cert_dir_env', [], rffi.CCHARP)
+ssl_external('X509_get_default_cert_dir', [], rffi.CCHARP)
+
ssl_external('OBJ_obj2txt',
[rffi.CCHARP, rffi.INT, ASN1_OBJECT, rffi.INT], rffi.INT)
ssl_external('OBJ_obj2nid', [ASN1_OBJECT], rffi.INT)
From noreply at buildbot.pypy.org Mon Feb 2 22:01:59 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 22:01:59 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: Improve the basic tests
Message-ID: <20150202210159.477D51C02D4@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75659:3ab2ca363785
Date: 2015-02-02 22:01 +0100
http://bitbucket.org/pypy/pypy/changeset/3ab2ca363785/
Log: Improve the basic tests
diff --git a/pypy/module/pypystm/test_pypy_c/support.py b/pypy/module/pypystm/test_pypy_c/support.py
--- a/pypy/module/pypystm/test_pypy_c/support.py
+++ b/pypy/module/pypystm/test_pypy_c/support.py
@@ -72,7 +72,10 @@
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = pipe.communicate()
- if getattr(pipe, 'returncode', 0) < 0:
+ if pipe.returncode > 0:
+ raise IOError("subprocess error %d:\n%s" % (pipe.returncode,
+ stderr))
+ if pipe.returncode < 0:
raise IOError("subprocess was killed by signal %d" % (
pipe.returncode,))
@@ -80,8 +83,18 @@
from pypy.stm.print_stm_log import StmLog
return StmLog(str(self.logfile))
- def check_almost_no_conflict(self, func_or_src, args=[]):
+ def _check_count_conflicts(self, func_or_src, args=[]):
self._write_source(func_or_src, args)
self._execute()
stmlog = self._parse_log()
- assert stmlog.get_total_aborts_and_pauses() < 1000
+ count = stmlog.get_total_aborts_and_pauses()
+ print 'stmlog.get_total_aborts_and_pauses():', count
+ return count
+
+ def check_almost_no_conflict(self, *args):
+ count = self._check_count_conflicts(*args)
+ assert count < 500
+
+ def check_many_conflicts(self, *args):
+ count = self._check_count_conflicts(*args)
+ assert count > 20000
diff --git a/pypy/module/pypystm/test_pypy_c/test_conflict.py b/pypy/module/pypystm/test_pypy_c/test_conflict.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/pypystm/test_pypy_c/test_conflict.py
@@ -0,0 +1,16 @@
+from pypy.module.pypystm.test_pypy_c.support import BaseTestSTM
+
+
+class TestConflict(BaseTestSTM):
+
+ def test_obvious(self):
+ def f():
+ class X(object):
+ pass
+ x = X() # shared
+ x.a = 0
+ def g():
+ x.a += 1
+ run_in_threads(g)
+ #
+ self.check_many_conflicts(f)
From noreply at buildbot.pypy.org Mon Feb 2 22:10:09 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 22:10:09 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: more tests
Message-ID: <20150202211009.DE9F11C026B@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75662:255b484dd279
Date: 2015-02-02 22:09 +0100
http://bitbucket.org/pypy/pypy/changeset/255b484dd279/
Log: more tests
diff --git a/pypy/module/pypystm/test_pypy_c/support.py b/pypy/module/pypystm/test_pypy_c/support.py
--- a/pypy/module/pypystm/test_pypy_c/support.py
+++ b/pypy/module/pypystm/test_pypy_c/support.py
@@ -8,24 +8,27 @@
HEADER = """
import thread, pypystm
-def _run(lock, result, function):
+def _run(lock, result, function, args):
start = pypystm.time()
try:
while True:
- function()
+ function(*args)
if pypystm.time() - start >= 3.0:
break
result.append(1)
finally:
lock.release()
-def run_in_threads(function):
+def run_in_threads(function, arg_thread_num=False):
locks = []
result = []
for i in range(3):
lock = thread.allocate_lock()
lock.acquire()
- thread.start_new_thread(_run, (lock, result, function))
+ args = ()
+ if arg_thread_num:
+ args += (i,)
+ thread.start_new_thread(_run, (lock, result, function, args))
locks.append(lock)
for lock in locks:
lock._py3k_acquire(timeout=30)
diff --git a/pypy/module/pypystm/test_pypy_c/test_conflict.py b/pypy/module/pypystm/test_pypy_c/test_conflict.py
--- a/pypy/module/pypystm/test_pypy_c/test_conflict.py
+++ b/pypy/module/pypystm/test_pypy_c/test_conflict.py
@@ -14,3 +14,12 @@
run_in_threads(g)
#
self.check_many_conflicts(f)
+
+ def test_plain_dict_access(self):
+ def f():
+ d = {} # shared
+ def g(n):
+ d[n] = d.get(n, 0) + 1
+ run_in_threads(g, arg_thread_num=True)
+ #
+ self.check_many_conflicts(f)
diff --git a/pypy/module/pypystm/test_pypy_c/test_no_conflict.py b/pypy/module/pypystm/test_pypy_c/test_no_conflict.py
--- a/pypy/module/pypystm/test_pypy_c/test_no_conflict.py
+++ b/pypy/module/pypystm/test_pypy_c/test_no_conflict.py
@@ -17,3 +17,13 @@
run_in_threads(g)
#
self.check_almost_no_conflict(f)
+
+ def test_stmdict_access(self):
+ def f():
+ import pypystm
+ d = pypystm.stmdict() # shared
+ def g(n):
+ d[n] = d.get(n, 0) + 1
+ run_in_threads(g, arg_thread_num=True)
+ #
+ self.check_almost_no_conflict(f)
From noreply at buildbot.pypy.org Mon Feb 2 22:12:20 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Mon, 2 Feb 2015 22:12:20 +0100 (CET)
Subject: [pypy-commit] pypy release-2.5.x: merge default into branch
Message-ID: <20150202211220.A3BF61C026B@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch: release-2.5.x
Changeset: r75663:10f1b29a2bd2
Date: 2015-02-02 23:12 +0200
http://bitbucket.org/pypy/pypy/changeset/10f1b29a2bd2/
Log: merge default into branch
diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info
--- a/lib_pypy/greenlet.egg-info
+++ b/lib_pypy/greenlet.egg-info
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: greenlet
-Version: 0.4.0
+Version: 0.4.5
Summary: Lightweight in-process concurrent programming
Home-page: https://github.com/python-greenlet/greenlet
Author: Ralf Schmitt (for CPython), PyPy team
diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py
--- a/lib_pypy/greenlet.py
+++ b/lib_pypy/greenlet.py
@@ -1,7 +1,7 @@
import sys
import _continuation
-__version__ = "0.4.0"
+__version__ = "0.4.5"
# ____________________________________________________________
# Exceptions
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -75,22 +75,32 @@
if order != 'C': # or order != 'F':
raise oefmt(space.w_ValueError, "Unknown order: %s", order)
- # arrays with correct dtype
- if isinstance(w_object, W_NDimArray) and \
- (space.is_none(w_dtype) or w_object.get_dtype() is dtype):
- if copy and (subok or type(w_object) is W_NDimArray):
- return w_object.descr_copy(space, w_order)
- elif not copy and (subok or type(w_object) is W_NDimArray):
- return w_object
- if isinstance(w_object, W_NDimArray) and copy and not subok:
- # TODO do the loop.assign without copying elems_w
- shape = w_object.get_shape()
- _elems_w = w_object.reshape(space, space.wrap(-1))
- elems_w = [None] * w_object.get_size()
- for i in range(len(elems_w)):
- elems_w[i] = _elems_w.descr_getitem(space, space.wrap(i))
- if space.is_none(w_dtype):
+ if isinstance(w_object, W_NDimArray):
+ if (dtype is None or w_object.get_dtype() is dtype):
+ if copy and (subok or type(w_object) is W_NDimArray):
+ return w_object.descr_copy(space, w_order)
+ elif not copy and (subok or type(w_object) is W_NDimArray):
+ return w_object
+ # we have a ndarray, but need to copy or change dtype or create W_NDimArray
+ if dtype is None:
dtype = w_object.get_dtype()
+ if dtype != w_object.get_dtype():
+ # silently reject the copy value
+ copy = True
+ if copy:
+ shape = w_object.get_shape()
+ _elems_w = w_object.reshape(space, space.wrap(-1))
+ elems_w = [None] * w_object.get_size()
+ for i in range(len(elems_w)):
+ elems_w[i] = _elems_w.descr_getitem(space, space.wrap(i))
+ elif subok:
+ raise oefmt(space.w_NotImplementedError,
+ "array(...copy=False, subok=True) not implemented yet")
+ else:
+ sz = support.product(w_object.get_shape()) * dtype.elsize
+ return W_NDimArray.from_shape_and_storage(space,
+ w_object.get_shape(),w_object.implementation.storage,
+ dtype, storage_bytes=sz, w_base=w_object)
else:
# not an array
shape, elems_w = strides.find_shape_and_elems(space, w_object, dtype)
diff --git a/pypy/module/micronumpy/test/test_subtype.py b/pypy/module/micronumpy/test/test_subtype.py
--- a/pypy/module/micronumpy/test/test_subtype.py
+++ b/pypy/module/micronumpy/test/test_subtype.py
@@ -268,7 +268,7 @@
c = array(a, float)
assert c.dtype is dtype(float)
- def test__getitem_modifies_shape(self):
+ def test_array_of_subtype(self):
import numpy as N
# numpy's matrix class caused an infinite loop
class matrix(N.ndarray):
@@ -309,8 +309,14 @@
a = matrix([[1., 2.], [3., 4.]])
b = N.array([a])
assert (b == a).all()
+
b = N.array(a)
assert len(b.shape) == 2
+ assert (b == a).all()
+
+ b = N.array(a, copy=False)
+ assert len(b.shape) == 2
+ assert (b == a).all()
def test_setstate_no_version(self):
# Some subclasses of ndarray, like MaskedArray, do not use
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -220,6 +220,9 @@
af = arange(10, dtype=float)
af2 = ufunc(af)
assert all(af2 == af * 2)
+ ac = arange(10, dtype=complex)
+ skip('casting not implemented yet')
+ ac1 = ufunc(ac)
def test_frompyfunc_2d_sig(self):
def times_2(in_array, out_array):
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -774,8 +774,13 @@
break
else:
if len(self.funcs) > 1:
- dtypesstr = ','.join(['%s%s%s' % (d.byteorder, d.kind, d.elsize) \
- for d in dtypes])
+
+ dtypesstr = ''
+ for d in dtypes:
+ if d is None:
+ dtypesstr += 'None,'
+ else:
+ dtypesstr += '%s%s%s,' % (d.byteorder, d.kind, d.elsize)
_dtypesstr = ','.join(['%s%s%s' % (d.byteorder, d.kind, d.elsize) \
for d in _dtypes])
raise oefmt(space.w_TypeError,
diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -535,3 +535,9 @@
def isatty(self):
self._check_closed()
return os.isatty(c_fileno(self._ll_file))
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.close()
diff --git a/rpython/rlib/test/test_rfile.py b/rpython/rlib/test/test_rfile.py
--- a/rpython/rlib/test/test_rfile.py
+++ b/rpython/rlib/test/test_rfile.py
@@ -26,6 +26,7 @@
f()
assert open(fname, "r").read() == "dupa"
+ os.unlink(fname)
self.interpret(f, [])
assert open(fname, "r").read() == "dupa"
@@ -102,6 +103,7 @@
f2.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
@py.test.mark.skipif("sys.platform == 'win32'")
@@ -121,6 +123,7 @@
f2.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
def test_open_buffering_full(self):
@@ -138,6 +141,7 @@
f2.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
def test_fdopen_buffering_full(self):
@@ -157,6 +161,7 @@
f2.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
def test_read_write(self):
@@ -203,6 +208,7 @@
f2.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
def test_read_sequentially(self):
@@ -277,6 +283,7 @@
f.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
def test_tempfile(self):
@@ -309,6 +316,7 @@
f()
assert open(fname).read() == "xxx"
+ os.unlink(fname)
self.interpret(f, [])
assert open(fname).read() == "xxx"
@@ -325,6 +333,7 @@
res = f()
assert res > 2
+ os.unlink(fname)
res = self.interpret(f, [])
assert res > 2
@@ -341,6 +350,7 @@
res = f()
assert res == 3
+ os.unlink(fname)
res = self.interpret(f, [])
assert res == 3
@@ -357,6 +367,7 @@
f.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
def test_truncate(self):
@@ -381,8 +392,28 @@
f.close()
f()
+ os.unlink(fname)
self.interpret(f, [])
+ def test_with_statement(self):
+ fname = str(self.tmpdir.join('file_6'))
+
+ def f():
+ with open(fname, "w") as f:
+ f.write("dupa")
+ try:
+ f.write("dupb")
+ except ValueError:
+ pass
+ else:
+ assert False
+
+ f()
+ assert open(fname, "r").read() == "dupa"
+ os.unlink(fname)
+ self.interpret(f, [])
+ assert open(fname, "r").read() == "dupa"
+
class TestDirect:
def setup_class(cls):
From noreply at buildbot.pypy.org Mon Feb 2 23:38:59 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Mon, 2 Feb 2015 23:38:59 +0100 (CET)
Subject: [pypy-commit] pypy stmgc-c7: Fight fight until I can reliably get a
failure mode for weakrefs
Message-ID: <20150202223859.A22271C0FDC@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch: stmgc-c7
Changeset: r75670:5b9137e56e6b
Date: 2015-02-02 23:38 +0100
http://bitbucket.org/pypy/pypy/changeset/5b9137e56e6b/
Log: Fight fight until I can reliably get a failure mode for weakrefs
diff --git a/pypy/module/pypystm/test_pypy_c/support.py b/pypy/module/pypystm/test_pypy_c/support.py
--- a/pypy/module/pypystm/test_pypy_c/support.py
+++ b/pypy/module/pypystm/test_pypy_c/support.py
@@ -8,27 +8,66 @@
HEADER = """
import thread, pypystm
-def _run(lock, result, function, args):
+NUM_THREADS = 3
+
+_b_to_go = NUM_THREADS
+_b_done = False
+_b_lock = thread.allocate_lock()
+_b_locks = [thread.allocate_lock() for _i in range(NUM_THREADS)]
+for _bl in _b_locks:
+ _bl.acquire()
+
+class BarrierThreadsDone(Exception):
+ pass
+
+def barrier(tnum, done=False):
+ '''Waits until NUM_THREADS call this function, and then returns
+ in all these threads at once.'''
+ global _b_to_go, _b_done
+ _b_lock.acquire()
+ if done:
+ _b_done = True
+ _b_to_go -= 1
+ if _b_to_go > 0:
+ _b_lock.release()
+ _b_locks[tnum].acquire()
+ else:
+ _b_to_go = NUM_THREADS
+ for i in range(NUM_THREADS):
+ if i != tnum:
+ _b_locks[i].release()
+ _b_lock.release()
+ if _b_done:
+ raise BarrierThreadsDone
+
+def _run(tnum, lock, result, function, args):
start = pypystm.time()
try:
- while True:
- function(*args)
- if pypystm.time() - start >= 3.0:
- break
+ try:
+ while True:
+ function(*args)
+ if pypystm.time() - start >= 3.0:
+ break
+ except BarrierThreadsDone:
+ pass
result.append(1)
finally:
lock.release()
+ while len(result) != NUM_THREADS:
+ barrier(tnum, done=True)
-def run_in_threads(function, arg_thread_num=False):
+def run_in_threads(function, arg_thread_num=False, arg_class=None):
locks = []
result = []
- for i in range(3):
+ for i in range(NUM_THREADS):
lock = thread.allocate_lock()
lock.acquire()
args = ()
if arg_thread_num:
args += (i,)
- thread.start_new_thread(_run, (lock, result, function, args))
+ if arg_class:
+ args += (arg_class(),)
+ thread.start_new_thread(_run, (i, lock, result, function, args))
locks.append(lock)
for lock in locks:
lock._py3k_acquire(timeout=30)
@@ -98,6 +137,10 @@
count = self._check_count_conflicts(*args)
assert count < 500
- def check_many_conflicts(self, *args):
+ def check_MANY_conflicts(self, *args):
count = self._check_count_conflicts(*args)
assert count > 20000
+
+ def check_SOME_conflicts(self, *args):
+ count = self._check_count_conflicts(*args)
+ assert count > 1000
diff --git a/pypy/module/pypystm/test_pypy_c/test_conflict.py b/pypy/module/pypystm/test_pypy_c/test_conflict.py
--- a/pypy/module/pypystm/test_pypy_c/test_conflict.py
+++ b/pypy/module/pypystm/test_pypy_c/test_conflict.py
@@ -13,7 +13,7 @@
x.a += 1
run_in_threads(g)
#
- self.check_many_conflicts(f)
+ self.check_MANY_conflicts(f)
def test_plain_dict_access(self):
def f():
@@ -22,4 +22,25 @@
d[n] = d.get(n, 0) + 1
run_in_threads(g, arg_thread_num=True)
#
- self.check_many_conflicts(f)
+ self.check_MANY_conflicts(f)
+
+ def test_write_to_many_objects_in_order(self):
+ def f():
+ import weakref
+
+ class X(object):
+ pass
+
+ lst = [] # shared
+
+ def g(tnum):
+ if tnum == 0:
+ lst[:] = [X() for i in range(1000)]
+ barrier(tnum)
+ for x in lst:
+ x.a = 5
+ barrier(tnum)
+
+ run_in_threads(g, arg_thread_num=True)
+ #
+ self.check_SOME_conflicts(f)
diff --git a/pypy/module/pypystm/test_pypy_c/test_no_conflict.py b/pypy/module/pypystm/test_pypy_c/test_no_conflict.py
--- a/pypy/module/pypystm/test_pypy_c/test_no_conflict.py
+++ b/pypy/module/pypystm/test_pypy_c/test_no_conflict.py
@@ -1,3 +1,4 @@
+import py
from pypy.module.pypystm.test_pypy_c.support import BaseTestSTM
@@ -27,3 +28,25 @@
run_in_threads(g, arg_thread_num=True)
#
self.check_almost_no_conflict(f)
+
+ def test_weakrefs(self):
+ py.test.skip("next issue")
+ def f():
+ import weakref
+
+ class X(object):
+ pass
+
+ lst = [] # shared
+
+ def g(tnum):
+ if tnum == 0:
+ lst[:] = [X() for i in range(1000)]
+ barrier(tnum)
+ for x in lst:
+ weakref.ref(x)
+ barrier(tnum)
+
+ run_in_threads(g, arg_thread_num=True)
+ #
+ self.check_almost_no_conflict(f)
From noreply at buildbot.pypy.org Tue Feb 3 11:36:34 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Tue, 3 Feb 2015 11:36:34 +0100 (CET)
Subject: [pypy-commit] pypy default: Fix jittest.py to accept targets with
no specified jitpolicy()
Message-ID: <20150203103634.A81CC1C068A@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch:
Changeset: r75674:410c76551947
Date: 2015-02-03 11:36 +0100
http://bitbucket.org/pypy/pypy/changeset/410c76551947/
Log: Fix jittest.py to accept targets with no specified jitpolicy()
diff --git a/rpython/jit/tl/jittest.py b/rpython/jit/tl/jittest.py
--- a/rpython/jit/tl/jittest.py
+++ b/rpython/jit/tl/jittest.py
@@ -15,16 +15,23 @@
reload(runsubprocess)
-ARGS = ["--jit", "threshold=100000,trace_eagerness=100000",
- "-S", "/home/arigo/pypysrc/32compiled/z.py"]
+#ARGS = ["--jit", "threshold=100000,trace_eagerness=100000",
+# "-S", "/home/arigo/pypysrc/32compiled/z.py"]
+ARGS = ["targettest_executable_name",
+ "-r", "13", "/home/arigo/git/pyrlang/test_beam/fact.beam",
+ "fact", "20000"]
def jittest(driver):
graph = driver.translator._graphof(driver.entry_point)
interp = LLInterpreter(driver.translator.rtyper)
- get_policy = driver.extra['jitpolicy']
- jitpolicy = get_policy(driver)
+ get_policy = driver.extra.get('jitpolicy', None)
+ if get_policy is None:
+ from rpython.jit.codewriter.policy import JitPolicy
+ jitpolicy = JitPolicy()
+ else:
+ jitpolicy = get_policy(driver)
from rpython.jit.backend.llgraph.runner import LLGraphCPU
apply_jit(jitpolicy, interp, graph, LLGraphCPU)
From noreply at buildbot.pypy.org Tue Feb 3 12:02:20 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Tue, 3 Feb 2015 12:02:20 +0100 (CET)
Subject: [pypy-commit] pypy default: Fix for tests
Message-ID: <20150203110220.B3F301C114E@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch:
Changeset: r75676:fdb74eb88378
Date: 2015-02-03 12:00 +0100
http://bitbucket.org/pypy/pypy/changeset/fdb74eb88378/
Log: Fix for tests
diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -3,6 +3,7 @@
from rpython.jit.metainterp.compile import ResumeAtPositionDescr
from rpython.jit.metainterp.jitexc import get_llexception, reraise
from rpython.jit.metainterp import jitexc
+from rpython.jit.metainterp.history import MissingValue
from rpython.rlib import longlong2float
from rpython.rlib.debug import ll_assert, make_sure_not_resized
from rpython.rlib.objectmodel import we_are_translated
@@ -29,9 +30,6 @@
class LeaveFrame(jitexc.JitException):
pass
-class MissingValue(object):
- "NOT_RPYTHON"
-
def signedord(c):
value = ord(c)
value = intmask(value << (LONG_BIT-8)) >> (LONG_BIT-8)
@@ -1595,14 +1593,20 @@
self.setposition(miframe.jitcode, miframe.pc)
for i in range(self.jitcode.num_regs_i()):
box = miframe.registers_i[i]
+ if not we_are_translated() and isinstance(box, MissingValue):
+ continue
if box is not None:
self.setarg_i(i, box.getint())
for i in range(self.jitcode.num_regs_r()):
box = miframe.registers_r[i]
+ if not we_are_translated() and isinstance(box, MissingValue):
+ continue
if box is not None:
self.setarg_r(i, box.getref_base())
for i in range(self.jitcode.num_regs_f()):
box = miframe.registers_f[i]
+ if not we_are_translated() and isinstance(box, MissingValue):
+ continue
if box is not None:
self.setarg_f(i, box.getfloatstorage())
diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py
--- a/rpython/jit/metainterp/history.py
+++ b/rpython/jit/metainterp/history.py
@@ -170,6 +170,10 @@
self.identifier = identifier # for testing
+class MissingValue(object):
+ "NOT_RPYTHON"
+
+
class Const(AbstractValue):
__slots__ = ()
diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -8,7 +8,7 @@
from rpython.jit.metainterp import history, compile, resume, executor, jitexc
from rpython.jit.metainterp.heapcache import HeapCache
from rpython.jit.metainterp.history import (Const, ConstInt, ConstPtr,
- ConstFloat, Box, TargetToken)
+ ConstFloat, Box, TargetToken, MissingValue)
from rpython.jit.metainterp.jitprof import EmptyProfiler
from rpython.jit.metainterp.logger import Logger
from rpython.jit.metainterp.optimizeopt.util import args_dict
@@ -43,9 +43,6 @@
"ge": "history.CONST_TRUE",
}
-class MissingValue(object):
- "NOT_RPYTHON"
-
class MIFrame(object):
debug = False
From noreply at buildbot.pypy.org Tue Feb 3 12:24:52 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Tue, 3 Feb 2015 12:24:52 +0100 (CET)
Subject: [pypy-commit] pypy default: even clearer
Message-ID: <20150203112452.A053D1C114F@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch:
Changeset: r75678:ed8716ebf22a
Date: 2015-02-03 12:24 +0100
http://bitbucket.org/pypy/pypy/changeset/ed8716ebf22a/
Log: even clearer
diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst
--- a/pypy/doc/how-to-release.rst
+++ b/pypy/doc/how-to-release.rst
@@ -41,7 +41,7 @@
* repackage and upload source "-src.tar.bz2" to bitbucket and to cobra, as some
packagers prefer a clearly labeled source package (download e.g.
https://bitbucket.org/pypy/pypy/get/release-2.5.x.tar.bz2, unpack,
- rename the top-level directory, repack, and upload)
+ rename the top-level directory to "pypy-2.5.0-src", repack, and upload)
* write release announcement pypy/doc/release-x.y(.z).txt
the release announcement should contain a direct link to the download page
From noreply at buildbot.pypy.org Tue Feb 3 15:24:15 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Tue, 3 Feb 2015 15:24:15 +0100 (CET)
Subject: [pypy-commit] pypy default: Document this restriction (for now).
Message-ID: <20150203142415.09AAE1C0F98@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch:
Changeset: r75681:b06ed3201641
Date: 2015-02-03 15:23 +0100
http://bitbucket.org/pypy/pypy/changeset/b06ed3201641/
Log: Document this restriction (for now).
diff --git a/rpython/doc/jit/virtualizable.rst b/rpython/doc/jit/virtualizable.rst
--- a/rpython/doc/jit/virtualizable.rst
+++ b/rpython/doc/jit/virtualizable.rst
@@ -66,3 +66,11 @@
virtualizable survives for longer, you want to force it before returning.
It's better to do it that way than by an external call some time later.
It's done using ``jit.hint(frame, force_virtualizable=True)``
+
+* Your interpreter should have a local variable similar to ``frame``
+ above. It must not be modified as long as it runs its
+ ``jit_merge_point`` loop, and in the loop it must be passed directly
+ to the ``jit_merge_point()`` and ``can_enter_jit()`` calls. The JIT
+ generator is known to produce buggy code if you fetch the
+ virtualizable from somewhere every iteration, instead of reusing the
+ same unmodified local variable.
From noreply at buildbot.pypy.org Tue Feb 3 19:06:02 2015
From: noreply at buildbot.pypy.org (fijal)
Date: Tue, 3 Feb 2015 19:06:02 +0100 (CET)
Subject: [pypy-commit] pypy vmprof: add some asserts
Message-ID: <20150203180602.052A41C0820@cobra.cs.uni-duesseldorf.de>
Author: Maciej Fijalkowski
Branch: vmprof
Changeset: r75683:c93a10fdfeef
Date: 2015-02-03 20:05 +0200
http://bitbucket.org/pypy/pypy/changeset/c93a10fdfeef/
Log: add some asserts
diff --git a/rpython/jit/backend/llsupport/codemap.py b/rpython/jit/backend/llsupport/codemap.py
--- a/rpython/jit/backend/llsupport/codemap.py
+++ b/rpython/jit/backend/llsupport/codemap.py
@@ -52,5 +52,13 @@
pos = self.patch_position.pop()
self.l[pos] = size
self.l[pos + 1] = len(self.l)
+ # at the end there should be no zeros
+ for i in range(len(self.l) / 4):
+ item = self.l[i * 4] # unique_id
+ assert item > 0 # no zeros here
+ item = self.l[i * 4 + 2] # end in asm
+ assert item > 0
+ item = self.l[i * 4 + 3] # end in l
+ assert item > 0
return (addr, size, self.l) # XXX compact self.l
From noreply at buildbot.pypy.org Tue Feb 3 20:06:19 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Tue, 3 Feb 2015 20:06:19 +0100 (CET)
Subject: [pypy-commit] pypy release-2.5.x: cleanup release notice
Message-ID: <20150203190619.24A0C1C0F98@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch: release-2.5.x
Changeset: r75684:62a418bcbc7f
Date: 2015-02-03 17:28 +0200
http://bitbucket.org/pypy/pypy/changeset/62a418bcbc7f/
Log: cleanup release notice
diff --git a/pypy/doc/release-2.5.0.rst b/pypy/doc/release-2.5.0.rst
--- a/pypy/doc/release-2.5.0.rst
+++ b/pypy/doc/release-2.5.0.rst
@@ -3,7 +3,7 @@
=================================================
We're pleased to announce PyPy 2.5, which contains significant performance
-enhancements and bug fixes.
+enhancements and bug fixes.
You can download the PyPy 2.5.0 release here:
@@ -11,7 +11,7 @@
We would like to thank our donors for the continued support of the PyPy
project, and for those who donate to our three sub-projects, as well as our
-volunteers and contributors (10 new commiters joined PyPy since the last
+volunteers and contributors (10 new commiters joined PyPy since the last
release).
We've shown quite a bit of progress, but we're slowly running out of funds.
Please consider donating more, or even better convince your employer to donate,
@@ -23,13 +23,13 @@
* `STM`_ (software transactional memory): We have released a first working version,
and continue to try out new promising paths of achieving a fast multithreaded Python
-* `NumPy`_ which requires installation of our fork of upstream numpy,
+* `NumPy`_ which requires installation of our fork of upstream numpy,
available `on bitbucket`_
.. _`Py3k`: http://pypy.org/py3donate.html
.. _`STM`: http://pypy.org/tmdonate2.html
.. _`NumPy`: http://pypy.org/numpydonate.html
-.. _`on bitbucket`: https://www.bitbucket.org/pypy/numpy
+.. _`on bitbucket`: https://www.bitbucket.org/pypy/numpy
What is PyPy?
=============
@@ -38,9 +38,9 @@
CPython 2.7. It's fast (`pypy and cpython 2.7.x`_ performance comparison)
due to its integrated tracing JIT compiler.
-This release supports **x86** machines on most common operating systems
+This release supports **x86** machines on most common operating systems
(Linux 32/64, Mac OS X 64, Windows, and OpenBSD),
-as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux.
+as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux.
While we support 32 bit python on Windows, work on the native Windows 64
bit python is still stalling, we would welcome a volunteer
@@ -55,36 +55,34 @@
* The past months have seen pypy mature and grow, as rpython becomes the goto
solution for writing fast dynamic language interpreters. Our separation of
rpython and the python interpreter PyPy is now much clearer in the
- `documentation`_ .
+ `PyPy documentation`_ and we now have seperate `Rpython documentation`_.
* We have improved warmup time as well as jitted code performance: more than 10%
- compared to pypy-2.4.0, due to internal cleanup and gc nursery improvements.
+ compared to pypy-2.4.0, due to internal cleanup and gc nursery improvements.
* Our integrated numpy support gained much of the GenericUfunc api in order to
support the lapack/blas linalg module of numpy. This dovetails with work in the
pypy/numpy repository to support linalg both through the (slower) cpyext capi
interface and also via (the faster) pure python cffi interface, using an
- extended frompyfunc() api.
+ extended frompyfunc() api. We will soon post a seperate blog post specifically
+ about linalg and PyPy.
* Dictionaries are now ordered by default, see the `blog post`_
-* Issues reported with our previous release were fixed after reports from users on
- our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at
- #pypy. Here is a summary of some of the user-facing changes;
- for more information see `whats-new`_:
-
* Our nightly translations use --shared by default, including on OS/X and linux
* We now more carefully handle errno (and GetLastError, WSAGetLastError) tying
the handlers as close as possible to the external function call, in non-jitted
as well as jitted code.
-
-* Many issues were resolved_ since the 2.4.0 release in September 2014
-.. _`documentation`: http://doc.pypy.org
+* Issues reported with our previous release were resolved_ after reports from users on
+ our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at
+ #pypy.
+
+.. _`PyPy documentation`: http://doc.pypy.org
+.. _`Rpython documentation`: http://rpython.readthedocs.org
.. _`blog post`: http://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html
.. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.5.0.html
-.. _resolved: https://bitbucket.org/pypy/pypy/issues?status=resolved
We have further improvements on the way: rpython file handling,
finishing numpy linalg compatibility, numpy object dtypes, a better profiler,
@@ -96,4 +94,3 @@
Cheers
The PyPy Team
-
From noreply at buildbot.pypy.org Tue Feb 3 20:45:36 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Tue, 3 Feb 2015 20:45:36 +0100 (CET)
Subject: [pypy-commit] pypy.org extradoc: 2.5.0 release
Message-ID: <20150203194536.D91981C0F98@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch: extradoc
Changeset: r564:5072e83d9f25
Date: 2015-02-03 21:46 +0200
http://bitbucket.org/pypy/pypy.org/changeset/5072e83d9f25/
Log: 2.5.0 release
diff --git a/source/download.txt b/source/download.txt
--- a/source/download.txt
+++ b/source/download.txt
@@ -9,32 +9,31 @@
.. class:: download_menu
There are `nightly binary builds`_ available. Those builds are not always
- as stable as the release, but they contain numerous bugfixes and
+ as stable as the release, but they contain numerous bugfixes and
performance improvements. **Note that the OS X nightly builds
(but not the release) are slightly
miscompiled due to buildslave being old. Contributions are welcomed**.
We provide binaries for x86 and ARM Linux, Mac OS/X and Windows for:
-* the Python2.7 compatible release — **PyPy 2.4.0** — (`what's new in PyPy 2.4.0?`_ )
+* the Python2.7 compatible release — **PyPy 2.5.0** — (`what's new in PyPy 2.5.0?`_ )
* the Python3.2.5 compatible release — **PyPy3 2.4.0** — (`what's new in PyPy3 2.4.0?`_).
-.. _what's new in PyPy 2.4.0?: http://doc.pypy.org/en/latest/release-2.4.0.html
+.. _what's new in PyPy 2.5.0?: http://doc.pypy.org/en/latest/release-2.5.0.html
.. _what's new in PyPy3 2.4.0?: http://doc.pypy.org/en/latest/release-pypy3-2.4.0.html
-.. _what's new in PyPy 2.4?: http://doc.pypy.org/en/latest/release-2.4.0.html
.. class:: download_menu
- * Download
-
+ * Download
+
* `Default (with a JIT Compiler)`_
* `Other versions`_
* `Installing`_ (optional)
* `Installing more modules`_
* `Installing NumPy`_ (optional)
- * `Building from source`_
+ * `Building from source`_
* `Packaging`_
* `Checksums`_
@@ -72,7 +71,7 @@
.. _`portable Linux binaries`: https://github.com/squeaky-pl/portable-pypy
-Python2.7 compatible PyPy 2.4.0
+Python2.7 compatible PyPy 2.5.0
-----------------------------------
* `Linux x86 binary (32bit, tar.bz2 built on Ubuntu 12.04 - 14.04)`__ (see ``[1]`` below)
@@ -82,18 +81,22 @@
* `ARM Softfloat Linux binary (ARMEL/gnueabi, tar.bz2, Ubuntu Precise)`__ (see ``[1]`` below)
* `Mac OS/X binary (64bit)`__
* `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library
+* `Source (tar.bz2)`__
+* `Source (zip)`__
installer vcredist_x86.exe`_.)
* `All our downloads,`__ including previous versions. We also have a
mirror_, but please use only if you have troubles accessing the links above
* See below for the sources.
-.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.4.0-linux.tar.bz2
-.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.4.0-linux64.tar.bz2
-.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.4.0-linux-armhf-raspbian.tar.bz2
-.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.4.0-linux-armhf-raring.tar.bz2
-.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.4.0-linux-armel.tar.bz2
-.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.4.0-osx64.tar.bz2
-.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.4.0-win32.zip
+.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.5.0-linux.tar.bz2
+.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.5.0-linux64.tar.bz2
+.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.5.0-linux-armhf-raspbian.tar.bz2
+.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.5.0-linux-armhf-raring.tar.bz2
+.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.5.0-linux-armel.tar.bz2
+.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.5.0-osx64.tar.bz2
+.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.5.0-win32.zip
+.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.5.0-src.tar.bz2
+.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.5.0-src.zip
.. _`VS 2008 runtime library installer vcredist_x86.exe`: http://www.microsoft.com/en-us/download/details.aspx?id=5582
.. __: https://bitbucket.org/pypy/pypy/downloads
.. _mirror: http://cobra.cs.uni-duesseldorf.de/~buildmaster/mirror/
@@ -172,7 +175,7 @@
uncompressed, they run in-place. For now you can uncompress them
either somewhere in your home directory or, say, in ``/opt``, and
if you want, put a symlink from somewhere like
-``/usr/local/bin/pypy`` to ``/path/to/pypy-2.4.0/bin/pypy``. Do
+``/usr/local/bin/pypy`` to ``/path/to/pypy-2.5.0/bin/pypy``. Do
not move or copy the executable ``pypy`` outside the tree --- put
a symlink to it, otherwise it will not find its libraries.
@@ -221,9 +224,9 @@
1. Get the source code. The following packages contain the source at
the same revision as the above binaries:
- * `pypy-2.4.0-src.tar.bz2`__ (sources)
+ * `pypy-2.5.0-src.tar.bz2`__ (sources)
- .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.4.0-src.tar.bz2
+ .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.5.0-src.tar.bz2
Or you can checkout the current trunk using Mercurial_ (the trunk
usually works and is of course more up-to-date)::
@@ -297,7 +300,7 @@
cd ./pypy/pypy/tool/release/
python package.py --help #for information
- python package.py --archive-name pypy-my-own-package-name
+ python package.py --archive-name pypy-my-own-package-name
It is recommended to use package.py because custom scripts will
invariably become out-of-date. If you want to write custom scripts
@@ -317,14 +320,15 @@
Here are the checksums for each of the downloads (md5 and sha1)::
- 63bd68546f60cf5921ba7654f3fe47aa pypy-2.4.0-linux64.tar.bz2
- 6c9b444a1cd090ab7b43083a24e07734 pypy-2.4.0-linux-armel.tar.bz2
- 5ff951da5989a00e01611678c311f8af pypy-2.4.0-linux-armhf-raring.tar.bz2
- d7540883a52f91433da62b0cdfaaa30f pypy-2.4.0-linux-armhf-raspbian.tar.bz2
- 77a971f5198685ff60528de5def407dd pypy-2.4.0-linux.tar.bz2
- 907d6fbabc5bcd5bafdcf02a76a8ca33 pypy-2.4.0-win32.zip
- 6a25a212e7c5121f1f3988c118d05695 pypy-2.4.0-src.tar.bz2
- 07896c0ac37f82884e021c9a4514f479 pypy-2.4.0-osx64.tar.bz2
+
+ 0a109c96bbce20931c17dfded57a3d46 pypy-2.5.0-linux64.tar.bz2
+ fc79e0ef640371fa7bdbb040c3211bcf pypy-2.5.0-linux-armel.tar.bz2
+ d8d0fe8a1503a7ed4ec5ff52d0630b88 pypy-2.5.0-linux-armhf-raring.tar.bz2
+ 9a4430abd36dd619c45705c3fe70f5ca pypy-2.5.0-linux-armhf-raspbian.tar.bz2
+ 1c14e954fdd1d112540790ec5b0cea26 pypy-2.5.0-linux.tar.bz2
+ 9916a1485f32953a46afdd36f8f01f83 pypy-2.5.0-osx64.tar.bz2
+ f4700c0af45e986178b36ce91a45136e pypy-2.5.0-src.tar.bz2
+ 2461a4e4fe4ea64ce7fb1a07aa310e6a pypy-2.5.0-win32.zip
eadbc9790823fc0ae40c943087cd7cb3 pypy3-2.4.0-linux64.tar.bz2
7ab84727da2d5363866907f2f7921d86 pypy3-2.4.0-linux-armel.tar.bz2
@@ -339,14 +343,14 @@
2c9f0054f3b93a6473f10be35277825a pypy-1.8-sandbox-linux64.tar.bz2
009c970b5fa75754ae4c32a5d108a8d4 pypy-1.8-sandbox-linux.tar.bz2
- c362247226f1cde2b957ab5e885f41475381553b pypy-2.4.0-linux64.tar.bz2
- d542ee549ded9face573ac9fb49a23f5a5b4be60 pypy-2.4.0-linux-armel.tar.bz2
- b8e02dc381e5040e2bf50541e82f0148f9a46a48 pypy-2.4.0-linux-armhf-raring.tar.bz2
- ad65e7ddb1582b465a37090dc4a13bc37a8cd95d pypy-2.4.0-linux-armhf-raspbian.tar.bz2
- fd52b42069287ca11e816c8e18fc95f53542c73d pypy-2.4.0-linux.tar.bz2
- e2e0bcf8457c0ae5a24f126a60aa921dabfe60fb pypy-2.4.0-src.tar.bz2
- b72c3365c23c34ffd35a781fb72d8722e0b7517e pypy-2.4.0-win32.zip
- aa7f9b41d8bfda16239b629cd1b8dc884c2ad808 pypy-2.4.0-osx64.tar.bz2
+ 303bdc29e80640e337f1d65c7787870738a3ebf5 pypy-2.5.0-linux64.tar.bz2
+ 1bc8de2db37233051d84c9c27e1e64608283b67c pypy-2.5.0-linux-armel.tar.bz2
+ 01427d7dd52e2b679c38bfad414ebe676b019ea0 pypy-2.5.0-linux-armhf-raring.tar.bz2
+ e3483d52182ab3ee02f665fda02f9fac4ab40ab1 pypy-2.5.0-linux-armhf-raspbian.tar.bz2
+ 7334013255670f4ae60b316a5b35499861e0714f pypy-2.5.0-linux.tar.bz2
+ ad47285526b1b3c14f4eecc874bb82a133a8e551 pypy-2.5.0-osx64.tar.bz2
+ 1d215a22ea16581de338700d556b21a8c02b4eff pypy-2.5.0-src.tar.bz2
+ 3492aa6fe96987537b23d09d66bb0c52f1760652 pypy-2.5.0-win32.zip
7d715742f6929351b310a2ca3b924cab35913089 pypy3-2.4.0-linux64.tar.bz2
b33e817f3557f91c434032c9f74e5220fe70036c pypy3-2.4.0-linux-armel.tar.bz2
diff --git a/source/features.txt b/source/features.txt
--- a/source/features.txt
+++ b/source/features.txt
@@ -10,7 +10,7 @@
language that was co-developed with it. The main reason to use it
instead of CPython is speed: it runs generally faster (see next section).
-**PyPy 2.4** implements **Python 2.7.8** and runs on Intel
+**PyPy 2.5** implements **Python 2.7.8** and runs on Intel
`x86 (IA-32)`_ , `x86_64`_ and `ARM`_ platforms, with PPC being
stalled. It supports all of the core language, passing the Python test suite
(with minor modifications that were already accepted in the main python
From noreply at buildbot.pypy.org Tue Feb 3 21:31:38 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Tue, 3 Feb 2015 21:31:38 +0100 (CET)
Subject: [pypy-commit] pypy default: merge release-2.5.x into default to get
documentation updates
Message-ID: <20150203203138.3BFD01C114E@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch:
Changeset: r75685:22ce6f3699f0
Date: 2015-02-03 21:48 +0200
http://bitbucket.org/pypy/pypy/changeset/22ce6f3699f0/
Log: merge release-2.5.x into default to get documentation updates
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -42,19 +42,19 @@
Amaury Forgeot d'Arc
Samuele Pedroni
Alex Gaynor
+ Brian Kearns
+ Matti Picus
+ Philip Jenvey
Michael Hudson
David Schneider
- Matti Picus
- Brian Kearns
- Philip Jenvey
Holger Krekel
Christian Tismer
Hakan Ardo
Benjamin Peterson
Manuel Jacob
+ Ronan Lamy
Anders Chrigstrom
Eric van Riet Paap
- Ronan Lamy
Wim Lavrijsen
Richard Emslie
Alexander Schremmer
@@ -68,9 +68,9 @@
Camillo Bruni
Laura Creighton
Toon Verwaest
+ Romain Guillebert
Leonardo Santagada
Seo Sanghyeon
- Romain Guillebert
Justin Peel
Ronny Pfannschmidt
David Edelsohn
@@ -91,15 +91,16 @@
Michal Bendowski
Jan de Mooij
stian
+ Tyler Wade
Michael Foord
Stephan Diehl
- Tyler Wade
Stefan Schwarzer
Valentino Volonghi
Tomek Meka
Patrick Maupin
Bob Ippolito
Bruno Gola
+ David Malcolm
Jean-Paul Calderone
Timo Paulssen
Squeaky
@@ -108,18 +109,19 @@
Marius Gedminas
Martin Matusiak
Konstantin Lopuhin
+ Wenzhu Man
John Witulski
- Wenzhu Man
+ Laurence Tratt
+ Ivan Sichmann Freitas
Greg Price
Dario Bertini
Mark Pearse
Simon Cross
- Ivan Sichmann Freitas
Andreas Stührk
+ Stefano Rivera
Jean-Philippe St. Pierre
Guido van Rossum
Pavel Vinogradov
- Stefano Rivera
Paweł Piotr Przeradowski
Paul deGrandis
Ilya Osadchiy
@@ -129,7 +131,6 @@
tav
Taavi Burns
Georg Brandl
- Laurence Tratt
Bert Freudenberg
Stian Andreassen
Wanja Saatkamp
@@ -141,13 +142,12 @@
Jeremy Thurgood
Rami Chowdhury
Tobias Pape
- David Malcolm
Eugene Oden
Henry Mason
Vasily Kuznetsov
Preston Timmons
+ David Ripton
Jeff Terrace
- David Ripton
Dusty Phillips
Lukas Renggli
Guenter Jantzen
@@ -166,13 +166,16 @@
Gintautas Miliauskas
Michael Twomey
Lucian Branescu Mihaila
+ Yichao Yu
Gabriel Lavoie
Olivier Dormond
Jared Grubb
Karl Bartel
+ Wouter van Heyst
Brian Dorsey
Victor Stinner
Andrews Medina
+ anatoly techtonik
Stuart Williams
Jasper Schulz
Christian Hudon
@@ -182,12 +185,11 @@
Michael Cheng
Justas Sadzevicius
Gasper Zejn
- anatoly techtonik
Neil Shepperd
+ Stanislaw Halik
Mikael Schönenberg
Elmo M?ntynen
Jonathan David Riehl
- Stanislaw Halik
Anders Qvist
Corbin Simpson
Chirag Jadwani
@@ -196,10 +198,13 @@
Vincent Legoll
Alan McIntyre
Alexander Sedov
+ Attila Gobi
Christopher Pope
Christian Tismer
Marc Abramowitz
Dan Stromberg
+ Arjun Naik
+ Valentina Mukhamedzhanova
Stefano Parmesan
Alexis Daboville
Jens-Uwe Mager
@@ -213,8 +218,6 @@
Sylvain Thenault
Nathan Taylor
Vladimir Kryachko
- Arjun Naik
- Attila Gobi
Jacek Generowicz
Alejandro J. Cura
Jacob Oscarson
@@ -222,22 +225,23 @@
Ryan Gonzalez
Ian Foote
Kristjan Valur Jonsson
+ David Lievens
Neil Blakey-Milner
Lutz Paelike
Lucio Torre
Lars Wassermann
- Valentina Mukhamedzhanova
Henrik Vendelbo
Dan Buch
Miguel de Val Borro
Artur Lisiecki
Sergey Kishchenko
- Yichao Yu
Ignas Mikalajunas
Christoph Gerum
Martin Blais
Lene Wagner
Tomo Cocoa
+ Toni Mattis
+ Lucas Stadler
roberto at goyle
Yury V. Zaytsev
Anna Katrina Dominguez
@@ -265,23 +269,30 @@
Stephan Busemann
Rafał Gałczyński
Christian Muirhead
+ Berker Peksag
James Lan
shoma hosaka
- Daniel Neuh?user
- Matthew Miller
+ Daniel Neuhäuser
+ Ben Mather
+ halgari
+ Boglarka Vezer
+ Chris Pressey
Buck Golemon
Konrad Delong
Dinu Gherman
Chris Lambacher
coolbutuseless at gmail.com
+ Jim Baker
Rodrigo Araújo
- Jim Baker
+ Nikolaos-Digenis Karagiannis
James Robert
Armin Ronacher
Brett Cannon
+ Donald Stufft
yrttyr
aliceinwire
OlivierBlanvillain
+ Dan Sanders
Zooko Wilcox-O Hearn
Tomer Chachamu
Christopher Groskopf
@@ -295,6 +306,7 @@
Markus Unterwaditzer
Even Wiik Thomassen
jbs
+ squeaky
soareschen
Kurt Griffiths
Mike Bayer
@@ -306,6 +318,7 @@
Anna Ravencroft
Dan Crosta
Julien Phalip
+ Roman Podoliaka
Dan Loewenherz
Heinrich-Heine University, Germany
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -65,9 +65,9 @@
# built documents.
#
# The short X.Y version.
-version = '2.4'
+version = '2.5'
# The full version, including alpha/beta/rc tags.
-release = '2.4.0'
+release = '2.5.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst
--- a/pypy/doc/contributor.rst
+++ b/pypy/doc/contributor.rst
@@ -12,19 +12,19 @@
Amaury Forgeot d'Arc
Samuele Pedroni
Alex Gaynor
+ Brian Kearns
+ Matti Picus
+ Philip Jenvey
Michael Hudson
David Schneider
- Matti Picus
- Brian Kearns
- Philip Jenvey
Holger Krekel
Christian Tismer
Hakan Ardo
Benjamin Peterson
Manuel Jacob
+ Ronan Lamy
Anders Chrigstrom
Eric van Riet Paap
- Ronan Lamy
Wim Lavrijsen
Richard Emslie
Alexander Schremmer
@@ -38,9 +38,9 @@
Camillo Bruni
Laura Creighton
Toon Verwaest
+ Romain Guillebert
Leonardo Santagada
Seo Sanghyeon
- Romain Guillebert
Justin Peel
Ronny Pfannschmidt
David Edelsohn
@@ -61,15 +61,16 @@
Michal Bendowski
Jan de Mooij
stian
+ Tyler Wade
Michael Foord
Stephan Diehl
- Tyler Wade
Stefan Schwarzer
Valentino Volonghi
Tomek Meka
Patrick Maupin
Bob Ippolito
Bruno Gola
+ David Malcolm
Jean-Paul Calderone
Timo Paulssen
Squeaky
@@ -78,18 +79,19 @@
Marius Gedminas
Martin Matusiak
Konstantin Lopuhin
+ Wenzhu Man
John Witulski
- Wenzhu Man
+ Laurence Tratt
+ Ivan Sichmann Freitas
Greg Price
Dario Bertini
Mark Pearse
Simon Cross
- Ivan Sichmann Freitas
Andreas Stührk
+ Stefano Rivera
Jean-Philippe St. Pierre
Guido van Rossum
Pavel Vinogradov
- Stefano Rivera
Paweł Piotr Przeradowski
Paul deGrandis
Ilya Osadchiy
@@ -99,7 +101,6 @@
tav
Taavi Burns
Georg Brandl
- Laurence Tratt
Bert Freudenberg
Stian Andreassen
Wanja Saatkamp
@@ -111,13 +112,12 @@
Jeremy Thurgood
Rami Chowdhury
Tobias Pape
- David Malcolm
Eugene Oden
Henry Mason
Vasily Kuznetsov
Preston Timmons
+ David Ripton
Jeff Terrace
- David Ripton
Dusty Phillips
Lukas Renggli
Guenter Jantzen
@@ -136,13 +136,16 @@
Gintautas Miliauskas
Michael Twomey
Lucian Branescu Mihaila
+ Yichao Yu
Gabriel Lavoie
Olivier Dormond
Jared Grubb
Karl Bartel
+ Wouter van Heyst
Brian Dorsey
Victor Stinner
Andrews Medina
+ anatoly techtonik
Stuart Williams
Jasper Schulz
Christian Hudon
@@ -152,12 +155,11 @@
Michael Cheng
Justas Sadzevicius
Gasper Zejn
- anatoly techtonik
Neil Shepperd
+ Stanislaw Halik
Mikael Schönenberg
Elmo M?ntynen
Jonathan David Riehl
- Stanislaw Halik
Anders Qvist
Corbin Simpson
Chirag Jadwani
@@ -166,10 +168,13 @@
Vincent Legoll
Alan McIntyre
Alexander Sedov
+ Attila Gobi
Christopher Pope
Christian Tismer
Marc Abramowitz
Dan Stromberg
+ Arjun Naik
+ Valentina Mukhamedzhanova
Stefano Parmesan
Alexis Daboville
Jens-Uwe Mager
@@ -183,8 +188,6 @@
Sylvain Thenault
Nathan Taylor
Vladimir Kryachko
- Arjun Naik
- Attila Gobi
Jacek Generowicz
Alejandro J. Cura
Jacob Oscarson
@@ -192,22 +195,23 @@
Ryan Gonzalez
Ian Foote
Kristjan Valur Jonsson
+ David Lievens
Neil Blakey-Milner
Lutz Paelike
Lucio Torre
Lars Wassermann
- Valentina Mukhamedzhanova
Henrik Vendelbo
Dan Buch
Miguel de Val Borro
Artur Lisiecki
Sergey Kishchenko
- Yichao Yu
Ignas Mikalajunas
Christoph Gerum
Martin Blais
Lene Wagner
Tomo Cocoa
+ Toni Mattis
+ Lucas Stadler
roberto at goyle
Yury V. Zaytsev
Anna Katrina Dominguez
@@ -235,23 +239,30 @@
Stephan Busemann
Rafał Gałczyński
Christian Muirhead
+ Berker Peksag
James Lan
shoma hosaka
- Daniel Neuh?user
- Matthew Miller
+ Daniel Neuhäuser
+ Ben Mather
+ halgari
+ Boglarka Vezer
+ Chris Pressey
Buck Golemon
Konrad Delong
Dinu Gherman
Chris Lambacher
coolbutuseless at gmail.com
+ Jim Baker
Rodrigo Araújo
- Jim Baker
+ Nikolaos-Digenis Karagiannis
James Robert
Armin Ronacher
Brett Cannon
+ Donald Stufft
yrttyr
aliceinwire
OlivierBlanvillain
+ Dan Sanders
Zooko Wilcox-O Hearn
Tomer Chachamu
Christopher Groskopf
@@ -265,6 +276,7 @@
Markus Unterwaditzer
Even Wiik Thomassen
jbs
+ squeaky
soareschen
Kurt Griffiths
Mike Bayer
@@ -276,5 +288,6 @@
Anna Ravencroft
Dan Crosta
Julien Phalip
+ Roman Podoliaka
Dan Loewenherz
diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst
--- a/pypy/doc/how-to-release.rst
+++ b/pypy/doc/how-to-release.rst
@@ -22,12 +22,12 @@
will capture the revision number of this change for the release;
some of the next updates may be done before or after branching; make
sure things are ported back to the trunk and to the branch as
- necessary; also update the version number in pypy/doc/conf.py,
- and in pypy/doc/index.rst
+ necessary; also update the version number in pypy/doc/conf.py.
* update pypy/doc/contributor.rst (and possibly LICENSE)
pypy/doc/tool/makecontributor.py generates the list of contributors
* rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst
- and create a fresh whatsnew_head.rst after the release
+ create a fresh whatsnew_head.rst after the release
+ and add the new file to pypy/doc/index-of-whatsnew.rst
* go to pypy/tool/release and run:
force-builds.py
* wait for builds to complete, make sure there are no failures
@@ -45,6 +45,7 @@
* write release announcement pypy/doc/release-x.y(.z).txt
the release announcement should contain a direct link to the download page
+ and add new files to pypy/doc/index-of-release-notes.rst
* update pypy.org (under extradoc/pypy.org), rebuild and commit
* post announcement on morepypy.blogspot.com
diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst
--- a/pypy/doc/index-of-release-notes.rst
+++ b/pypy/doc/index-of-release-notes.rst
@@ -6,6 +6,7 @@
.. toctree::
+ release-2.5.0.rst
release-2.4.0.rst
release-2.3.1.rst
release-2.3.0.rst
diff --git a/pypy/doc/index-of-whatsnew.rst b/pypy/doc/index-of-whatsnew.rst
--- a/pypy/doc/index-of-whatsnew.rst
+++ b/pypy/doc/index-of-whatsnew.rst
@@ -7,6 +7,7 @@
.. toctree::
whatsnew-head.rst
+ whatsnew-2.5.0.rst
whatsnew-2.4.0.rst
whatsnew-2.3.1.rst
whatsnew-2.3.0.rst
diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst
--- a/pypy/doc/project-ideas.rst
+++ b/pypy/doc/project-ideas.rst
@@ -191,3 +191,37 @@
to make them work at all if they currently don't. A part of this work would
be to get cpyext into a shape where it supports running Cython generated
extensions.
+
+======================================
+Make more python modules pypy-friendly
+======================================
+
+Work has been started on a few popular python packages. Here is a partial
+list of good work that needs to be finished:
+
+**matplotlib** https://github.com/mattip/matplotlib
+
+ Status: the repo is an older version of matplotlib adapted to pypy and cpyext
+
+ TODO: A suggested first step would be to merge the differences into
+ matplotlib/HEAD. The major problem is the use of a generic view into a
+ numpy ndarray. The int* fields would need to be converted into int[MAX_DIMS]
+ c-arrays and filled in.
+
+**wxPython** https://bitbucket.org/waedt/wxpython_cffi
+
+ Status: A GSOC 2013 project to adapt the Phoenix sip build system to cffi
+
+ TODO: Merge the latest version of the wrappers and finish the sip conversion
+
+**pygame** https://github.com/CTPUG/pygame_cffi
+
+ Status: see blog post
+
+ TODO: see the end of the blog post
+
+**pyopengl** https://bitbucket.org/duangle/pyopengl-cffi
+
+ Status: unknown
+
+
diff --git a/pypy/doc/release-2.5.0.rst b/pypy/doc/release-2.5.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-2.5.0.rst
@@ -0,0 +1,96 @@
+=================================================
+PyPy 2.5 - XXXXXX
+=================================================
+
+We're pleased to announce PyPy 2.5, which contains significant performance
+enhancements and bug fixes.
+
+You can download the PyPy 2.5.0 release here:
+
+ http://pypy.org/download.html
+
+We would like to thank our donors for the continued support of the PyPy
+project, and for those who donate to our three sub-projects, as well as our
+volunteers and contributors (10 new commiters joined PyPy since the last
+release).
+We've shown quite a bit of progress, but we're slowly running out of funds.
+Please consider donating more, or even better convince your employer to donate,
+so we can finish those projects! The three sub-projects are:
+
+* `Py3k`_ (supporting Python 3.x): We have released a Python 3.2.5 compatible version
+ we call PyPy3 2.4.0, and are working toward a Python 3.3 compatible version
+
+* `STM`_ (software transactional memory): We have released a first working version,
+ and continue to try out new promising paths of achieving a fast multithreaded Python
+
+* `NumPy`_ which requires installation of our fork of upstream numpy,
+ available `on bitbucket`_
+
+.. _`Py3k`: http://pypy.org/py3donate.html
+.. _`STM`: http://pypy.org/tmdonate2.html
+.. _`NumPy`: http://pypy.org/numpydonate.html
+.. _`on bitbucket`: https://www.bitbucket.org/pypy/numpy
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy and cpython 2.7.x`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports **x86** machines on most common operating systems
+(Linux 32/64, Mac OS X 64, Windows, and OpenBSD),
+as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux.
+
+While we support 32 bit python on Windows, work on the native Windows 64
+bit python is still stalling, we would welcome a volunteer
+to `handle that`_.
+
+.. _`pypy and cpython 2.7.x`: http://speed.pypy.org
+.. _`handle that`: http://doc.pypy.org/en/latest/windows.html#what-is-missing-for-a-full-64-bit-translation
+
+Highlights
+==========
+
+* The past months have seen pypy mature and grow, as rpython becomes the goto
+ solution for writing fast dynamic language interpreters. Our separation of
+ rpython and the python interpreter PyPy is now much clearer in the
+ `PyPy documentation`_ and we now have seperate `Rpython documentation`_.
+
+* We have improved warmup time as well as jitted code performance: more than 10%
+ compared to pypy-2.4.0, due to internal cleanup and gc nursery improvements.
+
+* Our integrated numpy support gained much of the GenericUfunc api in order to
+ support the lapack/blas linalg module of numpy. This dovetails with work in the
+ pypy/numpy repository to support linalg both through the (slower) cpyext capi
+ interface and also via (the faster) pure python cffi interface, using an
+ extended frompyfunc() api. We will soon post a seperate blog post specifically
+ about linalg and PyPy.
+
+* Dictionaries are now ordered by default, see the `blog post`_
+
+* Our nightly translations use --shared by default, including on OS/X and linux
+
+* We now more carefully handle errno (and GetLastError, WSAGetLastError) tying
+ the handlers as close as possible to the external function call, in non-jitted
+ as well as jitted code.
+
+* Issues reported with our previous release were resolved_ after reports from users on
+ our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at
+ #pypy.
+
+.. _`PyPy documentation`: http://doc.pypy.org
+.. _`Rpython documentation`: http://rpython.readthedocs.org
+.. _`blog post`: http://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html
+.. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.5.0.html
+
+We have further improvements on the way: rpython file handling,
+finishing numpy linalg compatibility, numpy object dtypes, a better profiler,
+as well as support for Python stdlib 2.7.9.
+
+Please try it out and let us know what you think. We especially welcome
+success stories, we know you are using PyPy, please tell us about it!
+
+Cheers
+
+The PyPy Team
diff --git a/pypy/doc/whatsnew-2.5.0.rst b/pypy/doc/whatsnew-2.5.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/whatsnew-2.5.0.rst
@@ -0,0 +1,139 @@
+=======================
+What's new in PyPy 2.5
+=======================
+
+.. this is a revision shortly after release-2.4.x
+.. startrev: 7026746cbb1b
+
+.. branch: win32-fixes5
+
+Fix c code generation for msvc so empty "{ }" are avoided in unions,
+Avoid re-opening files created with NamedTemporaryFile,
+Allocate by 4-byte chunks in rffi_platform,
+Skip testing objdump if it does not exist,
+and other small adjustments in own tests
+
+.. branch: rtyper-stuff
+
+Small internal refactorings in the rtyper.
+
+.. branch: var-in-Some
+
+Store annotations on the Variable objects, rather than in a big dict.
+Introduce a new framework for double-dispatched annotation implementations.
+
+.. branch: ClassRepr
+
+Refactor ClassRepr and make normalizecalls independent of the rtyper.
+
+.. branch: remove-remaining-smm
+
+Remove all remaining multimethods.
+
+.. branch: improve-docs
+
+Split RPython documentation from PyPy documentation and clean up. There now is
+a clearer separation between documentation for users, developers and people
+interested in background information.
+
+.. branch: kill-multimethod
+
+Kill multimethod machinery, all multimethods were removed earlier.
+
+.. branch nditer-external_loop
+
+Implement `external_loop` arguement to numpy's nditer
+
+.. branch kill-rctime
+
+Rename pypy/module/rctime to pypy/module/time, since it contains the implementation of the 'time' module.
+
+.. branch: ssa-flow
+
+Use SSA form for flow graphs inside build_flow() and part of simplify_graph()
+
+.. branch: ufuncapi
+
+Implement most of the GenericUfunc api to support numpy linalg. The strategy is
+to encourage use of pure python or cffi ufuncs by extending frompyfunc().
+See the docstring of frompyfunc for more details. This dovetails with a branch
+of pypy/numpy - cffi-linalg which is a rewrite of the _umath_linalg module in
+python, calling lapack from cffi. The branch also support traditional use of
+cpyext GenericUfunc definitions in c.
+
+.. branch: all_ordered_dicts
+
+This makes ordered dicts the default dictionary implementation in
+RPython and in PyPy. It polishes the basic idea of rordereddict.py
+and then fixes various things, up to simplifying
+collections.OrderedDict.
+
+Note: Python programs can rely on the guaranteed dict order in PyPy
+now, but for compatibility with other Python implementations they
+should still use collections.OrderedDict where that really matters.
+Also, support for reversed() was *not* added to the 'dict' class;
+use OrderedDict.
+
+Benchmark results: in the noise. A few benchmarks see good speed
+improvements but the average is very close to parity.
+
+.. branch: berkerpeksag/fix-broken-link-in-readmerst-1415127402066
+.. branch: bigint-with-int-ops
+.. branch: dstufft/update-pip-bootstrap-location-to-the-new-1420760611527
+.. branch: float-opt
+.. branch: gc-incminimark-pinning
+
+This branch adds an interface rgc.pin which would (very temporarily)
+make object non-movable. That's used by rffi.alloc_buffer and
+rffi.get_nonmovable_buffer and improves performance considerably for
+IO operations.
+
+.. branch: gc_no_cleanup_nursery
+
+A branch started by Wenzhu Man (SoC'14) and then done by fijal. It
+removes the clearing of the nursery. The drawback is that new objects
+are not automatically filled with zeros any longer, which needs some
+care, mostly for GC references (which the GC tries to follow, so they
+must not contain garbage). The benefit is a quite large speed-up.
+
+.. branch: improve-gc-tracing-hooks
+.. branch: improve-ptr-conv-error
+.. branch: intern-not-immortal
+
+Fix intern() to return mortal strings, like in CPython.
+
+.. branch: issue1922-take2
+.. branch: kill-exported-symbols-list
+.. branch: kill-rctime
+.. branch: kill_ll_termios
+.. branch: look-into-all-modules
+.. branch: nditer-external_loop
+.. branch: numpy-generic-item
+.. branch: osx-shared
+
+``--shared`` support on OS/X (thanks wouter)
+
+.. branch: portable-threadlocal
+.. branch: pypy-dont-copy-ops
+.. branch: recursion_and_inlining
+.. branch: slim-down-resumedescr
+.. branch: squeaky/use-cflags-for-compiling-asm
+.. branch: unicode-fix
+.. branch: zlib_zdict
+
+.. branch: errno-again
+
+Changes how errno, GetLastError, and WSAGetLastError are handled.
+The idea is to tie reading the error status as close as possible to
+the external function call. This fixes some bugs, both of the very
+rare kind (e.g. errno on Linux might in theory be overwritten by
+mmap(), called rarely during major GCs, if such a major GC occurs at
+exactly the wrong time), and some of the less rare kind
+(particularly on Windows tests).
+
+.. branch: osx-package.py
+.. branch: package.py-helpful-error-message
+
+.. branch: typed-cells
+
+Improve performance of integer globals and class attributes.
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -2,138 +2,6 @@
What's new in PyPy 2.5+
=======================
-.. this is a revision shortly after release-2.4.x
-.. startrev: 7026746cbb1b
+.. this is a revision shortly after release-2.5.x
+.. startrev: 397b96217b85
-.. branch: win32-fixes5
-
-Fix c code generation for msvc so empty "{ }" are avoided in unions,
-Avoid re-opening files created with NamedTemporaryFile,
-Allocate by 4-byte chunks in rffi_platform,
-Skip testing objdump if it does not exist,
-and other small adjustments in own tests
-
-.. branch: rtyper-stuff
-
-Small internal refactorings in the rtyper.
-
-.. branch: var-in-Some
-
-Store annotations on the Variable objects, rather than in a big dict.
-Introduce a new framework for double-dispatched annotation implementations.
-
-.. branch: ClassRepr
-
-Refactor ClassRepr and make normalizecalls independent of the rtyper.
-
-.. branch: remove-remaining-smm
-
-Remove all remaining multimethods.
-
-.. branch: improve-docs
-
-Split RPython documentation from PyPy documentation and clean up. There now is
-a clearer separation between documentation for users, developers and people
-interested in background information.
-
-.. branch: kill-multimethod
-
-Kill multimethod machinery, all multimethods were removed earlier.
-
-.. branch nditer-external_loop
-
-Implement `external_loop` arguement to numpy's nditer
-
-.. branch kill-rctime
-
-Rename pypy/module/rctime to pypy/module/time, since it contains the implementation of the 'time' module.
-
-.. branch: ssa-flow
-
-Use SSA form for flow graphs inside build_flow() and part of simplify_graph()
-
-.. branch: ufuncapi
-
-Implement most of the GenericUfunc api to support numpy linalg. The strategy is
-to encourage use of pure python or cffi ufuncs by extending frompyfunc().
-See the docstring of frompyfunc for more details. This dovetails with a branch
-of pypy/numpy - cffi-linalg which is a rewrite of the _umath_linalg module in
-python, calling lapack from cffi. The branch also support traditional use of
-cpyext GenericUfunc definitions in c.
-
-.. branch: all_ordered_dicts
-
-This makes ordered dicts the default dictionary implementation in
-RPython and in PyPy. It polishes the basic idea of rordereddict.py
-and then fixes various things, up to simplifying
-collections.OrderedDict.
-
-Note: Python programs can rely on the guaranteed dict order in PyPy
-now, but for compatibility with other Python implementations they
-should still use collections.OrderedDict where that really matters.
-Also, support for reversed() was *not* added to the 'dict' class;
-use OrderedDict.
-
-Benchmark results: in the noise. A few benchmarks see good speed
-improvements but the average is very close to parity.
-
-.. branch: berkerpeksag/fix-broken-link-in-readmerst-1415127402066
-.. branch: bigint-with-int-ops
-.. branch: dstufft/update-pip-bootstrap-location-to-the-new-1420760611527
-.. branch: float-opt
-.. branch: gc-incminimark-pinning
-
-This branch adds an interface rgc.pin which would (very temporarily)
-make object non-movable. That's used by rffi.alloc_buffer and
-rffi.get_nonmovable_buffer and improves performance considerably for
-IO operations.
-
-.. branch: gc_no_cleanup_nursery
-
-A branch started by Wenzhu Man (SoC'14) and then done by fijal. It
-removes the clearing of the nursery. The drawback is that new objects
-are not automatically filled with zeros any longer, which needs some
-care, mostly for GC references (which the GC tries to follow, so they
-must not contain garbage). The benefit is a quite large speed-up.
-
-.. branch: improve-gc-tracing-hooks
-.. branch: improve-ptr-conv-error
-.. branch: intern-not-immortal
-
-Fix intern() to return mortal strings, like in CPython.
-
-.. branch: issue1922-take2
-.. branch: kill-exported-symbols-list
-.. branch: kill-rctime
-.. branch: kill_ll_termios
-.. branch: look-into-all-modules
-.. branch: nditer-external_loop
-.. branch: numpy-generic-item
-.. branch: osx-shared
-
-``--shared`` support on OS/X (thanks wouter)
-
-.. branch: portable-threadlocal
-.. branch: pypy-dont-copy-ops
-.. branch: recursion_and_inlining
-.. branch: slim-down-resumedescr
-.. branch: squeaky/use-cflags-for-compiling-asm
-.. branch: unicode-fix
-.. branch: zlib_zdict
-
-.. branch: errno-again
-
-Changes how errno, GetLastError, and WSAGetLastError are handled.
-The idea is to tie reading the error status as close as possible to
-the external function call. This fixes some bugs, both of the very
-rare kind (e.g. errno on Linux might in theory be overwritten by
-mmap(), called rarely during major GCs, if such a major GC occurs at
-exactly the wrong time), and some of the less rare kind
-(particularly on Windows tests).
-
-.. branch: osx-package.py
-.. branch: package.py-helpful-error-message
-
-.. branch: typed-cells
-
-Improve performance of integer globals and class attributes.
diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h
--- a/pypy/module/cpyext/include/patchlevel.h
+++ b/pypy/module/cpyext/include/patchlevel.h
@@ -29,7 +29,7 @@
#define PY_VERSION "2.7.8"
/* PyPy version as a string */
-#define PYPY_VERSION "2.6.0-alpha0"
+#define PYPY_VERSION "2.5.0"
/* Subversion Revision number of this file (not of the repository).
* Empty since Mercurial migration. */
diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py
--- a/pypy/module/sys/version.py
+++ b/pypy/module/sys/version.py
@@ -10,7 +10,7 @@
#XXX # sync CPYTHON_VERSION with patchlevel.h, package.py
CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h
-PYPY_VERSION = (2, 6, 0, "alpha", 0) #XXX # sync patchlevel.h
+PYPY_VERSION = (2, 5, 0, "final", 0) #XXX # sync patchlevel.h
if platform.name == 'msvc':
COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600)
From noreply at buildbot.pypy.org Tue Feb 3 21:31:39 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Tue, 3 Feb 2015 21:31:39 +0100 (CET)
Subject: [pypy-commit] pypy default: tweak 2.5.0 release notice
Message-ID: <20150203203139.5BBCF1C114E@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch:
Changeset: r75686:d924ae5db23e
Date: 2015-02-03 22:32 +0200
http://bitbucket.org/pypy/pypy/changeset/d924ae5db23e/
Log: tweak 2.5.0 release notice
diff --git a/pypy/doc/release-2.5.0.rst b/pypy/doc/release-2.5.0.rst
--- a/pypy/doc/release-2.5.0.rst
+++ b/pypy/doc/release-2.5.0.rst
@@ -1,6 +1,6 @@
-=================================================
-PyPy 2.5 - XXXXXX
-=================================================
+==============================
+PyPy 2.5.0 - Protea Pincushion
+==============================
We're pleased to announce PyPy 2.5, which contains significant performance
enhancements and bug fixes.
@@ -59,6 +59,10 @@
* We have improved warmup time as well as jitted code performance: more than 10%
compared to pypy-2.4.0, due to internal cleanup and gc nursery improvements.
+ We no longer zero-out memory allocated in the gc nursery by default.
+
+* IO operations got a performance boost by adding a pinning interface that is
+ used by rffi.alloc_buffer and rff.get_nonmovablebuffer.
* Our integrated numpy support gained much of the GenericUfunc api in order to
support the lapack/blas linalg module of numpy. This dovetails with work in the
From noreply at buildbot.pypy.org Tue Feb 3 21:41:12 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Tue, 3 Feb 2015 21:41:12 +0100 (CET)
Subject: [pypy-commit] pypy default: Added tag release-2.5.0 for changeset
62a418bcbc7f
Message-ID: <20150203204112.820F61C0F98@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch:
Changeset: r75688:94feb5506033
Date: 2015-02-03 22:41 +0200
http://bitbucket.org/pypy/pypy/changeset/94feb5506033/
Log: Added tag release-2.5.0 for changeset 62a418bcbc7f
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -14,3 +14,4 @@
32f35069a16d819b58c1b6efb17c44e3e53397b2 release-2.3.1
32f35069a16d819b58c1b6efb17c44e3e53397b2 release-2.2=3.1
0000000000000000000000000000000000000000 release-2.2=3.1
+62a418bcbc7ffc542136569cec30373c5cbe7fb1 release-2.5.0
From noreply at buildbot.pypy.org Tue Feb 3 21:45:55 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Tue, 3 Feb 2015 21:45:55 +0100 (CET)
Subject: [pypy-commit] pypy default: spelling (camara)
Message-ID: <20150203204555.3C7A51C114E@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch:
Changeset: r75689:84a627b39a2c
Date: 2015-02-03 22:46 +0200
http://bitbucket.org/pypy/pypy/changeset/84a627b39a2c/
Log: spelling (camara)
diff --git a/pypy/doc/release-2.5.0.rst b/pypy/doc/release-2.5.0.rst
--- a/pypy/doc/release-2.5.0.rst
+++ b/pypy/doc/release-2.5.0.rst
@@ -63,7 +63,7 @@
was started during a GSoC.
* IO operations got a performance boost by adding a **pinning** interface that is
- used by rffi.alloc_buffer and rff.get_nonmovablebuffer.
+ used by rffi.alloc_buffer and rffi.get_nonmovablebuffer.
* Our integrated numpy support gained much of the GenericUfunc api in order to
support the lapack/blas linalg module of numpy. This dovetails with work in the
From noreply at buildbot.pypy.org Tue Feb 3 21:58:27 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Tue, 3 Feb 2015 21:58:27 +0100 (CET)
Subject: [pypy-commit] pypy default: rework pinning description
Message-ID: <20150203205827.7FA1E1C114F@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch:
Changeset: r75690:e781f33da96b
Date: 2015-02-03 22:59 +0200
http://bitbucket.org/pypy/pypy/changeset/e781f33da96b/
Log: rework pinning description
diff --git a/pypy/doc/release-2.5.0.rst b/pypy/doc/release-2.5.0.rst
--- a/pypy/doc/release-2.5.0.rst
+++ b/pypy/doc/release-2.5.0.rst
@@ -62,8 +62,11 @@
We no longer zero-out memory allocated in the gc nursery by default, work that
was started during a GSoC.
-* IO operations got a performance boost by adding a **pinning** interface that is
- used by rffi.alloc_buffer and rffi.get_nonmovablebuffer.
+* Passing objects between C and PyPy has been improved. We are now able to pass
+ raw pointers to C (without copying) using **pinning**. This improves I/O;
+ benchmarks that use networking intensively improved by about 50%. File()
+ operations still need some refactoring but are already showing a 20%
+ improvement on our benchmarks. Let us know if you see similar improvements.
* Our integrated numpy support gained much of the GenericUfunc api in order to
support the lapack/blas linalg module of numpy. This dovetails with work in the
From noreply at buildbot.pypy.org Tue Feb 3 22:01:00 2015
From: noreply at buildbot.pypy.org (arigo)
Date: Tue, 3 Feb 2015 22:01:00 +0100 (CET)
Subject: [pypy-commit] pypy default: fix capitalization
Message-ID: <20150203210100.7CAB81C114F@cobra.cs.uni-duesseldorf.de>
Author: Armin Rigo
Branch:
Changeset: r75691:6f31bff804a9
Date: 2015-02-03 22:00 +0100
http://bitbucket.org/pypy/pypy/changeset/6f31bff804a9/
Log: fix capitalization
diff --git a/pypy/doc/release-2.5.0.rst b/pypy/doc/release-2.5.0.rst
--- a/pypy/doc/release-2.5.0.rst
+++ b/pypy/doc/release-2.5.0.rst
@@ -55,7 +55,7 @@
* The past months have seen pypy mature and grow, as rpython becomes the goto
solution for writing fast dynamic language interpreters. Our separation of
rpython and the python interpreter PyPy is now much clearer in the
- `PyPy documentation`_ and we now have seperate `Rpython documentation`_.
+ `PyPy documentation`_ and we now have seperate `RPython documentation`_.
* We have improved warmup time as well as jitted code performance: more than 10%
compared to pypy-2.4.0, due to internal cleanup and gc nursery improvements.
@@ -88,7 +88,7 @@
#pypy.
.. _`PyPy documentation`: http://doc.pypy.org
-.. _`Rpython documentation`: http://rpython.readthedocs.org
+.. _`RPython documentation`: http://rpython.readthedocs.org
.. _`blog post`: http://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html
.. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.5.0.html
From noreply at buildbot.pypy.org Tue Feb 3 22:09:03 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Tue, 3 Feb 2015 22:09:03 +0100 (CET)
Subject: [pypy-commit] pypy default: Removed tag release-2.5.0
Message-ID: <20150203210903.7732A1C0820@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch:
Changeset: r75692:55d23c7d8a2c
Date: 2015-02-03 23:03 +0200
http://bitbucket.org/pypy/pypy/changeset/55d23c7d8a2c/
Log: Removed tag release-2.5.0
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -15,3 +15,5 @@
32f35069a16d819b58c1b6efb17c44e3e53397b2 release-2.2=3.1
0000000000000000000000000000000000000000 release-2.2=3.1
62a418bcbc7ffc542136569cec30373c5cbe7fb1 release-2.5.0
+62a418bcbc7ffc542136569cec30373c5cbe7fb1 release-2.5.0
+0000000000000000000000000000000000000000 release-2.5.0
From noreply at buildbot.pypy.org Tue Feb 3 22:09:04 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Tue, 3 Feb 2015 22:09:04 +0100 (CET)
Subject: [pypy-commit] pypy default: Added tag release-2.5.0 for changeset
10f1b29a2bd2
Message-ID: <20150203210904.945201C0820@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch:
Changeset: r75693:063a74d884c9
Date: 2015-02-03 23:03 +0200
http://bitbucket.org/pypy/pypy/changeset/063a74d884c9/
Log: Added tag release-2.5.0 for changeset 10f1b29a2bd2
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -17,3 +17,5 @@
62a418bcbc7ffc542136569cec30373c5cbe7fb1 release-2.5.0
62a418bcbc7ffc542136569cec30373c5cbe7fb1 release-2.5.0
0000000000000000000000000000000000000000 release-2.5.0
+0000000000000000000000000000000000000000 release-2.5.0
+10f1b29a2bd21f837090286174a9ca030b8680b2 release-2.5.0
From noreply at buildbot.pypy.org Tue Feb 3 22:09:05 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Tue, 3 Feb 2015 22:09:05 +0100 (CET)
Subject: [pypy-commit] pypy default: clean up strangeness in hgtags file
Message-ID: <20150203210905.DF8721C0820@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch:
Changeset: r75694:2ef6e6fedee6
Date: 2015-02-03 23:09 +0200
http://bitbucket.org/pypy/pypy/changeset/2ef6e6fedee6/
Log: clean up strangeness in hgtags file
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -7,15 +7,7 @@
9b623bc48b5950cf07184462a0e48f2c4df0d720 pypy-2.1-beta1-arm
ab0dd631c22015ed88e583d9fdd4c43eebf0be21 pypy-2.1-beta1-arm
20e51c4389ed4469b66bb9d6289ce0ecfc82c4b9 release-2.3.0
-20e51c4389ed4469b66bb9d6289ce0ecfc82c4b9 release-2.3.0
-0000000000000000000000000000000000000000 release-2.3.0
394146e9bb673514c61f0150ab2013ccf78e8de7 release-2.3
32f35069a16d819b58c1b6efb17c44e3e53397b2 release-2.2=3.1
32f35069a16d819b58c1b6efb17c44e3e53397b2 release-2.3.1
-32f35069a16d819b58c1b6efb17c44e3e53397b2 release-2.2=3.1
-0000000000000000000000000000000000000000 release-2.2=3.1
-62a418bcbc7ffc542136569cec30373c5cbe7fb1 release-2.5.0
-62a418bcbc7ffc542136569cec30373c5cbe7fb1 release-2.5.0
-0000000000000000000000000000000000000000 release-2.5.0
-0000000000000000000000000000000000000000 release-2.5.0
10f1b29a2bd21f837090286174a9ca030b8680b2 release-2.5.0
From noreply at buildbot.pypy.org Tue Feb 3 22:34:03 2015
From: noreply at buildbot.pypy.org (mattip)
Date: Tue, 3 Feb 2015 22:34:03 +0100 (CET)
Subject: [pypy-commit] pypy.org extradoc: create html
Message-ID: <20150203213403.304BD1C0FF4@cobra.cs.uni-duesseldorf.de>
Author: mattip
Branch: extradoc
Changeset: r565:7935f316ec12
Date: 2015-02-03 23:35 +0200
http://bitbucket.org/pypy/pypy.org/changeset/7935f316ec12/
Log: create html
diff --git a/download.html b/download.html
--- a/download.html
+++ b/download.html
@@ -76,7 +76,7 @@
miscompiled due to buildslave being old. Contributions are welcomed.
We provide binaries for x86 and ARM Linux, Mac OS/X and Windows for: