Object c_GenArrayWaitHandle::ti_create(const char* cls, CArrRef dependencies) { Array deps = dependencies->copy(); for (ssize_t iter_pos = deps->iter_begin(); iter_pos != ArrayData::invalid_index; iter_pos = deps->iter_advance(iter_pos)) { TypedValue* current = deps->nvGetValueRef(iter_pos); if (UNLIKELY(current->m_type == KindOfRef)) { tvUnbox(current); } if (!c_WaitHandle::fromTypedValue(current) && !IS_NULL_TYPE(current->m_type)) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be an array of WaitHandle instances")); throw e; } } Object exception; for (ssize_t iter_pos = deps->iter_begin(); iter_pos != ArrayData::invalid_index; iter_pos = deps->iter_advance(iter_pos)) { TypedValue* current = deps->nvGetValueRef(iter_pos); if (IS_NULL_TYPE(current->m_type)) { // {uninit,null} yields null tvWriteNull(current); continue; } assert(current->m_type == KindOfObject); assert(dynamic_cast<c_WaitHandle*>(current->m_data.pobj)); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { tvSetIgnoreRef(child->getResult(), current); } else if (child->isFailed()) { putException(exception, child->getException()); } else { assert(dynamic_cast<c_WaitableWaitHandle*>(child)); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); c_GenArrayWaitHandle* my_wh = NEWOBJ(c_GenArrayWaitHandle)(); my_wh->initialize(exception, deps, iter_pos, child_wh); return my_wh; } } if (exception.isNull()) { TypedValue tv; tv.m_type = KindOfArray; tv.m_data.parr = deps.get(); return c_StaticResultWaitHandle::Create(&tv); } else { return c_StaticExceptionWaitHandle::Create(exception.get()); } }
TypedValue* zend_wrap_func(ActRec* ar) { // Sync the translator state. // We need to do this before a native function calls into a C library // compiled with -fomit-frame-pointer with the intention of having it call // back. Normal HHVM extensions have the luxury of only when such a thing // will be attempted, but we have no way to know in advance. VMRegAnchor _; TSRMLS_FETCH(); zend_ext_func native_func = reinterpret_cast<zend_ext_func>(ar->func()->nativeFuncPtr()); // Using Variant so exceptions will decref them Variant return_value_var(Variant::NullInit{}); auto const return_value = return_value_var.asTypedValue(); tvBox(return_value); Variant this_ptr_var(Variant::NullInit{}); auto const this_ptr = this_ptr_var.asTypedValue(); tvBox(this_ptr); if (ar->func()->cls() && ar->hasThis()) { tvWriteObject( ar->getThis(), this_ptr->m_data.pref->tv() ); } auto *return_value_ptr = &return_value->m_data.pref; // Clear any stored exception zend_clear_exception(TSRMLS_C); // Invoke the PHP extension function/method ZendExecutionStack::pushHHVMStack((void*)ar); try { native_func( ar->numArgs(), return_value->m_data.pref, return_value_ptr, this_ptr_var.isNull() ? nullptr : this_ptr->m_data.pref, 1 TSRMLS_CC ); } catch (...) { zend_wrap_func_cleanup(); throw; } zend_wrap_func_cleanup(); // If an exception was caught, rethrow it ZendExceptionStore& exceptionStore = ZendExceptionStore::getInstance(); if (!exceptionStore.empty()) { exceptionStore.rethrow(); } // Take care of freeing the args, tearing down the ActRec, and moving the // return value to the right place. Note that frame_free_locals expects to // be able to free return_value in the event of an exception, so we have to // take it out of our Variant /before/ calling that. TypedValue return_value_copy = *return_value; return_value->m_type = KindOfNull; // clear the Variant's copy frame_free_locals_inl(ar, ar->func()->numLocals(), &return_value_copy); memcpy(&ar->m_r, &return_value_copy, sizeof(TypedValue)); if (ar->func()->isReturnRef()) { if (!ar->m_r.m_data.pref->isReferenced()) { tvUnbox(&ar->m_r); } } else { tvUnbox(&ar->m_r); } return &ar->m_r; }
TypedValue* zend_wrap_func( ActRec* ar, zend_ext_func builtin_func, int numParams, bool isReturnRef) { TSRMLS_FETCH(); // Prepare the arguments and return value before they are // exposed to the PHP extension zPrepArgs(ar); // Using Variant so exceptions will decref them Variant return_value_var(Variant::NullInit{}); auto const return_value = return_value_var.asTypedValue(); tvBox(return_value); Variant this_ptr_var(Variant::NullInit{}); auto const this_ptr = this_ptr_var.asTypedValue(); tvBox(this_ptr); if (ar->hasThis()) { tvWriteObject( ar->getThis(), this_ptr->m_data.pref->tv() ); } auto *return_value_ptr = &return_value->m_data.pref; // Clear any stored exception ZendExceptionStore& exceptionStore = ZendExceptionStore::getInstance(); exceptionStore.clear(); // Invoke the PHP extension function/method ZendExecutionStack::pushHHVMStack(); try { builtin_func( ar->numArgs(), return_value->m_data.pref, return_value_ptr, this_ptr_var.isNull() ? nullptr : this_ptr->m_data.pref, 1 TSRMLS_CC ); } catch (...) { ZendExecutionStack::popHHVMStack(); throw; } ZendExecutionStack::popHHVMStack(); // If an exception was caught, rethrow it if (!exceptionStore.empty()) { exceptionStore.rethrow(); } // Take care of freeing the args, tearing down the ActRec, // and moving the return value to the right place frame_free_locals_inl(ar, numParams); memcpy(&ar->m_r, return_value, sizeof(TypedValue)); return_value->m_type = KindOfNull; if (isReturnRef) { if (!ar->m_r.m_data.pref->isReferenced()) { tvUnbox(&ar->m_r); } } else { tvUnbox(&ar->m_r); } return &ar->m_r; }
inline void tvUnboxIfNeeded(TypedValue *tv) { if (tv->m_type == KindOfRef) { tvUnbox(tv); } }