Skip to content

Commit

Permalink
anonymous class support, fix krakjoe#505 krakjoe#658 krakjoe#659
Browse files Browse the repository at this point in the history
  • Loading branch information
sirsnyder committed Jun 11, 2017
1 parent 61a5e8f commit c559473
Show file tree
Hide file tree
Showing 12 changed files with 302 additions and 62 deletions.
2 changes: 1 addition & 1 deletion examples/stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ public function synchronized(\Closure $function, $args = null) {}
* @link http://www.php.net/manual/en/threaded.wait.php
* @return bool A boolean indication of success
*/
public function wait($timeout) {}
public function wait($timeout = 0) {}
}

/**
Expand Down
7 changes: 6 additions & 1 deletion src/copy.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@ static HashTable* pthreads_copy_statics(HashTable *old) {
pthreads_store_separate(next, &copy, 1);
zend_hash_add(statics, name, &copy);
break;


case IS_CONSTANT_AST:
ZVAL_NEW_AST(&copy, zend_ast_copy(Z_AST_P(next)->ast));
zend_hash_add(statics, name, &copy);
break;

default:
zend_hash_add_empty_element(statics, name);
}
Expand Down
148 changes: 91 additions & 57 deletions src/prepare.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,30 +48,36 @@ static zend_trait_method_reference * pthreads_preparation_copy_trait_method_ref
static void pthreads_prepared_resource_dtor(zval *zv); /* }}} */

/* {{{ */
static zend_class_entry* pthreads_copy_entry(pthreads_object_t* thread, zend_class_entry *candidate) {
zend_class_entry *prepared;

if (candidate->ce_flags & ZEND_ACC_ANON_CLASS) {
if (!(candidate->ce_flags & ZEND_ACC_ANON_BOUND)) {
return NULL;
}
}

prepared = (zend_class_entry*) emalloc(sizeof(zend_class_entry));
prepared->name = zend_string_new(candidate->name);
prepared->type = candidate->type;

zend_initialize_class_data(prepared, 1);

zend_hash_index_update_ptr(&PTHREADS_ZG(resolve), (zend_ulong) candidate, prepared);
static void pthreads_prepared_entry_static_members(pthreads_object_t* thread, zend_class_entry *candidate, zend_class_entry *prepared) {
if (candidate->default_static_members_count) {
int i;

if(prepared->default_static_members_table != NULL) {
efree(prepared->default_static_members_table);
}
prepared->default_static_members_table = (zval*) ecalloc(
sizeof(zval), candidate->default_static_members_count);
prepared->default_static_members_count = candidate->default_static_members_count;
memcpy(prepared->default_static_members_table,
candidate->default_static_members_table,
sizeof(zval) * candidate->default_static_members_count);

prepared->ce_flags = candidate->ce_flags;
prepared->refcount = 1;
for (i=0; i<prepared->default_static_members_count; i++) {
pthreads_store_separate(
&candidate->default_static_members_table[i],
&prepared->default_static_members_table[i], 0);
}
prepared->static_members_table = prepared->default_static_members_table;
} else prepared->default_static_members_count = 0;
} /* }}} */

/* {{{ */
static zend_class_entry* pthreads_complete_entry(pthreads_object_t* thread, zend_class_entry *candidate, zend_class_entry *prepared, zend_bool prepare_static_members) {

if (candidate->parent) {
if (zend_hash_index_exists(&PTHREADS_ZG(resolve), (zend_ulong) candidate->parent)) {
prepared->parent = zend_hash_index_find_ptr(&PTHREADS_ZG(resolve), (zend_ulong) candidate->parent);
} else prepared->parent = pthreads_prepared_entry(thread, candidate->parent);
} else prepared->parent = pthreads_prepared_entry_internal(thread, candidate->parent, prepare_static_members);
}

if (candidate->num_interfaces) {
Expand Down Expand Up @@ -132,7 +138,7 @@ static zend_class_entry* pthreads_copy_entry(pthreads_object_t* thread, zend_cla

{
uint umethod = 0;
void *usources[7] = {
void *usources[6] = {
candidate->create_object,
candidate->serialize,
candidate->unserialize,
Expand All @@ -155,7 +161,7 @@ static zend_class_entry* pthreads_copy_entry(pthreads_object_t* thread, zend_cla
case 5: prepared->get_static_method = candidate->get_static_method; break;
}
}
} while(++umethod < 7);
} while(++umethod < 6);
}

{
Expand All @@ -164,9 +170,12 @@ static zend_class_entry* pthreads_copy_entry(pthreads_object_t* thread, zend_cla

ZEND_HASH_FOREACH_STR_KEY_PTR(&candidate->function_table, key, value) {
zend_string *name = zend_string_new(key);
value = pthreads_copy_function(value);
zend_hash_add_ptr(
&prepared->function_table, name, value);

if (!zend_hash_exists(&prepared->function_table, name)) {
value = pthreads_copy_function(value);
zend_hash_add_ptr(
&prepared->function_table, name, value);
}
zend_string_release(name);
} ZEND_HASH_FOREACH_END();
}
Expand Down Expand Up @@ -224,7 +233,7 @@ while(0)
if (info->ce) {
if (info->ce == candidate) {
dup.ce = prepared;
} else dup.ce = pthreads_prepared_entry(thread, info->ce);
} else dup.ce = pthreads_prepared_entry_internal(thread, info->ce, prepare_static_members);
}

if (!zend_hash_str_add_mem(&prepared->properties_info, name->val, name->len, &dup, sizeof(zend_property_info))) {
Expand Down Expand Up @@ -256,6 +265,10 @@ while(0)

if (candidate->default_properties_count) {
int i;

if(prepared->default_properties_table != NULL) {
efree(prepared->default_properties_table);
}
prepared->default_properties_table = emalloc(
sizeof(zval) * candidate->default_properties_count);

Expand All @@ -274,32 +287,9 @@ while(0)
prepared->default_properties_count = candidate->default_properties_count;
} else prepared->default_properties_count = 0;

if (candidate->default_static_members_count) {
int i;
prepared->default_static_members_table = (zval*) ecalloc(
sizeof(zval), candidate->default_static_members_count);
prepared->default_static_members_count = candidate->default_static_members_count;
memcpy(prepared->default_static_members_table,
candidate->default_static_members_table,
sizeof(zval) * candidate->default_static_members_count);

for (i=0; i<prepared->default_static_members_count; i++) {
pthreads_store_separate(
&candidate->default_static_members_table[i],
&prepared->default_static_members_table[i], 0);
}
prepared->static_members_table = prepared->default_static_members_table;
} else prepared->default_static_members_count = 0;

memcpy(&prepared->info.user, &candidate->info.user, sizeof(candidate->info.user));

if ((thread->options & PTHREADS_INHERIT_COMMENTS) &&
(candidate->info.user.doc_comment)) {
prepared->info.user.doc_comment = zend_string_new(candidate->info.user.doc_comment);
} else prepared->info.user.doc_comment = NULL;

if (prepared->info.user.filename)
prepared->info.user.filename = zend_string_new(candidate->info.user.filename);
if(prepare_static_members) {
pthreads_prepared_entry_static_members(thread, candidate, prepared);
}

{
zend_string *key;
Expand Down Expand Up @@ -352,6 +342,35 @@ while(0)
return prepared;
} /* }}} */

/* {{{ */
static zend_class_entry* pthreads_copy_entry(pthreads_object_t* thread, zend_class_entry *candidate, zend_bool prepare_static_members) {
zend_class_entry *prepared;

prepared = (zend_class_entry*) emalloc(sizeof(zend_class_entry));
prepared->name = zend_string_new(candidate->name);
prepared->type = candidate->type;

zend_initialize_class_data(prepared, 1);

zend_hash_index_update_ptr(&PTHREADS_ZG(resolve), (zend_ulong) candidate, prepared);

prepared->ce_flags = candidate->ce_flags;
prepared->refcount = 1;

memcpy(&prepared->info.user, &candidate->info.user, sizeof(candidate->info.user));

if ((thread->options & PTHREADS_INHERIT_COMMENTS) &&
(candidate->info.user.doc_comment)) {
prepared->info.user.doc_comment = zend_string_new(candidate->info.user.doc_comment);
} else prepared->info.user.doc_comment = NULL;

if (prepared->info.user.filename) {
prepared->info.user.filename = zend_string_new(candidate->info.user.filename);
}

return pthreads_complete_entry(thread, candidate, prepared, prepare_static_members);
} /* }}} */

/* {{{ */
static inline int pthreads_prepared_entry_function_prepare(zval *bucket, int argc, va_list argv, zend_hash_key *key) {
zend_function *function = (zend_function*) Z_PTR_P(bucket);
Expand Down Expand Up @@ -383,6 +402,11 @@ static inline int pthreads_prepared_entry_function_prepare(zval *bucket, int arg

/* {{{ */
zend_class_entry* pthreads_prepared_entry(pthreads_object_t* thread, zend_class_entry *candidate) {
return pthreads_prepared_entry_internal(thread, candidate, 1);
} /* }}} */

/* {{{ */
zend_class_entry* pthreads_prepared_entry_internal(pthreads_object_t* thread, zend_class_entry *candidate, zend_bool prepare_static_members) {
zend_class_entry *prepared = NULL;
zend_string *lookup = NULL;

Expand All @@ -398,10 +422,14 @@ zend_class_entry* pthreads_prepared_entry(pthreads_object_t* thread, zend_class_

if ((prepared = zend_hash_find_ptr(EG(class_table), lookup))) {
zend_string_release(lookup);

if(prepared->create_object == NULL && candidate->create_object != NULL) {
return pthreads_complete_entry(thread, candidate, prepared, prepare_static_members);
}
return prepared;
}

if (!(prepared = pthreads_copy_entry(thread, candidate))) {
if (!(prepared = pthreads_copy_entry(thread, candidate, prepare_static_members))) {
zend_string_release(lookup);
return NULL;
}
Expand Down Expand Up @@ -577,12 +605,18 @@ static inline void pthreads_prepare_closures(pthreads_object_t *thread) {
static inline void pthreads_prepare_classes(pthreads_object_t* thread) {
zend_class_entry *entry;
zend_string *name;

ZEND_HASH_FOREACH_STR_KEY_PTR(PTHREADS_CG(thread->creator.ls, class_table), name, entry) {
if (!zend_hash_exists(PTHREADS_CG(thread->local.ls, class_table), name)) {
pthreads_prepared_entry(thread, entry);
pthreads_prepared_entry_internal(thread, entry, 0);
}
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();

ZEND_HASH_FOREACH_STR_KEY_PTR(PTHREADS_CG(thread->local.ls, class_table), name, entry) {
if (entry->type != ZEND_INTERNAL_CLASS) {
pthreads_prepared_entry_static_members(thread, zend_hash_find_ptr(PTHREADS_CG(thread->creator.ls, class_table), name), entry);
}
} ZEND_HASH_FOREACH_END();
} /* }}} */

/* {{{ */
Expand Down Expand Up @@ -651,7 +685,7 @@ void pthreads_prepare_parent(pthreads_object_t *thread) {
pthreads_rebuild_object(&EG(user_exception_handler));
} /* }}} */

#if PHP_VERSION_ID >= 70100
#if PHP_VERSION_ID < 70200 && PHP_VERSION_ID >= 70100
/*
It doesn't seem right that I should have to do this ... think bug in php-src
*/
Expand All @@ -678,7 +712,7 @@ int pthreads_prepared_startup(pthreads_object_t* thread, pthreads_monitor_t *rea

php_request_startup();

#if PHP_VERSION_ID >= 70100
#if PHP_VERSION_ID < 70200 && PHP_VERSION_ID >= 70100
pthreads_prepare_compiler(thread);
#endif

Expand Down
3 changes: 3 additions & 0 deletions src/prepare.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
/* {{{ fetch prepared class entry */
zend_class_entry* pthreads_prepared_entry(pthreads_object_t* thread, zend_class_entry *candidate); /* }}} */

/* {{{ fetch prepared class entry */
zend_class_entry* pthreads_prepared_entry_internal(pthreads_object_t* thread, zend_class_entry *candidate, zend_bool prepare_static_members); /* }}} */

/* {{{ */
void pthreads_prepare_parent(pthreads_object_t *thread); /* }}} */

Expand Down
2 changes: 1 addition & 1 deletion src/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ void pthreads_socket_select(zval *read, zval *write, zval *except, uint32_t sec,

void pthreads_socket_free(pthreads_socket_t *socket, zend_bool closing) {
if (closing) {
if (socket->fd > -1)
if (socket->fd)
close(socket->fd);
}

Expand Down
7 changes: 5 additions & 2 deletions src/store.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,8 @@ int pthreads_store_write(zval *object, zval *key, zval *write) {

if (zend_hash_update_ptr(threaded->store.props, keyed, storage)) {
result = SUCCESS;
} else zend_string_release(keyed);
}
else zend_string_release(keyed);
}
}
pthreads_monitor_unlock(threaded->monitor);
Expand All @@ -351,14 +352,16 @@ int pthreads_store_write(zval *object, zval *key, zval *write) {
normal refcounting, we'll just never read the reference
*/
rebuild_object_properties(&threaded->std);

if (Z_TYPE(member) == IS_LONG) {
zend_hash_index_update(threaded->std.properties, Z_LVAL(member), write);
} else {
zend_string *keyed = zend_string_dup(Z_STR(member), 1);
if (zend_hash_update(
threaded->std.properties, keyed, write)) {
result = SUCCESS;
} else zend_string_release(keyed);
}
else zend_string_release(keyed);
}
Z_ADDREF_P(write);
}
Expand Down
29 changes: 29 additions & 0 deletions tests/class-static-properties-order-dependencies-inheritance.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--TEST--
Testing inherited class statics properties and dependencies (gh bug #666)
--DESCRIPTION--
If a inherited static property holds a reference to a threaded object, the order of class definition is important.
--FILE--
<?php

class SecondClass extends FirstClass {}
class FirstClass extends \Threaded
{
public static $prop = [];
}

FirstClass::$prop[] = new SecondClass();

$thread = new class extends Thread {
public function run() {
var_dump(FirstClass::$prop);
}
};

$thread->start() && $thread->join();
--EXPECT--
array(1) {
[0]=>
object(SecondClass)#1 (0) {
}
}

29 changes: 29 additions & 0 deletions tests/class-static-properties-order-dependencies.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--TEST--
Testing class statics properties and dependencies (gh bug #666)
--DESCRIPTION--
If a static property holds a reference to a threaded object, the order of class definition is important.
--FILE--
<?php
class FirstClass extends \Threaded
{
public static $prop = [];
}

class SecondClass extends \Threaded {}

FirstClass::$prop[] = new SecondClass();

$thread = new class extends Thread {
public function run() {
var_dump(FirstClass::$prop);
}
};

$thread->start() && $thread->join();
--EXPECT--
array(1) {
[0]=>
object(SecondClass)#1 (0) {
}
}

Loading

0 comments on commit c559473

Please sign in to comment.