MutableSlice StringData::reserve(int cap) { assert(!isImmutable() && m_count <= 1 && cap >= 0); if (cap + 1 <= capacity()) return mutableSlice(); switch (mode()) { default: assert(false); case Mode::Small: m_data = (char*) smart_malloc(cap + 1); memcpy(m_data, m_small, m_len + 1); // includes \0 setModeAndCap(Mode::Smart, cap + 1); break; case Mode::Smart: // We only use geometric growth when we're heading to the smart // allocator. This is mostly because it was what was tested as // a perf win, but it might make sense to do it for Mode::Malloc // as well. Will be revisited soon. cap += cap >> 2; m_data = (char*) smart_realloc(m_data, cap + 1); setModeAndCap(Mode::Smart, cap + 1); break; case Mode::Malloc: m_data = (char*) realloc(m_data, cap + 1); setModeAndCap(Mode::Malloc, cap + 1); break; } return MutableSlice(m_data, cap); }
ZendCustomElement::ZendCustomElement(void* data_, unsigned data_size, DtorFunc destructor) : m_destructor(destructor) { m_data = smart_malloc(data_size); memcpy(m_data, data_, data_size); }
// Convert the typical getopt input characters to the php_getopt struct array static int parse_opts(const char * opts, int opts_len, opt_struct **result) { int count = 0; for (int i = 0; i < opts_len; i++) { if ((opts[i] >= 48 && opts[i] <= 57) || (opts[i] >= 65 && opts[i] <= 90) || (opts[i] >= 97 && opts[i] <= 122)) { count++; } } opt_struct *paras = (opt_struct *)smart_malloc(sizeof(opt_struct) * count); memset(paras, 0, sizeof(opt_struct) * count); *result = paras; while ((*opts >= 48 && *opts <= 57) || /* 0 - 9 */ (*opts >= 65 && *opts <= 90) || /* A - Z */ (*opts >= 97 && *opts <= 122)) { /* a - z */ paras->opt_char = *opts; paras->need_param = (*(++opts) == ':') ? 1 : 0; paras->opt_name = NULL; if (paras->need_param == 1) { opts++; if (*opts == ':') { paras->need_param++; opts++; } } paras++; } return count; }
inline void* MemoryManager::smartRealloc(void* inputPtr, size_t nbytes) { FTRACE(1, "smartRealloc: {} to {}\n", inputPtr, nbytes); assert(nbytes > 0); void* ptr = debug ? static_cast<DebugHeader*>(inputPtr) - 1 : inputPtr; auto const n = static_cast<SweepNode*>(ptr) - 1; if (LIKELY(n->padbytes <= kMaxSmartSize)) { void* newmem = smart_malloc(nbytes); auto const copySize = std::min( n->padbytes - sizeof(SmallNode) - (debug ? sizeof(DebugHeader) : 0), nbytes ); newmem = memcpy(newmem, inputPtr, copySize); smart_free(inputPtr); return newmem; } // Ok, it's a big allocation. Since we don't know how big it is // (i.e. how much data we should memcpy), we have no choice but to // ask malloc to realloc for us. auto const oldNext = n->next; auto const oldPrev = n->prev; auto const newNode = static_cast<SweepNode*>( realloc(n, debugAddExtra(nbytes + sizeof(SweepNode))) ); refreshStatsHelper(); if (newNode != n) { oldNext->prev = oldPrev->next = newNode; } return debugPostAllocate(newNode + 1, 0, 0); }
inline void* MemoryManager::smartRealloc(void* ptr, size_t nbytes) { FTRACE(3, "smartRealloc: {} to {}\n", ptr, nbytes); assert(nbytes > 0); auto const n = static_cast<MallocNode*>(ptr) - 1; if (LIKELY(n->small.padbytes <= kMaxSmartSize)) { void* newmem = smart_malloc(nbytes); auto const copySize = std::min( n->small.padbytes - sizeof(SmallNode), nbytes ); newmem = memcpy(newmem, ptr, copySize); smart_free(ptr); return newmem; } // Ok, it's a big allocation. Since we don't know how big it is // (i.e. how much data we should memcpy), we have no choice but to // ask malloc to realloc for us. auto const oldNext = n->big.next; auto const oldPrev = n->big.prev; auto const newNode = static_cast<BigNode*>( safe_realloc(n, nbytes + sizeof(BigNode)) ); refreshStats(); if (newNode != &n->big) { oldNext->prev = oldPrev->next = newNode; } return newNode + 1; }
void* smart_calloc(size_t count, size_t nbytes) { auto& mm = MM(); auto const totalBytes = std::max<size_t>(count * nbytes, 1); if (totalBytes <= kMaxSmartSize) { return memset(smart_malloc(totalBytes), 0, totalBytes); } return mm.smartCallocBig(totalBytes); }
char* smart_concat(const char* s1, uint32_t len1, const char* s2, uint32_t len2) { uint32_t len = len1 + len2; char* s = (char*)smart_malloc(len + 1); memcpy(s, s1, len1); memcpy(s + len1, s2, len2); s[len] = 0; return s; }
c_AwaitAllWaitHandle* c_AwaitAllWaitHandle::Alloc(int32_t cnt) { auto size = sizeof(c_AwaitAllWaitHandle) + cnt * sizeof(c_WaitableWaitHandle*); auto mem = smart_malloc(size); auto const waitHandle = new (mem) c_AwaitAllWaitHandle(); waitHandle->m_cur = cnt - 1; return waitHandle; }
void* smart_realloc(void* ptr, size_t nbytes) { auto& mm = MM(); if (!ptr) return smart_malloc(nbytes); if (!nbytes) { smart_free(ptr); return nullptr; } return mm.smartRealloc(ptr, nbytes); }
iter_t list_insert(list *plist, iter_t pwhere, void* pdata){ ++plist->m_size; iter_t new_item = smart_malloc(sizeof(list_node)); new_item->m_pdata = pdata; new_item->m_next = pwhere; new_item->m_prev = pwhere->m_prev; new_item->m_next->m_prev = new_item; new_item->m_prev->m_next = new_item; return new_item; }
void* smart_calloc(size_t count, size_t nbytes) { auto& mm = MM(); auto const totalBytes = std::max<size_t>(count * nbytes, 1); if (totalBytes <= kMaxSmartSize) { return memset(smart_malloc(totalBytes), 0, totalBytes); } auto const withExtra = mm.debugAddExtra(totalBytes); return mm.debugPostAllocate( mm.smartCallocBig(withExtra), 0, 0 ); }
void BaseVector::cow() { TypedValue* newData = (TypedValue*)smart_malloc(m_capacity * sizeof(TypedValue)); assert(newData); for (uint i = 0; i < m_size; i++) { cellDup(m_data[i], newData[i]); } m_data = newData; m_frozenCopy.reset(); }
static String HHVM_FUNCTION(get_current_user) { int pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); if (pwbuflen < 1) { return ""; } char *pwbuf = (char*)smart_malloc(pwbuflen); struct passwd pw; struct passwd *retpwptr = NULL; if (getpwuid_r(getuid(), &pw, pwbuf, pwbuflen, &retpwptr) != 0) { smart_free(pwbuf); return ""; } String ret(pw.pw_name, CopyString); smart_free(pwbuf); return ret; }
void VectorArray::alloc(uint size) { if (size <= FixedSize) { m_capacity = FixedSize; m_elems = m_fixed; m_allocMode = kInline; return; } uint cap = Util::nextPower2(size); m_capacity = cap; if (!m_nonsmart) { m_elems = (TypedValue*) smart_malloc(cap * sizeof(TypedValue)); m_allocMode = kSmart; } else { m_elems = (TypedValue*) malloc(cap * sizeof(TypedValue)); m_allocMode = kMalloc; } }
/* * Change to smart-malloced string. Then returns a mutable slice of * the usable string buffer (minus space for the null terminator). */ MutableSlice StringData::escalate(uint32_t cap) { assert(isShared() && !isStatic() && cap >= m_len); char *buf = (char*)smart_malloc(cap + 1); StringSlice s = slice(); memcpy(buf, s.ptr, s.len); buf[s.len] = 0; m_big.shared->decRef(); delist(); m_data = buf; setModeAndCap(Mode::Smart, cap + 1); // clear precomputed hashcode m_hash = 0; assert(checkSane()); return MutableSlice(buf, cap); }
// make an empty string with cap reserve bytes, plus one more for \0 HOT_FUNC StringData::StringData(int cap) { m_hash = 0; m_count = 0; if (uint32_t(cap) <= MaxSmallSize) { m_len = 0; m_data = m_small; m_small[0] = 0; setSmall(); } else { if (UNLIKELY(uint32_t(cap) > MaxSize)) { throw InvalidArgumentException("len > 2^31-2", cap); } m_len = 0; m_data = (char*) smart_malloc(cap + 1); m_data[0] = 0; setModeAndCap(Mode::Smart, cap + 1); } }
inline void* MemoryManager::smartRealloc(void* ptr, size_t nbytes) { FTRACE(3, "smartRealloc: {} to {}\n", ptr, nbytes); assert(nbytes > 0); auto const n = static_cast<MallocNode*>(ptr) - 1; if (LIKELY(n->small.padbytes <= kMaxSmartSize)) { void* newmem = smart_malloc(nbytes); auto const copySize = std::min( n->small.padbytes - sizeof(SmallNode), nbytes ); newmem = memcpy(newmem, ptr, copySize); smart_free(ptr); return newmem; } // Ok, it's a big allocation. auto block = m_heap.resizeBig(ptr, nbytes); refreshStats(); return block.ptr; }
String StringUtil::Implode(const Variant& items, const String& delim) { if (!isContainer(items)) { throw_param_is_not_container(); } int size = getContainerSize(items); if (size == 0) return ""; String* sitems = (String*)smart_malloc(size * sizeof(String)); int len = 0; int lenDelim = delim.size(); int i = 0; for (ArrayIter iter(items); iter; ++iter) { new (&sitems[i]) String(iter.second().toString()); len += sitems[i].size() + lenDelim; i++; } len -= lenDelim; // always one delimiter less than count of items assert(i == size); String s = String(len, ReserveString); char *buffer = s.bufferSlice().ptr; const char *sdelim = delim.data(); char *p = buffer; for (int i = 0; i < size; i++) { String &item = sitems[i]; if (i && lenDelim) { memcpy(p, sdelim, lenDelim); p += lenDelim; } int lenItem = item.size(); if (lenItem) { memcpy(p, item.data(), lenItem); p += lenItem; } sitems[i].~String(); } smart_free(sitems); assert(p - buffer == len); s.setSize(len); return s; }
void StringBuffer::printf(const char *format, ...) { va_list ap; va_start(ap, format); bool printed = false; for (int len = 1024; !printed; len <<= 1) { va_list v; va_copy(v, ap); char *buf = (char*)smart_malloc(len); if (vsnprintf(buf, len, format, v) < len) { append(buf); printed = true; } smart_free(buf); va_end(v); } va_end(ap); }
void VectorArray::grow(uint newSize) { assert(newSize > FixedSize); m_capacity = Util::nextPower2(newSize); if (!m_nonsmart) { assert(m_allocMode == kInline || m_allocMode == kSmart); if (m_allocMode == kInline) { m_elems = (TypedValue*)smart_malloc(m_capacity * sizeof(TypedValue)); memcpy(m_elems, m_fixed, m_size * sizeof(TypedValue)); m_allocMode = kSmart; } else { m_elems = (TypedValue*)smart_realloc(m_elems, m_capacity * sizeof(TypedValue)); } } else if (m_allocMode == kInline) { m_elems = (TypedValue*)malloc(m_capacity * sizeof(TypedValue)); memcpy(m_elems, m_fixed, m_size * sizeof(TypedValue)); m_allocMode = kMalloc; } else { assert(m_allocMode == kMalloc); m_elems = (TypedValue*)realloc(m_elems, m_capacity * sizeof(TypedValue)); } }
HOT_FUNC void StringData::initCopy(const char* data, int len) { if (uint32_t(len) > MaxSize) { throw InvalidArgumentException("len > 2^31-2", len); } m_hash = 0; m_count = 0; if (uint32_t(len) <= MaxSmallSize) { memcpy(m_small, data, len); m_len = len; m_data = m_small; m_small[len] = 0; setSmall(); } else { char *buf = (char*)smart_malloc(len + 1); memcpy(buf, data, len); buf[len] = 0; m_len = len; m_cdata = buf; setModeAndCap(Mode::Smart, len + 1); } assert(checkSane()); }
static Variant HHVM_FUNCTION(gmp_strval, const Variant& data, const int64_t base /* = 10 */) { mpz_t gmpData; if (base < GMP_MIN_BASE || (base > -2 && base < 2) || base > GMP_MAX_BASE) { raise_warning(cs_GMP_INVALID_BASE_VALUE, cs_GMP_FUNC_NAME_GMP_STRVAL, base, GMP_MAX_BASE); return false; } if (!variantToGMPData(cs_GMP_FUNC_NAME_GMP_STRVAL, gmpData, data, base)) { return false; } int charLength = mpz_sizeinbase(gmpData, abs(base)) + 1; if (mpz_sgn(gmpData) < 0) { ++charLength; } char *charStr = (char*) smart_malloc(charLength); if (!mpz_get_str(charStr, base, gmpData)) { smart_free(charStr); mpz_clear(gmpData); return false; } String returnValue(charStr); smart_free(charStr); mpz_clear(gmpData); return returnValue; }
static Array HHVM_FUNCTION(getopt, const String& options, const Variant& longopts /*=null */) { opt_struct *opts, *orig_opts; int len = parse_opts(options.data(), options.size(), &opts); if (!longopts.isNull()) { Array arropts = longopts.toArray(); int count = arropts.size(); /* the first <len> slots are filled by the one short ops * we now extend our array and jump to the new added structs */ opts = (opt_struct *)smart_realloc( opts, sizeof(opt_struct) * (len + count + 1)); orig_opts = opts; opts += len; memset(opts, 0, count * sizeof(opt_struct)); for (ArrayIter iter(arropts); iter; ++iter) { String entry = iter.second().toString(); opts->need_param = 0; opts->opt_name = strdup(entry.data()); len = strlen(opts->opt_name); if ((len > 0) && (opts->opt_name[len - 1] == ':')) { opts->need_param++; opts->opt_name[len - 1] = '\0'; if ((len > 1) && (opts->opt_name[len - 2] == ':')) { opts->need_param++; opts->opt_name[len - 2] = '\0'; } } opts->opt_char = 0; opts++; } } else { opts = (opt_struct*) smart_realloc(opts, sizeof(opt_struct) * (len + 1)); orig_opts = opts; opts += len; } /* php_getopt want to identify the last param */ opts->opt_char = '-'; opts->need_param = 0; opts->opt_name = NULL; static const StaticString s_argv("argv"); Array vargv = php_global(s_argv).toArray(); int argc = vargv.size(); char **argv = (char **)smart_malloc((argc+1) * sizeof(char*)); std::vector<String> holders; int index = 0; for (ArrayIter iter(vargv); iter; ++iter) { String arg = iter.second().toString(); holders.push_back(arg); argv[index++] = (char*)arg.data(); } argv[index] = NULL; /* after our pointer arithmetic jump back to the first element */ opts = orig_opts; int o; char *php_optarg = NULL; int php_optind = 1; SCOPE_EXIT { free_longopts(orig_opts); smart_free(orig_opts); smart_free(argv); }; Array ret = Array::Create(); Variant val; int optchr = 0; int dash = 0; /* have already seen the - */ char opt[2] = { '\0' }; char *optname; int optname_len = 0; int php_optidx; while ((o = php_getopt(argc, argv, opts, &php_optarg, &php_optind, 0, 1, optchr, dash, php_optidx)) != -1) { /* Skip unknown arguments. */ if (o == '?') { continue; } /* Prepare the option character and the argument string. */ if (o == 0) { optname = opts[php_optidx].opt_name; } else { if (o == 1) { o = '-'; } opt[0] = o; optname = opt; } if (php_optarg != NULL) { /* keep the arg as binary, since the encoding is not known */ val = String(php_optarg, CopyString); } else { val = false; } /* Add this option / argument pair to the result hash. */ optname_len = strlen(optname); if (!(optname_len > 1 && optname[0] == '0') && is_numeric_string(optname, optname_len, NULL, NULL, 0) == KindOfInt64) { /* numeric string */ int optname_int = atoi(optname); if (ret.exists(optname_int)) { Variant &e = ret.lvalAt(optname_int); if (!e.isArray()) { ret.set(optname_int, make_packed_array(e, val)); } else { e.toArrRef().append(val); } } else { ret.set(optname_int, val); } } else { /* other strings */ String key(optname, strlen(optname), CopyString); if (ret.exists(key)) { Variant &e = ret.lvalAt(key); if (!e.isArray()) { ret.set(key, make_packed_array(e, val)); } else { e.toArrRef().append(val); } } else { ret.set(key, val); } } php_optarg = NULL; } return ret; }
static bool HHVM_METHOD(Collator, sortWithSortKeys, VRefParam arr) { FETCH_COL(data, this_, false); data->clearError(); if (!arr.isArray()) { return true; } Array hash = arr.toArray(); if (hash.size() == 0) { return true; } // Preallocate sort keys buffer size_t sortKeysOffset = 0; size_t sortKeysLength = DEF_SORT_KEYS_BUF_SIZE; char* sortKeys = (char*)smart_malloc(sortKeysLength); if (!sortKeys) { throw Exception("Out of memory"); } SCOPE_EXIT{ smart_free(sortKeys); }; // Preallocate index buffer size_t sortIndexPos = 0; size_t sortIndexLength = DEF_SORT_KEYS_INDX_BUF_SIZE; auto sortIndex = (collator_sort_key_index_t*)smart_malloc( sortIndexLength * sizeof(collator_sort_key_index_t)); if (!sortIndex) { throw Exception("Out of memory"); } SCOPE_EXIT{ smart_free(sortIndex); }; // Translate input hash to sortable index auto pos_limit = hash->iter_end(); for (ssize_t pos = hash->iter_begin(); pos != pos_limit; pos = hash->iter_advance(pos)) { Variant val(hash->getValue(pos)); // Convert to UTF16 icu::UnicodeString strval; if (val.isString()) { UErrorCode error = U_ZERO_ERROR; strval = u16(val.toString(), error); if (U_FAILURE(error)) { return false; } } // Generate sort key int sortkey_len = ucol_getSortKey(data->collator(), strval.getBuffer(), strval.length(), (uint8_t*)(sortKeys + sortKeysOffset), sortKeysLength - sortKeysOffset); // Check for key buffer overflow if (sortkey_len > (sortKeysLength - sortKeysOffset)) { int32_t inc = (sortkey_len > DEF_SORT_KEYS_BUF_INCREMENT) ? sortkey_len : DEF_SORT_KEYS_BUF_INCREMENT; sortKeysLength += inc; sortKeys = (char*)smart_realloc(sortKeys, sortKeysLength); if (!sortKeys) { throw Exception("Out of memory"); } sortkey_len = ucol_getSortKey(data->collator(), strval.getBuffer(), strval.length(), (uint8_t*)(sortKeys + sortKeysOffset), sortKeysLength - sortKeysOffset); assert(sortkey_len <= (sortKeysLength - sortKeysOffset)); } // Check for index buffer overflow if ((sortIndexPos + 1) > sortIndexLength) { sortIndexLength += DEF_SORT_KEYS_INDX_BUF_INCREMENT; sortIndex = (collator_sort_key_index_t*)smart_realloc(sortIndex, sortIndexLength * sizeof(collator_sort_key_index_t)); if (!sortIndex) { throw Exception("Out of memory"); } } // Initially store offset into buffer, update later to deal with reallocs sortIndex[sortIndexPos].key = (char*)sortKeysOffset; sortKeysOffset += sortkey_len; sortIndex[sortIndexPos].valPos = pos; ++sortIndexPos; } // Update keys to location in realloc'd buffer for (int i = 0; i < sortIndexPos; ++i) { sortIndex[i].key = sortKeys + (ptrdiff_t)sortIndex[i].key; } zend_qsort(sortIndex, sortIndexPos, sizeof(collator_sort_key_index_t), collator_cmp_sort_keys, nullptr); Array ret = Array::Create(); for (int i = 0; i < sortIndexPos; ++i) { ret.append(hash->getValue(sortIndex[i].valPos)); } arr = ret; return true; }
static void *php_xml_malloc_wrapper(size_t sz) { return smart_malloc(sz); }
static double collator_u_strtod(const UChar *nptr, UChar **endptr) { const UChar *u = nptr, *nstart; UChar c = *u; int any = 0; while (u_isspace(c)) { c = *++u; } nstart = u; if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) { c = *++u; } while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) { any = 1; c = *++u; } if (c == 0x2E /*'.'*/) { c = *++u; while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) { any = 1; c = *++u; } } if ((c == 0x65 /*'e'*/ || c == 0x45 /*'E'*/) && any) { const UChar *e = u; int any_exp = 0; c = *++u; if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) { c = *++u; } while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) { any_exp = 1; c = *++u; } if (!any_exp) { u = e; } } if (any) { char buf[64], *numbuf, *bufpos; int length = u - nstart; double value; if (length < (int)sizeof(buf)) { numbuf = buf; } else { numbuf = (char *) smart_malloc(length + 1); } bufpos = numbuf; while (nstart < u) { *bufpos++ = (char) *nstart++; } *bufpos = '\0'; value = zend_strtod(numbuf, nullptr); if (numbuf != buf) { smart_free(numbuf); } if (endptr != nullptr) { *endptr = (UChar *)u; } return value; } if (endptr != nullptr) { *endptr = (UChar *)nptr; } return 0; }